knip 5.70.1 → 5.71.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 (64) hide show
  1. package/dist/DependencyDeputy.js +2 -2
  2. package/dist/ProjectPrincipal.js +1 -1
  3. package/dist/WorkspaceWorker.js +32 -35
  4. package/dist/binaries/bash-parser.js +14 -1
  5. package/dist/compilers/index.js +1 -1
  6. package/dist/constants.js +1 -0
  7. package/dist/graph/analyze.js +21 -16
  8. package/dist/graph/build.js +71 -87
  9. package/dist/graph-explorer/constants.d.ts +2 -0
  10. package/dist/graph-explorer/constants.js +2 -0
  11. package/dist/graph-explorer/explorer.d.ts +11 -0
  12. package/dist/graph-explorer/explorer.js +10 -0
  13. package/dist/graph-explorer/operations/build-trace-tree.d.ts +12 -0
  14. package/dist/graph-explorer/operations/build-trace-tree.js +51 -0
  15. package/dist/graph-explorer/operations/has-strictly-ns-references.d.ts +2 -0
  16. package/dist/graph-explorer/operations/has-strictly-ns-references.js +98 -0
  17. package/dist/graph-explorer/operations/is-referenced.d.ts +4 -0
  18. package/dist/graph-explorer/operations/is-referenced.js +89 -0
  19. package/dist/graph-explorer/utils.d.ts +4 -0
  20. package/dist/graph-explorer/utils.js +28 -0
  21. package/dist/graph-explorer/visitors.d.ts +12 -0
  22. package/dist/graph-explorer/visitors.js +30 -0
  23. package/dist/graph-explorer/walk-down.d.ts +4 -0
  24. package/dist/graph-explorer/walk-down.js +119 -0
  25. package/dist/index.js +2 -98
  26. package/dist/plugins/angular/index.js +3 -3
  27. package/dist/plugins/astro/index.js +0 -2
  28. package/dist/plugins/next/index.js +4 -3
  29. package/dist/plugins/next/resolveFromAST.d.ts +1 -0
  30. package/dist/plugins/next/resolveFromAST.js +42 -1
  31. package/dist/plugins/vite/helpers.js +1 -1
  32. package/dist/reporters/codeclimate.js +3 -7
  33. package/dist/reporters/util/util.d.ts +2 -1
  34. package/dist/reporters/util/util.js +1 -0
  35. package/dist/reporters/watch.js +1 -1
  36. package/dist/run.d.ts +25 -0
  37. package/dist/run.js +107 -0
  38. package/dist/types/issues.d.ts +4 -4
  39. package/dist/types/module-graph.d.ts +14 -12
  40. package/dist/typescript/ast-helpers.d.ts +4 -0
  41. package/dist/typescript/ast-helpers.js +48 -0
  42. package/dist/typescript/get-imports-and-exports.js +18 -3
  43. package/dist/typescript/visitors/dynamic-imports/importCall.js +5 -19
  44. package/dist/typescript/visitors/dynamic-imports/jsDocType.js +7 -5
  45. package/dist/typescript/visitors/imports/importDeclaration.js +5 -4
  46. package/dist/util/create-options.js +1 -1
  47. package/dist/util/file-entry-cache.js +1 -1
  48. package/dist/util/graph-sequencer.js +1 -1
  49. package/dist/util/input.d.ts +1 -0
  50. package/dist/util/module-graph.js +7 -7
  51. package/dist/util/plugin.d.ts +1 -1
  52. package/dist/util/plugin.js +4 -3
  53. package/dist/util/trace.d.ts +3 -13
  54. package/dist/util/trace.js +10 -41
  55. package/dist/util/watch.d.ts +19 -3
  56. package/dist/util/watch.js +28 -17
  57. package/dist/version.d.ts +1 -1
  58. package/dist/version.js +1 -1
  59. package/package.json +1 -1
  60. package/vendor/bash-parser/index.d.ts +6 -1
  61. package/dist/util/has-strictly-ns-references.d.ts +0 -4
  62. package/dist/util/has-strictly-ns-references.js +0 -103
  63. package/dist/util/is-identifier-referenced.d.ts +0 -9
  64. package/dist/util/is-identifier-referenced.js +0 -145
