knip 5.70.2 → 5.72.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/dist/ConfigurationChief.d.ts +6 -0
- package/dist/ConsoleStreamer.js +1 -1
- package/dist/DependencyDeputy.js +2 -2
- package/dist/ProjectPrincipal.js +1 -1
- package/dist/WorkspaceWorker.js +1 -1
- package/dist/binaries/bash-parser.js +14 -1
- package/dist/compilers/index.d.ts +10 -0
- package/dist/compilers/index.js +4 -1
- package/dist/compilers/scss.d.ts +6 -0
- package/dist/compilers/scss.js +14 -0
- package/dist/constants.js +1 -0
- package/dist/graph/analyze.js +38 -22
- package/dist/graph-explorer/constants.d.ts +2 -0
- package/dist/graph-explorer/constants.js +2 -0
- package/dist/graph-explorer/explorer.d.ts +11 -0
- package/dist/graph-explorer/explorer.js +10 -0
- package/dist/graph-explorer/operations/build-exports-tree.d.ts +15 -0
- package/dist/graph-explorer/operations/build-exports-tree.js +96 -0
- package/dist/graph-explorer/operations/has-strictly-ns-references.d.ts +2 -0
- package/dist/graph-explorer/operations/has-strictly-ns-references.js +98 -0
- package/dist/graph-explorer/operations/is-referenced.d.ts +4 -0
- package/dist/graph-explorer/operations/is-referenced.js +89 -0
- package/dist/graph-explorer/utils.d.ts +3 -0
- package/dist/graph-explorer/utils.js +13 -0
- package/dist/graph-explorer/visitors.d.ts +12 -0
- package/dist/graph-explorer/visitors.js +30 -0
- package/dist/graph-explorer/walk-down.d.ts +5 -0
- package/dist/graph-explorer/walk-down.js +116 -0
- package/dist/index.js +2 -98
- package/dist/plugins/angular/index.js +3 -3
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/next/index.js +4 -3
- package/dist/plugins/next/resolveFromAST.d.ts +1 -0
- package/dist/plugins/next/resolveFromAST.js +42 -1
- package/dist/plugins/rsbuild/index.js +8 -0
- package/dist/plugins/rsbuild/types.d.ts +1 -0
- package/dist/plugins/storybook/index.js +12 -4
- package/dist/plugins/storybook/types.d.ts +5 -0
- package/dist/plugins/svgo/index.js +1 -1
- package/dist/plugins/svgr/index.d.ts +3 -0
- package/dist/plugins/svgr/index.js +24 -0
- package/dist/plugins/svgr/types.d.ts +3 -0
- package/dist/plugins/svgr/types.js +1 -0
- package/dist/plugins/vite/helpers.js +1 -1
- package/dist/plugins/vite/index.js +4 -0
- package/dist/plugins/vitest/index.js +1 -1
- package/dist/reporters/codeclimate.js +3 -7
- package/dist/reporters/util/util.d.ts +2 -1
- package/dist/reporters/util/util.js +1 -0
- package/dist/reporters/watch.js +1 -1
- package/dist/run.d.ts +25 -0
- package/dist/run.js +107 -0
- package/dist/schema/configuration.d.ts +10 -0
- package/dist/schema/plugins.d.ts +5 -0
- package/dist/schema/plugins.js +1 -0
- package/dist/types/PluginNames.d.ts +2 -2
- package/dist/types/PluginNames.js +1 -0
- package/dist/types/issues.d.ts +4 -4
- package/dist/types/module-graph.d.ts +11 -13
- package/dist/typescript/ast-helpers.d.ts +5 -1
- package/dist/typescript/ast-helpers.js +47 -2
- package/dist/typescript/get-imports-and-exports.js +78 -12
- package/dist/typescript/resolve-module-names.js +5 -4
- package/dist/typescript/visitors/dynamic-imports/importCall.js +5 -19
- package/dist/util/Performance.js +4 -2
- package/dist/util/create-options.d.ts +10 -0
- package/dist/util/create-options.js +8 -4
- package/dist/util/file-entry-cache.js +1 -1
- package/dist/util/graph-sequencer.js +1 -1
- package/dist/util/module-graph.js +7 -8
- package/dist/util/resolve.d.ts +3 -2
- package/dist/util/resolve.js +25 -2
- package/dist/util/trace.d.ts +2 -20
- package/dist/util/trace.js +41 -66
- package/dist/util/watch.d.ts +19 -3
- package/dist/util/watch.js +28 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -7
- package/schema.json +4 -0
- package/vendor/bash-parser/index.d.ts +6 -1
- package/dist/util/has-strictly-ns-references.d.ts +0 -4
- package/dist/util/has-strictly-ns-references.js +0 -103
- package/dist/util/is-identifier-referenced.d.ts +0 -9
- package/dist/util/is-identifier-referenced.js +0 -145
|
@@ -527,6 +527,11 @@ export declare class ConfigurationChief {
|
|
|
527
527
|
entry?: string | string[] | undefined;
|
|
528
528
|
project?: string | string[] | undefined;
|
|
529
529
|
} | undefined;
|
|
530
|
+
svgr?: string | boolean | string[] | {
|
|
531
|
+
config?: string | string[] | undefined;
|
|
532
|
+
entry?: string | string[] | undefined;
|
|
533
|
+
project?: string | string[] | undefined;
|
|
534
|
+
} | undefined;
|
|
530
535
|
syncpack?: string | boolean | string[] | {
|
|
531
536
|
config?: string | string[] | undefined;
|
|
532
537
|
entry?: string | string[] | undefined;
|
|
@@ -761,6 +766,7 @@ export declare class ConfigurationChief {
|
|
|
761
766
|
stylelint?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
762
767
|
svelte?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
763
768
|
svgo?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
769
|
+
svgr?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
764
770
|
syncpack?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
765
771
|
tailwind?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
|
766
772
|
taskfile?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
|
package/dist/ConsoleStreamer.js
CHANGED
package/dist/DependencyDeputy.js
CHANGED
|
@@ -174,7 +174,7 @@ export class DependencyDeputy {
|
|
|
174
174
|
const dependencyIssues = [];
|
|
175
175
|
const devDependencyIssues = [];
|
|
176
176
|
const optionalPeerDependencyIssues = [];
|
|
177
|
-
for (const [workspace, { manifestPath: filePath, manifestStr }] of this._manifests
|
|
177
|
+
for (const [workspace, { manifestPath: filePath, manifestStr }] of this._manifests) {
|
|
178
178
|
const referencedDependencies = this.referencedDependencies.get(workspace);
|
|
179
179
|
const hasTypesIncluded = this.getHasTypesIncluded(workspace);
|
|
180
180
|
const peeker = new PackagePeeker(manifestStr);
|
|
@@ -342,7 +342,7 @@ export class DependencyDeputy {
|
|
|
342
342
|
}
|
|
343
343
|
getConfigurationHints() {
|
|
344
344
|
const configurationHints = new Set();
|
|
345
|
-
for (const [workspaceName, manifest] of this._manifests
|
|
345
|
+
for (const [workspaceName, manifest] of this._manifests) {
|
|
346
346
|
for (const identifier of manifest.unusedIgnoreDependencies) {
|
|
347
347
|
configurationHints.add({ workspaceName, identifier, type: 'ignoreDependencies' });
|
|
348
348
|
}
|
package/dist/ProjectPrincipal.js
CHANGED
|
@@ -217,7 +217,7 @@ export class ProjectPrincipal {
|
|
|
217
217
|
return externalRefs.length > 0;
|
|
218
218
|
}
|
|
219
219
|
reconcileCache(graph) {
|
|
220
|
-
for (const [filePath, file] of graph
|
|
220
|
+
for (const [filePath, file] of graph) {
|
|
221
221
|
const fd = this.cache.getFileDescriptor(filePath);
|
|
222
222
|
if (!fd?.meta)
|
|
223
223
|
continue;
|
package/dist/WorkspaceWorker.js
CHANGED
|
@@ -319,7 +319,7 @@ export class WorkspaceWorker {
|
|
|
319
319
|
const configFiles = this.configFilesMap.get(wsName);
|
|
320
320
|
if (configFiles) {
|
|
321
321
|
do {
|
|
322
|
-
for (const [pluginName, dependencies] of configFiles
|
|
322
|
+
for (const [pluginName, dependencies] of configFiles) {
|
|
323
323
|
configFiles.delete(pluginName);
|
|
324
324
|
if (this.enabledPlugins.includes(pluginName)) {
|
|
325
325
|
for (const input of await runPlugin(pluginName, Array.from(dependencies)))
|
|
@@ -25,6 +25,12 @@ export const getDependenciesFromScript = (script, options) => {
|
|
|
25
25
|
knownBinsOnly: false,
|
|
26
26
|
});
|
|
27
27
|
};
|
|
28
|
+
const definedFunctions = new Set();
|
|
29
|
+
const collectFunctionNames = (nodes) => {
|
|
30
|
+
for (const node of nodes)
|
|
31
|
+
if (node.type === 'Function')
|
|
32
|
+
definedFunctions.add(node.name.text);
|
|
33
|
+
};
|
|
28
34
|
const getDependenciesFromNodes = (nodes) => nodes.flatMap(node => {
|
|
29
35
|
switch (node.type) {
|
|
30
36
|
case 'Command': {
|
|
@@ -41,6 +47,8 @@ export const getDependenciesFromScript = (script, options) => {
|
|
|
41
47
|
return [];
|
|
42
48
|
if (binary.startsWith('-') || binary.startsWith('"') || binary.startsWith('..'))
|
|
43
49
|
return [];
|
|
50
|
+
if (definedFunctions.has(binary))
|
|
51
|
+
return [];
|
|
44
52
|
const args = node.suffix?.map(arg => arg.text) ?? [];
|
|
45
53
|
if (['!', 'test'].includes(binary))
|
|
46
54
|
return fromArgs(args);
|
|
@@ -82,13 +90,18 @@ export const getDependenciesFromScript = (script, options) => {
|
|
|
82
90
|
return getDependenciesFromNodes(node.commands);
|
|
83
91
|
case 'Function':
|
|
84
92
|
return getDependenciesFromNodes(node.body.commands);
|
|
93
|
+
case 'Subshell':
|
|
94
|
+
return getDependenciesFromNodes(node.list.commands);
|
|
85
95
|
default:
|
|
86
96
|
return [];
|
|
87
97
|
}
|
|
88
98
|
});
|
|
89
99
|
try {
|
|
90
100
|
const parsed = parse(script);
|
|
91
|
-
|
|
101
|
+
if (!parsed?.commands)
|
|
102
|
+
return [];
|
|
103
|
+
collectFunctionNames(parsed.commands);
|
|
104
|
+
return getDependenciesFromNodes(parsed.commands);
|
|
92
105
|
}
|
|
93
106
|
catch (error) {
|
|
94
107
|
const msg = `Warning: failed to parse and ignoring script in ${relative(options.cwd, options.containingFilePath)} (${truncate(script, 30)})`;
|
|
@@ -479,6 +479,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
|
|
|
479
479
|
entry?: string | string[] | undefined;
|
|
480
480
|
project?: string | string[] | undefined;
|
|
481
481
|
} | undefined;
|
|
482
|
+
svgr?: string | boolean | string[] | {
|
|
483
|
+
config?: string | string[] | undefined;
|
|
484
|
+
entry?: string | string[] | undefined;
|
|
485
|
+
project?: string | string[] | undefined;
|
|
486
|
+
} | undefined;
|
|
482
487
|
syncpack?: string | boolean | string[] | {
|
|
483
488
|
config?: string | string[] | undefined;
|
|
484
489
|
entry?: string | string[] | undefined;
|
|
@@ -1075,6 +1080,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
|
|
|
1075
1080
|
entry?: string | string[] | undefined;
|
|
1076
1081
|
project?: string | string[] | undefined;
|
|
1077
1082
|
} | undefined;
|
|
1083
|
+
svgr?: string | boolean | string[] | {
|
|
1084
|
+
config?: string | string[] | undefined;
|
|
1085
|
+
entry?: string | string[] | undefined;
|
|
1086
|
+
project?: string | string[] | undefined;
|
|
1087
|
+
} | undefined;
|
|
1078
1088
|
syncpack?: string | boolean | string[] | {
|
|
1079
1089
|
config?: string | string[] | undefined;
|
|
1080
1090
|
entry?: string | string[] | undefined;
|
package/dist/compilers/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import Astro from './astro.js';
|
|
|
2
2
|
import AstroMDX from './astro-mdx.js';
|
|
3
3
|
import MDX from './mdx.js';
|
|
4
4
|
import Prisma from './prisma.js';
|
|
5
|
+
import SCSS from './scss.js';
|
|
5
6
|
import Svelte from './svelte.js';
|
|
6
7
|
import CSS from './tailwind.js';
|
|
7
8
|
import Vue from './vue.js';
|
|
@@ -33,12 +34,14 @@ const compilers = new Map([
|
|
|
33
34
|
['.css', CSS],
|
|
34
35
|
['.mdx', MDX],
|
|
35
36
|
['.prisma', Prisma],
|
|
37
|
+
['.sass', SCSS],
|
|
38
|
+
['.scss', SCSS],
|
|
36
39
|
['.svelte', Svelte],
|
|
37
40
|
['.vue', Vue],
|
|
38
41
|
]);
|
|
39
42
|
export const getIncludedCompilers = (syncCompilers, asyncCompilers, dependencies) => {
|
|
40
43
|
const hasDependency = (packageName) => dependencies.has(packageName);
|
|
41
|
-
for (const [extension, { condition, compiler }] of compilers
|
|
44
|
+
for (const [extension, { condition, compiler }] of compilers) {
|
|
42
45
|
if (extension === '.mdx' && AstroMDX.condition(hasDependency)) {
|
|
43
46
|
syncCompilers.set(extension, AstroMDX.compiler);
|
|
44
47
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const condition = (hasDependency) => hasDependency('sass') || hasDependency('sass-embedded') || hasDependency('node-sass');
|
|
2
|
+
const importMatcher = /@(?:use|import|forward)\s+['"](pkg:)?([^'"]+)['"]/g;
|
|
3
|
+
const toRelative = (specifier) => (specifier.startsWith('.') ? specifier : `./${specifier}`);
|
|
4
|
+
const compiler = (text) => {
|
|
5
|
+
const imports = [];
|
|
6
|
+
let match;
|
|
7
|
+
let index = 0;
|
|
8
|
+
while ((match = importMatcher.exec(text))) {
|
|
9
|
+
if (match[2])
|
|
10
|
+
imports.push(`import _$${index++} from '${match[1] ? match[2] : toRelative(match[2])}';`);
|
|
11
|
+
}
|
|
12
|
+
return imports.join('\n');
|
|
13
|
+
};
|
|
14
|
+
export default { condition, compiler };
|
package/dist/constants.js
CHANGED
package/dist/graph/analyze.js
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createGraphExplorer } from '../graph-explorer/explorer.js';
|
|
2
|
+
import { getIssueType, hasStrictlyEnumReferences } from '../graph-explorer/utils.js';
|
|
3
3
|
import { getPackageNameFromModuleSpecifier } from '../util/modules.js';
|
|
4
|
+
import { toRelative } from '../util/path.js';
|
|
4
5
|
import { findMatch } from '../util/regex.js';
|
|
5
6
|
import { getShouldIgnoreHandler, getShouldIgnoreTagHandler } from '../util/tag.js';
|
|
6
|
-
import {
|
|
7
|
+
import { formatTrace } from '../util/trace.js';
|
|
7
8
|
export const analyze = async ({ analyzedFiles, counselor, chief, collector, deputy, entryPaths, factory, graph, streamer, unreferencedFiles, options, }) => {
|
|
8
9
|
const shouldIgnore = getShouldIgnoreHandler(options.isProduction);
|
|
9
10
|
const shouldIgnoreTags = getShouldIgnoreTagHandler(options.tags);
|
|
10
|
-
const
|
|
11
|
+
const explorer = createGraphExplorer(graph, entryPaths);
|
|
11
12
|
const ignoreExportsUsedInFile = chief.config.ignoreExportsUsedInFile;
|
|
12
|
-
const
|
|
13
|
-
(exportedItem.
|
|
13
|
+
const isExportReferencedInFile = (exportedItem) => exportedItem.self[1] ||
|
|
14
|
+
(exportedItem.self[0] > 0 &&
|
|
14
15
|
(typeof ignoreExportsUsedInFile === 'object'
|
|
15
16
|
? exportedItem.type !== 'unknown' && !!ignoreExportsUsedInFile[exportedItem.type]
|
|
16
17
|
: ignoreExportsUsedInFile));
|
|
17
18
|
const analyzeGraph = async () => {
|
|
18
19
|
if (options.isReportValues || options.isReportTypes) {
|
|
19
20
|
streamer.cast('Connecting the dots');
|
|
20
|
-
for (const [filePath, file] of graph
|
|
21
|
+
for (const [filePath, file] of graph) {
|
|
21
22
|
const exportItems = file.exports;
|
|
22
23
|
if (!exportItems || exportItems.size === 0)
|
|
23
24
|
continue;
|
|
@@ -27,17 +28,18 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
27
28
|
const principal = factory.getPrincipalByPackageName(workspace.pkgName);
|
|
28
29
|
const isEntry = entryPaths.has(filePath);
|
|
29
30
|
if (!isIncludeEntryExports && isEntry) {
|
|
30
|
-
createAndPrintTrace(filePath, options, { isEntry });
|
|
31
31
|
continue;
|
|
32
32
|
}
|
|
33
33
|
const importsForExport = file.imported;
|
|
34
|
-
for (const [identifier, exportedItem] of exportItems
|
|
34
|
+
for (const [identifier, exportedItem] of exportItems) {
|
|
35
35
|
if (shouldIgnore(exportedItem.jsDocTags))
|
|
36
36
|
continue;
|
|
37
37
|
const isIgnored = shouldIgnoreTags(exportedItem.jsDocTags);
|
|
38
38
|
if (importsForExport) {
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
const [isReferenced, reExportingEntryFile] = explorer.isReferenced(filePath, identifier, {
|
|
40
|
+
includeEntryExports: isIncludeEntryExports,
|
|
41
|
+
});
|
|
42
|
+
if ((isReferenced || exportedItem.self[1]) && isIgnored) {
|
|
41
43
|
for (const tagName of exportedItem.jsDocTags) {
|
|
42
44
|
if (options.tags[1].includes(tagName.replace(/^@/, ''))) {
|
|
43
45
|
collector.addTagHint({ type: 'tag', filePath, identifier, tagName });
|
|
@@ -46,17 +48,14 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
46
48
|
}
|
|
47
49
|
if (isIgnored)
|
|
48
50
|
continue;
|
|
49
|
-
if (reExportingEntryFile) {
|
|
51
|
+
if (reExportingEntryFile && !isReferenced) {
|
|
50
52
|
if (!isIncludeEntryExports) {
|
|
51
|
-
createAndPrintTrace(filePath, options, { identifier, isEntry, hasRef: isReferenced });
|
|
52
53
|
continue;
|
|
53
54
|
}
|
|
54
55
|
const reExportedItem = graph.get(reExportingEntryFile)?.exports.get(identifier);
|
|
55
56
|
if (reExportedItem && shouldIgnore(reExportedItem.jsDocTags))
|
|
56
57
|
continue;
|
|
57
58
|
}
|
|
58
|
-
if (traceNode)
|
|
59
|
-
printTrace(traceNode, filePath, options, identifier);
|
|
60
59
|
if (isReferenced) {
|
|
61
60
|
if (options.includedIssueTypes.enumMembers && exportedItem.type === 'enum') {
|
|
62
61
|
if (!options.includedIssueTypes.nsTypes && importsForExport.refs.has(identifier))
|
|
@@ -68,11 +67,13 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
68
67
|
continue;
|
|
69
68
|
if (shouldIgnore(member.jsDocTags))
|
|
70
69
|
continue;
|
|
71
|
-
if (member.
|
|
70
|
+
if (member.self[0] === 0) {
|
|
72
71
|
const id = `${identifier}.${member.identifier}`;
|
|
73
|
-
const
|
|
72
|
+
const [isMemberReferenced] = explorer.isReferenced(filePath, id, {
|
|
73
|
+
includeEntryExports: true,
|
|
74
|
+
});
|
|
74
75
|
const isIgnored = shouldIgnoreTags(member.jsDocTags);
|
|
75
|
-
if (!
|
|
76
|
+
if (!isMemberReferenced) {
|
|
76
77
|
if (isIgnored)
|
|
77
78
|
continue;
|
|
78
79
|
collector.addIssue({
|
|
@@ -125,17 +126,17 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
125
126
|
continue;
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
|
-
const [hasStrictlyNsRefs, namespace] = hasStrictlyNsReferences(
|
|
129
|
+
const [hasStrictlyNsRefs, namespace] = explorer.hasStrictlyNsReferences(filePath, identifier);
|
|
129
130
|
const isType = ['enum', 'type', 'interface'].includes(exportedItem.type);
|
|
130
131
|
if (hasStrictlyNsRefs &&
|
|
131
132
|
((!options.includedIssueTypes.nsTypes && isType) || !(options.includedIssueTypes.nsExports || isType)))
|
|
132
133
|
continue;
|
|
133
|
-
if (!
|
|
134
|
+
if (!isExportReferencedInFile(exportedItem)) {
|
|
134
135
|
if (isIgnored)
|
|
135
136
|
continue;
|
|
136
137
|
if (!options.isSkipLibs && principal?.hasExternalReferences(filePath, exportedItem))
|
|
137
138
|
continue;
|
|
138
|
-
const type =
|
|
139
|
+
const type = getIssueType(hasStrictlyNsRefs, isType);
|
|
139
140
|
collector.addIssue({
|
|
140
141
|
type,
|
|
141
142
|
filePath,
|
|
@@ -153,7 +154,7 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
|
-
for (const [filePath, file] of graph
|
|
157
|
+
for (const [filePath, file] of graph) {
|
|
157
158
|
const ws = chief.findWorkspaceByFilePath(filePath);
|
|
158
159
|
if (ws) {
|
|
159
160
|
if (file.duplicates && options.includedIssueTypes.duplicates) {
|
|
@@ -227,5 +228,20 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
|
|
|
227
228
|
collector.addConfigurationHint(hint);
|
|
228
229
|
};
|
|
229
230
|
await analyzeGraph();
|
|
231
|
+
if (options.isTrace) {
|
|
232
|
+
const nodes = explorer.buildExportsTree({ filePath: options.traceFile, identifier: options.traceExport });
|
|
233
|
+
nodes.sort((a, b) => a.filePath.localeCompare(b.filePath) || a.identifier.localeCompare(b.identifier));
|
|
234
|
+
const toRel = (path) => toRelative(path, options.cwd);
|
|
235
|
+
const isReferenced = (node) => {
|
|
236
|
+
if (explorer.isReferenced(node.filePath, node.identifier, { includeEntryExports: false })[0])
|
|
237
|
+
return true;
|
|
238
|
+
if (explorer.hasStrictlyNsReferences(node.filePath, node.identifier)[0])
|
|
239
|
+
return true;
|
|
240
|
+
const exportItem = graph.get(node.filePath)?.exports.get(node.identifier);
|
|
241
|
+
return exportItem ? isExportReferencedInFile(exportItem) : false;
|
|
242
|
+
};
|
|
243
|
+
for (const node of nodes)
|
|
244
|
+
console.log(formatTrace(node, toRel, isReferenced(node)));
|
|
245
|
+
}
|
|
230
246
|
return analyzeGraph;
|
|
231
247
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ModuleGraph } from '../types/module-graph.js';
|
|
2
|
+
export declare const createGraphExplorer: (graph: ModuleGraph, entryPaths: Set<string>) => {
|
|
3
|
+
isReferenced: (filePath: string, identifier: string, options: {
|
|
4
|
+
includeEntryExports: boolean;
|
|
5
|
+
}) => [boolean, string | undefined];
|
|
6
|
+
hasStrictlyNsReferences: (filePath: string, identifier: string) => [boolean, (string | undefined)?];
|
|
7
|
+
buildExportsTree: (options: {
|
|
8
|
+
filePath?: string;
|
|
9
|
+
identifier?: string;
|
|
10
|
+
}) => import("./operations/build-exports-tree.js").TreeNode[];
|
|
11
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { buildExportsTree } from './operations/build-exports-tree.js';
|
|
2
|
+
import { hasStrictlyNsReferences } from './operations/has-strictly-ns-references.js';
|
|
3
|
+
import { isReferenced } from './operations/is-referenced.js';
|
|
4
|
+
export const createGraphExplorer = (graph, entryPaths) => {
|
|
5
|
+
return {
|
|
6
|
+
isReferenced: (filePath, identifier, options) => isReferenced(graph, entryPaths, filePath, identifier, options),
|
|
7
|
+
hasStrictlyNsReferences: (filePath, identifier) => hasStrictlyNsReferences(graph, graph.get(filePath)?.imported, identifier),
|
|
8
|
+
buildExportsTree: (options) => buildExportsTree(graph, entryPaths, options),
|
|
9
|
+
};
|
|
10
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Identifier, ModuleGraph } from '../../types/module-graph.js';
|
|
2
|
+
import type { Via } from '../walk-down.js';
|
|
3
|
+
export interface TreeNode {
|
|
4
|
+
filePath: string;
|
|
5
|
+
identifier: string;
|
|
6
|
+
originalId: string | undefined;
|
|
7
|
+
via: Via | undefined;
|
|
8
|
+
refs: string[];
|
|
9
|
+
isEntry: boolean;
|
|
10
|
+
children: TreeNode[];
|
|
11
|
+
}
|
|
12
|
+
export declare const buildExportsTree: (graph: ModuleGraph, entryPaths: Set<string>, options: {
|
|
13
|
+
filePath?: string;
|
|
14
|
+
identifier?: Identifier;
|
|
15
|
+
}) => TreeNode[];
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { CONTINUE } from '../constants.js';
|
|
2
|
+
import { walkDown } from '../walk-down.js';
|
|
3
|
+
export const buildExportsTree = (graph, entryPaths, options) => {
|
|
4
|
+
const traces = [];
|
|
5
|
+
const processFile = (filePath, file) => {
|
|
6
|
+
for (const exportId of options.identifier ? [options.identifier] : file.exports.keys()) {
|
|
7
|
+
if (!options.identifier || file.exports.has(exportId)) {
|
|
8
|
+
const trace = buildExportTree(graph, entryPaths, filePath, exportId);
|
|
9
|
+
if (trace)
|
|
10
|
+
traces.push(trace);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
if (options.filePath) {
|
|
15
|
+
const file = graph.get(options.filePath);
|
|
16
|
+
if (file)
|
|
17
|
+
processFile(options.filePath, file);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
for (const [filePath, file] of graph)
|
|
21
|
+
processFile(filePath, file);
|
|
22
|
+
}
|
|
23
|
+
return traces;
|
|
24
|
+
};
|
|
25
|
+
const buildExportTree = (graph, entryPaths, filePath, identifier) => {
|
|
26
|
+
const file = graph.get(filePath);
|
|
27
|
+
const rootNode = {
|
|
28
|
+
filePath,
|
|
29
|
+
identifier,
|
|
30
|
+
refs: filterRefs(file?.imported?.refs, identifier),
|
|
31
|
+
isEntry: entryPaths.has(filePath),
|
|
32
|
+
children: [],
|
|
33
|
+
originalId: undefined,
|
|
34
|
+
via: undefined,
|
|
35
|
+
};
|
|
36
|
+
const nodeMap = new Map();
|
|
37
|
+
nodeMap.set(`${filePath}:${identifier}`, rootNode);
|
|
38
|
+
walkDown(graph, filePath, identifier, (sourceFile, sourceId, importingFile, id, isEntry, via) => {
|
|
39
|
+
const importMaps = graph.get(importingFile)?.imports.internal.get(sourceFile);
|
|
40
|
+
const importRefs = importMaps?.refs;
|
|
41
|
+
const ns = id.split('.')[0];
|
|
42
|
+
if (via === 'importNS' && !hasRelevantRef(importRefs, id) && !isNsReExported(importMaps, ns))
|
|
43
|
+
return CONTINUE;
|
|
44
|
+
const key = `${importingFile}:${id}`;
|
|
45
|
+
const isRenamed = via.endsWith('As') && sourceId !== ns;
|
|
46
|
+
const refs = filterRefs(importRefs, id);
|
|
47
|
+
const childNode = nodeMap.get(key) ?? {
|
|
48
|
+
filePath: importingFile,
|
|
49
|
+
identifier: id,
|
|
50
|
+
originalId: isRenamed ? sourceId : undefined,
|
|
51
|
+
via,
|
|
52
|
+
refs,
|
|
53
|
+
isEntry,
|
|
54
|
+
children: [],
|
|
55
|
+
};
|
|
56
|
+
nodeMap.set(key, childNode);
|
|
57
|
+
let parentNode = nodeMap.get(`${sourceFile}:${sourceId}`);
|
|
58
|
+
if (!parentNode) {
|
|
59
|
+
for (const [k, v] of nodeMap) {
|
|
60
|
+
if (k.startsWith(`${sourceFile}:${sourceId}.`) || k === `${sourceFile}:${sourceId}`) {
|
|
61
|
+
parentNode = v;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
(parentNode ?? rootNode).children.push(childNode);
|
|
67
|
+
return CONTINUE;
|
|
68
|
+
}, entryPaths);
|
|
69
|
+
pruneReExportStarOnlyBranches(rootNode);
|
|
70
|
+
return rootNode;
|
|
71
|
+
};
|
|
72
|
+
const filterRefs = (refs, id) => {
|
|
73
|
+
if (!refs)
|
|
74
|
+
return [];
|
|
75
|
+
return Array.from(refs).filter(ref => id === ref || id.startsWith(`${ref}.`) || ref.startsWith(`${id}.`));
|
|
76
|
+
};
|
|
77
|
+
const hasRelevantRef = (refs, id) => {
|
|
78
|
+
if (!refs || refs.size === 0)
|
|
79
|
+
return false;
|
|
80
|
+
return Array.from(refs).some(ref => ref === id || ref.startsWith(`${id}.`));
|
|
81
|
+
};
|
|
82
|
+
const isNsReExported = (importMaps, ns) => {
|
|
83
|
+
if (!importMaps)
|
|
84
|
+
return false;
|
|
85
|
+
return importMaps.reExportedAs.has(ns) || importMaps.reExportedNs.has(ns);
|
|
86
|
+
};
|
|
87
|
+
const hasNonReExportStar = (node) => {
|
|
88
|
+
if (node.via && node.via !== 'reExportStar')
|
|
89
|
+
return true;
|
|
90
|
+
return node.children.some(child => hasNonReExportStar(child));
|
|
91
|
+
};
|
|
92
|
+
const pruneReExportStarOnlyBranches = (node) => {
|
|
93
|
+
node.children = node.children.filter(child => hasNonReExportStar(child));
|
|
94
|
+
for (const child of node.children)
|
|
95
|
+
pruneReExportStarOnlyBranches(child);
|
|
96
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { forEachAliasReExport, forEachNamespaceReExport, forEachPassThroughReExport, getStarReExportSources, } from '../visitors.js';
|
|
2
|
+
export const hasStrictlyNsReferences = (graph, importsForExport, identifier) => {
|
|
3
|
+
if (!importsForExport)
|
|
4
|
+
return [false];
|
|
5
|
+
let foundNamespace;
|
|
6
|
+
const aliasByIdentifier = new Map();
|
|
7
|
+
const namespaceReExports = new Map();
|
|
8
|
+
const namespaceEdges = [];
|
|
9
|
+
const directById = new Map();
|
|
10
|
+
forEachPassThroughReExport(importsForExport, (id, sources) => {
|
|
11
|
+
directById.set(id, sources);
|
|
12
|
+
});
|
|
13
|
+
forEachAliasReExport(importsForExport, (id, alias, sources) => {
|
|
14
|
+
let arr = aliasByIdentifier.get(id);
|
|
15
|
+
if (!arr) {
|
|
16
|
+
arr = [];
|
|
17
|
+
aliasByIdentifier.set(id, arr);
|
|
18
|
+
}
|
|
19
|
+
arr.push({ alias, sources });
|
|
20
|
+
});
|
|
21
|
+
forEachNamespaceReExport(importsForExport, (namespace, sources) => {
|
|
22
|
+
namespaceEdges.push({ namespace, sources });
|
|
23
|
+
let arr = namespaceReExports.get(namespace);
|
|
24
|
+
if (!arr) {
|
|
25
|
+
arr = [];
|
|
26
|
+
namespaceReExports.set(namespace, arr);
|
|
27
|
+
}
|
|
28
|
+
arr.push(sources);
|
|
29
|
+
});
|
|
30
|
+
const starSources = getStarReExportSources(importsForExport);
|
|
31
|
+
const followReExports = (sources, nextId, propagateNamespace = true) => {
|
|
32
|
+
for (const filePath of sources) {
|
|
33
|
+
const file = graph.get(filePath);
|
|
34
|
+
if (!file?.imported)
|
|
35
|
+
continue;
|
|
36
|
+
const result = hasStrictlyNsReferences(graph, file.imported, nextId);
|
|
37
|
+
if (result[0] === false)
|
|
38
|
+
return result;
|
|
39
|
+
if (propagateNamespace && result[1])
|
|
40
|
+
foundNamespace = result[1];
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
};
|
|
44
|
+
for (const ns of importsForExport.importedNs.keys()) {
|
|
45
|
+
const hasNsRef = importsForExport.refs.has(ns);
|
|
46
|
+
if (!hasNsRef)
|
|
47
|
+
return [false, ns];
|
|
48
|
+
for (const ref of importsForExport.refs) {
|
|
49
|
+
if (ref.startsWith(`${ns}.`))
|
|
50
|
+
return [false, ns];
|
|
51
|
+
}
|
|
52
|
+
const nsReExports = namespaceReExports.get(ns);
|
|
53
|
+
if (nsReExports) {
|
|
54
|
+
for (const sources of nsReExports) {
|
|
55
|
+
const result = followReExports(sources, identifier, false);
|
|
56
|
+
if (result)
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const nsAliases = aliasByIdentifier.get(ns);
|
|
61
|
+
if (nsAliases) {
|
|
62
|
+
for (const { sources } of nsAliases) {
|
|
63
|
+
const result = followReExports(sources, identifier, false);
|
|
64
|
+
if (result)
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
foundNamespace = ns;
|
|
69
|
+
}
|
|
70
|
+
const directSources = directById.get(identifier);
|
|
71
|
+
if (directSources) {
|
|
72
|
+
const result = followReExports(directSources, identifier, true);
|
|
73
|
+
if (result)
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
if (starSources) {
|
|
77
|
+
const result = followReExports(starSources, identifier, true);
|
|
78
|
+
if (result)
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
const [id, ...rest] = identifier.split('.');
|
|
82
|
+
const aliasEntries = aliasByIdentifier.get(id);
|
|
83
|
+
if (aliasEntries) {
|
|
84
|
+
for (const { alias, sources } of aliasEntries) {
|
|
85
|
+
const result = followReExports(sources, [alias, ...rest].join('.'), true);
|
|
86
|
+
if (result)
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const { namespace: ns, sources } of namespaceEdges) {
|
|
91
|
+
const result = followReExports(sources, `${ns}.${identifier}`, true);
|
|
92
|
+
if (result)
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
if (foundNamespace)
|
|
96
|
+
return [true, foundNamespace];
|
|
97
|
+
return [false];
|
|
98
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Identifier, ModuleGraph } from '../../types/module-graph.js';
|
|
2
|
+
export declare const isReferenced: (graph: ModuleGraph, entryPaths: Set<string>, filePath: string, id: Identifier, options: {
|
|
3
|
+
includeEntryExports: boolean;
|
|
4
|
+
}) => [boolean, string | undefined];
|