knip 6.35.1 → 6.37.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.
Files changed (109) hide show
  1. package/dist/ConfigurationChief.d.ts +20 -2
  2. package/dist/ConfigurationChief.js +15 -1
  3. package/dist/DependencyDeputy.d.ts +0 -2
  4. package/dist/DependencyDeputy.js +1 -17
  5. package/dist/WorkspaceWorker.js +7 -6
  6. package/dist/binaries/bash-parser.js +1 -1
  7. package/dist/binaries/command.js +21 -10
  8. package/dist/binaries/fallback.js +5 -4
  9. package/dist/binaries/plugins.js +4 -4
  10. package/dist/binaries/resolvers/bun.js +2 -2
  11. package/dist/binaries/resolvers/find.js +5 -4
  12. package/dist/binaries/resolvers/index.d.ts +2 -1
  13. package/dist/binaries/resolvers/index.js +3 -2
  14. package/dist/binaries/resolvers/npm.js +46 -4
  15. package/dist/binaries/resolvers/npx.js +8 -4
  16. package/dist/binaries/resolvers/nub.js +3 -2
  17. package/dist/binaries/resolvers/pnpm.js +17 -10
  18. package/dist/binaries/resolvers/yarn.js +1 -1
  19. package/dist/binaries/util.d.ts +4 -1
  20. package/dist/binaries/util.js +2 -0
  21. package/dist/compilers/compilers.js +1 -1
  22. package/dist/compilers/scss.js +2 -2
  23. package/dist/graph-explorer/cache.d.ts +3 -0
  24. package/dist/graph-explorer/cache.js +6 -0
  25. package/dist/graph-explorer/explorer.d.ts +1 -0
  26. package/dist/graph-explorer/explorer.js +2 -0
  27. package/dist/graph-explorer/operations/build-exports-tree.js +14 -2
  28. package/dist/graph-explorer/operations/get-ambiguous-star-export.d.ts +8 -0
  29. package/dist/graph-explorer/operations/get-ambiguous-star-export.js +11 -0
  30. package/dist/graph-explorer/operations/get-contention.js +265 -122
  31. package/dist/graph-explorer/operations/resolve-export-origins.d.ts +32 -0
  32. package/dist/graph-explorer/operations/resolve-export-origins.js +255 -0
  33. package/dist/graph-explorer/utils.js +8 -0
  34. package/dist/manifest/index.js +1 -3
  35. package/dist/plugins/ava/index.js +1 -1
  36. package/dist/plugins/eslint/helpers.d.ts +2 -1
  37. package/dist/plugins/eslint/helpers.js +59 -14
  38. package/dist/plugins/eslint/index.js +2 -2
  39. package/dist/plugins/eslint/resolveFromAST.js +17 -11
  40. package/dist/plugins/eslint/types.d.ts +3 -3
  41. package/dist/plugins/github-actions/index.js +1 -1
  42. package/dist/plugins/graphql-codegen/index.js +15 -4
  43. package/dist/plugins/graphql-codegen/types.d.ts +11 -1
  44. package/dist/plugins/graphql-codegen/types.js +6 -0
  45. package/dist/plugins/husky/index.js +1 -1
  46. package/dist/plugins/index.d.ts +2 -0
  47. package/dist/plugins/index.js +4 -0
  48. package/dist/plugins/lefthook/index.js +1 -1
  49. package/dist/plugins/mise/scripts.js +5 -5
  50. package/dist/plugins/next/index.js +39 -5
  51. package/dist/plugins/node/index.js +6 -0
  52. package/dist/plugins/tailwind/compiler.js +2 -2
  53. package/dist/plugins/tailwind/index.js +7 -1
  54. package/dist/plugins/taskfile/index.js +1 -1
  55. package/dist/plugins/tauri/index.js +1 -1
  56. package/dist/plugins/textlint/helpers.d.ts +4 -0
  57. package/dist/plugins/textlint/helpers.js +39 -0
  58. package/dist/plugins/textlint/index.d.ts +3 -0
  59. package/dist/plugins/textlint/index.js +52 -0
  60. package/dist/plugins/textlint/types.d.ts +5 -0
  61. package/dist/plugins/textlint/types.js +1 -0
  62. package/dist/plugins/travis/index.js +1 -1
  63. package/dist/plugins/typedoc/index.js +3 -2
  64. package/dist/plugins/typedoc/types.d.ts +2 -2
  65. package/dist/plugins/varlock/index.d.ts +3 -0
  66. package/dist/plugins/varlock/index.js +31 -0
  67. package/dist/plugins/varlock/parse.d.ts +11 -0
  68. package/dist/plugins/varlock/parse.js +185 -0
  69. package/dist/plugins/varlock/scan.d.ts +2 -0
  70. package/dist/plugins/varlock/scan.js +78 -0
  71. package/dist/plugins/vite-plus/resolveFromAST.js +1 -1
  72. package/dist/plugins/vitest/index.js +4 -2
  73. package/dist/reporters/trace.js +30 -1
  74. package/dist/schema/configuration.d.ts +33 -0
  75. package/dist/schema/configuration.js +2 -0
  76. package/dist/schema/plugins.d.ts +10 -0
  77. package/dist/schema/plugins.js +2 -0
  78. package/dist/session/build-maps.js +9 -1
  79. package/dist/session/file-descriptor.js +0 -2
  80. package/dist/session/index.d.ts +1 -1
  81. package/dist/session/types.d.ts +18 -0
  82. package/dist/types/PluginNames.d.ts +2 -2
  83. package/dist/types/PluginNames.js +2 -0
  84. package/dist/types/config.d.ts +5 -1
  85. package/dist/types/module-graph.d.ts +3 -0
  86. package/dist/types/package-json.d.ts +1 -1
  87. package/dist/typescript/get-imports-and-exports.js +43 -9
  88. package/dist/typescript/visitors/exports.js +9 -4
  89. package/dist/typescript/visitors/walk.d.ts +1 -1
  90. package/dist/typescript/visitors/walk.js +4 -1
  91. package/dist/util/array.d.ts +1 -1
  92. package/dist/util/array.js +5 -1
  93. package/dist/util/create-input-handler.js +3 -3
  94. package/dist/util/create-options.d.ts +28 -2
  95. package/dist/util/file-entry-cache.js +1 -1
  96. package/dist/util/glob-core.d.ts +1 -0
  97. package/dist/util/glob-core.js +11 -3
  98. package/dist/util/jiti.js +1 -0
  99. package/dist/util/modules.d.ts +2 -0
  100. package/dist/util/modules.js +3 -1
  101. package/dist/util/package-json.d.ts +185 -183
  102. package/dist/util/parse-args.d.ts +2 -0
  103. package/dist/util/parse-args.js +6 -1
  104. package/dist/util/url.d.ts +1 -0
  105. package/dist/util/url.js +2 -0
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/package.json +5 -5
  109. package/schema.json +20 -0