@@ -4,7 +4,7 @@ export const getReactBabelPlugins = (sourceFile) => {
4
4
  const babelPlugins = [];
5
5
  const importMap = getImportMap(sourceFile);
6
6
  const reactPluginNames = new Set();
7
- for (const [importName, importPath] of importMap.entries()) {
7
+ for (const [importName, importPath] of importMap) {
8
8
  if (importPath.includes('@vitejs/plugin-react')) {
9
9
  reactPluginNames.add(importName);
10
10
  }
@@ -1,7 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { ISSUE_TYPE_TITLE } from '../constants.js';
3
2
  import { toRelative } from '../util/path.js';
4
- import { getIssueTypeTitle } from './util/util.js';
3
+ import { getIssuePrefix, getIssueTypeTitle } from './util/util.js';
5
4
  export default async ({ report, issues, cwd }) => {
6
5
  const entries = [];
7
6
  for (const [type, isReportType] of Object.entries(report)) {
@@ -52,15 +51,12 @@ function convertSeverity(severity) {
52
51
  return 'info';
53
52
  }
54
53
  }
55
- function getPrefix(type) {
56
- return ISSUE_TYPE_TITLE[type].replace(/ies$/, 'y').replace(/s$/, '');
57
- }
58
54
  function getIssueDescription({ type, symbol, symbols, parentSymbol }) {
59
55
  const symbolDescription = symbols ? `${symbols.map(s => s.symbol).join(', ')}` : symbol;
60
- return `${getPrefix(type)}: ${symbolDescription}${parentSymbol ? ` (${parentSymbol})` : ''}`;
56
+ return `${getIssuePrefix(type)}: ${symbolDescription}${parentSymbol ? ` (${parentSymbol})` : ''}`;
61
57
  }
62
58
  function getSymbolDescription({ type, symbol, parentSymbol, }) {
63
- return `${getPrefix(type)}: ${symbol.symbol}${parentSymbol ? ` (${parentSymbol})` : ''}`;
59
+ return `${getIssuePrefix(type)}: ${symbol.symbol}${parentSymbol ? ` (${parentSymbol})` : ''}`;
64
60
  }
65
61
  function createLocation(filePath, cwd, line, col) {
66
62
  if (col !== undefined) {
@@ -1,5 +1,5 @@
1
1
  import { ISSUE_TYPE_TITLE } from '../../constants.js';
2
- import type { Issue, IssueSeverity, IssueSymbol } from '../../types/issues.js';
2
+ import type { Issue, IssueSeverity, IssueSymbol, IssueType } from '../../types/issues.js';
3
3
  import { Table } from '../../util/table.js';
4
4
  export declare const dim: import("picocolors/types.js").Formatter;
5
5
  export declare const bright: import("picocolors/types.js").Formatter;
@@ -23,4 +23,5 @@ export declare const convert: (issue: Issue | IssueSymbol) => {
23
23
  export declare const getTableForType: (issues: Issue[], cwd: string, options?: {
24
24
  isUseColors?: boolean;
25
25
  }) => Table;
26
+ export declare const getIssuePrefix: (type: IssueType) => string;
26
27
  export {};
@@ -54,3 +54,4 @@ export const getTableForType = (issues, cwd, options = { isUseColors: true }) =>
54
54
  }
55
55
  return table;
56
56
  };
57
+ export const getIssuePrefix = (type) => ISSUE_TYPE_TITLE[type].replace(/ies$/, 'y').replace(/s$/, '');
@@ -23,7 +23,7 @@ export default (options, { issues, streamer, duration, size }) => {
23
23
  }
24
24
  const mem = perfObserver.getCurrentMemUsageInMb();
25
25
  const ms = duration ?? perfObserver.getCurrentDurationInMs();
26
- const summary = `${size} files in ${prettyMilliseconds(ms)} (${mem}MB)`;
26
+ const summary = `${size} files (${prettyMilliseconds(ms)} ${mem}MB)`;
27
27
  const messages = totalIssues === 0
28
28
  ? ['✂️ Excellent, Knip found no issues.', '', picocolors.gray(summary)]
29
29
  : [...lines, '', picocolors.gray(summary)];
package/dist/run.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { ConsoleStreamer } from './ConsoleStreamer.js';
2
+ import type { MainOptions } from './util/create-options.js';
3
+ export declare const run: (options: MainOptions) => Promise<{
4
+ results: {
5
+ issues: import("./types/issues.js").Issues;
6
+ counters: import("./types/issues.js").Counters;
7
+ tagHints: Set<import("./types/issues.js").TagHint>;
8
+ configurationHints: Set<import("./types/issues.js").ConfigurationHint>;
9
+ includedWorkspaceDirs: string[];
10
+ };
11
+ watchHandler: {
12
+ listener: import("fs").WatchListener<string | Buffer<ArrayBufferLike>>;
13
+ handleFileChanges: (changes: {
14
+ type: "added" | "deleted" | "modified";
15
+ filePath: string;
16
+ }[]) => Promise<{
17
+ duration: number;
18
+ mem: number;
19
+ }>;
20
+ getEntryPaths: () => Set<string>;
21
+ getGraph: () => import("./types/module-graph.js").ModuleGraph;
22
+ getIssues: () => import("./types/issues.js").Issues;
23
+ } | undefined;
24
+ streamer: ConsoleStreamer;
25
+ }>;
package/dist/run.js ADDED
@@ -0,0 +1,107 @@
1
+ import { watch } from 'node:fs';
2
+ import { formatly } from 'formatly';
3
+ import { CatalogCounselor } from './CatalogCounselor.js';
4
+ import { ConfigurationChief } from './ConfigurationChief.js';
5
+ import { ConsoleStreamer } from './ConsoleStreamer.js';
6
+ import { DependencyDeputy } from './DependencyDeputy.js';
7
+ import { analyze } from './graph/analyze.js';
8
+ import { build } from './graph/build.js';
9
+ import { IssueCollector } from './IssueCollector.js';
10
+ import { IssueFixer } from './IssueFixer.js';
11
+ import { PrincipalFactory } from './PrincipalFactory.js';
12
+ import watchReporter from './reporters/watch.js';
13
+ import { debugLogArray, debugLogObject } from './util/debug.js';
14
+ import { getGitIgnoredHandler } from './util/glob-core.js';
15
+ import { getWatchHandler } from './util/watch.js';
16
+ export const run = async (options) => {
17
+ debugLogObject('*', 'Unresolved configuration', options);
18
+ debugLogObject('*', 'Included issue types', options.includedIssueTypes);
19
+ const chief = new ConfigurationChief(options);
20
+ const deputy = new DependencyDeputy(options);
21
+ const factory = new PrincipalFactory();
22
+ const streamer = new ConsoleStreamer(options);
23
+ const fixer = new IssueFixer(options);
24
+ const collector = new IssueCollector(options);
25
+ const counselor = new CatalogCounselor(options);
26
+ streamer.cast('Reading workspace configuration');
27
+ const workspaces = await chief.getWorkspaces();
28
+ const isGitIgnored = await getGitIgnoredHandler(options);
29
+ collector.setIgnoreIssues(chief.config.ignoreIssues);
30
+ debugLogObject('*', 'Included workspaces', () => workspaces.map(w => w.pkgName));
31
+ debugLogObject('*', 'Included workspace configs', () => workspaces.map(w => ({ pkgName: w.pkgName, name: w.name, config: w.config, ancestors: w.ancestors })));
32
+ const { graph, entryPaths, analyzedFiles, unreferencedFiles, analyzeSourceFile } = await build({
33
+ chief,
34
+ collector,
35
+ counselor,
36
+ deputy,
37
+ factory,
38
+ isGitIgnored,
39
+ streamer,
40
+ workspaces,
41
+ options,
42
+ });
43
+ const reAnalyze = await analyze({
44
+ analyzedFiles,
45
+ counselor,
46
+ chief,
47
+ collector,
48
+ deputy,
49
+ entryPaths,
50
+ factory,
51
+ fixer,
52
+ graph,
53
+ streamer,
54
+ unreferencedFiles,
55
+ options,
56
+ });
57
+ let watchHandler;
58
+ if (options.isWatch) {
59
+ const isIgnored = (filePath) => (!!options.cacheLocation && filePath.startsWith(options.cacheLocation)) ||
60
+ filePath.includes('/.git/') ||
61
+ isGitIgnored(filePath);
62
+ const onFileChange = options.isWatch
63
+ ? ({ issues, duration }) => watchReporter(options, { issues, streamer, size: analyzedFiles.size, duration })
64
+ : undefined;
65
+ watchHandler = await getWatchHandler(options, {
66
+ analyzedFiles,
67
+ analyzeSourceFile,
68
+ chief,
69
+ collector,
70
+ analyze: reAnalyze,
71
+ factory,
72
+ graph,
73
+ isIgnored,
74
+ onFileChange,
75
+ unreferencedFiles,
76
+ entryPaths,
77
+ });
78
+ if (options.isWatch)
79
+ watch('.', { recursive: true }, watchHandler.listener);
80
+ }
81
+ const { issues, counters, tagHints, configurationHints } = collector.getIssues();
82
+ if (options.isFix) {
83
+ const touchedFiles = await fixer.fixIssues(issues);
84
+ if (options.isFormat) {
85
+ const report = await formatly(Array.from(touchedFiles));
86
+ if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
87
+ debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
88
+ }
89
+ else {
90
+ debugLogObject('*', 'Formatting files failed', report);
91
+ }
92
+ }
93
+ }
94
+ if (!options.isWatch)
95
+ streamer.clear();
96
+ return {
97
+ results: {
98
+ issues,
99
+ counters,
100
+ tagHints,
101
+ configurationHints,
102
+ includedWorkspaceDirs: chief.includedWorkspaces.map(w => w.dir),
103
+ },
104
+ watchHandler,
105
+ streamer,
106
+ };
107
+ };
@@ -1,13 +1,13 @@
1
1
  import type { SYMBOL_TYPE } from '../constants.js';
2
2
  import type { Fixes } from './exports.js';
3
3
  export type SymbolType = (typeof SYMBOL_TYPE)[keyof typeof SYMBOL_TYPE];
4
- export type IssueSymbol = {
4
+ export interface IssueSymbol {
5
5
  symbol: string;
6
6
  pos?: number;
7
7
  line?: number;
8
8
  col?: number;
9
- };
10
- export type Issue = {
9
+ }
10
+ export interface Issue {
11
11
  type: SymbolIssueType;
12
12
  filePath: string;
13
13
  workspace: string;
@@ -22,7 +22,7 @@ export type Issue = {
22
22
  col?: number;
23
23
  fixes: Fixes;
24
24
  isFixed?: boolean;
25
- };
25
+ }
26
26
  export type IssueSet = Set<string>;
27
27
  export type IssueRecords = Record<string, Record<string, Issue>>;
28
28
  export type Issues = {
@@ -1,12 +1,17 @@
1
1
  import type ts from 'typescript';
2
2
  import type { Fix, Fixes } from './exports.js';
3
3
  import type { IssueSymbol, SymbolType } from './issues.js';
4
- type Identifier = string;
4
+ export type Identifier = string;
5
5
  type FilePath = string;
6
6
  type NamespaceOrAlias = string;
7
7
  type Reference = string;
8
8
  type References = Set<Reference>;
9
9
  type Tags = Set<string>;
10
+ interface SourceLocation {
11
+ pos: number;
12
+ line: number;
13
+ col: number;
14
+ }
10
15
  export type IdToFileMap = Map<Identifier, Set<FilePath>>;
11
16
  export type IdToNsToFileMap = Map<Identifier, Map<NamespaceOrAlias, Set<FilePath>>>;
12
17
  export type ImportMaps = {
@@ -19,24 +24,21 @@ export type ImportMaps = {
19
24
  reExportedNs: IdToFileMap;
20
25
  };
21
26
  export type ImportMap = Map<FilePath, ImportMaps>;
22
- export type Import = {
27
+ export interface Import extends SourceLocation {
23
28
  specifier: string;
24
- identifier: string;
25
- pos?: number;
26
- line?: number;
27
- col?: number;
28
- };
29
- export interface Export {
29
+ filePath: string | undefined;
30
+ identifier: string | undefined;
31
+ isTypeOnly: boolean;
32
+ }
33
+ export interface Export extends SourceLocation {
30
34
  identifier: Identifier;
31
- pos: number;
32
- line: number;
33
- col: number;
34
35
  type: SymbolType;
35
36
  members: ExportMember[];
36
37
  jsDocTags: Tags;
37
38
  refs: [number, boolean];
38
39
  fixes: Fixes;
39
40
  symbol?: ts.Symbol;
41
+ isReExport?: boolean;
40
42
  }
41
43
  export type ExportMember = {
42
44
  identifier: Identifier;
@@ -50,7 +52,7 @@ export type ExportMember = {
50
52
  jsDocTags: Tags;
51
53
  };
52
54
  export type ExportMap = Map<Identifier, Export>;
53
- export type Imports = Set<[Import, FilePath]>;
55
+ export type Imports = Set<Import>;
54
56
  export type FileNode = {
55
57
  imports: {
56
58
  internal: ImportMap;
@@ -58,6 +58,10 @@ export declare const isModuleExportsAccess: (node: ts.PropertyAccessExpression)
58
58
  export declare const getImportMap: (sourceFile: ts.SourceFile) => Map<string, string>;
59
59
  export declare const getDefaultImportName: (importMap: ReturnType<typeof getImportMap>, specifier: string) => string | undefined;
60
60
  export declare const getPropertyValues: (node: ts.ObjectLiteralExpression, propertyName: string) => Set<string>;
61
+ export declare function getThenBindings(callExpression: ts.CallExpression): {
62
+ identifier: string;
63
+ pos: number;
64
+ }[] | undefined;
61
65
  export declare const getAccessedIdentifiers: (identifier: string, scope: ts.Node) => {
62
66
  identifier: string;
63
67
  pos: number;
@@ -203,6 +203,7 @@ export const isConsiderReferencedNS = (node) => ts.isPropertyAssignment(node.par
203
203
  ts.isSpreadAssignment(node.parent) ||
204
204
  ts.isArrayLiteralExpression(node.parent) ||
205
205
  ts.isExportAssignment(node.parent) ||
206
+ ts.isConditionalExpression(node.parent) ||
206
207
  (ts.isVariableDeclaration(node.parent) && node.parent.initializer === node) ||
207
208
  ts.isTypeQueryNode(node.parent.parent);
208
209
  export const isInOpaqueExpression = (node) => ts.isAwaitExpression(node.parent)
@@ -263,6 +264,18 @@ export const getImportMap = (sourceFile) => {
263
264
  importMap.set(element.name.text, importPath);
264
265
  }
265
266
  }
267
+ if (ts.isVariableStatement(statement)) {
268
+ for (const declaration of statement.declarationList.declarations) {
269
+ if (declaration.initializer &&
270
+ isRequireCall(declaration.initializer) &&
271
+ ts.isIdentifier(declaration.name) &&
272
+ ts.isStringLiteral(declaration.initializer.arguments[0])) {
273
+ const importName = declaration.name.text;
274
+ const importPath = stripQuotes(declaration.initializer.arguments[0].text);
275
+ importMap.set(importName, importPath);
276
+ }
277
+ }
278
+ }
266
279
  }
267
280
  return importMap;
268
281
  };
@@ -304,6 +317,32 @@ const isMatchAlias = (expression, identifier) => {
304
317
  expression = expression.expression;
305
318
  return expression && ts.isIdentifier(expression) && expression.escapedText === identifier;
306
319
  };
320
+ export function getThenBindings(callExpression) {
321
+ if (!ts.isFunctionLike(callExpression.arguments[0]))
322
+ return;
323
+ const fn = callExpression.arguments[0];
324
+ const param = fn.parameters[0];
325
+ if (!param)
326
+ return;
327
+ if (ts.isIdentifier(param.name)) {
328
+ const paramName = param.name.escapedText;
329
+ const identifiers = [];
330
+ for (const node of findDescendants(fn.body, ts.isPropertyAccessExpression)) {
331
+ if (ts.isIdentifier(node.expression) && node.expression.escapedText === paramName) {
332
+ identifiers.push({ identifier: String(node.name.escapedText), pos: node.name.pos });
333
+ }
334
+ }
335
+ if (identifiers.length > 0)
336
+ return identifiers;
337
+ }
338
+ else if (ts.isObjectBindingPattern(param.name)) {
339
+ return param.name.elements.map(element => {
340
+ const identifier = (element.propertyName ?? element.name).getText();
341
+ const alias = element.propertyName ? element.name.getText() : undefined;
342
+ return { identifier, alias, pos: element.pos };
343
+ });
344
+ }
345
+ }
307
346
  export const getAccessedIdentifiers = (identifier, scope) => {
308
347
  const identifiers = [];
309
348
  function visit(node) {
@@ -328,6 +367,15 @@ export const getAccessedIdentifiers = (identifier, scope) => {
328
367
  }
329
368
  }
330
369
  }
370
+ else if (ts.isCallExpression(node) &&
371
+ ts.isPropertyAccessExpression(node.expression) &&
372
+ isMatchAlias(node.expression.expression, identifier) &&
373
+ node.expression.name.escapedText === 'then') {
374
+ const accessed = getThenBindings(node);
375
+ if (accessed)
376
+ for (const acc of accessed)
377
+ identifiers.push(acc);
378
+ }
331
379
  ts.forEachChild(node, visit);
332
380
  }
333
381
  visit(scope);
@@ -79,7 +79,15 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
79
79
  const { symbol, filePath, namespace, specifier, modifiers } = options;
80
80
  const identifier = options.identifier ?? (modifiers & IMPORT_MODIFIERS.OPAQUE ? OPAQUE : SIDE_EFFECTS);
81
81
  const isStar = identifier === IMPORT_STAR;
82
- imports.add([{ specifier, identifier, pos: options.pos, line: options.line, col: options.col }, filePath]);
82
+ imports.add({
83
+ filePath,
84
+ specifier,
85
+ identifier: namespace ?? options.identifier,
86
+ pos: options.pos,
87
+ line: options.line,
88
+ col: options.col,
89
+ isTypeOnly: !!(modifiers & IMPORT_MODIFIERS.TYPE_ONLY),
90
+ });
83
91
  const file = internal.get(filePath);
84
92
  const importMaps = file ?? createImports();
85
93
  if (!file)
@@ -105,7 +113,7 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
105
113
  addNsValue(importMaps.importedAs, identifier, nsOrAlias, sourceFile.fileName);
106
114
  }
107
115
  }
108
- else if (identifier !== SIDE_EFFECTS && identifier !== IMPORT_STAR) {
116
+ else if (identifier !== IMPORT_STAR) {
109
117
  addValue(importMaps.imported, identifier, sourceFile.fileName);
110
118
  }
111
119
  if (symbol)
@@ -144,11 +152,13 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
144
152
  const pos = node.moduleSpecifier?.getStart() ?? opts.pos;
145
153
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);
146
154
  external.add({
155
+ filePath,
147
156
  specifier: sanitizedSpecifier,
148
157
  identifier: opts.identifier ?? SIDE_EFFECTS,
149
158
  pos: opts.pos,
150
159
  line: line + 1,
151
160
  col: character + 2,
161
+ isTypeOnly: !!(opts.modifiers & IMPORT_MODIFIERS.TYPE_ONLY),
152
162
  });
153
163
  }
154
164
  }
@@ -167,20 +177,24 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
167
177
  const pos = 'moduleSpecifier' in node ? node.moduleSpecifier.pos : node.pos;
168
178
  const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);
169
179
  unresolved.add({
180
+ filePath: undefined,
170
181
  specifier: opts.specifier,
171
182
  identifier: opts.identifier ?? SIDE_EFFECTS,
172
183
  pos,
173
184
  line: line + 1,
174
185
  col: character + 2,
186
+ isTypeOnly: !!(opts.modifiers & IMPORT_MODIFIERS.TYPE_ONLY),
175
187
  });
176
188
  }
177
189
  };
178
190
  const addExport = ({ node, symbol, identifier, type, pos, members = [], fix }) => {
179
191
  if (skipExports)
180
192
  return;
193
+ let isReExport = Boolean(node.parent?.parent && ts.isExportDeclaration(node.parent.parent) && node.parent.parent.moduleSpecifier);
181
194
  if (symbol) {
182
195
  const importedSymbolFilePath = importedInternalSymbols.get(symbol);
183
196
  if (importedSymbolFilePath) {
197
+ isReExport = true;
184
198
  const importId = String(symbol.escapedName);
185
199
  const internalImport = internal.get(importedSymbolFilePath);
186
200
  if (internalImport) {
@@ -203,7 +217,7 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
203
217
  const members = [...(item.members ?? []), ...exportMembers];
204
218
  const tags = new Set([...(item.jsDocTags ?? []), ...jsDocTags]);
205
219
  const fixes = fix ? [...(item.fixes ?? []), fix] : item.fixes;
206
- exports.set(identifier, { ...item, members, jsDocTags: tags, fixes });
220
+ exports.set(identifier, { ...item, members, jsDocTags: tags, fixes, isReExport });
207
221
  }
208
222
  else {
209
223
  const { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(pos);
@@ -218,6 +232,7 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
218
232
  col: character + 1,
219
233
  fixes: fix ? [fix] : [],
220
234
  refs: [0, false],
235
+ isReExport,
221
236
  });
222
237
  }
223
238
  if (!jsDocTags.has(ALIAS_TAG)) {
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
  import { IMPORT_MODIFIERS } from '../../../constants.js';
3
- import { findAncestor, findDescendants, getAccessedIdentifiers, isAccessExpression, isImportCall, isInOpaqueExpression, isTopLevel, stripQuotes, } from '../../ast-helpers.js';
3
+ import { findAncestor, findDescendants, getAccessedIdentifiers, getThenBindings, isAccessExpression, isImportCall, isInOpaqueExpression, isTopLevel, stripQuotes, } from '../../ast-helpers.js';
4
4
  import { importVisitor as visit } from '../index.js';
5
5
  const getSymbol = (node, isTopLevel) => (isTopLevel ? node.symbol : undefined);
6
6
  export default visit(() => true, node => {
@@ -20,24 +20,10 @@ export default visit(() => true, node => {
20
20
  const pos = accessExpression.name.pos;
21
21
  if (identifier === 'then') {
22
22
  const callExpression = node.parent.parent;
23
- if (ts.isCallExpression(callExpression) && ts.isFunctionLike(callExpression.arguments[0])) {
24
- const arg = callExpression.arguments[0].parameters[0];
25
- if (arg && ts.isIdentifier(arg.name)) {
26
- const argName = arg.name.escapedText;
27
- const accessExpressions = findDescendants(callExpression.arguments[0].body, ts.isPropertyAccessExpression).filter(binding => binding.expression.getText() === argName);
28
- if (accessExpressions.length > 0) {
29
- return accessExpressions.map(binding => {
30
- const identifier = String(binding.name.escapedText);
31
- return { identifier, specifier, pos, modifiers };
32
- });
33
- }
34
- }
35
- else if (arg && ts.isObjectBindingPattern(arg.name)) {
36
- return arg.name.elements.map(element => {
37
- const identifier = (element.propertyName ?? element.name).getText();
38
- const alias = element.propertyName ? element.name.getText() : undefined;
39
- return { identifier, alias, specifier, pos: element.pos, modifiers };
40
- });
23
+ if (ts.isCallExpression(callExpression)) {
24
+ const accessed = getThenBindings(callExpression);
25
+ if (accessed && accessed.length > 0) {
26
+ return accessed.map(acc => ({ ...acc, specifier, modifiers }));
41
27
  }
42
28
  }
43
29
  return { identifier: 'default', specifier, pos, modifiers };
@@ -13,16 +13,18 @@ const getImportSpecifiers = (node) => {
13
13
  specifier: importClause.literal.text,
14
14
  identifier,
15
15
  pos: node.qualifier?.getStart() ?? importClause.literal.pos,
16
- modifiers: IMPORT_MODIFIERS.NONE,
16
+ modifiers: IMPORT_MODIFIERS.TYPE_ONLY,
17
17
  });
18
18
  }
19
19
  }
20
20
  if (supportsJSDocImportTag && ts.isJSDocImportTag(node) && ts.isStringLiteralLike(node.moduleSpecifier)) {
21
- if (node.importClause?.namedBindings && ts.isNamedImportBindings(node.importClause.namedBindings)) {
22
- const bindings = node.importClause.namedBindings;
21
+ const moduleSpecifier = node.moduleSpecifier;
22
+ const importClause = node.importClause;
23
+ if (moduleSpecifier && importClause?.namedBindings && ts.isNamedImportBindings(importClause.namedBindings)) {
24
+ const bindings = importClause.namedBindings;
23
25
  if (ts.isNamespaceImport(bindings)) {
24
26
  imports.push({
25
- specifier: node.moduleSpecifier.text,
27
+ specifier: moduleSpecifier.text,
26
28
  identifier: IMPORT_STAR,
27
29
  pos: bindings.name.getStart(),
28
30
  modifiers: IMPORT_MODIFIERS.TYPE_ONLY,
@@ -31,7 +33,7 @@ const getImportSpecifiers = (node) => {
31
33
  else {
32
34
  for (const element of bindings.elements) {
33
35
  imports.push({
34
- specifier: node.moduleSpecifier.text,
36
+ specifier: moduleSpecifier.text,
35
37
  identifier: String((element.propertyName ?? element.name).escapedText),
36
38
  pos: element.name.getStart(),
37
39
  modifiers: IMPORT_MODIFIERS.TYPE_ONLY,
@@ -9,6 +9,7 @@ export default visit(() => true, node => {
9
9
  return { specifier, identifier: undefined, pos: node.pos, modifiers: IMPORT_MODIFIERS.SIDE_EFFECTS };
10
10
  }
11
11
  const imports = [];
12
+ const modifiers = node.importClause.isTypeOnly ? IMPORT_MODIFIERS.TYPE_ONLY : IMPORT_MODIFIERS.NONE;
12
13
  if (isDefaultImport(node)) {
13
14
  imports.push({
14
15
  identifier: 'default',
@@ -16,7 +17,7 @@ export default visit(() => true, node => {
16
17
  specifier,
17
18
  symbol: node.importClause.symbol,
18
19
  pos: node.importClause.name?.getStart() ?? node.getStart(),
19
- modifiers: IMPORT_MODIFIERS.NONE,
20
+ modifiers,
20
21
  });
21
22
  }
22
23
  if (node.importClause?.namedBindings) {
@@ -27,7 +28,7 @@ export default visit(() => true, node => {
27
28
  specifier,
28
29
  identifier: IMPORT_STAR,
29
30
  pos: node.importClause.namedBindings.name.getStart(),
30
- modifiers: node.importClause?.isTypeOnly ? IMPORT_MODIFIERS.TYPE_ONLY : IMPORT_MODIFIERS.NONE,
31
+ modifiers,
31
32
  });
32
33
  }
33
34
  if (ts.isNamedImports(node.importClause.namedBindings)) {
@@ -38,7 +39,7 @@ export default visit(() => true, node => {
38
39
  specifier,
39
40
  symbol: element.symbol,
40
41
  pos: element.name.getStart(),
41
- modifiers: node.importClause?.isTypeOnly ? IMPORT_MODIFIERS.TYPE_ONLY : IMPORT_MODIFIERS.NONE,
42
+ modifiers,
42
43
  });
43
44
  }
44
45
  }
@@ -47,7 +48,7 @@ export default visit(() => true, node => {
47
48
  specifier,
48
49
  identifier: undefined,
49
50
  pos: node.importClause.namedBindings.pos,
50
- modifiers: node.importClause?.isTypeOnly ? IMPORT_MODIFIERS.TYPE_ONLY : IMPORT_MODIFIERS.NONE,
51
+ modifiers,
51
52
  });
52
53
  }
53
54
  }
@@ -115,7 +115,7 @@ export const createOptions = async (options) => {
115
115
  rules,
116
116
  tags,
117
117
  traceExport: parsedCLIArgs['trace-export'],
118
- traceFile: parsedCLIArgs['trace-file'],
118
+ traceFile: parsedCLIArgs['trace-file'] ? toAbsolute(parsedCLIArgs['trace-file'], cwd) : undefined,
119
119
  tsConfigFile: parsedCLIArgs.tsConfig,
120
120
  workspace: options.workspace ?? parsedCLIArgs.workspace,
121
121
  workspaces,
@@ -86,7 +86,7 @@ export class FileEntryCache {
86
86
  }
87
87
  reconcile() {
88
88
  this.removeNotFoundFiles();
89
- for (const [entryName, cacheEntry] of this.normalizedEntries.entries()) {
89
+ for (const [entryName, cacheEntry] of this.normalizedEntries) {
90
90
  try {
91
91
  const meta = this._getMetaForFileUsingMtimeAndSize(cacheEntry);
92
92
  this.cache.set(entryName, meta);
@@ -6,7 +6,7 @@ export function graphSequencer(graph, includedNodes = [...graph.keys()]) {
6
6
  const nodes = new Set(includedNodes);
7
7
  const visited = new Set();
8
8
  const outDegree = new Map();
9
- for (const [from, edges] of graph.entries()) {
9
+ for (const [from, edges] of graph) {
10
10
  outDegree.set(from, 0);
11
11
  for (const to of edges) {
12
12
  if (nodes.has(from) && nodes.has(to)) {
@@ -10,6 +10,7 @@ export interface Input {
10
10
  containingFilePath?: string;
11
11
  allowIncludeExports?: boolean;
12
12
  skipExportsAnalysis?: boolean;
13
+ group?: string;
13
14
  }
14
15
  export interface ConfigInput extends Input {
15
16
  type: 'config';
@@ -2,21 +2,21 @@ export const getOrCreateFileNode = (graph, filePath) => graph.get(filePath) ?? c
2
2
  const updateImportMaps = (fromImportMaps, toImportMaps) => {
3
3
  for (const id of fromImportMaps.refs)
4
4
  toImportMaps.refs.add(id);
5
- for (const [id, v] of fromImportMaps.imported.entries())
5
+ for (const [id, v] of fromImportMaps.imported)
6
6
  addValues(toImportMaps.imported, id, v);
7
- for (const [id, v] of fromImportMaps.importedAs.entries())
7
+ for (const [id, v] of fromImportMaps.importedAs)
8
8
  addNsValues(toImportMaps.importedAs, id, v);
9
- for (const [id, v] of fromImportMaps.importedNs.entries())
9
+ for (const [id, v] of fromImportMaps.importedNs)
10
10
  addValues(toImportMaps.importedNs, id, v);
11
- for (const [id, v] of fromImportMaps.reExported.entries())
11
+ for (const [id, v] of fromImportMaps.reExported)
12
12
  addValues(toImportMaps.reExported, id, v);
13
- for (const [id, v] of fromImportMaps.reExportedAs.entries())
13
+ for (const [id, v] of fromImportMaps.reExportedAs)
14
14
  addNsValues(toImportMaps.reExportedAs, id, v);
15
- for (const [id, v] of fromImportMaps.reExportedNs.entries())
15
+ for (const [id, v] of fromImportMaps.reExportedNs)
16
16
  addValues(toImportMaps.reExportedNs, id, v);
17
17
  };
18
18
  export const updateImportMap = (file, importMap, graph) => {
19
- for (const [importedFilePath, fileImportMaps] of importMap.entries()) {
19
+ for (const [importedFilePath, fileImportMaps] of importMap) {
20
20
  const importMaps = file.imports.internal.get(importedFilePath);
21
21
  if (!importMaps)
22
22
  file.imports.internal.set(importedFilePath, fileImportMaps);
@@ -4,6 +4,6 @@ export declare const hasDependency: (dependencies: Set<string>, values: (string
4
4
  export declare const normalizePluginConfig: (pluginConfig: RawPluginConfiguration) => boolean | {
5
5
  config: string[] | null;
6
6
  entry: string[] | null;
7
- project: string[] | null;
7
+ project: string[];
8
8
  };
9
9
  export declare const loadConfigForPlugin: (configFilePath: string, plugin: Plugin, options: PluginOptions, pluginName: string) => Promise<any>;