knip 6.35.1 → 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 (69) hide show
  1. package/dist/ConfigurationChief.d.ts +12 -0
  2. package/dist/WorkspaceWorker.js +6 -4
  3. package/dist/binaries/command.js +2 -2
  4. package/dist/compilers/compilers.js +1 -1
  5. package/dist/compilers/scss.js +2 -2
  6. package/dist/graph-explorer/cache.d.ts +3 -0
  7. package/dist/graph-explorer/cache.js +6 -0
  8. package/dist/graph-explorer/explorer.d.ts +1 -0
  9. package/dist/graph-explorer/explorer.js +2 -0
  10. package/dist/graph-explorer/operations/build-exports-tree.js +14 -2
  11. package/dist/graph-explorer/operations/get-ambiguous-star-export.d.ts +8 -0
  12. package/dist/graph-explorer/operations/get-ambiguous-star-export.js +11 -0
  13. package/dist/graph-explorer/operations/get-contention.js +265 -122
  14. package/dist/graph-explorer/operations/resolve-export-origins.d.ts +32 -0
  15. package/dist/graph-explorer/operations/resolve-export-origins.js +255 -0
  16. package/dist/graph-explorer/utils.js +8 -0
  17. package/dist/plugins/eslint/helpers.js +31 -6
  18. package/dist/plugins/eslint/resolveFromAST.js +17 -11
  19. package/dist/plugins/eslint/types.d.ts +3 -3
  20. package/dist/plugins/index.d.ts +2 -0
  21. package/dist/plugins/index.js +4 -0
  22. package/dist/plugins/next/index.js +39 -5
  23. package/dist/plugins/node/index.js +6 -0
  24. package/dist/plugins/tailwind/compiler.js +2 -2
  25. package/dist/plugins/tailwind/index.js +7 -1
  26. package/dist/plugins/textlint/helpers.d.ts +4 -0
  27. package/dist/plugins/textlint/helpers.js +39 -0
  28. package/dist/plugins/textlint/index.d.ts +3 -0
  29. package/dist/plugins/textlint/index.js +52 -0
  30. package/dist/plugins/textlint/types.d.ts +5 -0
  31. package/dist/plugins/textlint/types.js +1 -0
  32. package/dist/plugins/typedoc/index.js +3 -2
  33. package/dist/plugins/typedoc/types.d.ts +2 -2
  34. package/dist/plugins/varlock/index.d.ts +3 -0
  35. package/dist/plugins/varlock/index.js +31 -0
  36. package/dist/plugins/varlock/parse.d.ts +11 -0
  37. package/dist/plugins/varlock/parse.js +185 -0
  38. package/dist/plugins/varlock/scan.d.ts +2 -0
  39. package/dist/plugins/varlock/scan.js +78 -0
  40. package/dist/plugins/vitest/index.js +4 -2
  41. package/dist/reporters/trace.js +30 -1
  42. package/dist/schema/configuration.d.ts +30 -0
  43. package/dist/schema/plugins.d.ts +10 -0
  44. package/dist/schema/plugins.js +2 -0
  45. package/dist/session/build-maps.js +9 -1
  46. package/dist/session/file-descriptor.js +0 -2
  47. package/dist/session/index.d.ts +1 -1
  48. package/dist/session/types.d.ts +18 -0
  49. package/dist/types/PluginNames.d.ts +2 -2
  50. package/dist/types/PluginNames.js +2 -0
  51. package/dist/types/config.d.ts +1 -0
  52. package/dist/types/module-graph.d.ts +3 -0
  53. package/dist/typescript/get-imports-and-exports.js +43 -9
  54. package/dist/typescript/visitors/exports.js +9 -4
  55. package/dist/typescript/visitors/walk.d.ts +1 -1
  56. package/dist/typescript/visitors/walk.js +4 -1
  57. package/dist/util/array.d.ts +1 -1
  58. package/dist/util/array.js +5 -1
  59. package/dist/util/create-options.d.ts +20 -0
  60. package/dist/util/file-entry-cache.js +1 -1
  61. package/dist/util/glob-core.d.ts +1 -0
  62. package/dist/util/glob-core.js +11 -3
  63. package/dist/util/package-json.d.ts +2 -0
  64. package/dist/util/url.d.ts +1 -0
  65. package/dist/util/url.js +2 -0
  66. package/dist/version.d.ts +1 -1
  67. package/dist/version.js +1 -1
  68. package/package.json +1 -1
  69. package/schema.json +8 -0
@@ -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 {};