@@ -1,6 +1,9 @@
1
1
  import type { Word } from 'unbash';
2
2
  import type { BinaryResolverOptions, GetInputsFromScriptsOptions, ScriptArg } from '../types/config.ts';
3
- import type { Input } from '../util/input.ts';
3
+ import { type Input } from '../util/input.ts';
4
+ export declare const toCommandBinary: (binary: string, { optionalBinaries }: GetInputsFromScriptsOptions, inputOptions?: {
5
+ dir?: string;
6
+ }) => Input;
4
7
  export declare const toScript: (args: ScriptArg[]) => string;
5
8
  export declare const argsFrom: <T extends string | Word>(args: readonly T[], from: string) => T[];
6
9
  export declare const argsAfter: <T extends string | Word>(args: readonly T[], token: string) => T[];
@@ -1,4 +1,6 @@
1
1
  import parseArgs from '../util/parse-args.js';
2
+ import { toBinary } from '../util/input.js';
3
+ export const toCommandBinary = (binary, { optionalBinaries }, inputOptions = {}) => toBinary(binary, optionalBinaries ? { ...inputOptions, optional: true } : inputOptions);
2
4
  const valueOf = (arg) => (typeof arg === 'string' ? arg : arg.value);
3
5
  export const toScript = (args) => {
4
6
  const parts = [];
@@ -5,7 +5,7 @@ export const styleExtractor = /<style\b((?:[^>"']|"[^"]*"|'[^']*')*)>([\s\S]*?)<
5
5
  const langAttrMatcher = /\blang\s*=\s*["']([^"']+)["']/i;
6
6
  export const blockCommentMatcher = /\/\*[\s\S]*?\*\//g;
7
7
  export const lineCommentMatcher = /^[ \t]*\/\/.*$/gm;
8
- export const importMatcher = /import(?:\s*\(\s*['"][^'"]+['"][^)]*\)|(?!\s*\()[^'"]+['"][^'"]+['"])/g;
8
+ export const importMatcher = /(?<![.\w$#])import\b(?:\s*\(\s*['"][^'"]+['"][^)]*\)|(?!\s*\()[^'"]+['"][^'"]+['"])/g;
9
9
  export const collectImports = text => {
10
10
  if (!text.includes('import'))
11
11
  return '';
@@ -1,13 +1,13 @@
1
1
  import { ensureRelative, isScopedPackage, isTildePackage, splitSpec } from './shared.js';
2
+ import { hasUrlScheme } from '../util/url.js';
2
3
  const dependencies = ['sass', 'sass-embedded', 'node-sass'];
3
4
  const dependencyMatcher = /"(?:\\(?:\r\n|[\s\S]|$)|[^"\\\r\n\f])*(?:"|[\r\n\f]|$)|'(?:\\(?:\r\n|[\s\S]|$)|[^'\\\r\n\f])*(?:'|[\r\n\f]|$)|\/\*[\s\S]*?(?:\*\/|$)|\/\/[^\r\n]*(?:[\r\n]|$)|@(?:use|import|forward)\s+['"](pkg:)?([^'"]+)['"]|url\(\s*(?:["']([^"']*)["']|([^'")\s]+))\s*\)/g;
4
- const urlSchemeMatcher = /^[a-z][a-z\d+.-]*:/i;
5
5
  const getUrlSpecifier = (url) => {
6
6
  if (!url ||
7
7
  url.startsWith('//') ||
8
8
  url.startsWith('/') ||
9
9
  url.startsWith('#') ||
10
- urlSchemeMatcher.test(url) ||
10
+ hasUrlScheme(url) ||
11
11
  url.includes('$') ||
12
12
  url.includes('#{'))
13
13
  return;
@@ -1,6 +1,7 @@
1
1
  import type { ModuleGraph } from '../types/module-graph.ts';
2
2
  import type { UsageResult } from './operations/get-usage.ts';
3
3
  import type { DefinitionResult } from './operations/resolve-definition.ts';
4
+ import type { ExportTableCache } from './operations/resolve-export-origins.ts';
4
5
  export declare const invalidateCache: (graph: ModuleGraph) => void;
5
6
  export declare const getCachedDefinition: (graph: ModuleGraph, filePath: string, identifier: string) => DefinitionResult | null | undefined;
6
7
  export declare const setCachedDefinition: (graph: ModuleGraph, filePath: string, identifier: string, result: DefinitionResult | null) => void;
@@ -8,3 +9,5 @@ export declare const getCachedUsage: (graph: ModuleGraph, filePath: string, iden
8
9
  export declare const setCachedUsage: (graph: ModuleGraph, filePath: string, identifier: string, result: UsageResult) => void;
9
10
  export declare const getCachedExportedIdentifiers: (graph: ModuleGraph, filePath: string) => Map<string, boolean> | undefined;
10
11
  export declare const setCachedExportedIdentifiers: (graph: ModuleGraph, filePath: string, result: Map<string, boolean>) => void;
12
+ export declare const getCachedExportTable: (graph: ModuleGraph, filePath: string) => ExportTableCache | undefined;
13
+ export declare const setCachedExportTable: (graph: ModuleGraph, filePath: string, table: ExportTableCache) => void;
@@ -4,6 +4,7 @@ const createEmptyCache = () => ({
4
4
  usage: new Map(),
5
5
  importLookup: new Map(),
6
6
  exportedIdentifiers: new Map(),
7
+ exportTables: new Map(),
7
8
  generation: 0,
8
9
  });
9
10
  const getCache = (graph) => {
@@ -21,6 +22,7 @@ export const invalidateCache = (graph) => {
21
22
  cache.usage.clear();
22
23
  cache.importLookup.clear();
23
24
  cache.exportedIdentifiers.clear();
25
+ cache.exportTables.clear();
24
26
  cache.generation++;
25
27
  }
26
28
  };
@@ -70,3 +72,7 @@ export const setCachedExportedIdentifiers = (graph, filePath, result) => {
70
72
  const cache = getCache(graph);
71
73
  cache.exportedIdentifiers.set(filePath, result);
72
74
  };
75
+ export const getCachedExportTable = (graph, filePath) => caches.get(graph)?.exportTables.get(filePath);
76
+ export const setCachedExportTable = (graph, filePath, table) => {
77
+ getCache(graph).exportTables.set(filePath, table);
78
+ };
@@ -10,6 +10,7 @@ export declare const createGraphExplorer: (graph: ModuleGraph, entryPaths: Set<s
10
10
  filePath?: string;
11
11
  identifier?: string;
12
12
  }) => import("./operations/build-exports-tree.ts").ExportsTreeNode[];
13
+ resolveExportOrigins: (filePath: string, identifier: string) => import("./operations/resolve-export-origins.ts").ExportOriginResolution;
13
14
  getDependencyUsage: (pattern?: string | RegExp) => Map<string, import("./operations/get-dependency-usage.ts").DependencyNodes>;
14
15
  resolveDefinition: (filePath: string, identifier: string) => import("./operations/resolve-definition.ts").DefinitionResult | null;
15
16
  getUsage: (filePath: string, identifier: string) => import("./operations/get-usage.ts").UsageResult;
@@ -9,12 +9,14 @@ import { hasStrictlyNsReferences } from './operations/has-strictly-ns-references
9
9
  import { isEnumerated } from './operations/is-enumerated.js';
10
10
  import { isReferenced } from './operations/is-referenced.js';
11
11
  import { resolveDefinition } from './operations/resolve-definition.js';
12
+ import { resolveExportOrigins } from './operations/resolve-export-origins.js';
12
13
  export const createGraphExplorer = (graph, entryPaths) => {
13
14
  return {
14
15
  isReferenced: (filePath, identifier, options) => isReferenced(graph, entryPaths, filePath, identifier, options),
15
16
  hasStrictlyNsReferences: (filePath, identifier) => hasStrictlyNsReferences(graph, filePath, graph.get(filePath)?.importedBy, identifier),
16
17
  isEnumerated: (filePath, identifier) => isEnumerated(graph, filePath, graph.get(filePath)?.importedBy, identifier),
17
18
  buildExportsTree: (options) => buildExportsTree(graph, entryPaths, options),
19
+ resolveExportOrigins: (filePath, identifier) => resolveExportOrigins(graph, filePath, identifier),
18
20
  getDependencyUsage: (pattern) => getDependencyUsage(graph, pattern),
19
21
  resolveDefinition: (filePath, identifier) => resolveDefinition(graph, filePath, identifier),
20
22
  getUsage: (filePath, identifier) => getUsage(graph, entryPaths, filePath, identifier),
@@ -45,7 +45,8 @@ const buildExportTree = (graph, entryPaths, filePath, identifier) => {
45
45
  const key = `${importingFile}:${id}`;
46
46
  const isRenamed = via.endsWith('As') && sourceId !== ns;
47
47
  const refs = filterRefs(importRefs, id);
48
- const childNode = nodeMap.get(key) ?? {
48
+ const existingNode = nodeMap.get(key);
49
+ const childNode = existingNode ?? {
49
50
  filePath: importingFile,
50
51
  identifier: id,
51
52
  originalId: isRenamed ? sourceId : undefined,
@@ -64,12 +65,23 @@ const buildExportTree = (graph, entryPaths, filePath, identifier) => {
64
65
  }
65
66
  }
66
67
  }
67
- (parentNode ?? rootNode).children.push(childNode);
68
+ const parent = parentNode ?? rootNode;
69
+ if (existingNode && reaches(existingNode, parent))
70
+ return CONTINUE;
71
+ parent.children.push(childNode);
68
72
  return CONTINUE;
69
73
  }, entryPaths);
70
74
  pruneReExportStarOnlyBranches(rootNode);
71
75
  return rootNode;
72
76
  };
77
+ const reaches = (node, target) => {
78
+ if (node === target)
79
+ return true;
80
+ for (const child of node.children)
81
+ if (reaches(child, target))
82
+ return true;
83
+ return false;
84
+ };
73
85
  const filterRefs = (refs, id) => {
74
86
  if (!refs)
75
87
  return [];
@@ -0,0 +1,8 @@
1
+ import type { ExportOriginResolution } from './resolve-export-origins.ts';
2
+ export interface AmbiguousStarExport {
3
+ origins: {
4
+ filePath: string;
5
+ identifier: string;
6
+ }[];
7
+ }
8
+ export declare const getAmbiguousStarExport: (resolution: ExportOriginResolution, identifier: string) => AmbiguousStarExport | undefined;
@@ -0,0 +1,11 @@
1
+ export const getAmbiguousStarExport = (resolution, identifier) => {
2
+ if (identifier === 'default')
3
+ return;
4
+ if (resolution.hasExplicitExport || resolution.origins.length < 2)
5
+ return;
6
+ const origins = [];
7
+ for (const origin of resolution.origins) {
8
+ origins.push({ filePath: origin.filePath, identifier: origin.identifier });
9
+ }
10
+ return { origins };
11
+ };
@@ -1,142 +1,285 @@
1
1
  import { IMPORT_STAR } from '../../constants.js';
2
- import { getExportedIdentifiers } from '../utils.js';
3
- import { forEachAliasReExport, forEachPassThroughReExport, getStarReExportSources } from '../visitors.js';
2
+ import { compareStrings } from '../../util/string.js';
3
+ import { createExportResolver } from './resolve-export-origins.js';
4
+ const SEVERITY = { ambiguous: 3, shadowed: 2, converged: 1 };
4
5
  export const getContention = (graph, filePath) => {
6
+ const result = new Map();
5
7
  const node = graph.get(filePath);
6
8
  if (!node)
7
- return new Map();
8
- const exportedIdentifiers = getExportedIdentifiers(graph, filePath);
9
- const result = new Map();
10
- for (const identifier of exportedIdentifiers.keys()) {
11
- if (identifier === 'default')
12
- continue;
13
- const details = getContentionForIdentifier(graph, filePath, identifier);
14
- if (details && (details.branching.length > 0 || details.conflict.length > 0)) {
15
- result.set(identifier, details);
9
+ return result;
10
+ const nodes = new Map([[filePath, node]]);
11
+ const getNode = (path) => {
12
+ if (nodes.has(path))
13
+ return nodes.get(path);
14
+ const found = graph.get(path);
15
+ nodes.set(path, found);
16
+ return found;
17
+ };
18
+ const positions = new Map();
19
+ const resolver = createExportResolver(graph);
20
+ const findOriginExport = (origin) => {
21
+ if (origin.identifier === IMPORT_STAR)
22
+ return;
23
+ const originNode = getNode(origin.filePath);
24
+ if (!originNode)
25
+ return;
26
+ const exact = originNode.exports.get(origin.identifier);
27
+ if (exact?.binding === origin.identifier)
28
+ return exact;
29
+ let nearest;
30
+ for (const _export of originNode.exports.values()) {
31
+ if (_export.binding !== origin.identifier)
32
+ continue;
33
+ if (!nearest || _export.pos < nearest.pos)
34
+ nearest = _export;
16
35
  }
17
- }
18
- return result;
19
- };
20
- const getContentionForIdentifier = (graph, startFilePath, identifier) => {
21
- const network = buildReExportNetwork(graph, startFilePath, identifier);
22
- if (network.files.size <= 1)
23
- return null;
24
- const branchingFiles = [];
25
- for (const file of network.files) {
26
- const sourceCount = network.reExportsFrom.get(file)?.size ?? 0;
27
- if (sourceCount > 1) {
28
- branchingFiles.push(file);
36
+ return nearest;
37
+ };
38
+ const locateOrigin = (origin) => {
39
+ const key = `${origin.filePath}:${origin.identifier}`;
40
+ const cached = positions.get(key);
41
+ if (cached)
42
+ return cached;
43
+ const _export = findOriginExport(origin);
44
+ const located = _export ? { ...origin, line: _export.line, col: _export.col } : { ...origin };
45
+ positions.set(key, located);
46
+ return located;
47
+ };
48
+ const materialize = (sitePath, identifier, entry, kind) => {
49
+ const isShadowed = kind === 'shadowed';
50
+ const origins = [];
51
+ for (const origin of (isShadowed && entry.shadowed ? entry.shadowed : entry.origins).values())
52
+ origins.push(locateOrigin(origin));
53
+ origins.sort((a, b) => compareStrings(a.filePath, b.filePath) || compareStrings(a.identifier, b.identifier));
54
+ const site = {
55
+ kind,
56
+ filePath: sitePath,
57
+ identifier,
58
+ origins,
59
+ sources: [...(isShadowed ? (entry.shadowedSources ?? []) : entry.sources.keys())],
60
+ };
61
+ const _export = getNode(sitePath)?.exports.get(identifier);
62
+ if (_export) {
63
+ site.line = _export.line;
64
+ site.col = _export.col;
29
65
  }
30
- }
31
- const hasConflict = network.definitions.size > 1;
32
- if (branchingFiles.length === 0 && !hasConflict)
33
- return null;
34
- return {
35
- branching: branchingFiles.sort(),
36
- conflict: hasConflict ? Array.from(network.definitions).sort() : [],
66
+ if (isShadowed) {
67
+ const [winner] = entry.origins.values();
68
+ if (winner)
69
+ site.winner = locateOrigin(winner);
70
+ }
71
+ return site;
37
72
  };
38
- };
39
- const buildReExportNetwork = (graph, startFilePath, identifier) => {
40
- const network = {
41
- files: new Set(),
42
- definitions: new Set(),
43
- reExportsFrom: new Map(),
73
+ const compareSites = (describedIdentifier) => (a, b) => {
74
+ const isOwnA = a.filePath === filePath && a.identifier === describedIdentifier;
75
+ const isOwnB = b.filePath === filePath && b.identifier === describedIdentifier;
76
+ if (isOwnA !== isOwnB)
77
+ return isOwnA ? -1 : 1;
78
+ return (SEVERITY[b.kind] - SEVERITY[a.kind] ||
79
+ compareStrings(a.filePath, b.filePath) ||
80
+ compareStrings(a.identifier, b.identifier));
44
81
  };
45
- const upVisited = new Set();
46
- const downVisited = new Set();
47
- walkUp(graph, network, startFilePath, identifier, upVisited);
48
- walkDown(graph, network, startFilePath, identifier, downVisited);
49
- for (const file of network.files) {
50
- if (!upVisited.has(file)) {
51
- walkUp(graph, network, file, identifier, upVisited);
82
+ const sitesByFile = new Map();
83
+ const inspect = (sitePath, identifier) => {
84
+ let sites = sitesByFile.get(sitePath);
85
+ if (!sites)
86
+ sitesByFile.set(sitePath, (sites = new Map()));
87
+ if (identifier !== undefined && (sitePath === filePath || sites.has(identifier)))
88
+ return sites.get(identifier);
89
+ const info = resolver.getInfo(sitePath);
90
+ const table = identifier === undefined ? resolver.getTable(sitePath) : new Map();
91
+ if (identifier !== undefined) {
92
+ const entry = resolver.resolve(sitePath, identifier);
93
+ if (entry)
94
+ table.set(identifier, entry);
52
95
  }
53
- }
54
- for (const definitionFile of network.definitions) {
55
- if (!downVisited.has(definitionFile))
56
- walkDown(graph, network, definitionFile, identifier, downVisited);
57
- }
58
- return network;
59
- };
60
- const walkUp = (graph, network, filePath, identifier, visited) => {
61
- if (visited.has(filePath))
62
- return;
63
- visited.add(filePath);
64
- const node = graph.get(filePath);
65
- if (!node)
66
- return;
67
- const exportedIds = getExportedIdentifiers(graph, filePath);
68
- if (!exportedIds.has(identifier))
69
- return;
70
- network.files.add(filePath);
71
- const exp = node.exports.get(identifier);
72
- if (exp && !exp.isReExport) {
73
- network.definitions.add(filePath);
74
- }
75
- for (const [sourcePath, importMaps] of node.imports.internal) {
76
- forEachPassThroughReExport(importMaps, (id, _sources) => {
77
- if (id !== identifier)
96
+ const entries = new Map();
97
+ const firstSources = new Map();
98
+ const addEntry = (name, resolution) => {
99
+ const entry = {
100
+ ...resolution,
101
+ sources: new Map(),
102
+ shadowed: undefined,
103
+ shadowedSources: undefined,
104
+ };
105
+ const first = firstSources.get(name);
106
+ if (first)
107
+ entry.sources.set(first.filePath, first);
108
+ entries.set(name, entry);
109
+ return entry;
110
+ };
111
+ for (const [name, entry] of table) {
112
+ if (entry.origins.size >= 2)
113
+ addEntry(name, entry);
114
+ }
115
+ const contribute = (name, source, origins, isStar) => {
116
+ const resolution = table.get(name);
117
+ if (!resolution || origins.size === 0)
78
118
  return;
79
- addEdge(network, sourcePath, filePath);
80
- walkUp(graph, network, sourcePath, identifier, visited);
81
- });
82
- forEachAliasReExport(importMaps, (sourceId, alias, _sources) => {
83
- if (alias !== identifier)
119
+ let entry = entries.get(name);
120
+ let contributes = false;
121
+ if (isStar && resolution.hasExplicitExport) {
122
+ for (const [key, origin] of origins) {
123
+ if (resolution.origins.has(key))
124
+ contributes = true;
125
+ else {
126
+ entry ??= addEntry(name, resolution);
127
+ (entry.shadowed ??= new Map()).set(key, origin);
128
+ (entry.shadowedSources ??= new Set()).add(source.filePath);
129
+ }
130
+ }
131
+ }
132
+ else
133
+ contributes = true;
134
+ if (!contributes)
84
135
  return;
85
- addEdge(network, sourcePath, filePath);
86
- walkUp(graph, network, sourcePath, sourceId, visited);
87
- });
88
- const starSources = getStarReExportSources(importMaps);
89
- if (starSources) {
90
- const sourceExports = getExportedIdentifiers(graph, sourcePath);
91
- if (sourceExports.has(identifier)) {
92
- addEdge(network, sourcePath, filePath);
93
- walkUp(graph, network, sourcePath, identifier, visited);
136
+ const first = firstSources.get(name);
137
+ if (!entry && first && first.filePath !== source.filePath)
138
+ entry = addEntry(name, resolution);
139
+ if (entry)
140
+ entry.sources.set(source.filePath, source);
141
+ else
142
+ firstSources.set(name, source);
143
+ };
144
+ for (const [name, sources] of info.references) {
145
+ if (!table.has(name))
146
+ continue;
147
+ for (const source of sources) {
148
+ const entry = resolver.resolve(source.filePath, source.identifier);
149
+ if (entry)
150
+ contribute(name, source, entry.origins, false);
94
151
  }
95
152
  }
96
- }
97
- };
98
- const walkDown = (graph, network, filePath, identifier, visited) => {
99
- if (visited.has(filePath))
100
- return;
101
- visited.add(filePath);
102
- const node = graph.get(filePath);
103
- if (!node?.importedBy)
104
- return;
105
- const processConsumer = (consumerPath) => {
106
- network.files.add(consumerPath);
107
- addEdge(network, filePath, consumerPath);
108
- const consumerExport = graph.get(consumerPath)?.exports.get(identifier);
109
- if (consumerExport && !consumerExport.isReExport)
110
- network.definitions.add(consumerPath);
111
- walkDown(graph, network, consumerPath, identifier, visited);
153
+ for (const [name, origins] of info.terminals) {
154
+ const entry = table.get(name);
155
+ if (!entry)
156
+ continue;
157
+ for (const origin of origins) {
158
+ if (origin.identifier === IMPORT_STAR && graph.has(origin.filePath))
159
+ contribute(name, origin, entry.origins, false);
160
+ }
161
+ }
162
+ for (const sourcePath of info.stars) {
163
+ if (identifier === undefined) {
164
+ for (const [name, entry] of resolver.getTable(sourcePath)) {
165
+ if (name !== 'default')
166
+ contribute(name, { filePath: sourcePath, identifier: name }, entry.origins, true);
167
+ }
168
+ }
169
+ else if (identifier !== 'default') {
170
+ const entry = resolver.resolve(sourcePath, identifier);
171
+ if (entry)
172
+ contribute(identifier, { filePath: sourcePath, identifier }, entry.origins, true);
173
+ }
174
+ }
175
+ for (const [name, entry] of entries) {
176
+ let kind;
177
+ if (entry.origins.size >= 2)
178
+ kind = 'ambiguous';
179
+ else if (entry.shadowed?.size)
180
+ kind = 'shadowed';
181
+ else if (entry.sources.size >= 2) {
182
+ const [origin] = entry.origins.values();
183
+ if (origin) {
184
+ for (const [path, source] of entry.sources) {
185
+ if (!resolver.reachesOrigin(source, origin, { filePath: sitePath, identifier: name }))
186
+ entry.sources.delete(path);
187
+ }
188
+ if (entry.sources.size >= 2)
189
+ kind = 'converged';
190
+ }
191
+ }
192
+ sites.set(name, kind ? materialize(sitePath, name, entry, kind) : undefined);
193
+ }
194
+ if (identifier !== undefined) {
195
+ if (!sites.has(identifier))
196
+ sites.set(identifier, undefined);
197
+ return sites.get(identifier);
198
+ }
112
199
  };
113
- const directConsumers = node.importedBy.reExport.get(identifier);
114
- if (directConsumers) {
115
- for (const consumerPath of directConsumers)
116
- processConsumer(consumerPath);
117
- }
118
- for (const [sourceId, aliasMap] of node.importedBy.reExportAs) {
119
- if (sourceId === identifier) {
120
- for (const [_alias, consumers] of aliasMap) {
200
+ inspect(filePath);
201
+ for (const [identifier, entry] of resolver.getTable(filePath)) {
202
+ if (identifier === 'default')
203
+ continue;
204
+ const sites = [];
205
+ const ownSite = inspect(filePath, identifier);
206
+ if (ownSite)
207
+ sites.push(ownSite);
208
+ else if (!node.importedBy?.reExport.size && !node.importedBy?.reExportAs.size)
209
+ continue;
210
+ const origins = entry.origins;
211
+ const visited = new Set([`${filePath}\0${identifier}`]);
212
+ const queue = [[filePath, identifier]];
213
+ const visitConsumer = (consumerPath, consumerId) => {
214
+ const key = `${consumerPath}\0${consumerId}`;
215
+ if (visited.has(key))
216
+ return;
217
+ visited.add(key);
218
+ const consumerEntry = resolver.resolve(consumerPath, consumerId);
219
+ if (!consumerEntry)
220
+ return;
221
+ const site = inspect(consumerPath, consumerId);
222
+ if (site)
223
+ sites.push(site);
224
+ if (site?.kind === 'ambiguous')
225
+ return;
226
+ for (const origin of consumerEntry.origins.keys()) {
227
+ if (origins.has(origin)) {
228
+ queue.push([consumerPath, consumerId]);
229
+ return;
230
+ }
231
+ }
232
+ };
233
+ for (let index = 0; index < queue.length; index++) {
234
+ const [currentPath, currentId] = queue[index];
235
+ const importedBy = getNode(currentPath)?.importedBy;
236
+ if (!importedBy)
237
+ continue;
238
+ const consumers = importedBy.reExport.get(currentId);
239
+ if (consumers)
121
240
  for (const consumerPath of consumers)
122
- processConsumer(consumerPath);
241
+ visitConsumer(consumerPath, currentId);
242
+ const aliases = importedBy.reExportAs.get(currentId);
243
+ if (aliases) {
244
+ for (const [alias, consumerPaths] of aliases) {
245
+ for (const consumerPath of consumerPaths)
246
+ visitConsumer(consumerPath, alias);
247
+ }
123
248
  }
249
+ const starConsumers = importedBy.reExport.get(IMPORT_STAR);
250
+ if (starConsumers)
251
+ for (const consumerPath of starConsumers)
252
+ visitConsumer(consumerPath, currentId);
124
253
  }
125
- }
126
- const starConsumers = node.importedBy.reExport.get(IMPORT_STAR);
127
- if (starConsumers) {
128
- for (const consumerPath of starConsumers) {
129
- const consumerExports = getExportedIdentifiers(graph, consumerPath);
130
- if (consumerExports.has(identifier))
131
- processConsumer(consumerPath);
254
+ if (sites.length === 0)
255
+ continue;
256
+ sites.sort(compareSites(identifier));
257
+ const branching = new Set();
258
+ const conflict = new Set();
259
+ for (const site of sites) {
260
+ if (site.kind === 'converged')
261
+ branching.add(site.filePath);
262
+ else {
263
+ let hasGraphOrigin = false;
264
+ for (const origin of site.origins) {
265
+ if (!graph.has(origin.filePath))
266
+ continue;
267
+ conflict.add(origin.filePath);
268
+ hasGraphOrigin = true;
269
+ }
270
+ if (site.winner && graph.has(site.winner.filePath)) {
271
+ conflict.add(site.winner.filePath);
272
+ hasGraphOrigin = true;
273
+ }
274
+ if (!hasGraphOrigin)
275
+ conflict.add(site.filePath);
276
+ }
132
277
  }
278
+ result.set(identifier, {
279
+ branching: [...branching].sort(),
280
+ conflict: [...conflict].sort(),
281
+ sites,
282
+ });
133
283
  }
134
- };
135
- const addEdge = (network, source, consumer) => {
136
- let sources = network.reExportsFrom.get(consumer);
137
- if (!sources) {
138
- sources = new Set();
139
- network.reExportsFrom.set(consumer, sources);
140
- }
141
- sources.add(source);
284
+ return new Map([...result].sort(([a], [b]) => compareStrings(a, b)));
142
285
  };
@@ -0,0 +1,32 @@
1
+ import type { FileNode, ModuleGraph } from '../../types/module-graph.ts';
2
+ export interface ExportOrigin {
3
+ filePath: string;
4
+ identifier: string;
5
+ }
6
+ export interface ExportOriginResolution {
7
+ origins: ExportOrigin[];
8
+ hasExplicitExport: boolean;
9
+ }
10
+ export interface ExportTableEntry {
11
+ origins: ReadonlyMap<string, ExportOrigin>;
12
+ hasExplicitExport: boolean;
13
+ }
14
+ export type ExportTable = Map<string, ExportTableEntry>;
15
+ export interface ExportTableCache {
16
+ entries: ExportTable;
17
+ complete: boolean;
18
+ }
19
+ interface ExportInfo {
20
+ node: FileNode | undefined;
21
+ references: Map<string, ExportOrigin[]>;
22
+ terminals: Map<string, ExportOrigin[]>;
23
+ stars: string[];
24
+ }
25
+ export declare const createExportResolver: (graph: ModuleGraph) => {
26
+ getTable: (filePath: string) => ExportTable;
27
+ resolve: (filePath: string, identifier: string) => ExportTableEntry | undefined;
28
+ getInfo: (filePath: string) => ExportInfo;
29
+ reachesOrigin: (source: ExportOrigin, origin: ExportOrigin, site: ExportOrigin) => boolean;
30
+ };
31
+ export declare const resolveExportOrigins: (graph: ModuleGraph, filePath: string, identifier: string) => ExportOriginResolution;
32
+ export {};