knip 6.24.0 → 6.26.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 (203) hide show
  1. package/dist/ConfigurationChief.d.ts +115 -1
  2. package/dist/ConfigurationChief.js +3 -0
  3. package/dist/ProjectPrincipal.d.ts +2 -0
  4. package/dist/ProjectPrincipal.js +4 -1
  5. package/dist/binaries/bash-parser.js +55 -83
  6. package/dist/binaries/index.js +3 -0
  7. package/dist/compilers/index.d.ts +199 -5
  8. package/dist/constants.d.ts +5 -1
  9. package/dist/constants.js +18 -0
  10. package/dist/graph/analyze.js +37 -2
  11. package/dist/graph/build.js +17 -3
  12. package/dist/graph-explorer/explorer.d.ts +1 -0
  13. package/dist/graph-explorer/explorer.js +2 -0
  14. package/dist/graph-explorer/operations/find-all-cycles.d.ts +3 -0
  15. package/dist/graph-explorer/operations/find-all-cycles.js +43 -0
  16. package/dist/graph-explorer/operations/find-cycles.js +3 -9
  17. package/dist/graph-explorer/utils.d.ts +10 -1
  18. package/dist/graph-explorer/utils.js +53 -0
  19. package/dist/plugins/_vue/auto-import.d.ts +12 -0
  20. package/dist/plugins/_vue/auto-import.js +272 -0
  21. package/dist/plugins/_vue/types.d.ts +38 -0
  22. package/dist/plugins/_vue/types.js +1 -0
  23. package/dist/plugins/astro/index.js +2 -37
  24. package/dist/plugins/astro/resolveFromAST.d.ts +4 -4
  25. package/dist/plugins/astro/resolveFromAST.js +34 -7
  26. package/dist/plugins/bun/index.js +28 -14
  27. package/dist/plugins/electron-vite/index.d.ts +3 -0
  28. package/dist/plugins/electron-vite/index.js +51 -0
  29. package/dist/plugins/electron-vite/types.d.ts +23 -0
  30. package/dist/plugins/electron-vite/types.js +1 -0
  31. package/dist/plugins/esbuild/index.d.ts +3 -0
  32. package/dist/plugins/esbuild/index.js +17 -0
  33. package/dist/plugins/eslint/resolveFromAST.js +18 -21
  34. package/dist/plugins/eve/index.d.ts +3 -0
  35. package/dist/plugins/eve/index.js +22 -0
  36. package/dist/plugins/execa/visitors/execa.js +10 -18
  37. package/dist/plugins/fumadocs/index.d.ts +3 -0
  38. package/dist/plugins/fumadocs/index.js +18 -0
  39. package/dist/plugins/graphql-codegen/index.js +9 -7
  40. package/dist/plugins/index.d.ts +19 -0
  41. package/dist/plugins/index.js +38 -0
  42. package/dist/plugins/jest/index.js +13 -3
  43. package/dist/plugins/laravel-vite-plugin/index.d.ts +3 -0
  44. package/dist/plugins/laravel-vite-plugin/index.js +14 -0
  45. package/dist/plugins/laravel-vite-plugin/resolveFromAST.d.ts +2 -0
  46. package/dist/plugins/laravel-vite-plugin/resolveFromAST.js +27 -0
  47. package/dist/plugins/next/index.js +25 -12
  48. package/dist/plugins/next-mdx/index.js +2 -8
  49. package/dist/plugins/next-mdx/resolveFromAST.d.ts +3 -2
  50. package/dist/plugins/next-mdx/resolveFromAST.js +17 -21
  51. package/dist/plugins/node/index.js +4 -1
  52. package/dist/plugins/nuxt/index.js +5 -68
  53. package/dist/plugins/nuxt/types.d.ts +0 -34
  54. package/dist/plugins/nuxtjs-i18n/index.d.ts +3 -0
  55. package/dist/plugins/nuxtjs-i18n/index.js +12 -0
  56. package/dist/plugins/oclif/index.js +10 -5
  57. package/dist/plugins/orval/index.js +1 -3
  58. package/dist/plugins/orval/resolveFromAST.d.ts +2 -2
  59. package/dist/plugins/orval/resolveFromAST.js +4 -7
  60. package/dist/plugins/oxlint/index.js +23 -2
  61. package/dist/plugins/pnpm/index.js +22 -1
  62. package/dist/plugins/pnpm/types.d.ts +4 -0
  63. package/dist/plugins/pnpm/types.js +1 -0
  64. package/dist/plugins/prettier/index.js +19 -3
  65. package/dist/plugins/prettier/types.d.ts +6 -1
  66. package/dist/plugins/quasar/index.d.ts +3 -0
  67. package/dist/plugins/quasar/index.js +15 -0
  68. package/dist/plugins/quasar/resolveFromAST.d.ts +3 -0
  69. package/dist/plugins/quasar/resolveFromAST.js +63 -0
  70. package/dist/plugins/qwik/index.js +1 -25
  71. package/dist/plugins/qwik/resolveFromAST.d.ts +5 -3
  72. package/dist/plugins/qwik/resolveFromAST.js +28 -9
  73. package/dist/plugins/rolldown/index.js +2 -5
  74. package/dist/plugins/rollup/index.js +2 -5
  75. package/dist/plugins/rslib/index.js +2 -5
  76. package/dist/plugins/rspack/index.js +5 -0
  77. package/dist/plugins/serverless-framework/index.js +12 -1
  78. package/dist/plugins/serverless-framework/types.d.ts +5 -2
  79. package/dist/plugins/sst/index.js +1 -5
  80. package/dist/plugins/sst/resolveFromAST.d.ts +1 -1
  81. package/dist/plugins/sst/resolveFromAST.js +1 -1
  82. package/dist/plugins/starlight/index.js +1 -19
  83. package/dist/plugins/starlight/resolveFromAST.d.ts +2 -2
  84. package/dist/plugins/starlight/resolveFromAST.js +12 -8
  85. package/dist/plugins/stencil/index.js +2 -37
  86. package/dist/plugins/stencil/resolveFromAST.d.ts +3 -0
  87. package/dist/plugins/stencil/resolveFromAST.js +36 -0
  88. package/dist/plugins/storybook/index.js +10 -0
  89. package/dist/plugins/sveltekit/index.js +1 -48
  90. package/dist/plugins/sveltekit/resolveFromAST.d.ts +2 -0
  91. package/dist/plugins/sveltekit/resolveFromAST.js +45 -0
  92. package/dist/plugins/tauri/index.d.ts +3 -0
  93. package/dist/plugins/tauri/index.js +42 -0
  94. package/dist/plugins/tauri/types.d.ts +16 -0
  95. package/dist/plugins/tauri/types.js +1 -0
  96. package/dist/plugins/tsdown/index.js +2 -5
  97. package/dist/plugins/tsup/index.js +2 -5
  98. package/dist/plugins/typedoc/index.js +9 -3
  99. package/dist/plugins/typedoc/types.d.ts +2 -0
  100. package/dist/plugins/unplugin-auto-import/index.d.ts +3 -0
  101. package/dist/plugins/unplugin-auto-import/index.js +18 -0
  102. package/dist/plugins/unplugin-icons/index.d.ts +3 -0
  103. package/dist/plugins/unplugin-icons/index.js +17 -0
  104. package/dist/plugins/unplugin-vue-components/index.d.ts +3 -0
  105. package/dist/plugins/unplugin-vue-components/index.js +16 -0
  106. package/dist/plugins/unplugin-vue-i18n/index.d.ts +3 -0
  107. package/dist/plugins/unplugin-vue-i18n/index.js +10 -0
  108. package/dist/plugins/unplugin-vue-markdown/index.d.ts +3 -0
  109. package/dist/plugins/unplugin-vue-markdown/index.js +16 -0
  110. package/dist/plugins/unplugin-vue-router/index.d.ts +3 -0
  111. package/dist/plugins/unplugin-vue-router/index.js +14 -0
  112. package/dist/plugins/vite/helpers.d.ts +2 -0
  113. package/dist/plugins/vite/helpers.js +46 -31
  114. package/dist/plugins/vite/index.js +1 -1
  115. package/dist/plugins/vite/visitors/importMetaGlob.js +1 -8
  116. package/dist/plugins/vite-plugin-pages/index.d.ts +3 -0
  117. package/dist/plugins/vite-plugin-pages/index.js +26 -0
  118. package/dist/plugins/vite-plugin-pwa/index.d.ts +3 -0
  119. package/dist/plugins/vite-plugin-pwa/index.js +17 -0
  120. package/dist/plugins/vite-plugin-pwa/resolveFromAST.d.ts +4 -0
  121. package/dist/plugins/vite-plugin-pwa/resolveFromAST.js +37 -0
  122. package/dist/plugins/vite-plugin-vue-layouts-next/index.d.ts +3 -0
  123. package/dist/plugins/vite-plugin-vue-layouts-next/index.js +23 -0
  124. package/dist/plugins/vite-plus/index.d.ts +3 -0
  125. package/dist/plugins/vite-plus/index.js +14 -0
  126. package/dist/plugins/vite-plus/resolveFromAST.d.ts +2 -0
  127. package/dist/plugins/vite-plus/resolveFromAST.js +37 -0
  128. package/dist/plugins/vite-pwa-assets-generator/index.d.ts +3 -0
  129. package/dist/plugins/vite-pwa-assets-generator/index.js +12 -0
  130. package/dist/plugins/vitepress/index.js +5 -1
  131. package/dist/plugins/vitest/index.js +4 -0
  132. package/dist/plugins/vitest/types.d.ts +3 -0
  133. package/dist/plugins/vue/index.js +5 -3
  134. package/dist/plugins/webpack/visitors/requireContext.js +2 -13
  135. package/dist/plugins/yarn/index.js +14 -4
  136. package/dist/plugins/yarn/types.d.ts +8 -0
  137. package/dist/plugins/yarn/types.js +1 -0
  138. package/dist/plugins/zx/visitors/zx.js +4 -4
  139. package/dist/reporters/cycles.d.ts +3 -0
  140. package/dist/reporters/cycles.js +79 -0
  141. package/dist/reporters/index.d.ts +1 -0
  142. package/dist/reporters/index.js +2 -0
  143. package/dist/reporters/json.d.ts +3 -0
  144. package/dist/reporters/json.js +2 -1
  145. package/dist/reporters/util/util.d.ts +3 -1
  146. package/dist/reporters/util/util.js +5 -1
  147. package/dist/schema/configuration.d.ts +295 -6
  148. package/dist/schema/configuration.js +6 -0
  149. package/dist/schema/plugins.d.ts +95 -0
  150. package/dist/schema/plugins.js +19 -0
  151. package/dist/types/PluginNames.d.ts +2 -2
  152. package/dist/types/PluginNames.js +19 -0
  153. package/dist/types/config.d.ts +9 -0
  154. package/dist/types/issues.d.ts +3 -0
  155. package/dist/types/module-graph.d.ts +7 -0
  156. package/dist/types/package-json.d.ts +8 -1
  157. package/dist/typescript/ast-helpers.d.ts +7 -2
  158. package/dist/typescript/ast-helpers.js +36 -8
  159. package/dist/typescript/ast-nodes.d.ts +4 -1
  160. package/dist/typescript/ast-nodes.js +17 -1
  161. package/dist/typescript/get-imports-and-exports.js +10 -0
  162. package/dist/typescript/glob-imports.d.ts +3 -0
  163. package/dist/typescript/glob-imports.js +49 -0
  164. package/dist/typescript/resolve-module-names.d.ts +2 -0
  165. package/dist/typescript/resolve-module-names.js +35 -1
  166. package/dist/typescript/visitors/calls.js +4 -6
  167. package/dist/typescript/visitors/imports.js +8 -8
  168. package/dist/typescript/visitors/script-visitors.js +4 -4
  169. package/dist/typescript/visitors/walk.js +2 -3
  170. package/dist/util/cli-arguments.d.ts +2 -1
  171. package/dist/util/cli-arguments.js +5 -3
  172. package/dist/util/create-options.d.ts +202 -5
  173. package/dist/util/create-options.js +4 -1
  174. package/dist/util/get-included-issue-types.d.ts +1 -0
  175. package/dist/util/get-included-issue-types.js +4 -2
  176. package/dist/util/issue-initializers.js +1 -1
  177. package/dist/util/load-tsconfig.js +17 -4
  178. package/dist/util/module-graph.js +1 -0
  179. package/dist/util/modules.js +25 -4
  180. package/dist/util/resolve.js +4 -1
  181. package/dist/util/scripts.d.ts +7 -0
  182. package/dist/util/scripts.js +75 -0
  183. package/dist/util/to-source-path.js +1 -1
  184. package/dist/version.d.ts +1 -1
  185. package/dist/version.js +1 -1
  186. package/package.json +1 -1
  187. package/schema.json +108 -1
  188. package/dist/plugins/next/resolveFromAST.d.ts +0 -2
  189. package/dist/plugins/next/resolveFromAST.js +0 -2
  190. package/dist/plugins/nuxt/helpers.d.ts +0 -15
  191. package/dist/plugins/nuxt/helpers.js +0 -133
  192. package/dist/plugins/rolldown/resolveFromAST.d.ts +0 -2
  193. package/dist/plugins/rolldown/resolveFromAST.js +0 -4
  194. package/dist/plugins/rollup/resolveFromAST.d.ts +0 -2
  195. package/dist/plugins/rollup/resolveFromAST.js +0 -4
  196. package/dist/plugins/rslib/resolveFromAST.d.ts +0 -2
  197. package/dist/plugins/rslib/resolveFromAST.js +0 -4
  198. package/dist/plugins/tsdown/resolveFromAST.d.ts +0 -2
  199. package/dist/plugins/tsdown/resolveFromAST.js +0 -4
  200. package/dist/plugins/tsup/resolveFromAST.d.ts +0 -2
  201. package/dist/plugins/tsup/resolveFromAST.js +0 -4
  202. package/dist/plugins/vue/compiler.d.ts +0 -3
  203. package/dist/plugins/vue/compiler.js +0 -10
