knip 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/constants.js +2 -0
- package/dist/dependency-deputy.d.ts +0 -2
- package/dist/dependency-deputy.js +0 -5
- package/dist/index.js +10 -5
- package/dist/manifest/index.d.ts +1 -0
- package/dist/manifest/index.js +7 -2
- package/dist/plugins/github-actions/index.js +6 -8
- package/dist/plugins/husky/index.js +5 -7
- package/dist/plugins/lint-staged/index.js +4 -3
- package/dist/plugins/nx/index.js +4 -4
- package/dist/plugins/release-it/index.js +8 -2
- package/dist/plugins/release-it/types.d.ts +1 -0
- package/dist/project-principal.d.ts +1 -0
- package/dist/project-principal.js +3 -0
- package/dist/types/plugins.d.ts +4 -1
- package/dist/util/binaries/bash-parser.d.ts +6 -0
- package/dist/util/binaries/bash-parser.js +54 -0
- package/dist/util/binaries/index.d.ts +12 -7
- package/dist/util/binaries/index.js +24 -46
- package/dist/util/binaries/resolvers/fallback.d.ts +1 -0
- package/dist/util/binaries/resolvers/fallback.js +28 -0
- package/dist/util/binaries/{globals → resolvers}/index.d.ts +0 -0
- package/dist/util/binaries/{globals → resolvers}/index.js +0 -0
- package/dist/util/binaries/resolvers/node.d.ts +1 -0
- package/dist/util/binaries/resolvers/node.js +19 -0
- package/dist/util/binaries/resolvers/npx.d.ts +4 -0
- package/dist/util/binaries/resolvers/npx.js +5 -0
- package/dist/util/binaries/resolvers/pnpm.d.ts +2 -0
- package/dist/util/binaries/{globals → resolvers}/pnpm.js +8 -7
- package/dist/util/binaries/resolvers/yarn.d.ts +2 -0
- package/dist/util/binaries/{globals → resolvers}/yarn.js +7 -6
- package/dist/util/debug.d.ts +0 -2
- package/dist/util/debug.js +0 -7
- package/dist/util/fs.js +8 -2
- package/dist/util/modules.d.ts +1 -0
- package/dist/util/modules.js +4 -0
- package/dist/util/require.d.ts +1 -0
- package/dist/util/require.js +7 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-worker.d.ts +12 -12
- package/dist/workspace-worker.js +55 -50
- package/package.json +9 -6
- package/dist/util/binaries/binaries/cross-env.d.ts +0 -1
- package/dist/util/binaries/binaries/cross-env.js +0 -5
- package/dist/util/binaries/binaries/dotenv.d.ts +0 -1
- package/dist/util/binaries/binaries/dotenv.js +0 -5
- package/dist/util/binaries/binaries/index.d.ts +0 -2
- package/dist/util/binaries/binaries/index.js +0 -2
- package/dist/util/binaries/globals/node.d.ts +0 -1
- package/dist/util/binaries/globals/node.js +0 -5
- package/dist/util/binaries/globals/npx.d.ts +0 -1
- package/dist/util/binaries/globals/npx.js +0 -8
- package/dist/util/binaries/globals/pnpm.d.ts +0 -2
- package/dist/util/binaries/globals/yarn.d.ts +0 -2
package/README.md
CHANGED
|
@@ -229,6 +229,10 @@ be part of the analysis. Here's an example:
|
|
|
229
229
|
{
|
|
230
230
|
"ignoreWorkspaces": ["packages/ignore-me"],
|
|
231
231
|
"workspaces": {
|
|
232
|
+
".": {
|
|
233
|
+
"entry": "src/index.ts",
|
|
234
|
+
"project": "src/**/*.ts"
|
|
235
|
+
},
|
|
232
236
|
"packages/*": {
|
|
233
237
|
"entry": "{index,cli}.ts",
|
|
234
238
|
"project": "**/*.ts"
|
|
@@ -240,6 +244,8 @@ be part of the analysis. Here's an example:
|
|
|
240
244
|
}
|
|
241
245
|
```
|
|
242
246
|
|
|
247
|
+
Note that if you have a root workspace, it must be under `workspaces` and have the `"."` key like in the example.
|
|
248
|
+
|
|
243
249
|
Knip supports workspaces as defined in three possible locations:
|
|
244
250
|
|
|
245
251
|
- In the `workspaces` array in `package.json`.
|
package/dist/constants.js
CHANGED
|
@@ -8,6 +8,7 @@ export const DEFAULT_WORKSPACE_CONFIG = {
|
|
|
8
8
|
};
|
|
9
9
|
export const TEST_FILE_PATTERNS = ['**/*.{test,spec}.{js,jsx,ts,tsx}', '**/__tests__/**/*.{js,jsx,ts,tsx}'];
|
|
10
10
|
export const IGNORED_GLOBAL_BINARIES = [
|
|
11
|
+
'bun',
|
|
11
12
|
'deno',
|
|
12
13
|
'git',
|
|
13
14
|
'node',
|
|
@@ -22,6 +23,7 @@ export const IGNORED_GLOBAL_BINARIES = [
|
|
|
22
23
|
'mkdir',
|
|
23
24
|
'mv',
|
|
24
25
|
'rm',
|
|
26
|
+
'sh',
|
|
25
27
|
'sudo',
|
|
26
28
|
];
|
|
27
29
|
export const IGNORE_DEFINITELY_TYPED = ['node'];
|
|
@@ -10,7 +10,6 @@ type Options = {
|
|
|
10
10
|
export default class DependencyDeputy {
|
|
11
11
|
isStrict: boolean;
|
|
12
12
|
_manifests: WorkspaceManifests;
|
|
13
|
-
manifests: Map<string, PackageJson>;
|
|
14
13
|
ignoreDependencies: string[];
|
|
15
14
|
referencedDependencies: Map<string, Set<string>>;
|
|
16
15
|
peerDependencies: Map<string, PeerDependencies>;
|
|
@@ -23,7 +22,6 @@ export default class DependencyDeputy {
|
|
|
23
22
|
manifestPath: string;
|
|
24
23
|
manifest: PackageJson;
|
|
25
24
|
}): void;
|
|
26
|
-
getManifest(workspaceName: string): PackageJson | undefined;
|
|
27
25
|
getWorkspaceManifest(workspaceName: string): {
|
|
28
26
|
workspaceDir: string;
|
|
29
27
|
manifestPath: string;
|
|
@@ -5,7 +5,6 @@ import { getPackageNameFromModuleSpecifier, isDefinitelyTyped, getDefinitelyType
|
|
|
5
5
|
export default class DependencyDeputy {
|
|
6
6
|
isStrict;
|
|
7
7
|
_manifests = new Map();
|
|
8
|
-
manifests = new Map();
|
|
9
8
|
ignoreDependencies;
|
|
10
9
|
referencedDependencies;
|
|
11
10
|
peerDependencies;
|
|
@@ -25,7 +24,6 @@ export default class DependencyDeputy {
|
|
|
25
24
|
const optionalDependencies = Object.keys(manifest.optionalDependencies ?? {});
|
|
26
25
|
const devDependencies = Object.keys(manifest.devDependencies ?? {});
|
|
27
26
|
const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies, ...optionalDependencies];
|
|
28
|
-
this.manifests.set(name, manifest);
|
|
29
27
|
this._manifests.set(name, {
|
|
30
28
|
workspaceDir: dir,
|
|
31
29
|
manifestPath,
|
|
@@ -37,9 +35,6 @@ export default class DependencyDeputy {
|
|
|
37
35
|
allDependencies,
|
|
38
36
|
});
|
|
39
37
|
}
|
|
40
|
-
getManifest(workspaceName) {
|
|
41
|
-
return this.manifests.get(workspaceName);
|
|
42
|
-
}
|
|
43
38
|
getWorkspaceManifest(workspaceName) {
|
|
44
39
|
return this._manifests.get(workspaceName);
|
|
45
40
|
}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
31
31
|
.reverse();
|
|
32
32
|
const lab = new SourceLab({ report, workspaceDirs, isIncludeEntryExports });
|
|
33
33
|
const principal = new ProjectPrincipal();
|
|
34
|
+
const enabledPluginsStore = new Map();
|
|
34
35
|
for (const { name, dir, config, ancestors } of workspaces) {
|
|
35
36
|
const isRoot = name === ROOT_WORKSPACE_NAME;
|
|
36
37
|
const suffix = isRoot ? '' : ` (${name})`;
|
|
@@ -63,15 +64,14 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
63
64
|
config,
|
|
64
65
|
rootWorkspaceConfig: chief.getConfigForWorkspace(ROOT_WORKSPACE_NAME),
|
|
65
66
|
manifest,
|
|
66
|
-
ancestorManifests: ancestors.map(name => deputy.getManifest(name)),
|
|
67
67
|
rootConfig: chief.config,
|
|
68
68
|
negatedWorkspacePatterns,
|
|
69
69
|
rootWorkspaceDir: cwd,
|
|
70
70
|
isProduction,
|
|
71
71
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const enabledPluginsInAncestors = ancestors.flatMap(ancestor => enabledPluginsStore.get(ancestor) ?? []);
|
|
73
|
+
await worker.setEnabledPlugins(enabledPluginsInAncestors);
|
|
74
|
+
await worker.initReferencedDependencies();
|
|
75
75
|
if (config?.entry && config?.project) {
|
|
76
76
|
if (isProduction) {
|
|
77
77
|
{
|
|
@@ -183,13 +183,18 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
if (report.dependencies || report.unlisted || report.files) {
|
|
186
|
-
|
|
186
|
+
await worker.findDependenciesByPlugins();
|
|
187
|
+
const { referencedDependencyIssues, peerDependencies, installedBinaries, entryFiles, enabledPlugins } = worker.getFinalDependencies();
|
|
187
188
|
referencedDependencyIssues.forEach(issue => {
|
|
188
189
|
const workspace = { name, dir, config, ancestors };
|
|
189
190
|
const unlistedDependency = deputy.maybeAddListedReferencedDependency(workspace, issue.symbol);
|
|
190
191
|
if (unlistedDependency)
|
|
191
192
|
collector.addIssue(issue);
|
|
192
193
|
});
|
|
194
|
+
deputy.addPeerDependencies(name, peerDependencies);
|
|
195
|
+
deputy.setInstalledBinaries(name, installedBinaries);
|
|
196
|
+
principal.addEntryPaths(entryFiles);
|
|
197
|
+
enabledPluginsStore.set(name, enabledPlugins);
|
|
193
198
|
}
|
|
194
199
|
}
|
|
195
200
|
}
|
package/dist/manifest/index.d.ts
CHANGED
package/dist/manifest/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _getReferencesFromScripts } from '../util/binaries/index.js';
|
|
2
2
|
import { timerify } from '../util/performance.js';
|
|
3
3
|
import { getPackageManifest } from './helpers.js';
|
|
4
4
|
const findManifestDependencies = async ({ rootConfig, manifest, isRoot, isProduction, dir, cwd }) => {
|
|
@@ -12,7 +12,11 @@ const findManifestDependencies = async ({ rootConfig, manifest, isRoot, isProduc
|
|
|
12
12
|
}
|
|
13
13
|
return scripts;
|
|
14
14
|
}, []);
|
|
15
|
-
const referencedBinaries =
|
|
15
|
+
const { entryFiles, binaries: referencedBinaries } = _getReferencesFromScripts(scripts, {
|
|
16
|
+
cwd: dir,
|
|
17
|
+
manifest,
|
|
18
|
+
ignore: rootConfig.ignoreBinaries,
|
|
19
|
+
});
|
|
16
20
|
const installedBinaries = new Map();
|
|
17
21
|
const packageNames = [...Object.keys(manifest.dependencies ?? {}), ...Object.keys(manifest.devDependencies ?? {})];
|
|
18
22
|
for (const packageName of packageNames) {
|
|
@@ -56,6 +60,7 @@ const findManifestDependencies = async ({ rootConfig, manifest, isRoot, isProduc
|
|
|
56
60
|
dependencies: Array.from(referencedDependencies),
|
|
57
61
|
peerDependencies,
|
|
58
62
|
installedBinaries,
|
|
63
|
+
entryFiles,
|
|
59
64
|
};
|
|
60
65
|
};
|
|
61
66
|
export const findDependencies = timerify(findManifestDependencies);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _getReferencesFromScripts } from '../../util/binaries/index.js';
|
|
2
2
|
import { _firstGlob } from '../../util/glob.js';
|
|
3
3
|
import { _load } from '../../util/loader.js';
|
|
4
4
|
import { getValuesByKeyDeep } from '../../util/object.js';
|
|
@@ -7,19 +7,17 @@ export const NAME = 'GitHub Actions';
|
|
|
7
7
|
export const ENABLERS = 'This plugin is enabled when a `.yml` file is found in the `.github/workflows` folder.';
|
|
8
8
|
export const isEnabled = async ({ cwd }) => Boolean(await _firstGlob({ cwd, patterns: ['.github/workflows/*.yml'] }));
|
|
9
9
|
export const CONFIG_FILE_PATTERNS = ['.github/workflows/*.yml', '.github/**/action.{yml,yaml}'];
|
|
10
|
-
const findGithubActionsDependencies = async (configFilePath, { manifest, rootConfig }) => {
|
|
10
|
+
const findGithubActionsDependencies = async (configFilePath, { cwd, manifest, rootConfig }) => {
|
|
11
11
|
const config = await _load(configFilePath);
|
|
12
12
|
if (!config)
|
|
13
13
|
return [];
|
|
14
|
-
const scripts = getValuesByKeyDeep(config, 'run')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.map(script => script.trim());
|
|
18
|
-
const binaries = getBinariesFromScripts(scripts, {
|
|
14
|
+
const scripts = getValuesByKeyDeep(config, 'run').filter((value) => typeof value === 'string');
|
|
15
|
+
const { binaries, entryFiles } = _getReferencesFromScripts(scripts, {
|
|
16
|
+
cwd,
|
|
19
17
|
manifest,
|
|
20
18
|
ignore: rootConfig.ignoreBinaries,
|
|
21
19
|
knownGlobalsOnly: true,
|
|
22
20
|
});
|
|
23
|
-
return binaries;
|
|
21
|
+
return { dependencies: binaries, entryFiles };
|
|
24
22
|
};
|
|
25
23
|
export const findDependencies = timerify(findGithubActionsDependencies);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
|
-
import {
|
|
2
|
+
import { _getReferencesFromScripts } from '../../util/binaries/index.js';
|
|
3
3
|
import { timerify } from '../../util/performance.js';
|
|
4
4
|
import { hasDependency } from '../../util/plugin.js';
|
|
5
5
|
export const NAME = 'husky';
|
|
@@ -10,16 +10,14 @@ export const CONFIG_FILE_PATTERNS = [
|
|
|
10
10
|
'.husky/pre-{applypatch,commit,merge-commit,push,rebase,receive}',
|
|
11
11
|
'.husky/post-{checkout,commit,merge,rewrite}',
|
|
12
12
|
];
|
|
13
|
-
const findHuskyDependencies = async (configFilePath, { manifest, rootConfig }) => {
|
|
13
|
+
const findHuskyDependencies = async (configFilePath, { cwd, manifest, rootConfig }) => {
|
|
14
14
|
const script = readFileSync(configFilePath);
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
.map(script => script.trim());
|
|
18
|
-
const binaries = getBinariesFromScripts(scripts, {
|
|
15
|
+
const { binaries, entryFiles } = _getReferencesFromScripts(String(script), {
|
|
16
|
+
cwd,
|
|
19
17
|
manifest,
|
|
20
18
|
ignore: rootConfig.ignoreBinaries,
|
|
21
19
|
knownGlobalsOnly: true,
|
|
22
20
|
});
|
|
23
|
-
return binaries;
|
|
21
|
+
return { dependencies: binaries, entryFiles };
|
|
24
22
|
};
|
|
25
23
|
export const findDependencies = timerify(findHuskyDependencies);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _getReferencesFromScripts } from '../../util/binaries/index.js';
|
|
2
2
|
import { _load } from '../../util/loader.js';
|
|
3
3
|
import { timerify } from '../../util/performance.js';
|
|
4
4
|
import { hasDependency } from '../../util/plugin.js';
|
|
@@ -13,7 +13,7 @@ export const CONFIG_FILE_PATTERNS = [
|
|
|
13
13
|
'lint-staged.config.{js,mjs,cjs}',
|
|
14
14
|
'package.json',
|
|
15
15
|
];
|
|
16
|
-
const findLintStagedDependencies = async (configFilePath, { manifest, rootConfig }) => {
|
|
16
|
+
const findLintStagedDependencies = async (configFilePath, { cwd, manifest, rootConfig }) => {
|
|
17
17
|
let config = configFilePath.endsWith('package.json')
|
|
18
18
|
? manifest['lint-staged']
|
|
19
19
|
: await _load(configFilePath);
|
|
@@ -25,7 +25,8 @@ const findLintStagedDependencies = async (configFilePath, { manifest, rootConfig
|
|
|
25
25
|
const binaries = new Set();
|
|
26
26
|
for (const entry of Object.values(config).flat()) {
|
|
27
27
|
const scripts = [typeof entry === 'function' ? await entry([]) : entry].flat();
|
|
28
|
-
|
|
28
|
+
const options = { cwd, manifest, ignore: rootConfig.ignoreBinaries };
|
|
29
|
+
_getReferencesFromScripts(scripts, options).binaries.forEach(bin => binaries.add(bin));
|
|
29
30
|
}
|
|
30
31
|
return Array.from(binaries);
|
|
31
32
|
};
|
package/dist/plugins/nx/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { compact } from '../../util/array.js';
|
|
2
|
-
import {
|
|
2
|
+
import { _getReferencesFromScripts } from '../../util/binaries/index.js';
|
|
3
3
|
import { _load } from '../../util/loader.js';
|
|
4
4
|
import { timerify } from '../../util/performance.js';
|
|
5
5
|
import { hasDependency } from '../../util/plugin.js';
|
|
@@ -7,7 +7,7 @@ export const NAME = 'Nx';
|
|
|
7
7
|
export const ENABLERS = [/^@nrwl\//];
|
|
8
8
|
export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
|
|
9
9
|
export const CONFIG_FILE_PATTERNS = ['{apps,libs}/**/project.json'];
|
|
10
|
-
const findNxDependencies = async (configFilePath, { manifest }) => {
|
|
10
|
+
const findNxDependencies = async (configFilePath, { cwd, manifest }) => {
|
|
11
11
|
const config = await _load(configFilePath);
|
|
12
12
|
if (!config)
|
|
13
13
|
return [];
|
|
@@ -19,7 +19,7 @@ const findNxDependencies = async (configFilePath, { manifest }) => {
|
|
|
19
19
|
const scripts = compact(targets
|
|
20
20
|
.filter(target => target.executor === 'nx:run-commands')
|
|
21
21
|
.flatMap(target => (target.options?.commands ?? target.options?.command ? [target.options.command] : [])));
|
|
22
|
-
const binaries =
|
|
23
|
-
return [...executors, ...binaries];
|
|
22
|
+
const { binaries, entryFiles } = _getReferencesFromScripts(scripts, { cwd, manifest, knownGlobalsOnly: true });
|
|
23
|
+
return { dependencies: [...executors, ...binaries], entryFiles };
|
|
24
24
|
};
|
|
25
25
|
export const findDependencies = timerify(findNxDependencies);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _getReferencesFromScripts } from '../../util/binaries/index.js';
|
|
1
2
|
import { _load } from '../../util/loader.js';
|
|
2
3
|
import { timerify } from '../../util/performance.js';
|
|
3
4
|
import { hasDependency } from '../../util/plugin.js';
|
|
@@ -10,10 +11,15 @@ export const CONFIG_FILE_PATTERNS = [
|
|
|
10
11
|
'.release-it.{yml,yaml}',
|
|
11
12
|
'package.json',
|
|
12
13
|
];
|
|
13
|
-
const findReleaseItDependencies = async (configFilePath, { manifest }) => {
|
|
14
|
+
const findReleaseItDependencies = async (configFilePath, { cwd, manifest }) => {
|
|
14
15
|
const config = configFilePath.endsWith('package.json')
|
|
15
16
|
? manifest['release-it']
|
|
16
17
|
: await _load(configFilePath);
|
|
17
|
-
|
|
18
|
+
if (!config)
|
|
19
|
+
return [];
|
|
20
|
+
const plugins = config.plugins ? Object.keys(config.plugins) : [];
|
|
21
|
+
const scripts = config.hooks ? Object.values(config.hooks).flat() : [];
|
|
22
|
+
const { binaries } = _getReferencesFromScripts(scripts, { cwd, manifest });
|
|
23
|
+
return [...plugins, ...binaries];
|
|
18
24
|
};
|
|
19
25
|
export const findDependencies = timerify(findReleaseItDependencies);
|
|
@@ -10,6 +10,7 @@ export default class ProjectPrincipal {
|
|
|
10
10
|
projectWorkspace?: Project;
|
|
11
11
|
entryFiles?: SourceFile[];
|
|
12
12
|
addEntryPath(filePath: string): void;
|
|
13
|
+
addEntryPaths(filePaths: Set<string>): void;
|
|
13
14
|
addSourceFile(filePath: string): void;
|
|
14
15
|
addProjectPath(filePath: string): void;
|
|
15
16
|
removeProjectPath(filePath: string): void;
|
|
@@ -26,6 +26,9 @@ export default class ProjectPrincipal {
|
|
|
26
26
|
addEntryPath(filePath) {
|
|
27
27
|
this.entryPaths.add(filePath);
|
|
28
28
|
}
|
|
29
|
+
addEntryPaths(filePaths) {
|
|
30
|
+
filePaths.forEach(filePath => this.entryPaths.add(filePath));
|
|
31
|
+
}
|
|
29
32
|
addSourceFile(filePath) {
|
|
30
33
|
this.entryWorkspace?.addSourceFileAtPath(filePath);
|
|
31
34
|
}
|
package/dist/types/plugins.d.ts
CHANGED
|
@@ -14,5 +14,8 @@ type GenericPluginCallbackOptions = {
|
|
|
14
14
|
rootConfig: Configuration;
|
|
15
15
|
isProduction: boolean;
|
|
16
16
|
};
|
|
17
|
-
export type GenericPluginCallback = (configFilePath: string, { cwd, manifest, config, workspaceConfig, isProduction }: GenericPluginCallbackOptions) => Promise<string[]
|
|
17
|
+
export type GenericPluginCallback = (configFilePath: string, { cwd, manifest, config, workspaceConfig, isProduction }: GenericPluginCallbackOptions) => Promise<string[] | {
|
|
18
|
+
dependencies: string[];
|
|
19
|
+
entryFiles?: string[];
|
|
20
|
+
}> | string[];
|
|
18
21
|
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import parse from 'bash-parser';
|
|
2
|
+
import parseArgs from 'minimist';
|
|
3
|
+
import * as FallbackResolver from './resolvers/fallback.js';
|
|
4
|
+
import * as KnownResolvers from './resolvers/index.js';
|
|
5
|
+
const spawningBinaries = ['cross-env', 'dotenv'];
|
|
6
|
+
export const getBinariesFromScript = (script, { cwd, manifest, knownGlobalsOnly = false }) => {
|
|
7
|
+
const findByArgs = (args) => (args.length > 0 ? findBinaries(parse(args.join(' ')).commands) : []);
|
|
8
|
+
const findBinaries = (items) => items.flatMap(item => {
|
|
9
|
+
switch (item.type) {
|
|
10
|
+
case 'Command': {
|
|
11
|
+
const binary = item.name?.text;
|
|
12
|
+
if (!binary || binary === '.' || binary === 'source')
|
|
13
|
+
return [];
|
|
14
|
+
if (binary.startsWith('-') || binary.startsWith('"') || binary.startsWith('..'))
|
|
15
|
+
return [];
|
|
16
|
+
if (['bun', 'deno'].includes(binary))
|
|
17
|
+
return [];
|
|
18
|
+
const args = item.suffix?.map(arg => arg.text) ?? [];
|
|
19
|
+
if (['!', 'test'].includes(binary))
|
|
20
|
+
return findByArgs(args);
|
|
21
|
+
if (binary in KnownResolvers) {
|
|
22
|
+
return KnownResolvers[binary].resolve(binary, args, cwd, manifest, (args) => {
|
|
23
|
+
const [binary, ...rest] = args;
|
|
24
|
+
return FallbackResolver.resolve(binary, rest, cwd);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (knownGlobalsOnly)
|
|
28
|
+
return [];
|
|
29
|
+
if (spawningBinaries.includes(binary)) {
|
|
30
|
+
const parsedArgs = parseArgs(args);
|
|
31
|
+
const [spawnedBinary] = parsedArgs._;
|
|
32
|
+
if (spawnedBinary) {
|
|
33
|
+
const restArgs = args.slice(args.indexOf(spawnedBinary));
|
|
34
|
+
return [binary, ...findByArgs(restArgs)];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return FallbackResolver.resolve(binary, args, cwd);
|
|
41
|
+
}
|
|
42
|
+
case 'LogicalExpression':
|
|
43
|
+
return findBinaries([item.left, item.right]);
|
|
44
|
+
case 'If':
|
|
45
|
+
return findBinaries([...item.clause.commands, ...item.then.commands]);
|
|
46
|
+
case 'For':
|
|
47
|
+
return findBinaries(item.do.commands);
|
|
48
|
+
default:
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const parsed = parse(script);
|
|
53
|
+
return parsed?.commands ? findBinaries(parsed.commands) : [];
|
|
54
|
+
};
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { PackageJson } from 'type-fest';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
type Options = {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
manifest?: PackageJson;
|
|
5
|
+
ignore?: string[];
|
|
6
|
+
knownGlobalsOnly?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type GetBinariesFromScripts = (npmScripts: string | string[], options?: Options) => {
|
|
9
|
+
entryFiles: string[];
|
|
10
|
+
binaries: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const _getReferencesFromScripts: GetBinariesFromScripts;
|
|
13
|
+
export {};
|
|
@@ -1,47 +1,25 @@
|
|
|
1
1
|
import { IGNORED_GLOBAL_BINARIES } from '../../constants.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.map(normalizeBinaries)
|
|
27
|
-
.filter(command => /^\w/.test(command))
|
|
28
|
-
.map(stripEnvironmentVariables)
|
|
29
|
-
.flatMap(command => {
|
|
30
|
-
const [binary, ...args] = command.trim().split(' ');
|
|
31
|
-
const camelCased = toCamelCase(binary);
|
|
32
|
-
if (['bun', 'deno'].includes(binary))
|
|
33
|
-
return [];
|
|
34
|
-
if (camelCased in GlobalBinaryResolvers) {
|
|
35
|
-
return GlobalBinaryResolvers[camelCased].resolve(binary, args, manifest);
|
|
36
|
-
}
|
|
37
|
-
if (knownGlobalsOnly)
|
|
38
|
-
return [];
|
|
39
|
-
if (camelCased in BinaryResolvers) {
|
|
40
|
-
return BinaryResolvers[camelCased].resolve(binary, args);
|
|
41
|
-
}
|
|
42
|
-
const dependenciesFromArguments = getDependenciesFromLoaderArguments(args);
|
|
43
|
-
return [binary, ...dependenciesFromArguments];
|
|
44
|
-
})
|
|
45
|
-
.forEach(binary => binary && binaries.add(binary));
|
|
46
|
-
return binaries;
|
|
47
|
-
}, new Set())).filter(binaryName => !IGNORED_GLOBAL_BINARIES.includes(binaryName) && !ignore.includes(binaryName));
|
|
2
|
+
import { compact } from '../array.js';
|
|
3
|
+
import { getPackageNameFromModuleSpecifier, stripBinary } from '../modules.js';
|
|
4
|
+
import { timerify } from '../performance.js';
|
|
5
|
+
import { getBinariesFromScript } from './bash-parser.js';
|
|
6
|
+
const partition = (values) => values.reduce((acc, value) => {
|
|
7
|
+
acc[/^(\/|[A-Z]:)/.test(value) ? 1 : 0].push(value);
|
|
8
|
+
return acc;
|
|
9
|
+
}, [[], []]);
|
|
10
|
+
const getReferencesFromScripts = (npmScripts, options = {}) => {
|
|
11
|
+
const { cwd = process.cwd(), manifest = {}, ignore = [], knownGlobalsOnly = false } = options;
|
|
12
|
+
const results = [npmScripts]
|
|
13
|
+
.flat()
|
|
14
|
+
.flatMap(script => getBinariesFromScript(script, { cwd, manifest, knownGlobalsOnly }));
|
|
15
|
+
const [binaries, entryFiles] = partition(compact(results));
|
|
16
|
+
return {
|
|
17
|
+
entryFiles,
|
|
18
|
+
binaries: binaries
|
|
19
|
+
.map(stripBinary)
|
|
20
|
+
.filter(binary => !binary.startsWith('.'))
|
|
21
|
+
.map(getPackageNameFromModuleSpecifier)
|
|
22
|
+
.filter(binaryName => !IGNORED_GLOBAL_BINARIES.includes(binaryName) && !ignore.includes(binaryName)),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export const _getReferencesFromScripts = timerify(getReferencesFromScripts);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolve: (binary: string, args: string[], cwd: string) => string[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import parseArgs from 'minimist';
|
|
3
|
+
import { tryResolve } from '../../require.js';
|
|
4
|
+
const resolveArguments = {
|
|
5
|
+
'ts-node': (parsed) => [parsed._[0], parsed.require].flat(),
|
|
6
|
+
tsx: (parsed) => parsed._.filter(p => p !== 'watch'),
|
|
7
|
+
default: (parsed) => [parsed.require].flat(),
|
|
8
|
+
};
|
|
9
|
+
export const resolve = (binary, args, cwd) => {
|
|
10
|
+
const parsed = parseArgs(args, { string: ['r'], alias: { require: ['r', 'loader'] } });
|
|
11
|
+
const resolver = resolveArguments[binary] ?? resolveArguments.default;
|
|
12
|
+
const resolve = resolver(parsed);
|
|
13
|
+
return [
|
|
14
|
+
binary,
|
|
15
|
+
...resolve.flatMap(specifier => {
|
|
16
|
+
if (specifier) {
|
|
17
|
+
const filePath = path.join(cwd, specifier);
|
|
18
|
+
if (filePath.startsWith(cwd)) {
|
|
19
|
+
const resolvedFilePath = tryResolve(filePath);
|
|
20
|
+
if (resolvedFilePath)
|
|
21
|
+
return [resolvedFilePath];
|
|
22
|
+
}
|
|
23
|
+
return [specifier];
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}),
|
|
27
|
+
];
|
|
28
|
+
};
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const resolve: (binary: string, args: string[], cwd: string) => string[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import parseArgs from 'minimist';
|
|
3
|
+
import { tryResolve } from '../../require.js';
|
|
4
|
+
export const resolve = (binary, args, cwd) => {
|
|
5
|
+
const parsed = parseArgs(args, { string: ['r'], alias: { require: ['r', 'loader', 'experimental-loader'] } });
|
|
6
|
+
const resolve = [parsed._[0], parsed.require].flat();
|
|
7
|
+
return resolve.flatMap(specifier => {
|
|
8
|
+
if (specifier) {
|
|
9
|
+
const filePath = path.join(cwd, specifier);
|
|
10
|
+
if (filePath.startsWith(cwd)) {
|
|
11
|
+
const resolvedFilePath = tryResolve(filePath);
|
|
12
|
+
if (resolvedFilePath)
|
|
13
|
+
return [resolvedFilePath];
|
|
14
|
+
}
|
|
15
|
+
return [specifier];
|
|
16
|
+
}
|
|
17
|
+
return [];
|
|
18
|
+
});
|
|
19
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import parseArgs from 'minimist';
|
|
2
|
+
export const resolve = (binary, args, cwd, manifest, findByArgs) => {
|
|
3
|
+
const parsed = parseArgs(args, { '--': true, stopEarly: true, boolean: ['yes', 'no'], alias: { yes: 'y', no: 'n' } });
|
|
4
|
+
return [...(parsed.yes ? [] : findByArgs(parsed._)), ...(parsed['--'] ? findByArgs(parsed['--']) : [])];
|
|
5
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import parseArgs from 'minimist';
|
|
2
2
|
const commands = [
|
|
3
3
|
'add',
|
|
4
4
|
'i',
|
|
@@ -31,14 +31,15 @@ const commands = [
|
|
|
31
31
|
't',
|
|
32
32
|
'tst',
|
|
33
33
|
];
|
|
34
|
-
export const resolve = (binary, args, manifest) => {
|
|
34
|
+
export const resolve = (binary, args, cwd, manifest) => {
|
|
35
35
|
const scripts = manifest.scripts ? Object.keys(manifest.scripts) : [];
|
|
36
|
-
const
|
|
36
|
+
const parsed = parseArgs(args, {});
|
|
37
|
+
const [command, result] = parsed._;
|
|
37
38
|
if (scripts.includes(command) || commands.includes(command))
|
|
38
39
|
return [];
|
|
39
|
-
if (command === 'run' && scripts.includes(
|
|
40
|
+
if (command === 'run' && scripts.includes(result))
|
|
40
41
|
return [];
|
|
41
|
-
if (command === '
|
|
42
|
-
return
|
|
43
|
-
return
|
|
42
|
+
if (command === 'exec' || command === 'run')
|
|
43
|
+
return [result];
|
|
44
|
+
return command ? [command] : [];
|
|
44
45
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import parseArgs from 'minimist';
|
|
2
2
|
const commands = [
|
|
3
3
|
'add',
|
|
4
4
|
'bin',
|
|
@@ -30,14 +30,15 @@ const commands = [
|
|
|
30
30
|
'workspace',
|
|
31
31
|
'workspaces',
|
|
32
32
|
];
|
|
33
|
-
export const resolve = (binary, args, manifest) => {
|
|
33
|
+
export const resolve = (binary, args, cwd, manifest) => {
|
|
34
34
|
const scripts = manifest.scripts ? Object.keys(manifest.scripts) : [];
|
|
35
|
-
const
|
|
35
|
+
const parsed = parseArgs(args, {});
|
|
36
|
+
const [command, result] = parsed._;
|
|
36
37
|
if (scripts.includes(command) || commands.includes(command))
|
|
37
38
|
return [];
|
|
38
|
-
if (command === 'run' && scripts.includes(
|
|
39
|
+
if (command === 'run' && scripts.includes(result))
|
|
39
40
|
return [];
|
|
40
41
|
if (command === 'run' || command === 'exec')
|
|
41
|
-
return
|
|
42
|
-
return
|
|
42
|
+
return [result];
|
|
43
|
+
return command ? [command] : [];
|
|
43
44
|
};
|
package/dist/util/debug.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type { Issue } from '../types/issues.js';
|
|
2
1
|
import type { SourceFile } from 'ts-morph';
|
|
3
2
|
export declare const debugLogObject: (name: string, obj: unknown) => void;
|
|
4
3
|
export declare const debugLogFiles: (name: string, filePaths: Set<string> | string[]) => void;
|
|
5
4
|
export declare const debugLogSourceFiles: (name: string, sourceFiles: Set<SourceFile> | SourceFile[]) => void;
|
|
6
|
-
export declare const debugLogIssues: (name: string, issues: Issue[]) => void;
|
package/dist/util/debug.js
CHANGED
|
@@ -40,10 +40,3 @@ export const debugLogSourceFiles = (name, sourceFiles) => {
|
|
|
40
40
|
logArray(files);
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
|
-
export const debugLogIssues = (name, issues) => {
|
|
44
|
-
if (!IS_ENABLED)
|
|
45
|
-
return;
|
|
46
|
-
const symbols = Array.from(new Set(issues.map(issue => issue.symbol)));
|
|
47
|
-
console.debug(`[knip] ${name} (${symbols.length})`);
|
|
48
|
-
logArray(symbols);
|
|
49
|
-
};
|
package/dist/util/fs.js
CHANGED
|
@@ -2,6 +2,7 @@ import { statSync } from 'node:fs';
|
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import stripJsonComments from 'strip-json-comments';
|
|
5
|
+
import { LoaderError } from './errors.js';
|
|
5
6
|
export const isFile = (filePath) => {
|
|
6
7
|
const stat = statSync(filePath, { throwIfNoEntry: false });
|
|
7
8
|
return stat !== undefined && stat.isFile();
|
|
@@ -11,6 +12,11 @@ export const findFile = (workingDir, fileName) => {
|
|
|
11
12
|
return isFile(filePath) ? filePath : undefined;
|
|
12
13
|
};
|
|
13
14
|
export const loadJSON = async (filePath) => {
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
try {
|
|
16
|
+
const contents = await readFile(filePath);
|
|
17
|
+
return JSON.parse(stripJsonComments(contents.toString()));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new LoaderError(`Error loading ${filePath}`, { cause: error });
|
|
21
|
+
}
|
|
16
22
|
};
|
package/dist/util/modules.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const getPackageNameFromModuleSpecifier: (moduleSpecifier: string) => string;
|
|
2
2
|
export declare const getPackageName: (value: string) => string;
|
|
3
|
+
export declare const stripBinary: (command: string) => string;
|
|
3
4
|
export declare const isDefinitelyTyped: (packageName: string) => boolean;
|
|
4
5
|
export declare const getDefinitelyTypedFor: (packageName: string) => string;
|
|
5
6
|
export declare const getPackageFromDefinitelyTyped: (typedDependency: string) => string;
|
package/dist/util/modules.js
CHANGED
|
@@ -13,6 +13,10 @@ export const getPackageName = (value) => {
|
|
|
13
13
|
}
|
|
14
14
|
return value.startsWith('/') ? value : value.split('/')[0];
|
|
15
15
|
};
|
|
16
|
+
export const stripBinary = (command) => command
|
|
17
|
+
.replace(/(\.\/)?node_modules\/(\.bin\/)?(\w+)/, '$3')
|
|
18
|
+
.replace(/\$\(npm bin\)\/(\w+)/, '$1')
|
|
19
|
+
.replace(/(\S+)@.*/, '$1');
|
|
16
20
|
export const isDefinitelyTyped = (packageName) => packageName.startsWith('@types/');
|
|
17
21
|
export const getDefinitelyTypedFor = (packageName) => {
|
|
18
22
|
if (isDefinitelyTyped(packageName))
|
package/dist/util/require.d.ts
CHANGED
package/dist/util/require.js
CHANGED
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "1.
|
|
1
|
+
export declare const version = "1.11.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.
|
|
1
|
+
export const version = '1.11.0';
|
|
@@ -7,7 +7,6 @@ type WorkspaceManagerOptions = {
|
|
|
7
7
|
dir: string;
|
|
8
8
|
config: WorkspaceConfiguration;
|
|
9
9
|
manifest: PackageJson;
|
|
10
|
-
ancestorManifests: (PackageJson | undefined)[];
|
|
11
10
|
rootWorkspaceConfig: WorkspaceConfiguration;
|
|
12
11
|
rootConfig: Configuration;
|
|
13
12
|
negatedWorkspacePatterns: string[];
|
|
@@ -15,28 +14,26 @@ type WorkspaceManagerOptions = {
|
|
|
15
14
|
isProduction: boolean;
|
|
16
15
|
};
|
|
17
16
|
type ReferencedDependencyIssues = Set<Issue>;
|
|
18
|
-
type ReferencedDependencies = Set<string>;
|
|
19
17
|
export default class WorkspaceWorker {
|
|
20
18
|
name: string;
|
|
21
19
|
dir: string;
|
|
22
20
|
config: WorkspaceConfiguration;
|
|
23
|
-
ancestorManifests: (PackageJson | undefined)[];
|
|
24
21
|
rootWorkspaceConfig: WorkspaceConfiguration;
|
|
25
22
|
rootConfig: Configuration;
|
|
26
|
-
referencedDependencyIssues: ReferencedDependencyIssues;
|
|
27
23
|
manifest: PackageJson;
|
|
28
24
|
rootWorkspaceDir: string;
|
|
29
|
-
|
|
25
|
+
referencedDependencyIssues: ReferencedDependencyIssues;
|
|
30
26
|
peerDependencies: PeerDependencies;
|
|
31
27
|
installedBinaries: InstalledBinaries;
|
|
28
|
+
entryFiles: Set<string>;
|
|
32
29
|
negatedWorkspacePatterns: string[];
|
|
33
30
|
enabled: Record<PluginName, boolean>;
|
|
31
|
+
enabledPlugins: PluginName[];
|
|
34
32
|
isRoot: boolean;
|
|
35
33
|
isProduction: boolean;
|
|
36
|
-
constructor({ name, dir, config,
|
|
34
|
+
constructor({ name, dir, config, rootWorkspaceConfig, rootConfig, negatedWorkspacePatterns, manifest, rootWorkspaceDir, isProduction, }: WorkspaceManagerOptions);
|
|
37
35
|
getConfigForPlugin(pluginName: PluginName): PluginConfiguration;
|
|
38
|
-
|
|
39
|
-
setEnabledPlugins(): Promise<void>;
|
|
36
|
+
setEnabledPlugins(enabledPluginsInAncestors: string[]): Promise<void>;
|
|
40
37
|
initReferencedDependencies(): Promise<void>;
|
|
41
38
|
getEntryFilePatterns(): string[];
|
|
42
39
|
getProjectFilePatterns(): string[];
|
|
@@ -48,10 +45,13 @@ export default class WorkspaceWorker {
|
|
|
48
45
|
getProductionPluginEntryFilePatterns(): string[];
|
|
49
46
|
getConfigurationEntryFilePattern(pluginName: PluginName): string[];
|
|
50
47
|
getWorkspaceIgnorePatterns(): string[];
|
|
51
|
-
findDependenciesByPlugins(): Promise<
|
|
48
|
+
findDependenciesByPlugins(): Promise<void>;
|
|
49
|
+
getFinalDependencies(): {
|
|
50
|
+
peerDependencies: PeerDependencies;
|
|
51
|
+
installedBinaries: InstalledBinaries;
|
|
52
52
|
referencedDependencyIssues: ReferencedDependencyIssues;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
entryFiles: Set<string>;
|
|
54
|
+
enabledPlugins: ("babel" | "capacitor" | "changesets" | "commitlint" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "typescript" | "vitest" | "webpack" | "githubActions" | "lintStaged" | "npmPackageJsonLint" | "releaseIt")[];
|
|
55
|
+
};
|
|
56
56
|
}
|
|
57
57
|
export {};
|
package/dist/workspace-worker.js
CHANGED
|
@@ -2,31 +2,30 @@ import path from 'node:path';
|
|
|
2
2
|
import { ROOT_WORKSPACE_NAME, TEST_FILE_PATTERNS } from './constants.js';
|
|
3
3
|
import * as npm from './manifest/index.js';
|
|
4
4
|
import * as plugins from './plugins/index.js';
|
|
5
|
-
import { debugLogFiles,
|
|
5
|
+
import { debugLogFiles, debugLogObject } from './util/debug.js';
|
|
6
6
|
import { _pureGlob, negate, hasProductionSuffix, hasNoProductionSuffix } from './util/glob.js';
|
|
7
7
|
const negatedTestFilePatterns = TEST_FILE_PATTERNS.map(negate);
|
|
8
8
|
export default class WorkspaceWorker {
|
|
9
9
|
name;
|
|
10
10
|
dir;
|
|
11
11
|
config;
|
|
12
|
-
ancestorManifests;
|
|
13
12
|
rootWorkspaceConfig;
|
|
14
13
|
rootConfig;
|
|
15
|
-
referencedDependencyIssues = new Set();
|
|
16
14
|
manifest;
|
|
17
15
|
rootWorkspaceDir;
|
|
18
|
-
|
|
16
|
+
referencedDependencyIssues = new Set();
|
|
19
17
|
peerDependencies = new Map();
|
|
20
18
|
installedBinaries = new Map();
|
|
19
|
+
entryFiles = new Set();
|
|
21
20
|
negatedWorkspacePatterns = [];
|
|
22
21
|
enabled;
|
|
22
|
+
enabledPlugins = [];
|
|
23
23
|
isRoot;
|
|
24
24
|
isProduction;
|
|
25
|
-
constructor({ name, dir, config,
|
|
25
|
+
constructor({ name, dir, config, rootWorkspaceConfig, rootConfig, negatedWorkspacePatterns, manifest, rootWorkspaceDir, isProduction, }) {
|
|
26
26
|
this.name = name;
|
|
27
27
|
this.dir = dir;
|
|
28
28
|
this.config = config;
|
|
29
|
-
this.ancestorManifests = ancestorManifests;
|
|
30
29
|
this.isRoot = name === ROOT_WORKSPACE_NAME;
|
|
31
30
|
this.isProduction = isProduction;
|
|
32
31
|
this.rootConfig = rootConfig;
|
|
@@ -39,27 +38,23 @@ export default class WorkspaceWorker {
|
|
|
39
38
|
getConfigForPlugin(pluginName) {
|
|
40
39
|
return this.config[pluginName] ?? { config: null, entry: null, project: null };
|
|
41
40
|
}
|
|
42
|
-
async
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
async setEnabledPlugins() {
|
|
47
|
-
const dependencies = new Set([this.manifest, ...this.ancestorManifests]
|
|
48
|
-
.flatMap(manifest => [Object.keys(manifest?.dependencies ?? {}), Object.keys(manifest?.devDependencies ?? {})])
|
|
49
|
-
.flat());
|
|
41
|
+
async setEnabledPlugins(enabledPluginsInAncestors) {
|
|
42
|
+
const { manifest } = this;
|
|
43
|
+
const dependencies = new Set([Object.keys(manifest?.dependencies ?? {}), Object.keys(manifest?.devDependencies ?? {})].flat());
|
|
50
44
|
const pluginEntries = Object.entries(plugins);
|
|
51
45
|
for (const [pluginName, plugin] of pluginEntries) {
|
|
52
46
|
const hasIsEnabled = typeof plugin.isEnabled === 'function';
|
|
53
47
|
this.enabled[pluginName] =
|
|
54
48
|
this.config[pluginName] !== false &&
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
(enabledPluginsInAncestors.includes(pluginName) ||
|
|
50
|
+
(hasIsEnabled && (await plugin.isEnabled({ cwd: this.dir, manifest: this.manifest, dependencies }))));
|
|
57
51
|
}
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
this.enabledPlugins = pluginEntries.filter(([name]) => this.enabled[name]).map(([name]) => name);
|
|
53
|
+
const enabledPluginNames = this.enabledPlugins.map(name => plugins[name].NAME);
|
|
54
|
+
debugLogObject(`Enabled plugins (${this.name})`, enabledPluginNames);
|
|
60
55
|
}
|
|
61
56
|
async initReferencedDependencies() {
|
|
62
|
-
const { dependencies, peerDependencies, installedBinaries } = await npm.findDependencies({
|
|
57
|
+
const { dependencies, peerDependencies, installedBinaries, entryFiles } = await npm.findDependencies({
|
|
63
58
|
rootConfig: this.rootConfig,
|
|
64
59
|
manifest: this.manifest,
|
|
65
60
|
isRoot: this.isRoot,
|
|
@@ -68,8 +63,9 @@ export default class WorkspaceWorker {
|
|
|
68
63
|
cwd: this.rootWorkspaceDir,
|
|
69
64
|
});
|
|
70
65
|
const filePath = path.join(this.dir, 'package.json');
|
|
71
|
-
|
|
72
|
-
dependencies.forEach(dependency =>
|
|
66
|
+
const issues = this.referencedDependencyIssues;
|
|
67
|
+
dependencies.forEach(dependency => issues.add({ type: 'unlisted', filePath, symbol: dependency }));
|
|
68
|
+
entryFiles.forEach(entryFile => this.entryFiles.add(entryFile));
|
|
73
69
|
this.peerDependencies = peerDependencies;
|
|
74
70
|
this.installedBinaries = installedBinaries;
|
|
75
71
|
}
|
|
@@ -202,40 +198,49 @@ export default class WorkspaceWorker {
|
|
|
202
198
|
if (this.enabled[pluginName] && isIncludePlugin) {
|
|
203
199
|
const hasDependencyFinder = 'findDependencies' in plugin && typeof plugin.findDependencies === 'function';
|
|
204
200
|
if (hasDependencyFinder) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
const pluginConfig = this.getConfigForPlugin(pluginName);
|
|
202
|
+
if (!pluginConfig)
|
|
203
|
+
continue;
|
|
204
|
+
const patterns = this.getConfigurationEntryFilePattern(pluginName);
|
|
205
|
+
const cwd = this.dir;
|
|
206
|
+
const ignore = this.getWorkspaceIgnorePatterns();
|
|
207
|
+
const configFilePaths = await _pureGlob({ patterns, cwd, ignore });
|
|
208
|
+
debugLogFiles(`Globbed ${plugin.NAME} config file paths`, configFilePaths);
|
|
209
|
+
if (configFilePaths.length === 0)
|
|
210
|
+
continue;
|
|
211
|
+
const pluginDependencies = new Set();
|
|
212
|
+
const pluginEntryFiles = new Set();
|
|
213
|
+
for (const configFilePath of configFilePaths) {
|
|
214
|
+
const results = await plugin.findDependencies(configFilePath, {
|
|
215
|
+
cwd,
|
|
216
|
+
manifest: this.manifest,
|
|
217
|
+
config: pluginConfig,
|
|
218
|
+
rootConfig: this.rootConfig,
|
|
219
|
+
workspaceConfig: this.config,
|
|
220
|
+
isProduction: this.isProduction,
|
|
221
|
+
});
|
|
222
|
+
const dependencies = Array.isArray(results) ? results : results.dependencies;
|
|
223
|
+
const entryFiles = !Array.isArray(results) && results.entryFiles ? results.entryFiles : [];
|
|
224
|
+
const issues = this.referencedDependencyIssues;
|
|
225
|
+
dependencies.forEach(symbol => issues.add({ type: 'unlisted', filePath: configFilePath, symbol }));
|
|
226
|
+
entryFiles.forEach(entryFile => this.entryFiles.add(entryFile));
|
|
227
|
+
dependencies.forEach(dependency => pluginDependencies.add(dependency));
|
|
228
|
+
entryFiles.forEach(entryFile => pluginEntryFiles.add(entryFile));
|
|
229
|
+
}
|
|
230
|
+
debugLogFiles(`Dependencies referenced in ${plugin.NAME}`, pluginDependencies);
|
|
231
|
+
if (pluginEntryFiles.size > 0)
|
|
232
|
+
debugLogFiles(`Entry files referenced in ${plugin.NAME}`, pluginEntryFiles);
|
|
208
233
|
}
|
|
209
234
|
}
|
|
210
235
|
}
|
|
236
|
+
}
|
|
237
|
+
getFinalDependencies() {
|
|
211
238
|
return {
|
|
239
|
+
peerDependencies: this.peerDependencies,
|
|
240
|
+
installedBinaries: this.installedBinaries,
|
|
212
241
|
referencedDependencyIssues: this.referencedDependencyIssues,
|
|
213
|
-
|
|
242
|
+
entryFiles: this.entryFiles,
|
|
243
|
+
enabledPlugins: this.enabledPlugins,
|
|
214
244
|
};
|
|
215
245
|
}
|
|
216
|
-
async findDependenciesByPlugin(pluginName, pluginTitle, pluginCallback) {
|
|
217
|
-
const pluginConfig = this.getConfigForPlugin(pluginName);
|
|
218
|
-
if (!pluginConfig)
|
|
219
|
-
return [];
|
|
220
|
-
const patterns = this.getConfigurationEntryFilePattern(pluginName);
|
|
221
|
-
const cwd = this.dir;
|
|
222
|
-
const ignore = this.getWorkspaceIgnorePatterns();
|
|
223
|
-
const configFilePaths = await _pureGlob({ patterns, cwd, ignore });
|
|
224
|
-
debugLogFiles(`Globbed ${pluginTitle} config file paths`, configFilePaths);
|
|
225
|
-
if (configFilePaths.length === 0)
|
|
226
|
-
return [];
|
|
227
|
-
const referencedDependencyIssues = (await Promise.all(configFilePaths.map(async (configFilePath) => {
|
|
228
|
-
const dependencies = await pluginCallback(configFilePath, {
|
|
229
|
-
cwd,
|
|
230
|
-
manifest: this.manifest,
|
|
231
|
-
config: pluginConfig,
|
|
232
|
-
rootConfig: this.rootConfig,
|
|
233
|
-
workspaceConfig: this.config,
|
|
234
|
-
isProduction: this.isProduction,
|
|
235
|
-
});
|
|
236
|
-
return dependencies.map(symbol => ({ type: 'unlisted', filePath: configFilePath, symbol }));
|
|
237
|
-
}))).flat();
|
|
238
|
-
debugLogIssues(`Dependencies used by ${pluginTitle} configuration`, referencedDependencyIssues);
|
|
239
|
-
return referencedDependencyIssues;
|
|
240
|
-
}
|
|
241
246
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
|
|
5
5
|
"homepage": "https://github.com/webpro/knip",
|
|
6
6
|
"repository": "github:webpro/knip",
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
"@esbuild-kit/esm-loader": "^2.5.4",
|
|
43
43
|
"@npmcli/map-workspaces": "^3.0.1",
|
|
44
44
|
"@snyk/github-codeowners": "^1.1.0",
|
|
45
|
+
"bash-parser": "^0.5.0",
|
|
45
46
|
"chalk": "^5.2.0",
|
|
46
47
|
"easy-table": "^1.2.0",
|
|
47
|
-
"esbuild": "^0.17.
|
|
48
|
+
"esbuild": "^0.17.4",
|
|
48
49
|
"esbuild-register": "3.4.2",
|
|
49
50
|
"eslint": "^8.32.0",
|
|
50
51
|
"fast-glob": "^3.2.12",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"globby": "^13.1.3",
|
|
53
54
|
"js-yaml": "^4.1.0",
|
|
54
55
|
"micromatch": "^4.0.5",
|
|
56
|
+
"minimist": "^1.2.7",
|
|
55
57
|
"nano-memoize": "^2.0.0",
|
|
56
58
|
"patch-package": "^6.5.1",
|
|
57
59
|
"pretty-ms": "^8.0.0",
|
|
@@ -62,17 +64,18 @@
|
|
|
62
64
|
"zod": "^3.20.2"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
|
-
"@jest/types": "29.
|
|
67
|
+
"@jest/types": "^29.4.0",
|
|
66
68
|
"@npmcli/package-json": "3.0.0",
|
|
67
69
|
"@release-it/bumper": "^4.0.2",
|
|
68
70
|
"@types/eslint": "8.4.10",
|
|
69
71
|
"@types/js-yaml": "4.0.5",
|
|
70
72
|
"@types/micromatch": "4.0.2",
|
|
73
|
+
"@types/minimist": "^1.2.2",
|
|
71
74
|
"@types/node": "18.11.18",
|
|
72
75
|
"@types/npmcli__map-workspaces": "3.0.0",
|
|
73
76
|
"@types/webpack": "5.28.0",
|
|
74
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
75
|
-
"@typescript-eslint/parser": "5.
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
|
78
|
+
"@typescript-eslint/parser": "^5.49.0",
|
|
76
79
|
"eslint-import-resolver-typescript": "3.5.3",
|
|
77
80
|
"eslint-plugin-import": "2.27.5",
|
|
78
81
|
"globstar": "1.0.0",
|
|
@@ -81,7 +84,7 @@
|
|
|
81
84
|
"remark-cli": "11.0.0",
|
|
82
85
|
"remark-preset-webpro": "0.0.1",
|
|
83
86
|
"tsx": "3.12.2",
|
|
84
|
-
"type-fest": "3.5.
|
|
87
|
+
"type-fest": "^3.5.3",
|
|
85
88
|
"typescript": "4.9.4"
|
|
86
89
|
},
|
|
87
90
|
"engines": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const resolve: (binary: string, args: string[]) => string[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const resolve: (binary: string, args: string[]) => string[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const resolve: (binary: string, args: string[]) => string[];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const resolve: (binary: string, args: string[]) => (string | undefined)[];
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { getDependenciesFromLoaderArguments, getFirstPositionalArg } from '../index.js';
|
|
2
|
-
export const resolve = (binary, args) => {
|
|
3
|
-
if (/-y|--yes/.test(args[0]))
|
|
4
|
-
return [];
|
|
5
|
-
const dependenciesFromArguments = getDependenciesFromLoaderArguments(args);
|
|
6
|
-
const firstArgument = getFirstPositionalArg(args);
|
|
7
|
-
return [firstArgument, ...dependenciesFromArguments];
|
|
8
|
-
};
|