Skip to content

Commit 8c599b2

Browse files
committed
Merge resolveEntryPaths into resolveConfig
1 parent fd5ef3e commit 8c599b2

File tree

47 files changed

+249
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+249
-266
lines changed

packages/docs/src/content/docs/guides/writing-a-plugin.md

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,14 @@ Compared to the first example, this plugin has two new variables:
139139
### 5. `config`
140140

141141
The `config` array contains all possible locations of the config file for the
142-
tool. Knip loads matching files and passes the results (i.e. what resolves as
143-
the default export) into the `resolveConfig` function:
142+
tool. Knip loads matching files and passes the results (i.e. its default export)
143+
into the `resolveConfig` function:
144144

145145
### 6. `resolveConfig`
146146

147-
This function receives the exported value of the `config` files, and executes
148-
the `resolveConfig` function with this object. The plugin should return the
149-
dependencies referenced in this object.
147+
This function receives the exported value of the `config` file, and executes the
148+
`resolveConfig` function with this object. The plugin should return the entry
149+
paths and dependencies referenced in this object.
150150

151151
Knip supports JSON, YAML, TOML, JavaScript and TypeScript config files. Files
152152
without an extension are provided as plain text strings.
@@ -155,49 +155,43 @@ without an extension are provided as plain text strings.
155155

156156
You should implement `resolveConfig` if any of these are true:
157157

158-
- The tool supports a `config` file in JSON or YAML format
158+
- The `config` file contains one or more options that represent [entry
159+
points][2]
159160
- The `config` file references dependencies by strings (not import statements)
160161

161162
:::
162163

163-
## Example 3: custom entry paths
164+
## Example 3: entry paths
164165

165166
Some tools operate mostly on entry files, some examples:
166167

167168
- Mocha looks for test files at `test/*.{js,cjs,mjs}`
168169
- Storybook looks for stories at `*.stories.@(mdx|js|jsx|tsx)`
169170

170171
And some of those tools allow to configure those locations and patterns. If
171-
that's the case, than we can define `resolveEntryPaths` in our plugin to take
172-
this from the configuration object and return it to Knip:
172+
that's the case we can define `resolveConfig` in our plugin to take this from
173+
the configuration object and return it to Knip:
173174

174-
### 7. resolveEntryPaths
175-
176-
Here's an example from the Preconstruct plugin:
175+
Here's an example from the Mocha plugin:
177176

178177
```ts
179-
const resolveEntryPaths: ResolveConfig<PreconstructConfig> = async config => {
180-
return (config.entrypoints ?? []).map(id => toEntry(id));
178+
const entry = ['**/test/*.{js,cjs,mjs}'];
179+
180+
const resolveConfig: ResolveConfig<MochaConfig> = localConfig => {
181+
const entryPatterns = localConfig.spec ? [localConfig.spec].flat() : entry;
182+
return entryPatterns.map(id => toEntry(id));
181183
};
182184
```
183185

184-
With Preconstruct, you can configure `entrypoints`. If this function is
185-
implemented in a plugin, Knip will use its return value over the default `entry`
186-
patterns. The result is that you don't need to duplicate this customization in
187-
both the tool (e.g. Preconstruct) and Knip.
188-
189-
:::tip[Should I implement resolveEntryPaths?]
190-
191-
Plugins should have `resolveEntryPaths` implemented if the configuration file
192-
contains one or more options that represent [entry points][2].
193-
194-
:::
186+
With Mocha, you can configure `spec` file patterns. The result of implementing
187+
`resolveConfig` is that users don't need to duplicate this configuration in both
188+
the tool (e.g. Mocha) and Knip.
195189

196190
## Example 4: Use the AST directly
197191

198-
For the `resolveEntryPaths` and `resolveFromConfig` functions, Knip loads the
199-
configuration file and passes the default-exported object to this plugin
200-
function. However, that object might then not contain the information we need.
192+
If the `resolveFromConfig` function is impemented, Knip loads the configuration
193+
file and passes the default-exported object to this plugin function. However,
194+
that object might then not contain the information we need.
201195

202196
Here's an example `astro.config.ts` configuration file with a Starlight
203197
integration:
@@ -226,7 +220,7 @@ In the Astro plugin, there's no way to access this object containing
226220
`components` to add the component files as entry files if we were to try:
227221

