knip 5.70.2 → 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 (57) hide show
  1. package/dist/DependencyDeputy.js +2 -2
  2. package/dist/ProjectPrincipal.js +1 -1
  3. package/dist/WorkspaceWorker.js +1 -1
  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-explorer/constants.d.ts +2 -0
  9. package/dist/graph-explorer/constants.js +2 -0
  10. package/dist/graph-explorer/explorer.d.ts +11 -0
  11. package/dist/graph-explorer/explorer.js +10 -0
  12. package/dist/graph-explorer/operations/build-trace-tree.d.ts +12 -0
  13. package/dist/graph-explorer/operations/build-trace-tree.js +51 -0
  14. package/dist/graph-explorer/operations/has-strictly-ns-references.d.ts +2 -0
  15. package/dist/graph-explorer/operations/has-strictly-ns-references.js +98 -0
  16. package/dist/graph-explorer/operations/is-referenced.d.ts +4 -0
  17. package/dist/graph-explorer/operations/is-referenced.js +89 -0
  18. package/dist/graph-explorer/utils.d.ts +4 -0
  19. package/dist/graph-explorer/utils.js +28 -0
  20. package/dist/graph-explorer/visitors.d.ts +12 -0
  21. package/dist/graph-explorer/visitors.js +30 -0
  22. package/dist/graph-explorer/walk-down.d.ts +4 -0
  23. package/dist/graph-explorer/walk-down.js +119 -0
  24. package/dist/index.js +2 -98
  25. package/dist/plugins/angular/index.js +3 -3
  26. package/dist/plugins/next/index.js +4 -3
  27. package/dist/plugins/next/resolveFromAST.d.ts +1 -0
  28. package/dist/plugins/next/resolveFromAST.js +42 -1
  29. package/dist/plugins/vite/helpers.js +1 -1
  30. package/dist/reporters/codeclimate.js +3 -7
  31. package/dist/reporters/util/util.d.ts +2 -1
  32. package/dist/reporters/util/util.js +1 -0
  33. package/dist/reporters/watch.js +1 -1
  34. package/dist/run.d.ts +25 -0
  35. package/dist/run.js +107 -0
  36. package/dist/types/issues.d.ts +4 -4
  37. package/dist/types/module-graph.d.ts +9 -10
  38. package/dist/typescript/ast-helpers.d.ts +4 -0
  39. package/dist/typescript/ast-helpers.js +48 -0
  40. package/dist/typescript/get-imports-and-exports.js +4 -1
  41. package/dist/typescript/visitors/dynamic-imports/importCall.js +5 -19
  42. package/dist/util/create-options.js +1 -1
  43. package/dist/util/file-entry-cache.js +1 -1
  44. package/dist/util/graph-sequencer.js +1 -1
  45. package/dist/util/module-graph.js +7 -7
  46. package/dist/util/trace.d.ts +3 -13
  47. package/dist/util/trace.js +10 -41
  48. package/dist/util/watch.d.ts +19 -3
  49. package/dist/util/watch.js +28 -17
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +1 -1
  52. package/package.json +1 -1
  53. package/vendor/bash-parser/index.d.ts +6 -1
  54. package/dist/util/has-strictly-ns-references.d.ts +0 -4
  55. package/dist/util/has-strictly-ns-references.js +0 -103
  56. package/dist/util/is-identifier-referenced.d.ts +0 -9
  57. package/dist/util/is-identifier-referenced.js +0 -145