@@ -0,0 +1,43 @@
1
+ import { getRuntimeSuccessors } from '../utils.js';
2
+ const UNVISITED = undefined;
3
+ const ON_STACK = 1;
4
+ const DONE = 2;
5
+ export const findAllCycles = (graph, ignoredFlags) => {
6
+ const cycles = [];
7
+ const state = new Map();
8
+ for (const root of graph.keys()) {
9
+ if (state.get(root) !== UNVISITED)
10
+ continue;
11
+ const path = [];
12
+ const indexOnPath = new Map();
13
+ const successorsStack = [];
14
+ const push = (filePath) => {
15
+ state.set(filePath, ON_STACK);
16
+ indexOnPath.set(filePath, path.length);
17
+ path.push(filePath);
18
+ const node = graph.get(filePath);
19
+ successorsStack.push((node ? getRuntimeSuccessors(node, ignoredFlags) : new Set()).values());
20
+ };
21
+ push(root);
22
+ while (path.length > 0) {
23
+ const current = path[path.length - 1];
24
+ const next = successorsStack[successorsStack.length - 1].next();
25
+ if (next.done) {
26
+ state.set(current, DONE);
27
+ indexOnPath.delete(current);
28
+ path.pop();
29
+ successorsStack.pop();
30
+ continue;
31
+ }
32
+ const successor = next.value;
33
+ const successorState = state.get(successor);
34
+ if (successorState === ON_STACK) {
35
+ cycles.push([...path.slice(indexOnPath.get(successor)), successor]);
36
+ }
37
+ else if (successorState === UNVISITED) {
38
+ push(successor);
39
+ }
40
+ }
41
+ }
42
+ return cycles;
43
+ };
@@ -1,3 +1,4 @@
1
+ import { getRuntimeSuccessors } from '../utils.js';
1
2
  export const findCycles = (graph, filePath, maxDepth = 16) => {
2
3
  const cycles = [];
3
4
  const visited = new Set();
@@ -7,16 +8,9 @@ export const findCycles = (graph, filePath, maxDepth = 16) => {
7
8
  if (path.length > maxDepth)
8
9
  return;
9
10
  const node = graph.get(currentPath);
10
- if (!node?.imports?.internal)
11
+ if (!node)
11
12
  return;
12
- const nonTypeOnlyImports = new Set();
13
- for (const _import of node.imports.imports) {
14
- if (_import.filePath && !_import.isTypeOnly)
15
- nonTypeOnlyImports.add(_import.filePath);
16
- }
17
- for (const [importedPath] of node.imports.internal) {
18
- if (!nonTypeOnlyImports.has(importedPath))
19
- continue;
13
+ for (const importedPath of getRuntimeSuccessors(node)) {
20
14
  if (importedPath === filePath) {
21
15
  cycles.push([...path, importedPath]);
22
16
  continue;
@@ -1,5 +1,14 @@
1
- import type { Import, ImportMaps, ModuleGraph } from '../types/module-graph.ts';
1
+ import type { FileNode, Import, ImportMaps, ModuleGraph } from '../types/module-graph.ts';
2
+ export declare const getIgnoredCycleImportFlags: (includeDynamicImports: boolean) => number;
2
3
  export declare const getExportedIdentifiers: (graph: ModuleGraph, filePath: string, visited?: Set<string>) => Map<string, boolean>;
4
+ export declare const getRuntimeSuccessors: (node: FileNode, ignoredFlags?: number) => Set<string>;
5
+ export declare const getRuntimeImport: (node: FileNode, filePath: string, ignoredFlags?: number) => {
6
+ kind: string;
7
+ specifier: string;
8
+ pos: number;
9
+ line: number;
10
+ col: number;
11
+ } | undefined;
3
12
  export declare const hasStrictlyEnumReferences: (importsForExport: ImportMaps | undefined, identifier: string) => boolean;
4
13
  export declare const getIssueType: (hasOnlyNsReference: boolean, isType: boolean) => "exports" | "nsExports" | "nsTypes" | "types";
5
14
  export declare const findImportRef: (graph: ModuleGraph, importingFile: string, importedFile: string, identifier: string) => Import | undefined;
@@ -1,5 +1,8 @@
1
+ import { IMPORT_FLAGS, IMPORT_STAR, OPAQUE, SIDE_EFFECTS } from '../constants.js';
1
2
  import { getCachedExportedIdentifiers, setCachedExportedIdentifiers } from './cache.js';
2
3
  import { forEachAliasReExport, forEachNamespaceReExport, forEachPassThroughReExport, getStarReExportSources, } from './visitors.js';
4
+ const IGNORED_CYCLE_IMPORT_FLAGS = IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.DYNAMIC;
5
+ export const getIgnoredCycleImportFlags = (includeDynamicImports) => includeDynamicImports ? IMPORT_FLAGS.ENTRY : IGNORED_CYCLE_IMPORT_FLAGS;
3
6
  export const getExportedIdentifiers = (graph, filePath, visited = new Set()) => {
4
7
  if (visited.has(filePath))
5
8
  return new Map();
@@ -49,6 +52,56 @@ export const getExportedIdentifiers = (graph, filePath, visited = new Set()) =>
49
52
  setCachedExportedIdentifiers(graph, filePath, identifiers);
50
53
  return identifiers;
51
54
  };
55
+ export const getRuntimeSuccessors = (node, ignoredFlags = IGNORED_CYCLE_IMPORT_FLAGS) => {
56
+ const successors = new Set();
57
+ for (const _import of node.imports.imports) {
58
+ if (_import.filePath &&
59
+ !_import.isTypeOnly &&
60
+ !(_import.modifiers & ignoredFlags) &&
61
+ node.imports.internal.has(_import.filePath)) {
62
+ successors.add(_import.filePath);
63
+ }
64
+ }
65
+ return successors;
66
+ };
67
+ const getImportKind = (importMaps, identifier, modifiers) => {
68
+ if (modifiers & IMPORT_FLAGS.DYNAMIC)
69
+ return 'dynamicImport';
70
+ if (identifier === IMPORT_STAR && importMaps.reExport.has(IMPORT_STAR))
71
+ return 'reExportStar';
72
+ if (identifier && importMaps.reExportNs.has(identifier))
73
+ return 'reExportNS';
74
+ if (identifier && importMaps.reExportAs.has(identifier))
75
+ return 'reExportAs';
76
+ if (identifier && importMaps.reExport.has(identifier))
77
+ return 'reExport';
78
+ if (identifier === IMPORT_STAR && importMaps.importNs.size > 0)
79
+ return 'importNS';
80
+ if (identifier && importMaps.importAs.has(identifier))
81
+ return 'importAs';
82
+ if (identifier === OPAQUE)
83
+ return 'dynamicImport';
84
+ if (identifier === SIDE_EFFECTS)
85
+ return 'sideEffectImport';
86
+ return 'import';
87
+ };
88
+ export const getRuntimeImport = (node, filePath, ignoredFlags = IGNORED_CYCLE_IMPORT_FLAGS) => {
89
+ const importMaps = node.imports.internal.get(filePath);
90
+ if (!importMaps)
91
+ return;
92
+ let result;
93
+ for (const _import of node.imports.imports) {
94
+ if (_import.filePath !== filePath || _import.isTypeOnly || _import.modifiers & ignoredFlags)
95
+ continue;
96
+ if (!result || _import.line < result.line || (_import.line === result.line && _import.col < result.col)) {
97
+ result = _import;
98
+ }
99
+ }
100
+ if (!result)
101
+ return;
102
+ const { specifier, pos, line, col, identifier, modifiers } = result;
103
+ return { kind: getImportKind(importMaps, identifier, modifiers), specifier, pos, line, col };
104
+ };
52
105
  export const hasStrictlyEnumReferences = (importsForExport, identifier) => {
53
106
  if (!importsForExport || !importsForExport.refs.has(identifier))
54
107
  return false;
@@ -0,0 +1,12 @@
1
+ import { type ParseResult } from 'oxc-parser';
2
+ import type { AutoImportMaps } from './types.ts';
3
+ export declare const readAndParseFile: (filePath: string) => ParseResult;
4
+ export declare const collectLocalImportPaths: (filePath: string, result: ParseResult) => Set<string>;
5
+ export declare function buildAutoImportMap(filePath: string, result: ParseResult, maps: AutoImportMaps, isComponents: boolean): void;
6
+ export declare const createAutoImportMaps: () => AutoImportMaps;
7
+ export declare const findGeneratedDts: (cwd: string, signature: string) => string[];
8
+ export declare const createVueCompiler: (maps: AutoImportMaps, cwd: string) => (source: string, path: string) => string;
9
+ export declare const createTsCompiler: (maps: AutoImportMaps) => (source: string, path: string) => string;
10
+ export declare const vueAutoImportCompiler: (source: string, path: string) => string;
11
+ export declare const tsAutoImportCompiler: (source: string, path: string) => string;
12
+ export declare const markdownAutoImportCompiler: (source: string, path: string) => string;
@@ -0,0 +1,272 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { Visitor } from 'oxc-parser';
4
+ import { scriptBodies } from '../../compilers/compilers.js';
5
+ import { stylePreprocessorImports } from '../../compilers/style-preprocessors.js';
6
+ import { _parseFile } from '../../typescript/ast-nodes.js';
7
+ import { isFile } from '../../util/fs.js';
8
+ import { _syncGlob } from '../../util/glob.js';
9
+ import { dirname, isInNodeModules, join } from '../../util/path.js';
10
+ const getVueSfc = (cwd) => {
11
+ try {
12
+ return createRequire(join(cwd, 'package.json'))('vue/compiler-sfc');
13
+ }
14
+ catch { }
15
+ return {
16
+ parse: (source, path) => ({
17
+ descriptor: { script: { content: scriptBodies(source, path) }, scriptSetup: null, template: { content: '' } },
18
+ }),
19
+ };
20
+ };
21
+ const readFile = (filePath) => {
22
+ try {
23
+ return readFileSync(filePath, 'utf8');
24
+ }
25
+ catch {
26
+ return '';
27
+ }
28
+ };
29
+ export const readAndParseFile = (filePath) => _parseFile(filePath, readFile(filePath));
30
+ const collectIdentifiers = (source, fileName) => {
31
+ const identifiers = new Set();
32
+ const visitor = new Visitor({
33
+ Identifier(node) {
34
+ identifiers.add(node.name);
35
+ },
36
+ });
37
+ visitor.visit(_parseFile(fileName, source).program);
38
+ return identifiers;
39
+ };
40
+ const collectTemplateInfo = (tree) => {
41
+ const tags = new Set();
42
+ const identifiers = new Set();
43
+ const addExprIdentifiers = (expr) => {
44
+ for (const id of collectIdentifiers(expr, 'expr.ts'))
45
+ identifiers.add(id);
46
+ };
47
+ const visit = (node) => {
48
+ if (node.tag)
49
+ tags.add(node.tag);
50
+ if (node.type === 5 && node.content && !node.content.isStatic)
51
+ addExprIdentifiers(node.content.content);
52
+ if (node.props) {
53
+ for (const prop of node.props) {
54
+ if (prop.type === 7) {
55
+ if (prop.exp && !prop.exp.isStatic)
56
+ addExprIdentifiers(prop.exp.content);
57
+ if (prop.arg && !prop.arg.isStatic)
58
+ addExprIdentifiers(prop.arg.content);
59
+ }
60
+ }
61
+ }
62
+ if (node.children)
63
+ for (const child of node.children)
64
+ visit(child);
65
+ };
66
+ visit(tree);
67
+ return { tags, identifiers };
68
+ };
69
+ const toKebabCase = (s) => s.replace(/[A-Z]/g, (m, i) => (i ? '-' : '') + m.toLowerCase());
70
+ const isLocalSpecifier = (specifier) => specifier.startsWith('.') && !isInNodeModules(specifier);
71
+ export const collectLocalImportPaths = (filePath, result) => {
72
+ const dir = dirname(filePath);
73
+ const paths = new Set();
74
+ const visitor = new Visitor({
75
+ TSImportType(node) {
76
+ const specifier = node.source.value;
77
+ if (isLocalSpecifier(specifier))
78
+ paths.add(join(dir, specifier));
79
+ },
80
+ });
81
+ visitor.visit(result.program);
82
+ return paths;
83
+ };
84
+ export function buildAutoImportMap(filePath, result, maps, isComponents) {
85
+ const dir = dirname(filePath);
86
+ const importTypes = [];
87
+ const collectVisitor = new Visitor({
88
+ TSImportType(node) {
89
+ importTypes.push({ start: node.start, end: node.end, specifier: node.source.value });
90
+ },
91
+ });
92
+ collectVisitor.visit(result.program);
93
+ const addEntry = (name, start, end) => {
94
+ const importType = importTypes.find(it => it.start >= start && it.end <= end);
95
+ if (!importType || !isLocalSpecifier(importType.specifier))
96
+ return;
97
+ const absSpecifier = join(dir, importType.specifier);
98
+ if (isComponents) {
99
+ const components = maps.componentMap.get(name);
100
+ if (components) {
101
+ if (!components.includes(absSpecifier))
102
+ components.push(absSpecifier);
103
+ }
104
+ else
105
+ maps.componentMap.set(name, [absSpecifier]);
106
+ }
107
+ else {
108
+ maps.importMap.set(name, absSpecifier);
109
+ }
110
+ };
111
+ const matchVisitor = new Visitor({
112
+ VariableDeclarator(node) {
113
+ if (node.id?.type !== 'Identifier' || node.id.name.startsWith('Lazy'))
114
+ return;
115
+ addEntry(node.id.name, node.start, node.end);
116
+ },
117
+ TSPropertySignature(node) {
118
+ if (!isComponents)
119
+ return;
120
+ const key = node.key;
121
+ const name = key?.type === 'Identifier' ? key.name : key?.type === 'Literal' ? String(key.value) : undefined;
122
+ if (name)
123
+ addEntry(name, node.start, node.end);
124
+ },
125
+ ExportNamedDeclaration(node) {
126
+ if (!node.source)
127
+ return;
128
+ const specifier = node.source.value;
129
+ if (!isLocalSpecifier(specifier))
130
+ return;
131
+ const absSpecifier = join(dir, specifier);
132
+ for (const s of node.specifiers) {
133
+ const name = s.exported.type === 'Identifier' ? s.exported.name : s.exported.value;
134
+ if (name)
135
+ maps.importMap.set(name, absSpecifier);
136
+ }
137
+ },
138
+ });
139
+ matchVisitor.visit(result.program);
140
+ }
141
+ export const createAutoImportMaps = () => ({ importMap: new Map(), componentMap: new Map() });
142
+ export const findGeneratedDts = (cwd, signature) => _syncGlob({ cwd, patterns: ['*.d.ts', 'src/**/*.d.ts'] }).filter(filePath => readFile(filePath).slice(0, 300).includes(signature));
143
+ const generators = [
144
+ { signature: 'Generated by unplugin-vue-components', isComponents: true },
145
+ { signature: 'Generated by unplugin-auto-import', isComponents: false },
146
+ ];
147
+ const getVueAutoImportMaps = (cwd) => {
148
+ const maps = createAutoImportMaps();
149
+ for (const filePath of _syncGlob({ cwd, patterns: ['*.d.ts', 'src/**/*.d.ts'] })) {
150
+ const source = readFile(filePath);
151
+ const generator = generators.find(({ signature }) => source.slice(0, 300).includes(signature));
152
+ if (generator)
153
+ buildAutoImportMap(filePath, _parseFile(filePath, source), maps, generator.isComponents);
154
+ }
155
+ return maps;
156
+ };
157
+ const getSyntheticImports = (maps, identifiers, templateTags) => {
158
+ const { importMap, componentMap } = maps;
159
+ if (importMap.size === 0 && (!templateTags || componentMap.size === 0))
160
+ return [];
161
+ const syntheticImports = [];
162
+ for (const [name, specifier] of importMap) {
163
+ if (identifiers.has(name))
164
+ syntheticImports.push(`import { ${name} } from '${specifier}';`);
165
+ }
166
+ if (templateTags) {
167
+ for (const [name, specifiers] of componentMap) {
168
+ const kebab = toKebabCase(name);
169
+ if (templateTags.has(name) ||
170
+ templateTags.has(kebab) ||
171
+ templateTags.has(`Lazy${name}`) ||
172
+ templateTags.has(`lazy-${kebab}`)) {
173
+ syntheticImports.push(`import { default as ${name} } from '${specifiers[0]}';`);
174
+ for (let i = 1; i < specifiers.length; i++)
175
+ syntheticImports.push(`import '${specifiers[i]}';`);
176
+ }
177
+ }
178
+ }
179
+ return syntheticImports;
180
+ };
181
+ const compileVueSfc = (source, path, maps, root) => {
182
+ if (maps.importMap.size === 0 && maps.componentMap.size === 0) {
183
+ return [scriptBodies(source, path), stylePreprocessorImports(source, path)].filter(Boolean).join(';\n');
184
+ }
185
+ const { descriptor } = sfcForRoot(root).parse(source, path);
186
+ const scripts = [];
187
+ if (descriptor.script?.content)
188
+ scripts.push(descriptor.script.content);
189
+ if (descriptor.scriptSetup?.content)
190
+ scripts.push(descriptor.scriptSetup.content);
191
+ const identifiers = scripts.length === 0 ? new Set() : collectIdentifiers(scripts.join('\n'), path);
192
+ let templateTags;
193
+ if (descriptor.template?.ast) {
194
+ const info = collectTemplateInfo(descriptor.template.ast);
195
+ templateTags = info.tags;
196
+ for (const id of info.identifiers)
197
+ identifiers.add(id);
198
+ }
199
+ scripts.push(...getSyntheticImports(maps, identifiers, templateTags));
200
+ const styles = stylePreprocessorImports(source, path);
201
+ if (styles)
202
+ scripts.push(styles);
203
+ return scripts.join(';\n');
204
+ };
205
+ const compileTs = (source, path, maps) => {
206
+ if (maps.importMap.size === 0 || path.endsWith('.d.ts') || path.endsWith('.config.ts'))
207
+ return source;
208
+ const syntheticImports = getSyntheticImports(maps, collectIdentifiers(source, path));
209
+ return syntheticImports.length === 0 ? source : `${source}\n${syntheticImports.join('\n')}`;
210
+ };
211
+ const tagMatcher = /<([a-zA-Z][\w.-]*)/g;
212
+ const fencedCodeMatcher = /(`{3,}|~{3,})[\s\S]*?^[ \t]*\1/gm;
213
+ const inlineCodeMatcher = /`[^`\n]*`/g;
214
+ const stripCode = (md) => md.replace(fencedCodeMatcher, '').replace(inlineCodeMatcher, '');
215
+ const compileMarkdown = (source, path, maps) => {
216
+ const code = stripCode(source);
217
+ const scripts = scriptBodies(code, path);
218
+ if (maps.importMap.size === 0 && maps.componentMap.size === 0)
219
+ return scripts;
220
+ const tags = new Set();
221
+ for (const [, tag] of code.matchAll(tagMatcher))
222
+ tags.add(tag);
223
+ const identifiers = scripts ? collectIdentifiers(scripts, path) : new Set();
224
+ return [scripts, ...getSyntheticImports(maps, identifiers, tags)].filter(Boolean).join(';\n');
225
+ };
226
+ export const createVueCompiler = (maps, cwd) => (source, path) => compileVueSfc(source, path, maps, cwd);
227
+ export const createTsCompiler = (maps) => (source, path) => compileTs(source, path, maps);
228
+ const EMPTY_MAPS = createAutoImportMaps();
229
+ const rootByDir = new Map();
230
+ const mapsByRoot = new Map();
231
+ const sfcByRoot = new Map();
232
+ const findRoot = (fromDir) => {
233
+ const cached = rootByDir.get(fromDir);
234
+ if (cached !== undefined)
235
+ return cached;
236
+ let dir = fromDir;
237
+ let root = '';
238
+ for (;;) {
239
+ if (isFile(join(dir, 'package.json'))) {
240
+ root = dir;
241
+ break;
242
+ }
243
+ const parent = dirname(dir);
244
+ if (parent === dir)
245
+ break;
246
+ dir = parent;
247
+ }
248
+ rootByDir.set(fromDir, root);
249
+ return root;
250
+ };
251
+ const mapsForFile = (path) => {
252
+ const root = findRoot(dirname(path));
253
+ if (!root)
254
+ return EMPTY_MAPS;
255
+ let maps = mapsByRoot.get(root);
256
+ if (!maps) {
257
+ maps = getVueAutoImportMaps(root);
258
+ mapsByRoot.set(root, maps);
259
+ }
260
+ return maps;
261
+ };
262
+ function sfcForRoot(root) {
263
+ let sfc = sfcByRoot.get(root);
264
+ if (!sfc) {
265
+ sfc = getVueSfc(root);
266
+ sfcByRoot.set(root, sfc);
267
+ }
268
+ return sfc;
269
+ }
270
+ export const vueAutoImportCompiler = (source, path) => compileVueSfc(source, path, mapsForFile(path), findRoot(dirname(path)));
271
+ export const tsAutoImportCompiler = (source, path) => compileTs(source, path, mapsForFile(path));
272
+ export const markdownAutoImportCompiler = (source, path) => compileMarkdown(source, path, mapsForFile(path));
@@ -0,0 +1,38 @@
1
+ interface TemplateExpressionNode {
2
+ content: string;
3
+ isStatic: boolean;
4
+ }
5
+ interface TemplateAstProp {
6
+ type: number;
7
+ exp?: TemplateExpressionNode;
8
+ arg?: TemplateExpressionNode;
9
+ }
10
+ export interface TemplateAstNode {
11
+ type?: number;
12
+ tag?: string;
13
+ props?: TemplateAstProp[];
14
+ content?: TemplateExpressionNode;
15
+ children?: TemplateAstNode[];
16
+ }
17
+ interface Descriptor {
18
+ script: {
19
+ content: string;
20
+ } | null;
21
+ scriptSetup: {
22
+ content: string;
23
+ } | null;
24
+ template: {
25
+ content: string;
26
+ ast?: TemplateAstNode;
27
+ } | null;
28
+ }
29
+ export type VueSfc = {
30
+ parse: (source: string, path: string) => {
31
+ descriptor: Descriptor;
32
+ };
33
+ };
34
+ export interface AutoImportMaps {
35
+ importMap: Map<string, string>;
36
+ componentMap: Map<string, string[]>;
37
+ }
38
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,47 +1,12 @@
1
- import { findCallArg, getDefaultImportName, getImportMap, getPropertyValues } from '../../typescript/ast-helpers.js';
2
- import { toConfig, toDependency, toEntry, toProductionEntry } from '../../util/input.js';
1
+ import { toDependency } from '../../util/input.js';
3
2
  import { hasDependency } from '../../util/plugin.js';
4
- import { getAliasInputs } from '../vitest/helpers.js';
5
3
  import compiler from './compiler.js';
6
4
  import mdxCompiler from './compiler-mdx.js';
7
- import { getSrcDir, getViteAliases, usesPassthroughImageService } from './resolveFromAST.js';
5
+ import { entry, production, resolveFromAST } from './resolveFromAST.js';
8
6
  const title = 'Astro';
9
7
  const enablers = ['astro'];
10
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
11
9
  export const config = ['astro.config.{js,cjs,mjs,ts,mts}'];
12
- const entry = ['src/content/config.ts', 'src/content.config.ts'];
13
- const production = [
14
- 'src/pages/**/*.{astro,mdx,js,ts}',
15
- '!src/pages/**/_*',
16
- '!src/pages/**/_*/**',
17
- 'src/content/**/*.mdx',
18
- 'src/middleware.{js,ts}',
19
- 'src/middleware/index.{js,ts}',
20
- 'src/actions/index.{js,ts}',
21
- ];
22
- const resolveFromAST = (program, options) => {
23
- const srcDir = getSrcDir(program);
24
- const setSrcDir = (entry) => entry.replace(/^src\//, `${srcDir}/`);
25
- const inputs = [
26
- ...entry.map(setSrcDir).map(path => toEntry(path)),
27
- ...production.map(setSrcDir).map(path => toProductionEntry(path)),
28
- ...getAliasInputs(getViteAliases(program), options.cwd),
29
- ];
30
- if (!usesPassthroughImageService(program))
31
- inputs.push(toDependency('sharp', { optional: true }));
32
- const importMap = getImportMap(program);
33
- const lunariaImportName = getDefaultImportName(importMap, '@lunariajs/starlight');
34
- if (lunariaImportName) {
35
- const lunariaConfig = findCallArg(program, lunariaImportName);
36
- if (lunariaConfig) {
37
- const configPaths = getPropertyValues(lunariaConfig, 'configPath');
38
- for (const id of configPaths) {
39
- inputs.push(toConfig('lunaria', id));
40
- }
41
- }
42
- }
43
- return inputs;
44
- };
45
10
  const registerCompilers = ({ registerCompiler, hasDependency }) => {
46
11
  if (hasDependency('astro'))
47
12
  registerCompiler({ extension: '.astro', compiler });
@@ -1,4 +1,4 @@
1
- import type { Program } from 'oxc-parser';
2
- export declare const getSrcDir: (program: Program) => string;
3
- export declare const usesPassthroughImageService: (program: Program) => boolean;
4
- export declare const getViteAliases: (program: Program) => Record<string, string>;
1
+ import type { ResolveFromAST } from '../../types/config.ts';
2
+ export declare const entry: string[];
3
+ export declare const production: string[];
4
+ export declare const resolveFromAST: ResolveFromAST;
@@ -1,10 +1,19 @@
1
+ import { collectFirstPropertyValue, findImportedCallArg, findProperty, getPropertyKey, getPropertyValues, hasImportSpecifier, resolveObjectArg, } from '../../typescript/ast-helpers.js';
1
2
  import { getStringValue } from '../../typescript/ast-nodes.js';
2
- import { collectPropertyValues, findProperty, getPropertyKey, hasImportSpecifier, resolveObjectArg, } from '../../typescript/ast-helpers.js';
3
- export const getSrcDir = (program) => {
4
- const values = collectPropertyValues(program, 'srcDir');
5
- return values.size > 0 ? Array.from(values)[0] : 'src';
6
- };
7
- export const usesPassthroughImageService = (program) => hasImportSpecifier(program, 'astro/config', 'passthroughImageService');
3
+ import { toConfig, toDependency, toEntry, toProductionEntry } from '../../util/input.js';
4
+ import { getAliasInputs } from '../vitest/helpers.js';
5
+ export const entry = ['src/content/config.ts', 'src/content.config.ts'];
6
+ export const production = [
7
+ 'src/pages/**/*.{astro,mdx,js,ts}',
8
+ '!src/pages/**/_*',
9
+ '!src/pages/**/_*/**',
10
+ 'src/content/**/*.mdx',
11
+ 'src/middleware.{js,ts}',
12
+ 'src/middleware/index.{js,ts}',
13
+ 'src/actions/index.{js,ts}',
14
+ ];
15
+ const getSrcDir = (program) => collectFirstPropertyValue(program, 'srcDir') ?? 'src';
16
+ const usesPassthroughImageService = (program) => hasImportSpecifier(program, 'astro/config', 'passthroughImageService');
8
17
  const findFirstStringArg = (node) => {
9
18
  const literal = getStringValue(node);
10
19
  if (literal)
@@ -17,7 +26,7 @@ const findFirstStringArg = (node) => {
17
26
  }
18
27
  }
19
28
  };
20
- export const getViteAliases = (program) => {
29
+ const getViteAliases = (program) => {
21
30
  const aliases = {};
22
31
  for (const node of program.body ?? []) {
23
32
  if (node.type !== 'ExportDefaultDeclaration')
@@ -40,3 +49,21 @@ export const getViteAliases = (program) => {
40
49
  }
41
50
  return aliases;
42
51
  };
52
+ export const resolveFromAST = (program, options) => {
53
+ const srcDir = getSrcDir(program);
54
+ const setSrcDir = (entry) => entry.replace(/^src\//, `${srcDir}/`);
55
+ const inputs = [
56
+ ...entry.map(setSrcDir).map(path => toEntry(path)),
57
+ ...production.map(setSrcDir).map(path => toProductionEntry(path)),
58
+ ...getAliasInputs(getViteAliases(program), options.cwd),
59
+ ];
60
+ if (!usesPassthroughImageService(program))
61
+ inputs.push(toDependency('sharp', { optional: true }));
62
+ const lunariaConfig = findImportedCallArg(program, '@lunariajs/starlight');
63
+ if (lunariaConfig) {
64
+ for (const id of getPropertyValues(lunariaConfig, 'configPath')) {
65
+ inputs.push(toConfig('lunaria', id));
66
+ }
67
+ }
68
+ return inputs;
69
+ };
@@ -1,11 +1,22 @@
1
+ import { isFile } from '../../util/fs.js';
2
+ import { toDeferResolve, toEntry, toIgnore } from '../../util/input.js';
1
3
  import parseArgs from '../../util/parse-args.js';
2
- import { toDeferResolve, toEntry } from '../../util/input.js';
4
+ import { getScriptCommands } from '../../util/scripts.js';
3
5
  const title = 'Bun';
4
- const enablers = ['bun'];
5
- const hasBunTest = (scripts) => scripts && Object.values(scripts).some(script => /(?<=^|\s)bun test/.test(script));
6
- const isEnabled = ({ manifest }) => !!hasBunTest(manifest.scripts);
7
- const config = ['bunfig.toml'];
6
+ const enablers = 'This plugin is enabled when a `bun.lock` or `bun.lockb` file is found or a `bun test` script is configured.';
8
7
  const patterns = ['**/*.{test,spec}.{js,jsx,ts,tsx}', '**/*_{test,spec}.{js,jsx,ts,tsx}'];
8
+ const getBunTest = (script) => {
9
+ for (const { binary, args } of getScriptCommands(script)) {
10
+ if (binary !== 'bun')
11
+ continue;
12
+ const parsed = parseArgs(args, { string: ['timeout', 'rerun-each', 'preload'] });
13
+ if (parsed._[0] === 'test')
14
+ return parsed;
15
+ }
16
+ };
17
+ const hasBunTest = (scripts) => scripts && Object.values(scripts).some(script => typeof script === 'string' && getBunTest(script));
18
+ const isEnabled = ({ cwd, manifest }) => isFile(cwd, 'bun.lock') || isFile(cwd, 'bun.lockb') || !!hasBunTest(manifest.scripts);
19
+ const config = ['bunfig.toml'];
9
20
  const resolveConfig = localConfig => {
10
21
  const preload = localConfig.test?.preload ?? [];
11
22
  return preload.map(specifier => toDeferResolve(specifier));
@@ -20,17 +31,20 @@ const toPatterns = (arg) => {
20
31
  };
21
32
  const resolve = options => {
22
33
  const scripts = { ...options.rootManifest?.scripts, ...options.manifest.scripts };
34
+ const inputs = [toIgnore('bun', 'dependencies')];
23
35
  for (const script of Object.values(scripts)) {
24
- if (/(?<=^|\s)bun test/.test(script)) {
25
- const parsed = parseArgs(script.split(' '), { string: ['timeout', 'rerun-each', 'preload'] });
26
- const args = parsed._.filter(id => id !== 'bun' && id !== 'test');
27
- const inputs = (args.length === 0 ? patterns : args.flatMap(toPatterns)).map(toEntry);
28
- for (const specifier of [parsed.preload ?? []].flat())
29
- inputs.push(toDeferResolve(specifier));
30
- return inputs;
31
- }
36
+ if (typeof script !== 'string')
37
+ continue;
38
+ const parsed = getBunTest(script);
39
+ if (!parsed)
40
+ continue;
41
+ const targets = parsed._.slice(1);
42
+ for (const pattern of targets.length === 0 ? patterns : targets.flatMap(toPatterns))
43
+ inputs.push(toEntry(pattern));
44
+ for (const specifier of [parsed.preload ?? []].flat())
45
+ inputs.push(toDeferResolve(specifier));
32
46
  }
33
- return [];
47
+ return inputs;
34
48
  };
35
49
  const plugin = {
36
50
  title,
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;