228222
```ts
229-
const resolveEntryPaths: ResolveEntryPaths<AstroConfig> = async config => {
223+
const resolveConfig: ResolveConfig<AstroConfig> = async config => {
230224
console.log(config); // ¯\_(ツ)_/¯
231225
};
232226
```
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
{
22
"name": "@fixtures/eslint",
33
"devDependencies": {
4-
"@eslint/js": "*",
54
"eslint": "*",
65
"@nrwl/eslint-plugin-nx": "*",
76
"@typescript-eslint/eslint-plugin": "*",
87
"@typescript-eslint/parser": "*",
98
"eslint-config-prettier": "*",
10-
"eslint-plugin-no-secrets": "*",
119
"eslint-plugin-prettier": "*"
1210
}
1311
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import { defineConfig } from 'eslint/config';
12
import prettier from 'eslint-plugin-prettier';
23
import noSecrets from 'eslint-plugin-no-secrets';
34

4-
export default [
5+
export default defineConfig([
56
'eslint:recommended',
67
{
78
plugins: {
89
prettier,
910
'no-secrets': noSecrets,
1011
},
1112
},
12-
];
13+
]);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const x = 1;

packages/knip/fixtures/plugins/eslint3/node_modules/eslint/index.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "@fixtures/eslint3",
3+
"devDependencies": {
4+
"eslint": "*",
5+
"eslint-plugin-no-secrets": "*",
6+
"eslint-plugin-prettier": "*"
7+
}
8+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const x = 1;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "@fixtures/eslint4",
3+
"devDependencies": {
4+
"eslint": "*",
5+
"@eslint/js": "*"
6+
}
7+
}

packages/knip/src/WorkspaceWorker.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type WorkspaceManagerOptions = {
5252
configFilesMap: Map<string, Map<PluginName, Set<string>>>;
5353
};
5454

55-
type CacheItem = { resolveEntryPaths?: Input[]; resolveConfig?: Input[]; resolveFromAST?: Input[] };
55+
type CacheItem = { resolveConfig?: Input[]; resolveFromAST?: Input[] };
5656

5757
const nullConfig: EnsuredPluginConfiguration = { config: null, entry: null, project: null };
5858