@@ -0,0 +1,119 @@
1
+ import { STOP } from './constants.js';
2
+ import { hasNamespaceMemberReference } from './utils.js';
3
+ import { getAliasReExportMap, getPassThroughReExportSources, getStarReExportSources } from './visitors.js';
4
+ export const walkDown = (graph, filePath, identifier, visitor, entryPaths, visited = new Set()) => {
5
+ const key = `${filePath}:${identifier}`;
6
+ if (visited.has(key))
7
+ return false;
8
+ visited.add(key);
9
+ const file = graph.get(filePath);
10
+ if (!file?.imported)
11
+ return false;
12
+ const restIds = identifier.split('.');
13
+ const id = restIds.shift();
14
+ if (!id)
15
+ return false;
16
+ const imported = file.imported;
17
+ const importedByFiles = imported.imported.get(id);
18
+ if (importedByFiles) {
19
+ for (const importingFile of importedByFiles) {
20
+ const isEntry = entryPaths.has(importingFile);
21
+ if (visitor(filePath, id, importingFile, id, isEntry, false) === STOP)
22
+ return true;
23
+ }
24
+ }
25
+ const importedAsAliases = imported.importedAs.get(id);
26
+ if (importedAsAliases) {
27
+ for (const [alias, byFilePaths] of importedAsAliases) {
28
+ for (const importingFile of byFilePaths) {
29
+ const isEntry = entryPaths.has(importingFile);
30
+ if (visitor(filePath, id, importingFile, alias, isEntry, false) === STOP)
31
+ return true;
32
+ }
33
+ }
34
+ }
35
+ for (const [namespace, byFilePaths] of imported.importedNs) {
36
+ for (const importingFile of byFilePaths) {
37
+ if (hasNamespaceMemberReference(graph, importingFile, filePath, namespace, identifier) === false)
38
+ continue;
39
+ const isEntry = entryPaths.has(importingFile);
40
+ if (visitor(filePath, identifier, importingFile, `${namespace}.${identifier}`, isEntry, false) === STOP) {
41
+ return true;
42
+ }
43
+ }
44
+ }
45
+ let done = false;
46
+ if (!done) {
47
+ const passThroughSources = getPassThroughReExportSources(imported, id);
48
+ if (passThroughSources) {
49
+ for (const reExportingFile of passThroughSources) {
50
+ const isEntry = entryPaths.has(reExportingFile);
51
+ if (visitor(filePath, id, reExportingFile, id, isEntry, true) === STOP) {
52
+ done = true;
53
+ break;
54
+ }
55
+ if (!isEntry && walkDown(graph, reExportingFile, identifier, visitor, entryPaths, visited)) {
56
+ done = true;
57
+ break;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ if (!done) {
63
+ const aliasReExportMap = getAliasReExportMap(imported, id);
64
+ if (aliasReExportMap) {
65
+ for (const [alias, sources] of aliasReExportMap) {
66
+ for (const reExportingFile of sources) {
67
+ const isEntry = entryPaths.has(reExportingFile);
68
+ if (visitor(filePath, id, reExportingFile, alias, isEntry, true) === STOP) {
69
+ done = true;
70
+ break;
71
+ }
72
+ if (!isEntry) {
73
+ const ref = [alias, ...restIds].join('.');
74
+ if (walkDown(graph, reExportingFile, ref, visitor, entryPaths, visited)) {
75
+ done = true;
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ if (done)
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ if (!done) {
86
+ for (const [namespace, sources] of imported.reExportedNs) {
87
+ for (const reExportingFile of sources) {
88
+ const isEntry = entryPaths.has(reExportingFile);
89
+ if (visitor(filePath, identifier, reExportingFile, `${namespace}.${identifier}`, isEntry, true) === STOP) {
90
+ done = true;
91
+ break;
92
+ }
93
+ if (!isEntry && walkDown(graph, reExportingFile, `${namespace}.${identifier}`, visitor, entryPaths, visited)) {
94
+ done = true;
95
+ break;
96
+ }
97
+ }
98
+ if (done)
99
+ break;
100
+ }
101
+ }
102
+ if (!done) {
103
+ const starSources = getStarReExportSources(imported);
104
+ if (starSources) {
105
+ for (const reExportingFile of starSources) {
106
+ const isEntry = entryPaths.has(reExportingFile);
107
+ if (visitor(filePath, id, reExportingFile, id, isEntry, true) === STOP) {
108
+ done = true;
109
+ break;
110
+ }
111
+ if (!isEntry && walkDown(graph, reExportingFile, identifier, visitor, entryPaths, visited)) {
112
+ done = true;
113
+ break;
114
+ }
115
+ }
116
+ }
117
+ }
118
+ return done;
119
+ };
package/dist/index.js CHANGED
@@ -1,98 +1,2 @@
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 main = 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
- if (options.isWatch) {
58
- const isIgnored = (filePath) => filePath.startsWith(options.cacheLocation) || filePath.includes('/.git/') || isGitIgnored(filePath);
59
- const onUpdate = options.isWatch
60
- ? ({ issues, duration }) => watchReporter(options, { issues, streamer, size: analyzedFiles.size, duration })
61
- : () => { };
62
- const watchHandler = await getWatchHandler(options, {
63
- analyzedFiles,
64
- analyzeSourceFile,
65
- chief,
66
- collector,
67
- analyze: reAnalyze,
68
- factory,
69
- graph,
70
- isIgnored,
71
- onUpdate,
72
- unreferencedFiles,
73
- });
74
- watch('.', { recursive: true }, watchHandler);
75
- }
76
- const { issues, counters, tagHints, configurationHints } = collector.getIssues();
77
- if (options.isFix) {
78
- const touchedFiles = await fixer.fixIssues(issues);
79
- if (options.isFormat) {
80
- const report = await formatly(Array.from(touchedFiles));
81
- if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
82
- debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
83
- }
84
- else {
85
- debugLogObject('*', 'Formatting files failed', report);
86
- }
87
- }
88
- }
89
- if (!options.isWatch)
90
- streamer.clear();
91
- return {
92
- issues,
93
- counters,
94
- tagHints,
95
- configurationHints,
96
- includedWorkspaceDirs: chief.includedWorkspaces.map(w => w.dir),
97
- };
98
- };
1
+ import { run } from './run.js';
2
+ export const main = async (options) => (await run(options)).results;
@@ -36,8 +36,8 @@ const resolveConfig = async (config, options) => {
36
36
  }
37
37
  return opts.isProduction ? toProductionEntry(normalizedPath) : toEntry(normalizedPath);
38
38
  };
39
- for (const [configName, entriesByOption] of entriesByOptionByConfig.entries()) {
40
- for (const [option, entries] of entriesByOption.entries()) {
39
+ for (const [configName, entriesByOption] of entriesByOptionByConfig) {
40
+ for (const [option, entries] of entriesByOption) {
41
41
  for (const entry of entries) {
42
42
  inputs.add(toInput(entry, {
43
43
  isProduction: isBuildTarget && configName === PRODUCTION_CONFIG_NAME,
@@ -46,7 +46,7 @@ const resolveConfig = async (config, options) => {
46
46
  }
47
47
  }
48
48
  }
49
- for (const [option, entries] of defaultEntriesByOption.entries()) {
49
+ for (const [option, entries] of defaultEntriesByOption) {
50
50
  for (const entry of entries) {
51
51
  inputs.add(toInput(entry, {
52
52
  isProduction: isBuildTarget && !productionEntriesByOption.get(option)?.length,
@@ -1,6 +1,6 @@
1
- import { toProductionEntry } from '../../util/input.js';
1
+ import { toDependency, toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
- import { getPageExtensions } from './resolveFromAST.js';
3
+ import { getMdxPlugins, getPageExtensions } from './resolveFromAST.js';
4
4
  const title = 'Next.js';
5
5
  const enablers = ['next'];
6
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -26,7 +26,8 @@ const resolveFromAST = sourceFile => {
26
26
  const pageExtensions = getPageExtensions(sourceFile);
27
27
  const extensions = pageExtensions.length > 0 ? pageExtensions : defaultPageExtensions;
28
28
  const patterns = getEntryFilePatterns(extensions);
29
- return patterns.map(id => toProductionEntry(id));
29
+ const mdxPlugins = getMdxPlugins(sourceFile);
30
+ return [...patterns.map(id => toProductionEntry(id)), ...Array.from(mdxPlugins).map(id => toDependency(id))];
30
31
  };
31
32
  const plugin = {
32
33
  title,
@@ -1,2 +1,3 @@
1
1
  import ts from 'typescript';
2
2
  export declare const getPageExtensions: (sourceFile: ts.SourceFile) => string[];
3
+ export declare const getMdxPlugins: (sourceFile: ts.SourceFile) => Set<string>;
@@ -1,5 +1,5 @@
1
1
  import ts from 'typescript';
2
- import { getPropertyValues } from '../../typescript/ast-helpers.js';
2
+ import { getDefaultImportName, getImportMap, getPropertyValues, stripQuotes } from '../../typescript/ast-helpers.js';
3
3
  export const getPageExtensions = (sourceFile) => {
4
4
  const pageExtensions = new Set();
5
5
  function visit(node) {
@@ -13,3 +13,44 @@ export const getPageExtensions = (sourceFile) => {
13
13
  visit(sourceFile);
14
14
  return Array.from(pageExtensions);
15
15
  };
16
+ const isNamedProp = (prop, name) => ts.isPropertyAssignment(prop) && prop.name.getText() === name;
17
+ export const getMdxPlugins = (sourceFile) => {
18
+ const plugins = new Set();
19
+ const importMap = getImportMap(sourceFile);
20
+ const mdxImportName = getDefaultImportName(importMap, '@next/mdx');
21
+ if (!mdxImportName)
22
+ return plugins;
23
+ function visit(node) {
24
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === mdxImportName) {
25
+ if (node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
26
+ const options = node.arguments[0]?.properties.find(prop => isNamedProp(prop, 'options'));
27
+ if (options && ts.isPropertyAssignment(options)) {
28
+ if (ts.isObjectLiteralExpression(options.initializer)) {
29
+ for (const pluginType of ['remarkPlugins', 'rehypePlugins', 'recmaPlugins']) {
30
+ const props = options.initializer.properties.find(prop => isNamedProp(prop, pluginType));
31
+ if (props && ts.isPropertyAssignment(props)) {
32
+ if (ts.isArrayLiteralExpression(props.initializer)) {
33
+ for (const element of props.initializer.elements) {
34
+ if (ts.isStringLiteral(element)) {
35
+ plugins.add(stripQuotes(element.text));
36
+ }
37
+ else if (ts.isArrayLiteralExpression(element) && element.elements.length > 0) {
38
+ const firstElement = element.elements[0];
39
+ if (ts.isStringLiteral(firstElement)) {
40
+ plugins.add(stripQuotes(firstElement.text));
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return true;
51
+ }
52
+ return ts.forEachChild(node, visit) ?? false;
53
+ }
54
+ visit(sourceFile);
55
+ return plugins;
56
+ };
@@ -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,20 +24,14 @@ 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
29
  filePath: string | undefined;
25
30
  identifier: string | undefined;
26
- pos?: number;
27
- line?: number;
28
- col?: number;
29
31
  isTypeOnly: boolean;
30
- };
31
- export interface Export {
32
+ }
33
+ export interface Export extends SourceLocation {
32
34
  identifier: Identifier;
33
- pos: number;
34
- line: number;
35
- col: number;
36
35
  type: SymbolType;
37
36
  members: ExportMember[];
38
37
  jsDocTags: Tags;
@@ -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;