knip 5.86.0 → 6.0.0-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 (197) hide show
  1. package/dist/ConfigurationChief.d.ts +6 -0
  2. package/dist/DependencyDeputy.d.ts +3 -3
  3. package/dist/IssueCollector.d.ts +1 -1
  4. package/dist/IssueCollector.js +8 -3
  5. package/dist/IssueFixer.js +2 -2
  6. package/dist/ProjectPrincipal.d.ts +22 -29
  7. package/dist/ProjectPrincipal.js +247 -144
  8. package/dist/WorkspaceWorker.d.ts +5 -5
  9. package/dist/WorkspaceWorker.js +80 -16
  10. package/dist/binaries/package-manager/pnpm.js +1 -0
  11. package/dist/cli.js +0 -3
  12. package/dist/compilers/index.d.ts +14 -4
  13. package/dist/constants.d.ts +2 -10
  14. package/dist/constants.js +1 -10
  15. package/dist/graph/analyze.d.ts +1 -3
  16. package/dist/graph/analyze.js +2 -30
  17. package/dist/graph/build.d.ts +3 -4
  18. package/dist/graph/build.js +47 -76
  19. package/dist/graph-explorer/operations/has-strictly-ns-references.js +7 -2
  20. package/dist/graph-explorer/operations/is-referenced.js +14 -1
  21. package/dist/plugins/astro/index.js +3 -3
  22. package/dist/plugins/astro/resolveFromAST.d.ts +3 -3
  23. package/dist/plugins/astro/resolveFromAST.js +5 -40
  24. package/dist/plugins/eleventy/index.js +1 -1
  25. package/dist/plugins/execa/index.js +3 -3
  26. package/dist/plugins/execa/visitors/execa.d.ts +2 -3
  27. package/dist/plugins/execa/visitors/execa.js +43 -26
  28. package/dist/plugins/index.d.ts +1 -0
  29. package/dist/plugins/index.js +2 -0
  30. package/dist/plugins/next/index.js +2 -2
  31. package/dist/plugins/next/resolveFromAST.d.ts +2 -2
  32. package/dist/plugins/next/resolveFromAST.js +2 -15
  33. package/dist/plugins/next-mdx/index.js +2 -2
  34. package/dist/plugins/next-mdx/resolveFromAST.d.ts +2 -2
  35. package/dist/plugins/next-mdx/resolveFromAST.js +22 -38
  36. package/dist/plugins/nuxt/helpers.d.ts +4 -4
  37. package/dist/plugins/nuxt/helpers.js +57 -55
  38. package/dist/plugins/nuxt/index.js +8 -6
  39. package/dist/plugins/oxfmt/index.d.ts +3 -0
  40. package/dist/plugins/oxfmt/index.js +16 -0
  41. package/dist/plugins/oxlint/index.js +1 -1
  42. package/dist/plugins/qwik/index.js +3 -3
  43. package/dist/plugins/qwik/resolveFromAST.d.ts +3 -3
  44. package/dist/plugins/qwik/resolveFromAST.js +5 -23
  45. package/dist/plugins/sst/index.js +2 -2
  46. package/dist/plugins/sst/resolveFromAST.js +31 -31
  47. package/dist/plugins/starlight/index.js +2 -2
  48. package/dist/plugins/starlight/resolveFromAST.d.ts +2 -2
  49. package/dist/plugins/starlight/resolveFromAST.js +7 -18
  50. package/dist/plugins/sveltekit/index.js +6 -12
  51. package/dist/plugins/vite/helpers.d.ts +2 -2
  52. package/dist/plugins/vite/helpers.js +34 -69
  53. package/dist/plugins/vite/index.js +6 -6
  54. package/dist/plugins/vite/visitors/importMetaGlob.d.ts +2 -2
  55. package/dist/plugins/vite/visitors/importMetaGlob.js +31 -28
  56. package/dist/plugins/vitest/index.js +1 -1
  57. package/dist/plugins/webpack/index.js +3 -3
  58. package/dist/plugins/webpack/visitors/requireContext.d.ts +2 -2
  59. package/dist/plugins/webpack/visitors/requireContext.js +29 -26
  60. package/dist/plugins/zx/index.js +3 -3
  61. package/dist/plugins/zx/visitors/zx.d.ts +2 -3
  62. package/dist/plugins/zx/visitors/zx.js +14 -8
  63. package/dist/reporters/codeclimate.js +5 -9
  64. package/dist/reporters/codeowners.js +1 -3
  65. package/dist/reporters/compact.js +10 -23
  66. package/dist/reporters/disclosure.js +3 -5
  67. package/dist/reporters/github-actions.js +4 -6
  68. package/dist/reporters/json.js +5 -7
  69. package/dist/reporters/markdown.js +10 -20
  70. package/dist/reporters/symbols.js +3 -5
  71. package/dist/reporters/util/configuration-hints.js +6 -4
  72. package/dist/reporters/util/util.d.ts +3 -2
  73. package/dist/reporters/util/util.js +1 -0
  74. package/dist/reporters/watch.js +3 -5
  75. package/dist/run.js +6 -5
  76. package/dist/schema/configuration.d.ts +19 -4
  77. package/dist/schema/configuration.js +0 -1
  78. package/dist/schema/plugins.d.ts +5 -0
  79. package/dist/schema/plugins.js +1 -0
  80. package/dist/types/PluginNames.d.ts +2 -2
  81. package/dist/types/PluginNames.js +1 -0
  82. package/dist/types/config.d.ts +11 -11
  83. package/dist/types/exports.d.ts +0 -21
  84. package/dist/types/issues.d.ts +2 -6
  85. package/dist/types/module-graph.d.ts +2 -2
  86. package/dist/types/options.d.ts +0 -1
  87. package/dist/types/project.d.ts +30 -12
  88. package/dist/typescript/SourceFileManager.d.ts +3 -8
  89. package/dist/typescript/SourceFileManager.js +31 -41
  90. package/dist/typescript/ast-helpers.d.ts +9 -73
  91. package/dist/typescript/ast-helpers.js +107 -404
  92. package/dist/typescript/get-imports-and-exports.d.ts +5 -12
  93. package/dist/typescript/get-imports-and-exports.js +224 -373
  94. package/dist/typescript/resolve-module-names.d.ts +12 -3
  95. package/dist/typescript/resolve-module-names.js +50 -98
  96. package/dist/typescript/visitors/calls.d.ts +4 -0
  97. package/dist/typescript/visitors/calls.js +128 -0
  98. package/dist/typescript/visitors/exports.d.ts +6 -0
  99. package/dist/typescript/visitors/exports.js +381 -0
  100. package/dist/typescript/visitors/helpers.d.ts +24 -6
  101. package/dist/typescript/visitors/helpers.js +89 -11
  102. package/dist/typescript/visitors/imports.d.ts +4 -0
  103. package/dist/typescript/visitors/imports.js +257 -0
  104. package/dist/typescript/visitors/jsdoc.d.ts +3 -0
  105. package/dist/typescript/visitors/jsdoc.js +66 -0
  106. package/dist/typescript/visitors/local-refs.d.ts +7 -0
  107. package/dist/typescript/visitors/local-refs.js +241 -0
  108. package/dist/typescript/visitors/members.d.ts +4 -0
  109. package/dist/typescript/visitors/members.js +155 -0
  110. package/dist/typescript/visitors/script-visitors.d.ts +2 -0
  111. package/dist/typescript/visitors/script-visitors.js +13 -0
  112. package/dist/typescript/visitors/walk.d.ts +60 -0
  113. package/dist/typescript/visitors/walk.js +321 -0
  114. package/dist/util/cli-arguments.d.ts +1 -2
  115. package/dist/util/cli-arguments.js +2 -4
  116. package/dist/util/create-options.d.ts +14 -8
  117. package/dist/util/create-options.js +27 -8
  118. package/dist/util/fs.d.ts +1 -0
  119. package/dist/util/fs.js +8 -1
  120. package/dist/util/get-included-issue-types.js +1 -1
  121. package/dist/util/glob-core.js +29 -3
  122. package/dist/util/issue-initializers.js +1 -5
  123. package/dist/util/load-tsconfig.d.ts +2 -2
  124. package/dist/util/load-tsconfig.js +82 -8
  125. package/dist/util/modules.js +1 -2
  126. package/dist/util/path.js +1 -1
  127. package/dist/util/regex.d.ts +0 -1
  128. package/dist/util/regex.js +0 -2
  129. package/dist/util/resolve.d.ts +3 -3
  130. package/dist/util/resolve.js +54 -24
  131. package/dist/util/to-source-path.d.ts +1 -1
  132. package/dist/util/to-source-path.js +8 -6
  133. package/dist/util/watch.d.ts +2 -3
  134. package/dist/util/watch.js +11 -21
  135. package/dist/version.d.ts +1 -1
  136. package/dist/version.js +1 -1
  137. package/package.json +4 -6
  138. package/schema-jsonc.json +1 -1
  139. package/schema.json +6 -6
  140. package/dist/PrincipalFactory.d.ts +0 -14
  141. package/dist/PrincipalFactory.js +0 -66
  142. package/dist/types/imports.d.ts +0 -10
  143. package/dist/types/imports.js +0 -1
  144. package/dist/typescript/SourceFile.d.ts +0 -35
  145. package/dist/typescript/SourceFile.js +0 -1
  146. package/dist/typescript/create-hosts.d.ts +0 -20
  147. package/dist/typescript/create-hosts.js +0 -35
  148. package/dist/typescript/has-refs-in-file.d.ts +0 -3
  149. package/dist/typescript/has-refs-in-file.js +0 -71
  150. package/dist/typescript/pragmas/custom.d.ts +0 -3
  151. package/dist/typescript/pragmas/custom.js +0 -33
  152. package/dist/typescript/pragmas/index.d.ts +0 -3
  153. package/dist/typescript/pragmas/index.js +0 -3
  154. package/dist/typescript/pragmas/typescript.d.ts +0 -3
  155. package/dist/typescript/pragmas/typescript.js +0 -45
  156. package/dist/typescript/visitors/dynamic-imports/importCall.d.ts +0 -3
  157. package/dist/typescript/visitors/dynamic-imports/importCall.js +0 -225
  158. package/dist/typescript/visitors/dynamic-imports/importType.d.ts +0 -3
  159. package/dist/typescript/visitors/dynamic-imports/importType.js +0 -18
  160. package/dist/typescript/visitors/dynamic-imports/index.d.ts +0 -4
  161. package/dist/typescript/visitors/dynamic-imports/index.js +0 -9
  162. package/dist/typescript/visitors/dynamic-imports/jsDocType.d.ts +0 -4
  163. package/dist/typescript/visitors/dynamic-imports/jsDocType.js +0 -67
  164. package/dist/typescript/visitors/dynamic-imports/moduleRegister.d.ts +0 -3
  165. package/dist/typescript/visitors/dynamic-imports/moduleRegister.js +0 -32
  166. package/dist/typescript/visitors/dynamic-imports/requireCall.d.ts +0 -3
  167. package/dist/typescript/visitors/dynamic-imports/requireCall.js +0 -108
  168. package/dist/typescript/visitors/dynamic-imports/resolveCall.d.ts +0 -3
  169. package/dist/typescript/visitors/dynamic-imports/resolveCall.js +0 -21
  170. package/dist/typescript/visitors/dynamic-imports/urlConstructor.d.ts +0 -3
  171. package/dist/typescript/visitors/dynamic-imports/urlConstructor.js +0 -27
  172. package/dist/typescript/visitors/exports/exportAssignment.d.ts +0 -3
  173. package/dist/typescript/visitors/exports/exportAssignment.js +0 -27
  174. package/dist/typescript/visitors/exports/exportDeclaration.d.ts +0 -3
  175. package/dist/typescript/visitors/exports/exportDeclaration.js +0 -24
  176. package/dist/typescript/visitors/exports/exportKeyword.d.ts +0 -3
  177. package/dist/typescript/visitors/exports/exportKeyword.js +0 -125
  178. package/dist/typescript/visitors/exports/exportsAccessExpression.d.ts +0 -3
  179. package/dist/typescript/visitors/exports/exportsAccessExpression.js +0 -23
  180. package/dist/typescript/visitors/exports/index.d.ts +0 -3
  181. package/dist/typescript/visitors/exports/index.js +0 -13
  182. package/dist/typescript/visitors/exports/moduleExportsAccessExpression.d.ts +0 -3
  183. package/dist/typescript/visitors/exports/moduleExportsAccessExpression.js +0 -78
  184. package/dist/typescript/visitors/imports/importDeclaration.d.ts +0 -3
  185. package/dist/typescript/visitors/imports/importDeclaration.js +0 -73
  186. package/dist/typescript/visitors/imports/importEqualsDeclaration.d.ts +0 -3
  187. package/dist/typescript/visitors/imports/importEqualsDeclaration.js +0 -21
  188. package/dist/typescript/visitors/imports/index.d.ts +0 -3
  189. package/dist/typescript/visitors/imports/index.js +0 -5
  190. package/dist/typescript/visitors/imports/reExportDeclaration.d.ts +0 -3
  191. package/dist/typescript/visitors/imports/reExportDeclaration.js +0 -54
  192. package/dist/typescript/visitors/index.d.ts +0 -14
  193. package/dist/typescript/visitors/index.js +0 -19
  194. package/dist/typescript/visitors/scripts/bun.d.ts +0 -3
  195. package/dist/typescript/visitors/scripts/bun.js +0 -9
  196. package/dist/typescript/visitors/scripts/index.d.ts +0 -4
  197. package/dist/typescript/visitors/scripts/index.js +0 -3