@@ -341,7 +341,7 @@ export class WorkspaceWorker {
341341
const toInput = isProduction && plugin.production && plugin.production.length > 0 ? toProductionEntry : toEntry;
342342
for (const id of config.entry) addInput(toInput(id));
343343
} else if (
344-
(!plugin.resolveEntryPaths && !plugin.resolveFromAST) ||
344+
(!plugin.resolveConfig && !plugin.resolveFromAST) ||
345345
(configFilePaths.filter(path => basename(path) !== 'package.json').length === 0 &&
346346
(!this.configFilesMap.get(wsName)?.get(pluginName) ||
347347
this.configFilesMap.get(wsName)?.get(pluginName)?.size === 0))
@@ -356,7 +356,6 @@ export class WorkspaceWorker {
356356

357357
if (fd?.meta?.data && !fd.changed) {
358358
const data = fd.meta.data;
359-
if (data.resolveEntryPaths) for (const id of data.resolveEntryPaths) addInput(id, configFilePath);
360359
if (data.resolveConfig) for (const id of data.resolveConfig) addInput(id, configFilePath);
361360
if (data.resolveFromAST) for (const id of data.resolveFromAST) addInput(id, configFilePath);
362361
continue;
@@ -371,21 +370,11 @@ export class WorkspaceWorker {
371370
};
372371

373372
const cache: CacheItem = {};
374-
let loadedConfig: unknown;
375-
376-
if (plugin.resolveEntryPaths && !seen.get(wsName)?.has(configFilePath)) {
377-
if (!loadedConfig) loadedConfig = await loadConfigForPlugin(configFilePath, plugin, resolveOpts, pluginName);
378-
if (loadedConfig) {
379-
const inputs = await plugin.resolveEntryPaths(loadedConfig, resolveOpts);
380-
for (const input of inputs) addInput(input, configFilePath);
381-
cache.resolveEntryPaths = inputs;
382-
}
383-
}
384373

385374
if (plugin.resolveConfig && !seen.get(wsName)?.has(configFilePath)) {
386-
if (!loadedConfig) loadedConfig = await loadConfigForPlugin(configFilePath, plugin, resolveOpts, pluginName);
387-
if (loadedConfig) {
388-
const inputs = await plugin.resolveConfig(loadedConfig, resolveOpts);
375+
const localConfig = await loadConfigForPlugin(configFilePath, plugin, resolveOpts, pluginName);
376+
if (localConfig) {
377+
const inputs = await plugin.resolveConfig(localConfig, resolveOpts);
389378
for (const input of inputs) addInput(input, configFilePath);
390379
cache.resolveConfig = inputs;
391380
}

packages/knip/src/plugins.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const PMap: PluginMap = Plugins;
99

1010
const { performance: isEnabled = false } = parsedArgValues;
1111

12-
const timerifyMethods = ['resolve', 'resolveConfig', 'resolveEntryPaths'] as const;
12+
const timerifyMethods = ['resolve', 'resolveConfig', 'resolveAST'] as const;
1313

1414
const PluginEntries = Object.entries(PMap) as Entries;
1515

packages/knip/src/plugins/ava/index.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IsPluginEnabled, Plugin, ResolveConfig, ResolveEntryPaths } from '../../types/config.js';
1+
import type { IsPluginEnabled, Plugin, ResolveConfig } from '../../types/config.js';
22
import { toEntry } from '../../util/input.js';
33
import { hasDependency } from '../../util/plugin.js';
44
import type { AvaConfig } from './types.js';
@@ -26,19 +26,15 @@ const entry = [
2626
'!**/test?(s)/**/{helper,fixture}?(s)/**/*',
2727
];
2828

29-
const resolveEntryPaths: ResolveEntryPaths<AvaConfig> = localConfig => {
30-
if (typeof localConfig === 'function') localConfig = localConfig();
31-
return (localConfig?.files ?? entry).map(id => toEntry(id));
32-
};
33-
3429
const resolveConfig: ResolveConfig<AvaConfig> = async (localConfig, options) => {
3530
if (typeof localConfig === 'function') localConfig = localConfig();
3631

32+
const files = (localConfig?.files ?? entry).map(id => toEntry(id));
3733
const nodeArgs = localConfig.nodeArguments ?? [];
3834
const requireArgs = (localConfig.require ?? []).map(require => `--require ${require}`);
3935
const fakeCommand = `node ${nodeArgs.join(' ')} ${requireArgs.join(' ')}`;
4036

41-
return options.getInputsFromScripts(fakeCommand, { knownBinsOnly: true });
37+
return files.concat(options.getInputsFromScripts(fakeCommand, { knownBinsOnly: true }));
4238
};
4339

4440
export default {
@@ -47,6 +43,5 @@ export default {
4743
isEnabled,
4844
config,
4945
entry,
50-
resolveEntryPaths,
5146
resolveConfig,
5247
} satisfies Plugin;

packages/knip/src/plugins/bun/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import parseArgs from 'minimist';
2-
import type { Plugin, ResolveEntryPaths } from '../../types/config.js';
2+
import type { Plugin, ResolveConfig } from '../../types/config.js';
33
import type { PackageJson } from '../../types/package-json.js';
44
import { toEntry } from '../../util/input.js';
55

@@ -15,7 +15,7 @@ const config = ['package.json'];
1515

1616
const packageJsonPath = (id: PackageJson) => id;
1717

18-
const resolveEntryPaths: ResolveEntryPaths<PackageJson> = localConfig => {
18+
const resolveConfig: ResolveConfig<PackageJson> = localConfig => {
1919
const scripts = localConfig.scripts;
2020

2121
if (scripts) {
@@ -37,5 +37,5 @@ export default {
3737
isEnabled,
3838
config,
3939
packageJsonPath,
40-
resolveEntryPaths,
40+
resolveConfig,
4141
} satisfies Plugin;

packages/knip/src/plugins/cucumber/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IsPluginEnabled, Plugin, ResolveConfig, ResolveEntryPaths } from '../../types/config.js';
1+
import type { IsPluginEnabled, Plugin, ResolveConfig } from '../../types/config.js';
22
import { toDeferResolve, toEntry } from '../../util/input.js';
33
import { hasDependency } from '../../util/plugin.js';
44
import type { CucumberConfig } from './types.js';
@@ -15,14 +15,11 @@ const config = ['cucumber.{json,yaml,yml,js,cjs,mjs}'];
1515

1616
const entry = ['features/**/*.@(js|cjs|mjs)'];
1717

18-
const resolveEntryPaths: ResolveEntryPaths<CucumberConfig> = config => {
19-
return (config?.import ? config.import : []).map(id => toEntry(id));
20-
};
21-
2218
const resolveConfig: ResolveConfig<CucumberConfig> = config => {
19+
const imports = (config?.import ? config.import : entry).map(id => toEntry(id));
2320
const formatters = config?.format ? config.format : [];
2421
const requires = config?.require ? config.require : [];
25-
return [...formatters, ...requires].map(toDeferResolve);
22+
return imports.concat([...formatters, ...requires].map(toDeferResolve));
2623
};
2724

2825
export default {
@@ -31,6 +28,5 @@ export default {
3128
isEnabled,
3229
config,
3330
entry,
34-
resolveEntryPaths,
3531
resolveConfig,
3632
} satisfies Plugin;

packages/knip/src/plugins/cypress/index.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IsPluginEnabled, Plugin, ResolveConfig, ResolveEntryPaths } from '../../types/config.js';
1+
import type { IsPluginEnabled, Plugin, ResolveConfig } from '../../types/config.js';
22
import { toDeferResolve, toEntry } from '../../util/input.js';
33
import { hasDependency } from '../../util/plugin.js';
44
import { resolveDependencies } from './helpers.js';
@@ -25,18 +25,15 @@ const SUPPORT_FILE_PATTERNS = [
2525

2626
const entry = [...TEST_FILE_PATTERNS, ...SUPPORT_FILE_PATTERNS];
2727

28-
const resolveEntryPaths: ResolveEntryPaths = async localConfig => {
28+
const resolveConfig: ResolveConfig<CypressConfig> = async (localConfig, options) => {
2929
const specPatterns = [localConfig.e2e?.specPattern ?? [], localConfig.component?.specPattern ?? []].flat();
3030
const supportFiles = [localConfig.e2e?.supportFile || [], localConfig.component?.supportFile || []].flat();
31+
const inputs = await resolveDependencies(localConfig, options);
3132
return [
32-
...(specPatterns.length > 0 ? specPatterns : TEST_FILE_PATTERNS),
33-
...(supportFiles.length > 0 ? supportFiles : SUPPORT_FILE_PATTERNS),
34-
].map(id => toEntry(id));
35-
};
36-
37-
const resolveConfig: ResolveConfig<CypressConfig> = async (config, options) => {
38-
const inputs = await resolveDependencies(config, options);
39-
return inputs.map(toDeferResolve);
33+
...inputs.map(toDeferResolve),
34+
...(specPatterns.length > 0 ? specPatterns : TEST_FILE_PATTERNS).map(id => toEntry(id)),
35+
...(supportFiles.length > 0 ? supportFiles : SUPPORT_FILE_PATTERNS).map(id => toEntry(id)),
36+
];
4037
};
4138

4239
export default {
@@ -45,6 +42,5 @@ export default {
4542
isEnabled,
4643
config,
4744
entry,
48-
resolveEntryPaths,
4945
resolveConfig,
5046
} satisfies Plugin;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
export interface CypressConfig {
22
reporter: string;
33
reporterOptions?: { configFile?: string };
4+
component?: {
5+
specPattern?: string[];
6+
supportFile?: string;
7+
};
8+
e2e?: {
9+
specPattern?: string[];
10+
supportFile?: string;
11+
};
412
}

packages/knip/src/plugins/eleventy/helpers.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import type { EleventyConfig } from './types.js';
2-
31
// https://github.com/11ty/eleventy/blob/main/src/UserConfig.js
42

53
/** @public */
@@ -150,7 +148,7 @@ export class DummyEleventyConfig {
150148
}
151149

152150
// https://www.11ty.dev/docs/config/#configuration-options
153-
export const defaultEleventyConfig: EleventyConfig = {
151+
export const defaultEleventyConfig = {
154152
dir: {
155153
input: '.',
156154
output: '_site',

0 commit comments

Comments
 (0)