knip 6.35.0 → 6.36.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 (82) hide show
  1. package/dist/ConfigurationChief.d.ts +12 -0
  2. package/dist/IssueCollector.d.ts +3 -0
  3. package/dist/IssueCollector.js +5 -0
  4. package/dist/WorkspaceWorker.d.ts +3 -1
  5. package/dist/WorkspaceWorker.js +10 -5
  6. package/dist/binaries/command.js +2 -2
  7. package/dist/cli.js +4 -0
  8. package/dist/compilers/compilers.js +1 -1
  9. package/dist/compilers/scss.js +2 -2
  10. package/dist/graph/build.js +1 -0
  11. package/dist/graph-explorer/cache.d.ts +3 -0
  12. package/dist/graph-explorer/cache.js +6 -0
  13. package/dist/graph-explorer/explorer.d.ts +1 -0
  14. package/dist/graph-explorer/explorer.js +2 -0
  15. package/dist/graph-explorer/operations/build-exports-tree.js +14 -2
  16. package/dist/graph-explorer/operations/get-ambiguous-star-export.d.ts +8 -0
  17. package/dist/graph-explorer/operations/get-ambiguous-star-export.js +11 -0
  18. package/dist/graph-explorer/operations/get-contention.js +265 -122
  19. package/dist/graph-explorer/operations/resolve-export-origins.d.ts +32 -0
  20. package/dist/graph-explorer/operations/resolve-export-origins.js +255 -0
  21. package/dist/graph-explorer/utils.js +8 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/plugins/eslint/helpers.js +31 -6
  24. package/dist/plugins/eslint/resolveFromAST.js +17 -11
  25. package/dist/plugins/eslint/types.d.ts +3 -3
  26. package/dist/plugins/index.d.ts +2 -0
  27. package/dist/plugins/index.js +4 -0
  28. package/dist/plugins/next/index.js +39 -5
  29. package/dist/plugins/node/index.js +6 -0
  30. package/dist/plugins/tailwind/compiler.js +2 -2
  31. package/dist/plugins/tailwind/index.js +7 -1
  32. package/dist/plugins/textlint/helpers.d.ts +4 -0
  33. package/dist/plugins/textlint/helpers.js +39 -0
  34. package/dist/plugins/textlint/index.d.ts +3 -0
  35. package/dist/plugins/textlint/index.js +52 -0
  36. package/dist/plugins/textlint/types.d.ts +5 -0
  37. package/dist/plugins/textlint/types.js +1 -0
  38. package/dist/plugins/typedoc/index.js +3 -2
  39. package/dist/plugins/typedoc/types.d.ts +2 -2
  40. package/dist/plugins/varlock/index.d.ts +3 -0
  41. package/dist/plugins/varlock/index.js +31 -0
  42. package/dist/plugins/varlock/parse.d.ts +11 -0
  43. package/dist/plugins/varlock/parse.js +185 -0
  44. package/dist/plugins/varlock/scan.d.ts +2 -0
  45. package/dist/plugins/varlock/scan.js +78 -0
  46. package/dist/plugins/vitest/index.js +4 -2
  47. package/dist/reporters/trace.js +30 -1
  48. package/dist/reporters/util/configuration-hints.d.ts +1 -1
  49. package/dist/reporters/util/configuration-hints.js +11 -2
  50. package/dist/run.d.ts +2 -0
  51. package/dist/run.js +2 -1
  52. package/dist/schema/configuration.d.ts +30 -0
  53. package/dist/schema/plugins.d.ts +10 -0
  54. package/dist/schema/plugins.js +2 -0
  55. package/dist/session/build-maps.js +9 -1
  56. package/dist/session/file-descriptor.js +0 -2
  57. package/dist/session/index.d.ts +1 -1
  58. package/dist/session/types.d.ts +18 -0
  59. package/dist/types/PluginNames.d.ts +2 -2
  60. package/dist/types/PluginNames.js +2 -0
  61. package/dist/types/config.d.ts +1 -0
  62. package/dist/types/issues.d.ts +1 -0
  63. package/dist/types/module-graph.d.ts +3 -0
  64. package/dist/typescript/get-imports-and-exports.js +43 -9
  65. package/dist/typescript/resolve-module-names.js +7 -27
  66. package/dist/typescript/visitors/exports.js +9 -4
  67. package/dist/typescript/visitors/walk.d.ts +1 -1
  68. package/dist/typescript/visitors/walk.js +4 -1
  69. package/dist/util/array.d.ts +1 -1
  70. package/dist/util/array.js +5 -1
  71. package/dist/util/create-options.d.ts +20 -0
  72. package/dist/util/file-entry-cache.js +1 -1
  73. package/dist/util/glob-core.d.ts +1 -0
  74. package/dist/util/glob-core.js +11 -3
  75. package/dist/util/package-json.d.ts +2 -0
  76. package/dist/util/url.d.ts +1 -0
  77. package/dist/util/url.js +2 -0
  78. package/dist/util/watch.d.ts +1 -0
  79. package/dist/version.d.ts +1 -1
  80. package/dist/version.js +1 -1
  81. package/package.json +1 -1
  82. package/schema.json +8 -0