@@ -411,6 +411,11 @@ export declare class ConfigurationChief {
411
411
  entry?: string | string[] | undefined;
412
412
  project?: string | string[] | undefined;
413
413
  } | undefined;
414
+ oxfmt?: string | boolean | string[] | {
415
+ config?: string | string[] | undefined;
416
+ entry?: string | string[] | undefined;
417
+ project?: string | string[] | undefined;
418
+ } | undefined;
414
419
  oxlint?: string | boolean | string[] | {
415
420
  config?: string | string[] | undefined;
416
421
  entry?: string | string[] | undefined;
@@ -837,6 +842,7 @@ export declare class ConfigurationChief {
837
842
  nyc?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
838
843
  oclif?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
839
844
  "openapi-ts"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
845
+ oxfmt?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
840
846
  oxlint?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
841
847
  parcel?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
842
848
  payload?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -1,5 +1,5 @@
1
1
  import type { Workspace } from './ConfigurationChief.ts';
2
- import type { ConfigurationHint, Counters, Issue, Issues, SymbolIssueType } from './types/issues.ts';
2
+ import type { ConfigurationHint, Counters, Issue, Issues, IssueType } from './types/issues.ts';
3
3
  import type { PackageJson } from './types/package-json.ts';
4
4
  import type { DependencyArray, DependencySet, HostDependencies, InstalledBinaries, WorkspaceManifests } from './types/workspace.ts';
5
5
  import type { MainOptions } from './util/create-options.ts';
@@ -65,8 +65,8 @@ export declare class DependencyDeputy {
65
65
  devDependencyIssues: Issue[];
66
66
  optionalPeerDependencyIssues: Issue[];
67
67
  };
68
- handleIgnoredDependencies(issues: Issues, counters: Counters, type: SymbolIssueType): void;
69
- handleIgnoredBinaries(issues: Issues, counters: Counters, type: SymbolIssueType): void;
68
+ handleIgnoredDependencies(issues: Issues, counters: Counters, type: IssueType): void;
69
+ handleIgnoredBinaries(issues: Issues, counters: Counters, type: IssueType): void;
70
70
  handleIgnoredUnresolved(issues: Issues, counters: Counters): void;
71
71
  removeIgnoredIssues({ issues, counters }: {
72
72
  issues: Issues;
@@ -43,7 +43,7 @@ export declare class IssueCollector {
43
43
  addIssue(issue: Issue): true | undefined;
44
44
  addConfigurationHint(issue: ConfigurationHint): void;
45
45
  addTagHint(issue: TagHint): void;
46
- purge(): import("./types/issues.ts").IssueSet;
46
+ purge(): Set<string>;
47
47
  getIssues(): {
48
48
  issues: import("./types/issues.ts").Issues;
49
49
  counters: import("./types/issues.ts").Counters;
@@ -122,9 +122,10 @@ export class IssueCollector {
122
122
  }
123
123
  if (this.shouldIgnoreIssue(filePath, 'files'))
124
124
  continue;
125
- this.issues.files.add(filePath);
126
125
  const symbol = relative(this.cwd, filePath);
127
- this.issues._files[symbol] = [{ type: 'files', filePath, symbol, severity: this.rules.files }];
126
+ this.issues.files[symbol] = {
127
+ [symbol]: { type: 'files', filePath, symbol, workspace: '', severity: this.rules.files, fixes: [] },
128
+ };
128
129
  this.counters.files++;
129
130
  this.counters.processed++;
130
131
  }
@@ -160,7 +161,11 @@ export class IssueCollector {
160
161
  this.tagHints.add(issue);
161
162
  }
162
163
  purge() {
163
- const unusedFiles = this.issues.files;
164
+ const unusedFiles = new Set();
165
+ for (const issues of Object.values(this.issues.files)) {
166
+ for (const issue of Object.values(issues))
167
+ unusedFiles.add(issue.filePath);
168
+ }
164
169
  this.issues = initIssues();
165
170
  this.counters = initCounters();
166
171
  return unusedFiles;
@@ -46,7 +46,7 @@ class IssueFixer {
46
46
  async removeUnusedFiles(issues) {
47
47
  if (!this.options.isFixFiles)
48
48
  return;
49
- for (const issue of Object.values(issues._files).flatMap(Object.values)) {
49
+ for (const issue of Object.values(issues.files).flatMap(Object.values)) {
50
50
  await rm(issue.filePath);
51
51
  issue.isFixed = true;
52
52
  }
@@ -54,7 +54,7 @@ class IssueFixer {
54
54
  async removeUnusedExports(issues) {
55
55
  const touchedFiles = new Set();
56
56
  const types = [
57
- ...(this.options.isFixUnusedTypes ? ['types', 'nsTypes', 'classMembers', 'enumMembers'] : []),
57
+ ...(this.options.isFixUnusedTypes ? ['types', 'nsTypes', 'enumMembers'] : []),
58
58
  ...(this.options.isFixUnusedExports ? ['exports', 'nsExports'] : []),
59
59
  ];
60
60
  if (types.length === 0)
@@ -1,10 +1,9 @@
1
- import ts from 'typescript';
1
+ import { type ParseResult } from 'oxc-parser';
2
2
  import { CacheConsultant } from './CacheConsultant.ts';
3
3
  import type { AsyncCompilers, SyncCompilers } from './compilers/types.ts';
4
- import type { GetImportsAndExportsOptions, IgnoreExportsUsedInFile, Visitors } from './types/config.ts';
5
- import type { Export, ExportMember, FileNode, ModuleGraph } from './types/module-graph.ts';
6
- import type { Paths, PrincipalOptions } from './types/project.ts';
7
- import type { ResolveModuleNames } from './typescript/resolve-module-names.ts';
4
+ import type { GetImportsAndExportsOptions, IgnoreExportsUsedInFile, PluginVisitorContext, PluginVisitorObject } from './types/config.ts';
5
+ import type { FileNode, ModuleGraph } from './types/module-graph.ts';
6
+ import type { Paths } from './types/project.ts';
8
7
  import { SourceFileManager } from './typescript/SourceFileManager.ts';
9
8
  import type { MainOptions } from './util/create-options.ts';
10
9
  import type { ToSourceFilePath } from './util/to-source-path.ts';
@@ -13,30 +12,24 @@ export declare class ProjectPrincipal {
13
12
  projectPaths: Set<string>;
14
13
  programPaths: Set<string>;
15
14
  skipExportsAnalysis: Set<string>;
16
- visitors: Visitors;
17
- cwd: string;
18
- compilerOptions: ts.CompilerOptions;
19
- extensions: Set<string>;
15
+ pluginCtx: PluginVisitorContext;
16
+ pluginVisitorObjects: PluginVisitorObject[];
17
+ private _visitor;
20
18
  syncCompilers: SyncCompilers;
21
19
  asyncCompilers: AsyncCompilers;
22
- isWatch: boolean;
20
+ private paths;
21
+ private extensions;
23
22
  cache: CacheConsultant<FileNode>;
24
23
  toSourceFilePath: ToSourceFilePath;
25
- backend: {
26
- fileManager: SourceFileManager;
27
- compilerHost?: ts.CompilerHost;
28
- resolveModuleNames: ResolveModuleNames;
29
- program?: ts.Program;
30
- typeChecker?: ts.TypeChecker;
31
- languageServiceHost: ts.LanguageServiceHost;
32
- };
33
- findReferences?: ts.LanguageService['findReferences'];
34
- getImplementationAtPosition?: ts.LanguageService['getImplementationAtPosition'];
35
- constructor(options: MainOptions, { compilerOptions, compilers, pkgName, toSourceFilePath }: PrincipalOptions);
36
- init(): void;
37
- addPaths(paths: Paths, basePath: string): void;
24
+ fileManager: SourceFileManager;
25
+ private resolver;
26
+ resolvedFiles: Set<string>;
27
+ deletedFiles: Set<string>;
28
+ constructor(options: MainOptions, toSourceFilePath: ToSourceFilePath);
38
29
  addCompilers(compilers: [SyncCompilers, AsyncCompilers]): void;
39
- private createProgram;
30
+ addPaths(paths: Paths, basePath: string): void;
31
+ init(): void;
32
+ readFile(filePath: string): string;
40
33
  private hasAcceptedExtension;
41
34
  addEntryPath(filePath: string, options?: {
42
35
  skipExportsAnalysis: boolean;
@@ -46,15 +39,15 @@ export declare class ProjectPrincipal {
46
39
  }): void;
47
40
  addProgramPath(filePath: string): void;
48
41
  addProjectPath(filePath: string): void;
49
- deletedFiles: Set<unknown>;
50
42
  removeProjectPath(filePath: string): void;
51
43
  runAsyncCompilers(): Promise<void>;
44
+ walkAndAnalyze(analyzeFile: (filePath: string, parseResult: ParseResult | undefined, sourceText: string) => Iterable<string> | undefined): void;
45
+ private followImportsLightweight;
52
46
  getUsedResolvedFiles(): string[];
53
- private getProgramSourceFiles;
47
+ private resolveSpecifier;
54
48
  getUnreferencedFiles(): string[];
55
- analyzeSourceFile(filePath: string, options: GetImportsAndExportsOptions, ignoreExportsUsedInFile: IgnoreExportsUsedInFile): FileNode;
49
+ analyzeSourceFile(filePath: string, options: GetImportsAndExportsOptions, ignoreExportsUsedInFile: IgnoreExportsUsedInFile, parseResult?: ParseResult, sourceText?: string): FileNode;
50
+ private buildVisitor;
56
51
  invalidateFile(filePath: string): void;
57
- findUnusedMembers(filePath: string, members: ExportMember[]): ExportMember[];
58
- hasExternalReferences(filePath: string, exportedItem: Export): boolean;
59
52
  reconcileCache(graph: ModuleGraph): void;
60
53
  }
@@ -1,104 +1,114 @@
1
- import ts from 'typescript';
1
+ import { parseSync, Visitor, rawTransferSupported } from 'oxc-parser';
2
+ import { isStringLiteral, getStringValue, stripQuotes } from "./typescript/visitors/helpers.js";
2
3
  import { CacheConsultant } from "./CacheConsultant.js";
3
4
  import { getCompilerExtensions } from "./compilers/index.js";
4
- import { ANONYMOUS, DEFAULT_EXTENSIONS, MEMBER_FLAGS, PUBLIC_TAG } from "./constants.js";
5
- import { createHosts } from "./typescript/create-hosts.js";
5
+ import { DEFAULT_EXTENSIONS } from "./constants.js";
6
6
  import { _getImportsAndExports } from "./typescript/get-imports-and-exports.js";
7
+ import { createBunShellVisitor } from "./typescript/visitors/script-visitors.js";
8
+ import { coreVisitorObject } from "./typescript/visitors/walk.js";
9
+ import { createCustomModuleResolver } from "./typescript/resolve-module-names.js";
7
10
  import { SourceFileManager } from "./typescript/SourceFileManager.js";
8
11
  import { compact } from "./util/array.js";
9
12
  import { timerify } from "./util/Performance.js";
10
13
  import { extname, isInNodeModules, toAbsolute } from "./util/path.js";
11
- const baseCompilerOptions = {
12
- allowJs: true,
13
- allowSyntheticDefaultImports: true,
14
- declaration: false,
15
- declarationMap: false,
16
- esModuleInterop: true,
17
- inlineSourceMap: false,
18
- inlineSources: false,
19
- jsx: ts.JsxEmit.Preserve,
20
- jsxImportSource: undefined,
21
- lib: [],
22
- noEmit: true,
23
- skipDefaultLibCheck: true,
24
- skipLibCheck: true,
25
- sourceMap: false,
26
- types: ['node'],
27
- };
28
- const tsCreateProgram = timerify(ts.createProgram);
14
+ const parseOptions = { sourceType: 'unambiguous', experimentalRawTransfer: rawTransferSupported() };
15
+ const _requireSpecs = [];
16
+ const _requireVisitor = new Visitor({
17
+ CallExpression(node) {
18
+ if (node.callee?.type === 'Identifier' && node.callee.name === 'require') {
19
+ const arg = node.arguments?.[0];
20
+ if (isStringLiteral(arg))
21
+ _requireSpecs.push(getStringValue(arg));
22
+ }
23
+ if (node.callee?.type === 'MemberExpression' &&
24
+ !node.callee.computed &&
25
+ node.callee.object?.type === 'Identifier' &&
26
+ node.callee.object.name === 'require' &&
27
+ node.callee.property?.name === 'resolve') {
28
+ const arg = node.arguments?.[0];
29
+ if (isStringLiteral(arg))
30
+ _requireSpecs.push(getStringValue(arg));
31
+ }
32
+ },
33
+ TSImportEqualsDeclaration(node) {
34
+ if (node.moduleReference?.type === 'TSExternalModuleReference') {
35
+ const expr = node.moduleReference.expression;
36
+ if (isStringLiteral(expr))
37
+ _requireSpecs.push(getStringValue(expr));
38
+ }
39
+ },
40
+ });
41
+ const _jsDocImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
29
42
  export class ProjectPrincipal {
30
43
  entryPaths = new Set();
31
44
  projectPaths = new Set();
32
45
  programPaths = new Set();
33
46
  skipExportsAnalysis = new Set();
34
- visitors = { dynamicImport: [], script: [] };
35
- cwd;
36
- compilerOptions;
37
- extensions;
38
- syncCompilers;
39
- asyncCompilers;
40
- isWatch;
47
+ pluginCtx = {
48
+ filePath: '',
49
+ sourceText: '',
50
+ addScript: () => { },
51
+ addImport: () => { },
52
+ };
53
+ pluginVisitorObjects = [];
54
+ _visitor;
55
+ syncCompilers = new Map();
56
+ asyncCompilers = new Map();
57
+ paths = {};
58
+ extensions = new Set(DEFAULT_EXTENSIONS);
41
59
  cache;
42
60
  toSourceFilePath;
43
- backend;
44
- findReferences;
45
- getImplementationAtPosition;
46
- constructor(options, { compilerOptions, compilers, pkgName, toSourceFilePath }) {
47
- this.compilerOptions = {
48
- ...compilerOptions,
49
- ...baseCompilerOptions,
50
- types: compact([...(compilerOptions.types ?? []), ...(baseCompilerOptions.types ?? [])]),
51
- allowNonTsExtensions: true,
52
- };
53
- const [syncCompilers, asyncCompilers] = compilers;
54
- this.extensions = new Set([...DEFAULT_EXTENSIONS, ...getCompilerExtensions(compilers)]);
55
- this.syncCompilers = syncCompilers;
56
- this.asyncCompilers = asyncCompilers;
57
- this.cwd = options.cwd;
58
- this.isWatch = options.isWatch || options.isSession;
59
- this.cache = new CacheConsultant(pkgName || ANONYMOUS, options);
61
+ fileManager;
62
+ resolver;
63
+ resolvedFiles = new Set();
64
+ deletedFiles = new Set();
65
+ constructor(options, toSourceFilePath) {
66
+ this.cache = new CacheConsultant('root', options);
60
67
  this.toSourceFilePath = toSourceFilePath;
61
- this.backend = {
62
- fileManager: new SourceFileManager({ compilers, isSkipLibs: options.isSkipLibs }),
63
- };
64
- }
65
- init() {
66
- const { compilerHost, resolveModuleNames, languageServiceHost } = createHosts({
67
- cwd: this.cwd,
68
- compilerOptions: this.compilerOptions,
69
- entryPaths: this.entryPaths,
68
+ this.pluginVisitorObjects.push(createBunShellVisitor(this.pluginCtx));
69
+ this.fileManager = new SourceFileManager({
70
70
  compilers: [this.syncCompilers, this.asyncCompilers],
71
- toSourceFilePath: this.toSourceFilePath,
72
- useResolverCache: !this.isWatch,
73
- fileManager: this.backend.fileManager,
71
+ isSkipLibs: options.isSkipLibs,
74
72
  });
75
- this.backend.compilerHost = compilerHost;
76
- this.backend.resolveModuleNames = resolveModuleNames;
77
- this.backend.languageServiceHost = languageServiceHost;
73
+ }
74
+ addCompilers(compilers) {
75
+ for (const [ext, compiler] of compilers[0]) {
76
+ if (!this.syncCompilers.has(ext)) {
77
+ this.syncCompilers.set(ext, compiler);
78
+ this.extensions.add(ext);
79
+ }
80
+ }
81
+ for (const [ext, compiler] of compilers[1]) {
82
+ if (!this.asyncCompilers.has(ext)) {
83
+ this.asyncCompilers.set(ext, compiler);
84
+ this.extensions.add(ext);
85
+ }
86
+ }
78
87
  }
79
88
  addPaths(paths, basePath) {
80
89
  if (!paths)
81
90
  return;
82
- this.compilerOptions.paths ??= {};
83
91
  for (const key in paths) {
84
92
  const prefixes = paths[key].map(prefix => toAbsolute(prefix, basePath));
85
- if (key in this.compilerOptions.paths) {
86
- this.compilerOptions.paths[key] = compact([...this.compilerOptions.paths[key], ...prefixes]);
93
+ if (key in this.paths) {
94
+ this.paths[key] = compact([...this.paths[key], ...prefixes]);
87
95
  }
88
96
  else {
89
- this.compilerOptions.paths[key] = prefixes;
97
+ this.paths[key] = prefixes;
90
98
  }
91
99
  }
92
100
  }
93
- addCompilers(compilers) {
94
- this.syncCompilers = new Map([...this.syncCompilers, ...compilers[0]]);
95
- this.asyncCompilers = new Map([...this.asyncCompilers, ...compilers[1]]);
96
- this.extensions = new Set([...this.extensions, ...getCompilerExtensions(compilers)]);
101
+ init() {
102
+ this.extensions = new Set([
103
+ ...DEFAULT_EXTENSIONS,
104
+ ...getCompilerExtensions([this.syncCompilers, this.asyncCompilers]),
105
+ ]);
106
+ const customCompilerExtensions = getCompilerExtensions([this.syncCompilers, this.asyncCompilers]);
107
+ const pathsOrUndefined = Object.keys(this.paths).length > 0 ? this.paths : undefined;
108
+ this.resolver = createCustomModuleResolver({ paths: pathsOrUndefined }, customCompilerExtensions, this.toSourceFilePath);
97
109
  }
98
- createProgram() {
99
- this.backend.program = tsCreateProgram([...this.entryPaths, ...this.programPaths], this.compilerOptions, this.backend.compilerHost, this.backend.program);
100
- const typeChecker = timerify(this.backend.program.getTypeChecker);
101
- this.backend.typeChecker = typeChecker();
110
+ readFile(filePath) {
111
+ return this.fileManager.readFile(filePath);
102
112
  }
103
113
  hasAcceptedExtension(filePath) {
104
114
  return this.extensions.has(extname(filePath));
@@ -126,7 +136,6 @@ export class ProjectPrincipal {
126
136
  this.deletedFiles.delete(filePath);
127
137
  }
128
138
  }
129
- deletedFiles = new Set();
130
139
  removeProjectPath(filePath) {
131
140
  this.entryPaths.delete(filePath);
132
141
  this.projectPaths.delete(filePath);
@@ -134,99 +143,193 @@ export class ProjectPrincipal {
134
143
  this.deletedFiles.add(filePath);
135
144
  }
136
145
  async runAsyncCompilers() {
137
- const add = timerify(this.backend.fileManager.compileAndAddSourceFile.bind(this.backend.fileManager));
146
+ const add = timerify(this.fileManager.compileAndAddSourceFile.bind(this.fileManager));
138
147
  const extensions = Array.from(this.asyncCompilers.keys());
139
148
  const files = Array.from(this.projectPaths).filter(filePath => extensions.includes(extname(filePath)));
140
149
  for (const filePath of files) {
141
150
  await add(filePath);
142
151
  }
143
152
  }
153
+ walkAndAnalyze(analyzeFile) {
154
+ this.resolvedFiles.clear();
155
+ const queue = [...this.entryPaths, ...this.programPaths];
156
+ const visited = new Set();
157
+ let lastEntrySize = this.entryPaths.size;
158
+ let lastProgramSize = this.programPaths.size;
159
+ for (let i = 0; i < queue.length; i++) {
160
+ const filePath = queue[i];
161
+ if (visited.has(filePath))
162
+ continue;
163
+ visited.add(filePath);
164
+ const sourceText = this.fileManager.readFile(filePath);
165
+ if (!sourceText) {
166
+ if (this.projectPaths.has(filePath))
167
+ analyzeFile(filePath, undefined, '');
168
+ continue;
169
+ }
170
+ try {
171
+ const ext = extname(filePath);
172
+ const parseFileName = DEFAULT_EXTENSIONS.has(ext) ? filePath : `${filePath}.ts`;
173
+ const result = parseSync(parseFileName, sourceText, parseOptions);
174
+ this.fileManager.sourceTextCache.delete(filePath);
175
+ if (this.projectPaths.has(filePath)) {
176
+ const internalPaths = analyzeFile(filePath, result, sourceText);
177
+ if (internalPaths) {
178
+ for (const p of internalPaths) {
179
+ if (!visited.has(p))
180
+ queue.push(p);
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ this.followImportsLightweight(result, sourceText, filePath, visited, queue);
186
+ }
187
+ if (this.entryPaths.size > lastEntrySize || this.programPaths.size > lastProgramSize) {
188
+ for (const p of this.entryPaths) {
189
+ if (!visited.has(p))
190
+ queue.push(p);
191
+ }
192
+ for (const p of this.programPaths) {
193
+ if (!visited.has(p))
194
+ queue.push(p);
195
+ }
196
+ lastEntrySize = this.entryPaths.size;
197
+ lastProgramSize = this.programPaths.size;
198
+ }
199
+ }
200
+ catch {
201
+ }
202
+ }
203
+ this.resolvedFiles = visited;
204
+ }
205
+ followImportsLightweight(result, sourceText, filePath, visited, queue) {
206
+ const mod = result.module;
207
+ for (const si of mod.staticImports) {
208
+ const resolved = this.resolveSpecifier(si.moduleRequest.value, filePath);
209
+ if (resolved && !isInNodeModules(resolved)) {
210
+ if (!visited.has(resolved))
211
+ queue.push(resolved);
212
+ }
213
+ }
214
+ for (const se of mod.staticExports) {
215
+ for (const entry of se.entries) {
216
+ if (entry.moduleRequest) {
217
+ const resolved = this.resolveSpecifier(entry.moduleRequest.value, filePath);
218
+ if (resolved && !isInNodeModules(resolved)) {
219
+ if (!visited.has(resolved))
220
+ queue.push(resolved);
221
+ }
222
+ }
223
+ }
224
+ }
225
+ for (const di of mod.dynamicImports) {
226
+ const cleaned = stripQuotes(sourceText.slice(di.moduleRequest.start, di.moduleRequest.end));
227
+ if (cleaned && !cleaned.includes('$') && !cleaned.includes('+')) {
228
+ const resolved = this.resolveSpecifier(cleaned, filePath);
229
+ if (resolved && !isInNodeModules(resolved)) {
230
+ if (!visited.has(resolved))
231
+ queue.push(resolved);
232
+ }
233
+ }
234
+ }
235
+ if (!isInNodeModules(filePath)) {
236
+ _requireSpecs.length = 0;
237
+ _requireVisitor.visit(result.program);
238
+ for (const spec of _requireSpecs) {
239
+ const resolved = this.resolveSpecifier(spec, filePath);
240
+ if (resolved && !isInNodeModules(resolved)) {
241
+ if (!visited.has(resolved))
242
+ queue.push(resolved);
243
+ }
244
+ }
245
+ }
246
+ for (const comment of result.comments) {
247
+ if (comment.type !== 'Block')
248
+ continue;
249
+ let m;
250
+ _jsDocImportRe.lastIndex = 0;
251
+ while ((m = _jsDocImportRe.exec(comment.value)) !== null) {
252
+ const resolved = this.resolveSpecifier(m[1], filePath);
253
+ if (resolved && !isInNodeModules(resolved)) {
254
+ if (!visited.has(resolved))
255
+ queue.push(resolved);
256
+ }
257
+ }
258
+ }
259
+ }
144
260
  getUsedResolvedFiles() {
145
- this.createProgram();
146
- const sourceFiles = this.getProgramSourceFiles();
147
- return Array.from(this.projectPaths).filter(filePath => sourceFiles.has(filePath));
261
+ this.resolvedFiles.clear();
262
+ const queue = [...this.entryPaths, ...this.programPaths];
263
+ const visited = new Set();
264
+ for (let i = 0; i < queue.length; i++) {
265
+ const filePath = queue[i];
266
+ if (visited.has(filePath))
267
+ continue;
268
+ visited.add(filePath);
269
+ const sourceText = this.fileManager.readFile(filePath);
270
+ if (!sourceText)
271
+ continue;
272
+ try {
273
+ const ext = extname(filePath);
274
+ const parseFileName = DEFAULT_EXTENSIONS.has(ext) ? filePath : `${filePath}.ts`;
275
+ const result = parseSync(parseFileName, sourceText, parseOptions);
276
+ this.followImportsLightweight(result, sourceText, filePath, visited, queue);
277
+ }
278
+ catch {
279
+ }
280
+ }
281
+ this.resolvedFiles = visited;
282
+ return Array.from(this.projectPaths).filter(filePath => visited.has(filePath));
148
283
  }
149
- getProgramSourceFiles() {
150
- const programSourceFiles = this.backend.program?.getSourceFiles().map(sourceFile => sourceFile.fileName);
151
- return new Set(programSourceFiles);
284
+ resolveSpecifier(specifier, containingFile) {
285
+ return this.resolver.resolveFileName(specifier, containingFile);
152
286
  }
153
287
  getUnreferencedFiles() {
154
- const sourceFiles = this.getProgramSourceFiles();
155
- return Array.from(this.projectPaths).filter(filePath => !sourceFiles.has(filePath));
288
+ return Array.from(this.projectPaths).filter(filePath => !this.resolvedFiles.has(filePath));
156
289
  }
157
- analyzeSourceFile(filePath, options, ignoreExportsUsedInFile) {
290
+ analyzeSourceFile(filePath, options, ignoreExportsUsedInFile, parseResult, sourceText) {
158
291
  const fd = this.cache.getFileDescriptor(filePath);
159
292
  if (!fd.changed && fd.meta?.data)
160
293
  return fd.meta.data;
161
- const typeChecker = this.backend.typeChecker;
162
- if (!typeChecker)
163
- throw new Error('TypeChecker must be initialized before source file analysis');
164
- const sourceFile = this.backend.fileManager.getSourceFile(filePath);
165
- if (!sourceFile)
166
- throw new Error(`Unable to find ${filePath}`);
294
+ sourceText ??= this.fileManager.readFile(filePath);
167
295
  const skipExports = this.skipExportsAnalysis.has(filePath);
168
296
  if (options.isFixExports || options.isFixTypes) {
169
297
  const ext = extname(filePath);
170
- if (!DEFAULT_EXTENSIONS.includes(ext) && (this.syncCompilers.has(ext) || this.asyncCompilers.has(ext))) {
298
+ if (!DEFAULT_EXTENSIONS.has(ext) && (this.syncCompilers.has(ext) || this.asyncCompilers.has(ext))) {
171
299
  options = { ...options, isFixExports: false, isFixTypes: false };
172
300
  }
173
301
  }
174
- const resolve = (specifier) => this.backend.resolveModuleNames([specifier], sourceFile.fileName)[0];
175
- return _getImportsAndExports(sourceFile, resolve, typeChecker, options, ignoreExportsUsedInFile, skipExports, this.visitors);
302
+ const resolveModule = this.resolver.resolveModuleName;
303
+ if (!this._visitor)
304
+ this._visitor = this.buildVisitor();
305
+ return _getImportsAndExports(filePath, sourceText, resolveModule, options, ignoreExportsUsedInFile, skipExports, this._visitor, this.pluginVisitorObjects.length > 0 ? this.pluginCtx : undefined, parseResult);
176
306
  }
177
- invalidateFile(filePath) {
178
- this.backend.fileManager.invalidate(filePath);
179
- }
180
- findUnusedMembers(filePath, members) {
181
- if (!this.findReferences || !this.getImplementationAtPosition) {
182
- const languageService = ts.createLanguageService(this.backend.languageServiceHost, ts.createDocumentRegistry());
183
- this.findReferences = timerify(languageService.findReferences);
184
- this.getImplementationAtPosition = timerify(languageService.getImplementationAtPosition);
185
- }
186
- return members.filter(member => {
187
- if (member.jsDocTags.has(PUBLIC_TAG))
188
- return false;
189
- const implementations = this.getImplementationAtPosition(filePath, member.pos)?.filter(impl => impl.fileName !== filePath || impl.textSpan.start !== member.pos) ?? [];
190
- const referencedSymbols = this.findReferences(filePath, member.pos) ?? [];
191
- if (referencedSymbols.length > 1 && referencedSymbols.some(sym => isInNodeModules(sym.definition.fileName))) {
192
- return false;
193
- }
194
- const refs = referencedSymbols
195
- .filter(sym => !implementations.some(impl => impl.fileName === sym.definition.fileName &&
196
- impl.textSpan.start === sym.definition.textSpan.start &&
197
- impl.textSpan.length === sym.definition.textSpan.length))
198
- .flatMap(refs => refs.references)
199
- .filter(ref => !ref.isDefinition);
200
- if (refs.length === 0)
201
- return true;
202
- if (member.flags & MEMBER_FLAGS.SETTER)
203
- return false;
204
- return !refs.some(ref => !ref.isWriteAccess);
205
- });
307
+ buildVisitor() {
308
+ if (this.pluginVisitorObjects.length === 0)
309
+ return new Visitor(coreVisitorObject);
310
+ const merged = { ...coreVisitorObject };
311
+ for (const obj of this.pluginVisitorObjects) {
312
+ const handlers = obj;
313
+ for (const key in handlers) {
314
+ const existing = merged[key];
315
+ const pluginFn = handlers[key];
316
+ if (!pluginFn)
317
+ continue;
318
+ if (existing) {
319
+ merged[key] = (node) => {
320
+ existing(node);
321
+ pluginFn(node);
322
+ };
323
+ }
324
+ else {
325
+ merged[key] = pluginFn;
326
+ }
327
+ }
328
+ }
329
+ return new Visitor(merged);
206
330
  }
207
- hasExternalReferences(filePath, exportedItem) {
208
- if (exportedItem.jsDocTags.has(PUBLIC_TAG))
209
- return false;
210
- if (!this.findReferences) {
211
- const languageService = ts.createLanguageService(this.backend.languageServiceHost, ts.createDocumentRegistry());
212
- this.findReferences = timerify(languageService.findReferences);
213
- }
214
- const referencedSymbols = this.findReferences(filePath, exportedItem.pos);
215
- if (!referencedSymbols?.length)
216
- return false;
217
- const externalRefs = referencedSymbols
218
- .flatMap(refs => refs.references)
219
- .filter(ref => !ref.isDefinition && ref.fileName !== filePath)
220
- .filter(ref => {
221
- const sourceFile = this.backend.program?.getSourceFile(ref.fileName);
222
- if (!sourceFile)
223
- return true;
224
- const node = ts.getTokenAtPosition(sourceFile, ref.textSpan.start);
225
- if (!node?.parent?.parent?.parent)
226
- return true;
227
- return !(ts.isExportSpecifier(node.parent) && node.parent.parent.parent.moduleSpecifier);
228
- });
229
- return externalRefs.length > 0;
331
+ invalidateFile(filePath) {
332
+ this.fileManager.invalidate(filePath);
230
333
  }
231
334
  reconcileCache(graph) {
232
335
  for (const [filePath, file] of graph) {