@@ -787,6 +787,11 @@ export declare class ConfigurationChief {
787
787
  entry?: string | string[] | undefined;
788
788
  project?: string | string[] | undefined;
789
789
  } | undefined;
790
+ textlint?: string | boolean | string[] | {
791
+ config?: string | string[] | undefined;
792
+ entry?: string | string[] | undefined;
793
+ project?: string | string[] | undefined;
794
+ } | undefined;
790
795
  travis?: string | boolean | string[] | {
791
796
  config?: string | string[] | undefined;
792
797
  entry?: string | string[] | undefined;
@@ -867,6 +872,11 @@ export declare class ConfigurationChief {
867
872
  entry?: string | string[] | undefined;
868
873
  project?: string | string[] | undefined;
869
874
  } | undefined;
875
+ varlock?: string | boolean | string[] | {
876
+ config?: string | string[] | undefined;
877
+ entry?: string | string[] | undefined;
878
+ project?: string | string[] | undefined;
879
+ } | undefined;
870
880
  vercel?: string | boolean | string[] | {
871
881
  config?: string | string[] | undefined;
872
882
  entry?: string | string[] | undefined;
@@ -1145,6 +1155,7 @@ export declare class ConfigurationChief {
1145
1155
  taskfile?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1146
1156
  tauri?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1147
1157
  temporal?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1158
+ textlint?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1148
1159
  travis?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1149
1160
  "ts-node"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1150
1161
  tsd?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -1161,6 +1172,7 @@ export declare class ConfigurationChief {
1161
1172
  "unplugin-vue-i18n"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1162
1173
  "unplugin-vue-markdown"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1163
1174
  "unplugin-vue-router"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1175
+ varlock?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1164
1176
  vercel?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1165
1177
  "vercel-og"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1166
1178
  vike?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -12,6 +12,7 @@ export declare class IssueCollector {
12
12
  private referencedFiles;
13
13
  private configurationHints;
14
14
  private tagHints;
15
+ private hasConfigLoadErrors;
15
16
  private ignorePatterns;
16
17
  private ignoreFilesPatterns;
17
18
  private isMatch;
@@ -46,12 +47,14 @@ export declare class IssueCollector {
46
47
  addIssue(issue: Issue): true | undefined;
47
48
  addConfigurationHint(issue: ConfigurationHint): void;
48
49
  addTagHint(issue: TagHint): void;
50
+ addConfigLoadError(): void;
49
51
  purge(): Set<string>;
50
52
  getIssues(): {
51
53
  issues: import("./types/issues.ts").Issues;
52
54
  counters: import("./types/issues.ts").Counters;
53
55
  tagHints: Set<TagHint>;
54
56
  configurationHints: ConfigurationHint[];
57
+ hasConfigLoadErrors: boolean;
55
58
  };
56
59
  getUnusedIgnorePatternHints(options: MainOptions): ConfigurationHint[];
57
60
  private retainedIssues;
@@ -22,6 +22,7 @@ export class IssueCollector {
22
22
  referencedFiles = new Set();
23
23
  configurationHints = new Map();
24
24
  tagHints = new Set();
25
+ hasConfigLoadErrors = false;
25
26
  ignorePatterns = new Set();
26
27
  ignoreFilesPatterns = new Set();
27
28
  isMatch;
@@ -162,6 +163,9 @@ export class IssueCollector {
162
163
  addTagHint(issue) {
163
164
  this.tagHints.add(issue);
164
165
  }
166
+ addConfigLoadError() {
167
+ this.hasConfigLoadErrors = true;
168
+ }
165
169
  purge() {
166
170
  const unusedFiles = new Set();
167
171
  for (const issues of Object.values(this.issues.files)) {
@@ -178,6 +182,7 @@ export class IssueCollector {
178
182
  counters: this.counters,
179
183
  tagHints: this.tagHints,
180
184
  configurationHints: Array.from(this.configurationHints.values()),
185
+ hasConfigLoadErrors: this.hasConfigLoadErrors,
181
186
  };
182
187
  }
183
188
  getUnusedIgnorePatternHints(options) {
@@ -16,6 +16,7 @@ type WorkspaceManagerOptions = {
16
16
  dependencies: DependencySet;
17
17
  rootManifest: Manifest | undefined;
18
18
  handleInput: HandleInput;
19
+ handleConfigLoadError: () => void;
19
20
  findWorkspaceByFilePath: (filePath: string) => Workspace | undefined;
20
21
  getManifest: (dir: string) => Manifest | undefined;
21
22
  readRawFile: (filePath: string) => string;
@@ -38,6 +39,7 @@ export declare class WorkspaceWorker {
38
39
  rootManifest: Manifest | undefined;
39
40
  dependencies: DependencySet;
40
41
  handleInput: HandleInput;
42
+ handleConfigLoadError: () => void;
41
43
  findWorkspaceByFilePath: (filePath: string) => Workspace | undefined;
42
44
  getManifest: (dir: string) => Manifest | undefined;
43
45
  readRawFile: (filePath: string) => string;
@@ -49,7 +51,7 @@ export declare class WorkspaceWorker {
49
51
  enabledPluginsInAncestors: string[];
50
52
  cache: CacheConsultant<CacheItem>;
51
53
  configFilesMap: Map<string, Map<PluginName, Set<string>>>;
52
- constructor({ name, dir, config, manifest, dependencies, rootManifest, negatedWorkspacePatterns, ignoredWorkspacePatterns, enabledPluginsInAncestors, handleInput, findWorkspaceByFilePath, getManifest, readRawFile, configFilesMap, options, }: WorkspaceManagerOptions);
54
+ constructor({ name, dir, config, manifest, dependencies, rootManifest, negatedWorkspacePatterns, ignoredWorkspacePatterns, enabledPluginsInAncestors, handleInput, handleConfigLoadError, findWorkspaceByFilePath, getManifest, readRawFile, configFilesMap, options, }: WorkspaceManagerOptions);
53
55
  init(): Promise<void>;
54
56
  private determineEnabledPlugins;
55
57
  private getConfigForPlugin;
@@ -29,6 +29,7 @@ export class WorkspaceWorker {
29
29
  rootManifest;
30
30
  dependencies;
31
31
  handleInput;
32
+ handleConfigLoadError;
32
33
  findWorkspaceByFilePath;
33
34
  getManifest;
34
35
  readRawFile;
@@ -40,7 +41,7 @@ export class WorkspaceWorker {
40
41
  enabledPluginsInAncestors;
41
42
  cache;
42
43
  configFilesMap;
43
- constructor({ name, dir, config, manifest, dependencies, rootManifest, negatedWorkspacePatterns, ignoredWorkspacePatterns, enabledPluginsInAncestors, handleInput, findWorkspaceByFilePath, getManifest, readRawFile, configFilesMap, options, }) {
44
+ constructor({ name, dir, config, manifest, dependencies, rootManifest, negatedWorkspacePatterns, ignoredWorkspacePatterns, enabledPluginsInAncestors, handleInput, handleConfigLoadError, findWorkspaceByFilePath, getManifest, readRawFile, configFilesMap, options, }) {
44
45
  this.name = name;
45
46
  this.dir = dir;
46
47
  this.config = config;
@@ -52,6 +53,7 @@ export class WorkspaceWorker {
52
53
  this.enabledPluginsInAncestors = enabledPluginsInAncestors;
53
54
  this.configFilesMap = configFilesMap;
54
55
  this.handleInput = handleInput;
56
+ this.handleConfigLoadError = handleConfigLoadError;
55
57
  this.findWorkspaceByFilePath = findWorkspaceByFilePath;
56
58
  this.getManifest = getManifest;
57
59
  this.readRawFile = readRawFile;
@@ -257,14 +259,15 @@ export class WorkspaceWorker {
257
259
  }
258
260
  };
259
261
  for (const input of [...inputsFromManifest, ...productionInputsFromManifest]) {
262
+ const inputContainingFilePath = input.containingFilePath ?? containingFilePath;
260
263
  if (isCatalog(input)) {
261
- inputs.push({ ...input, containingFilePath });
264
+ inputs.push({ ...input, containingFilePath: inputContainingFilePath });
262
265
  }
263
266
  else if (isConfig(input)) {
264
- storeConfigFilePath(input.pluginName, { ...input, containingFilePath });
267
+ storeConfigFilePath(input.pluginName, { ...input, containingFilePath: inputContainingFilePath });
265
268
  }
266
269
  else if (!isProduction || (isProduction && (input.production || hasProductionInput(input)))) {
267
- inputs.push({ ...input, containingFilePath });
270
+ inputs.push({ ...input, containingFilePath: inputContainingFilePath });
268
271
  }
269
272
  }
270
273
  const runPlugin = async (pluginName, patterns, isResolvedConfigFiles = false) => {
@@ -297,6 +300,7 @@ export class WorkspaceWorker {
297
300
  configFilePath: containingFilePath,
298
301
  configFileDir: cwd,
299
302
  configFileName: '',
303
+ isResolvedConfigFile: isResolvedConfigFiles,
300
304
  getInputsFromScripts: createGetInputsFromScripts(containingFilePath),
301
305
  };
302
306
  if (config.entry) {
@@ -378,6 +382,7 @@ export class WorkspaceWorker {
378
382
  if (!(error instanceof Error))
379
383
  throw error;
380
384
  hasLoadConfigError = true;
385
+ this.handleConfigLoadError();
381
386
  const relPath = toRelative(configFilePath, this.options.cwd);
382
387
  const cause = formatCauseMessage(error, this.options.cwd);
383
388
  logError(`Error loading ${relPath} (${cause})`);
@@ -408,7 +413,7 @@ export class WorkspaceWorker {
408
413
  if (plugin.resolve) {
409
414
  const dependencies = (await plugin.resolve(options)) ?? [];
410
415
  for (const id of dependencies)
411
- addInput(id, containingFilePath);
416
+ addInput(id, id.containingFilePath ?? containingFilePath);
412
417
  }
413
418
  if (inputs.some(input => input.specifier.startsWith('!')))
414
419
  for (const input of inputs)
@@ -26,13 +26,13 @@ export const getDependenciesFromCommand = (node, options, fromWords = options.fr
26
26
  const fromNodeOptions = getInputsFromNodeOptions(node.prefix);
27
27
  if (binary in KnownResolvers) {
28
28
  const resolver = KnownResolvers[binary];
29
- return resolver(binary, words, options);
29
+ return [...resolver(binary, words, options), ...fromNodeOptions];
30
30
  }
31
31
  if (pluginArgsMap.has(binary)) {
32
32
  return [...resolverFromPlugins(binary, words, options), ...fromNodeOptions];
33
33
  }
34
34
  if (spawningBinaries.includes(binary)) {
35
- return [toBinary(binary), ...fromWords(words, options)];
35
+ return [toBinary(binary), ...fromWords(words, options), ...fromNodeOptions];
36
36
  }
37
37
  if (binary in Plugins) {
38
38
  const inputs = fallbackResolve(binary, words, options);
package/dist/cli.js CHANGED
@@ -54,6 +54,10 @@ const main = async () => {
54
54
  console.log('\nTotal running time:', prettyMilliseconds(duration));
55
55
  perfObserver.reset();
56
56
  }
57
+ if (results.hasConfigLoadErrors) {
58
+ process.exitCode = 2;
59
+ return;
60
+ }
57
61
  if (!args['no-exit-code'] &&
58
62
  (totalErrorCount > options.maxIssues ||
59
63
  (!options.isDisableConfigHints &&
@@ -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;
@@ -88,6 +88,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
88
88
  dependencies,
89
89
  rootManifest,
90
90
  handleInput: (input) => handleInput(input, workspace),
91
+ handleConfigLoadError: () => collector.addConfigLoadError(),
91
92
  findWorkspaceByFilePath: chief.findWorkspaceByFilePath.bind(chief),
92
93
  getManifest,
93
94
  negatedWorkspacePatterns: chief.getNegatedWorkspacePatterns(name),
@@ -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
+ };