knip 6.23.0 → 6.25.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 (128) hide show
  1. package/LICENSE +1 -1
  2. package/dist/ConfigurationChief.d.ts +13 -1
  3. package/dist/ConfigurationChief.js +3 -0
  4. package/dist/ProjectPrincipal.d.ts +2 -0
  5. package/dist/ProjectPrincipal.js +7 -6
  6. package/dist/WorkspaceWorker.d.ts +3 -1
  7. package/dist/WorkspaceWorker.js +5 -2
  8. package/dist/binaries/bash-parser.js +55 -83
  9. package/dist/binaries/index.js +3 -0
  10. package/dist/binaries/resolvers/yarn.js +4 -3
  11. package/dist/compilers/compilers.d.ts +2 -0
  12. package/dist/compilers/compilers.js +15 -4
  13. package/dist/compilers/index.d.ts +30 -6
  14. package/dist/compilers/index.js +25 -10
  15. package/dist/compilers/less.d.ts +7 -0
  16. package/dist/compilers/less.js +37 -0
  17. package/dist/compilers/mdx.d.ts +1 -2
  18. package/dist/compilers/mdx.js +14 -8
  19. package/dist/compilers/scss.d.ts +3 -2
  20. package/dist/compilers/scss.js +17 -14
  21. package/dist/compilers/shared.d.ts +6 -0
  22. package/dist/compilers/shared.js +9 -0
  23. package/dist/compilers/style-preprocessors.d.ts +2 -0
  24. package/dist/compilers/style-preprocessors.js +41 -0
  25. package/dist/compilers/stylus.d.ts +7 -0
  26. package/dist/compilers/stylus.js +36 -0
  27. package/dist/constants.d.ts +5 -1
  28. package/dist/constants.js +7 -0
  29. package/dist/graph/analyze.js +37 -2
  30. package/dist/graph/build.js +23 -1
  31. package/dist/graph-explorer/explorer.d.ts +1 -0
  32. package/dist/graph-explorer/explorer.js +2 -0
  33. package/dist/graph-explorer/operations/find-all-cycles.d.ts +3 -0
  34. package/dist/graph-explorer/operations/find-all-cycles.js +43 -0
  35. package/dist/graph-explorer/operations/find-cycles.js +3 -9
  36. package/dist/graph-explorer/utils.d.ts +10 -1
  37. package/dist/graph-explorer/utils.js +53 -0
  38. package/dist/plugins/astro/compiler-mdx.js +11 -2
  39. package/dist/plugins/astro/compiler.js +8 -4
  40. package/dist/plugins/bun/index.js +28 -14
  41. package/dist/plugins/eve/index.d.ts +3 -0
  42. package/dist/plugins/eve/index.js +22 -0
  43. package/dist/plugins/execa/visitors/execa.js +10 -18
  44. package/dist/plugins/fumadocs/index.d.ts +3 -0
  45. package/dist/plugins/fumadocs/index.js +18 -0
  46. package/dist/plugins/github-actions/index.js +3 -2
  47. package/dist/plugins/graphql-codegen/index.js +9 -7
  48. package/dist/plugins/index.d.ts +2 -0
  49. package/dist/plugins/index.js +4 -0
  50. package/dist/plugins/jest/index.js +13 -3
  51. package/dist/plugins/next/index.js +23 -10
  52. package/dist/plugins/node/index.js +4 -1
  53. package/dist/plugins/nuxt/index.js +4 -2
  54. package/dist/plugins/pnpm/index.js +21 -1
  55. package/dist/plugins/pnpm/types.d.ts +6 -0
  56. package/dist/plugins/pnpm/types.js +1 -0
  57. package/dist/plugins/prettier/index.js +19 -3
  58. package/dist/plugins/prettier/types.d.ts +6 -1
  59. package/dist/plugins/prisma/compiler.js +3 -0
  60. package/dist/plugins/rspack/index.js +5 -0
  61. package/dist/plugins/serverless-framework/index.js +12 -1
  62. package/dist/plugins/serverless-framework/types.d.ts +5 -2
  63. package/dist/plugins/stencil/index.js +59 -1
  64. package/dist/plugins/storybook/index.js +7 -0
  65. package/dist/plugins/svelte/compiler.d.ts +2 -1
  66. package/dist/plugins/svelte/compiler.js +8 -1
  67. package/dist/plugins/tailwind/compiler.js +3 -0
  68. package/dist/plugins/tailwind/index.js +5 -1
  69. package/dist/plugins/typedoc/index.js +9 -3
  70. package/dist/plugins/typedoc/types.d.ts +2 -0
  71. package/dist/plugins/vite/visitors/importMetaGlob.js +1 -8
  72. package/dist/plugins/vue/compiler.d.ts +2 -1
  73. package/dist/plugins/vue/compiler.js +8 -1
  74. package/dist/plugins/webpack/visitors/requireContext.js +2 -13
  75. package/dist/plugins/yarn/index.js +13 -4
  76. package/dist/plugins/yarn/types.d.ts +10 -0
  77. package/dist/plugins/yarn/types.js +1 -0
  78. package/dist/plugins/zx/visitors/zx.js +4 -4
  79. package/dist/reporters/compact.js +1 -2
  80. package/dist/reporters/cycles.d.ts +3 -0
  81. package/dist/reporters/cycles.js +79 -0
  82. package/dist/reporters/index.d.ts +1 -0
  83. package/dist/reporters/index.js +2 -0
  84. package/dist/reporters/json.d.ts +3 -0
  85. package/dist/reporters/json.js +2 -1
  86. package/dist/reporters/symbols.js +1 -2
  87. package/dist/reporters/util/util.d.ts +3 -1
  88. package/dist/reporters/util/util.js +5 -1
  89. package/dist/schema/configuration.d.ts +40 -6
  90. package/dist/schema/configuration.js +6 -0
  91. package/dist/schema/plugins.d.ts +10 -0
  92. package/dist/schema/plugins.js +2 -0
  93. package/dist/types/PluginNames.d.ts +2 -2
  94. package/dist/types/PluginNames.js +2 -0
  95. package/dist/types/config.d.ts +10 -0
  96. package/dist/types/issues.d.ts +3 -0
  97. package/dist/types/module-graph.d.ts +7 -0
  98. package/dist/types/package-json.d.ts +4 -1
  99. package/dist/types.d.ts +1 -1
  100. package/dist/typescript/SourceFileManager.js +3 -2
  101. package/dist/typescript/ast-nodes.d.ts +4 -1
  102. package/dist/typescript/ast-nodes.js +60 -2
  103. package/dist/typescript/comments.js +22 -3
  104. package/dist/typescript/get-imports-and-exports.js +10 -0
  105. package/dist/typescript/glob-imports.d.ts +3 -0
  106. package/dist/typescript/glob-imports.js +49 -0
  107. package/dist/typescript/resolve-module-names.d.ts +2 -0
  108. package/dist/typescript/resolve-module-names.js +35 -1
  109. package/dist/typescript/visitors/calls.js +4 -6
  110. package/dist/typescript/visitors/imports.js +8 -8
  111. package/dist/typescript/visitors/script-visitors.js +4 -4
  112. package/dist/typescript/visitors/walk.js +6 -1
  113. package/dist/util/cli-arguments.d.ts +2 -1
  114. package/dist/util/cli-arguments.js +4 -2
  115. package/dist/util/create-options.d.ts +32 -5
  116. package/dist/util/create-options.js +4 -1
  117. package/dist/util/get-included-issue-types.d.ts +1 -0
  118. package/dist/util/get-included-issue-types.js +4 -2
  119. package/dist/util/issue-initializers.js +1 -1
  120. package/dist/util/load-tsconfig.js +17 -4
  121. package/dist/util/module-graph.js +1 -0
  122. package/dist/util/modules.js +25 -4
  123. package/dist/util/scripts.d.ts +7 -0
  124. package/dist/util/scripts.js +75 -0
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.js +1 -1
  127. package/package.json +1 -1
  128. package/schema.json +40 -1
@@ -1,8 +1,17 @@
1
1
  import { fencedCodeBlockMatcher, importMatcher, importsWithinFrontmatter, inlineCodeMatcher, } from '../../compilers/compilers.js';
2
2
  const frontmatterImportFields = ['layout'];
3
3
  const compiler = (text) => {
4
- const imports = text.replace(fencedCodeBlockMatcher, '').replace(inlineCodeMatcher, '').matchAll(importMatcher);
5
4
  const frontmatterImports = importsWithinFrontmatter(text, frontmatterImportFields);
6
- return [...imports, frontmatterImports].join('\n');
5
+ if (!text.includes('import'))
6
+ return frontmatterImports;
7
+ const imports = [];
8
+ const source = text.replace(fencedCodeBlockMatcher, '').replace(inlineCodeMatcher, '');
9
+ let match;
10
+ importMatcher.lastIndex = 0;
11
+ while ((match = importMatcher.exec(source)))
12
+ imports.push(match[0]);
13
+ if (frontmatterImports)
14
+ imports.push(frontmatterImports);
15
+ return imports.join('\n');
7
16
  };
8
17
  export default compiler;
@@ -1,17 +1,21 @@
1
1
  import { frontmatterMatcher, scriptBodies } from '../../compilers/compilers.js';
2
+ import { stylePreprocessorImports } from '../../compilers/style-preprocessors.js';
2
3
  const propsDeclMatcher = /(?:^|[\s;])(?:interface|type)\s+Props\b/;
3
4
  const compiler = (text, path) => {
4
- const scripts = [];
5
+ let out = '';
5
6
  const frontmatter = text.match(frontmatterMatcher);
6
7
  if (frontmatter?.[1]) {
7
8
  let fm = frontmatter[1];
8
9
  if (propsDeclMatcher.test(fm) && text.includes('Astro.props'))
9
10
  fm += '\ntype __knip_astro_props = Props;';
10
- scripts.push(fm);
11
+ out = fm;
11
12
  }
12
13
  const scriptContent = scriptBodies(text, path);
13
14
  if (scriptContent)
14
- scripts.push(scriptContent);
15
- return scripts.join('\n');
15
+ out = out ? `${out}\n${scriptContent}` : scriptContent;
16
+ const styleImports = stylePreprocessorImports(text, path);
17
+ if (styleImports)
18
+ out = out ? `${out}\n${styleImports}` : styleImports;
19
+ return out;
16
20
  };
17
21
  export default compiler;
@@ -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;
@@ -0,0 +1,22 @@
1
+ import { hasDependency } from '../../util/plugin.js';
2
+ const title = 'eve';
3
+ const enablers = ['eve'];
4
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
5
+ const extensions = '{js,jsx,ts,tsx,mjs,cjs,mts,cts}';
6
+ const rootAgentFileNames = '{agent,instructions,instrumentation,sandbox}';
7
+ const subagentFileNames = '{agent,instructions,sandbox}';
8
+ const production = [
9
+ `{,agent/}${rootAgentFileNames}.${extensions}`,
10
+ `{,agent/}sandbox/sandbox.${extensions}`,
11
+ `{,agent/}{channels,connections,hooks,skills,tools,schedules}/**/*.${extensions}`,
12
+ `{,agent/}subagents/**/${subagentFileNames}.${extensions}`,
13
+ `{,agent/}subagents/**/sandbox/sandbox.${extensions}`,
14
+ `{,agent/}subagents/**/{connections,hooks,skills,tools}/**/*.${extensions}`,
15
+ ];
16
+ const plugin = {
17
+ title,
18
+ enablers,
19
+ isEnabled,
20
+ production,
21
+ };
22
+ export default plugin;
@@ -1,4 +1,4 @@
1
- import { getSafeScriptFromArgs, getStringValue, isStringLiteral } from '../../../typescript/ast-nodes.js';
1
+ import { getSafeScriptFromArgs, getScriptFromArg, getScriptFromTemplate } from '../../../typescript/ast-nodes.js';
2
2
  const tags = new Set(['$', '$sync']);
3
3
  const methods = new Set(['execa', 'execaSync', 'execaCommand', 'execaCommandSync', 'execaNode', '$sync']);
4
4
  export function createExecaVisitor(ctx) {
@@ -10,18 +10,12 @@ export function createExecaVisitor(ctx) {
10
10
  : tag.type === 'CallExpression' && tag.callee.type === 'Identifier'
11
11
  ? tag.callee.name
12
12
  : undefined;
13
- if (tagName === 'execaNode') {
14
- for (const q of node.quasi.quasis) {
15
- if (q.value.raw)
16
- ctx.addScript(`node ${q.value.raw}`);
17
- }
18
- }
19
- else if (tagName && tags.has(tagName)) {
20
- for (const q of node.quasi.quasis) {
21
- if (q.value.raw)
22
- ctx.addScript(q.value.raw);
23
- }
24
- }
13
+ const isNode = tagName === 'execaNode';
14
+ if (!isNode && !(tagName && tags.has(tagName)))
15
+ return;
16
+ const script = getScriptFromTemplate(node.quasi);
17
+ if (script)
18
+ ctx.addScript(isNode ? `node ${script}` : script);
25
19
  },
26
20
  CallExpression(node) {
27
21
  if (node.callee.type !== 'Identifier' || !methods.has(node.callee.name))
@@ -33,11 +27,9 @@ export function createExecaVisitor(ctx) {
33
27
  ctx.addScript(`node ${script}`);
34
28
  }
35
29
  else if (fnName.startsWith('execaCommand')) {
36
- if (node.arguments[0] && isStringLiteral(node.arguments[0])) {
37
- const val = getStringValue(node.arguments[0]);
38
- if (val)
39
- ctx.addScript(val);
40
- }
30
+ const script = getScriptFromArg(node.arguments[0]);
31
+ if (script)
32
+ ctx.addScript(script);
41
33
  }
42
34
  else {
43
35
  const script = getSafeScriptFromArgs(node.arguments[0], node.arguments[1]);
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,18 @@
1
+ import MDX from '../../compilers/mdx.js';
2
+ import { hasDependency } from '../../util/plugin.js';
3
+ const title = 'Fumadocs';
4
+ const enablers = ['fumadocs-core', 'fumadocs-mdx', 'fumadocs-ui'];
5
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
+ const entry = ['source.config.{js,ts,mjs}', 'content/**/*.mdx'];
7
+ const registerCompilers = ({ registerCompiler, hasDependency }) => {
8
+ if (hasDependency('fumadocs-mdx'))
9
+ registerCompiler({ extension: '.mdx', compiler: MDX.compiler });
10
+ };
11
+ const plugin = {
12
+ title,
13
+ enablers,
14
+ isEnabled,
15
+ entry,
16
+ registerCompilers,
17
+ };
18
+ export default plugin;
@@ -18,7 +18,7 @@ export const getActionDependencies = (config, options) => {
18
18
  return scripts.map(script => join(configFileDir, script));
19
19
  };
20
20
  const resolveConfig = async (config, options) => {
21
- const { rootCwd, getInputsFromScripts, isProduction } = options;
21
+ const { rootCwd, getInputsFromScripts, isProduction, getManifest } = options;
22
22
  const inputs = new Set();
23
23
  const jobs = findByKeyDeep(config, 'steps');
24
24
  for (const steps of jobs) {
@@ -30,7 +30,8 @@ const resolveConfig = async (config, options) => {
30
30
  const workingDir = step['working-directory'];
31
31
  const dir = join(rootCwd, path && workingDir ? relative(workingDir, path) : workingDir ? workingDir : '.');
32
32
  if (step.run) {
33
- for (const input of getInputsFromScripts([step.run], { knownBinsOnly: true })) {
33
+ const manifest = getManifest(dir) ?? options.manifest;
34
+ for (const input of getInputsFromScripts([step.run], { knownBinsOnly: true, manifest })) {
34
35
  if (isDeferResolveEntry(input) && path && !workingDir) {
35
36
  input.specifier = relative(join(dir, path), join(rootCwd, input.specifier));
36
37
  }
@@ -1,6 +1,6 @@
1
- import { toDependency, toEntry } from '../../util/input.js';
1
+ import { toDependency, toEntry, toProductionEntry } from '../../util/input.js';
2
2
  import { get } from '../../util/object.js';
3
- import { isInternal } from '../../util/path.js';
3
+ import { isInternal, join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
5
  import { isConfigurationOutput, isGraphqlConfigTypes, isGraphqlProjectsConfigTypes } from './types.js';
6
6
  const title = 'GraphQL Codegen';
@@ -24,15 +24,17 @@ const getPluginPackageName = (name) => {
24
24
  return name;
25
25
  return `@graphql-codegen/${name}`;
26
26
  };
27
- const resolveConfig = config => {
27
+ const resolveConfig = (config, options) => {
28
28
  const codegenConfigs = isGraphqlProjectsConfigTypes(config)
29
29
  ? Object.values(config.projects).flatMap(project => project.extensions?.codegen ?? [])
30
30
  : isGraphqlConfigTypes(config)
31
31
  ? [config.extensions?.codegen]
32
32
  : [config];
33
- const generateSet = codegenConfigs
34
- .filter((config) => Boolean(config?.generates))
35
- .flatMap(config => Object.values(config.generates));
33
+ const generateConfigs = codegenConfigs.filter((config) => Boolean(config?.generates));
34
+ const generateSet = generateConfigs.flatMap(config => Object.values(config.generates));
35
+ const outputs = generateConfigs
36
+ .flatMap(config => Object.keys(config.generates))
37
+ .map(output => toProductionEntry(join(options.configFileDir, output.endsWith('/') ? `${output}**` : output)));
36
38
  const configurationOutput = generateSet.filter(isConfigurationOutput);
37
39
  const presets = configurationOutput
38
40
  .map(configOutput => (configOutput.preset ? configOutput.preset : undefined))
@@ -58,7 +60,7 @@ const resolveConfig = config => {
58
60
  return [toEntry(plugin)];
59
61
  return [toDependency(getPluginPackageName(plugin))];
60
62
  });
61
- return [...presets, ...flatPlugins, ...nestedPlugins].map(id => (typeof id === 'string' ? toDependency(id) : id));
63
+ return [...presets, ...flatPlugins, ...nestedPlugins, ...outputs].map(id => typeof id === 'string' ? toDependency(id) : id);
62
64
  };
63
65
  const plugin = {
64
66
  title,
@@ -29,6 +29,7 @@ export declare const Plugins: {
29
29
  drizzle: import("../types/config.ts").Plugin;
30
30
  eleventy: import("../types/config.ts").Plugin;
31
31
  eslint: import("../types/config.ts").Plugin;
32
+ eve: import("../types/config.ts").Plugin;
32
33
  execa: import("../types/config.ts").Plugin;
33
34
  expo: import("../types/config.ts").Plugin;
34
35
  'expressive-code': {
@@ -38,6 +39,7 @@ export declare const Plugins: {
38
39
  config: string[];
39
40
  };
40
41
  fast: import("../types/config.ts").Plugin;
42
+ fumadocs: import("../types/config.ts").Plugin;
41
43
  gatsby: import("../types/config.ts").Plugin;
42
44
  'github-action': import("../types/config.ts").Plugin;
43
45
  'github-actions': import("../types/config.ts").Plugin;
@@ -28,10 +28,12 @@ import { default as dotenv } from './dotenv/index.js';
28
28
  import { default as drizzle } from './drizzle/index.js';
29
29
  import { default as eleventy } from './eleventy/index.js';
30
30
  import { default as eslint } from './eslint/index.js';
31
+ import { default as eve } from './eve/index.js';
31
32
  import { default as execa } from './execa/index.js';
32
33
  import { default as expo } from './expo/index.js';
33
34
  import { default as expressiveCode } from './expressive-code/index.js';
34
35
  import { default as fast } from './fast/index.js';
36
+ import { default as fumadocs } from './fumadocs/index.js';
35
37
  import { default as gatsby } from './gatsby/index.js';
36
38
  import { default as githubAction } from './github-action/index.js';
37
39
  import { default as githubActions } from './github-actions/index.js';
@@ -186,10 +188,12 @@ export const Plugins = {
186
188
  drizzle,
187
189
  eleventy,
188
190
  eslint,
191
+ eve,
189
192
  execa,
190
193
  expo,
191
194
  'expressive-code': expressiveCode,
192
195
  fast,
196
+ fumadocs,
193
197
  gatsby,
194
198
  'github-action': githubAction,
195
199
  'github-actions': githubActions,
@@ -3,6 +3,7 @@ import { _glob, _dirGlob } from '../../util/glob.js';
3
3
  import { toDeferResolve, toEntry } from '../../util/input.js';
4
4
  import { isInternal, join, normalize, toAbsolute } from '../../util/path.js';
5
5
  import { hasDependency } from '../../util/plugin.js';
6
+ import { getDependenciesFromConfig } from '../babel/index.js';
6
7
  import { getReportersDependencies, resolveExtensibleConfig } from './helpers.js';
7
8
  const title = 'Jest';
8
9
  const enablers = ['jest'];
@@ -11,6 +12,7 @@ const config = ['jest.config.{js,ts,mjs,cjs,mts,cts,json}', 'package.json'];
11
12
  const mocks = ['**/__mocks__/**/*.[jt]s?(x)'];
12
13
  const entry = ['**/__tests__/**/*.?(c|m)[jt]s?(x)', '**/?(*.)+(spec|test).?(c|m)[jt]s?(x)', ...mocks];
13
14
  const rootDirRe = /<rootDir>/;
15
+ const isBabelJest = (transformer) => transformer[0] === 'babel-jest';
14
16
  const resolveDependencies = async (config, rootDir, options) => {
15
17
  const { configFileDir } = options;
16
18
  if (config?.preset) {
@@ -46,9 +48,17 @@ const resolveDependencies = async (config, rootDir, options) => {
46
48
  const resolvers = config.resolver ? [config.resolver] : [];
47
49
  const reporters = getReportersDependencies(config, options);
48
50
  const watchPlugins = config.watchPlugins?.map(watchPlugin => (typeof watchPlugin === 'string' ? watchPlugin : watchPlugin[0])) ?? [];
49
- const transform = config.transform
50
- ? Object.values(config.transform).map(transform => (typeof transform === 'string' ? transform : transform[0]))
51
- : [];
51
+ const transform = [];
52
+ for (const transformer of config.transform ? Object.values(config.transform) : []) {
53
+ if (typeof transformer === 'string') {
54
+ transform.push(transformer);
55
+ }
56
+ else {
57
+ transform.push(transformer[0]);
58
+ if (isBabelJest(transformer))
59
+ transform.push(...getDependenciesFromConfig(transformer[1]));
60
+ }
61
+ }
52
62
  const moduleNameMapper = (config.moduleNameMapper
53
63
  ? Object.values(config.moduleNameMapper).map(mapper => (typeof mapper === 'string' ? mapper : mapper[0]))
54
64
  : []).filter(value => !/\$[0-9]/.test(value));
@@ -1,3 +1,4 @@
1
+ import { isDirectory } from '../../util/fs.js';
1
2
  import { toConfig, toProductionEntry } from '../../util/input.js';
2
3
  import { join } from '../../util/path.js';
3
4
  import { hasDependency } from '../../util/plugin.js';
@@ -5,29 +6,41 @@ import { getPageExtensions } from './resolveFromAST.js';
5
6
  const title = 'Next.js';
6
7
  const enablers = ['next'];
7
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
- const config = ['next.config.{js,ts,cjs,mjs}'];
9
+ const config = ['next.config.{js,ts,cjs,mjs,mts}'];
9
10
  const defaultPageExtensions = ['{js,jsx,ts,tsx}'];
10
11
  const productionEntryFilePatterns = [
11
12
  'app/{,[(]*[)]/}{manifest,robots}.{js,ts}',
12
13
  'app/**/sitemap.{js,ts}',
13
14
  'app/**/{icon,apple-icon,opengraph-image,twitter-image}.{js,jsx,ts,tsx}',
14
15
  ];
15
- const getEntryFilePatterns = (pageExtensions = defaultPageExtensions) => {
16
+ const rootOrSrc = '{,src/}';
17
+ const getRouterDirPrefix = (cwd, name) => {
18
+ if (!cwd)
19
+ return rootOrSrc;
20
+ if (isDirectory(cwd, name))
21
+ return '';
22
+ if (isDirectory(cwd, `src/${name}`))
23
+ return 'src/';
24
+ return rootOrSrc;
25
+ };
26
+ const getEntryFilePatterns = (pageExtensions = defaultPageExtensions, cwd) => {
16
27
  const ext = pageExtensions.length === 1 ? pageExtensions[0] : `{${pageExtensions.join(',')}}`;
28
+ const appDirPrefix = getRouterDirPrefix(cwd, 'app');
29
+ const pagesDirPrefix = getRouterDirPrefix(cwd, 'pages');
17
30
  return [
18
- ...productionEntryFilePatterns,
19
- `{instrumentation,instrumentation-client,middleware,proxy}.${ext}`,
20
- `app/global-{error,not-found}.${ext}`,
21
- `app/**/{default,error,forbidden,loading,not-found,unauthorized}.${ext}`,
22
- `app/**/{layout,page,route,template}.${ext}`,
23
- `pages/**/*.${ext}`,
24
- ].flatMap(pattern => [pattern, `src/${pattern}`]);
31
+ ...productionEntryFilePatterns.map(pattern => `${appDirPrefix}${pattern}`),
32
+ `${rootOrSrc}{instrumentation,instrumentation-client,middleware,proxy}.${ext}`,
33
+ `${appDirPrefix}app/global-{error,not-found}.${ext}`,
34
+ `${appDirPrefix}app/**/{default,error,forbidden,loading,not-found,unauthorized}.${ext}`,
35
+ `${appDirPrefix}app/**/{layout,page,route,template}.${ext}`,
36
+ `${pagesDirPrefix}pages/**/*.${ext}`,
37
+ ];
25
38
  };
26
39
  const production = getEntryFilePatterns();
27
40
  const resolveFromAST = (program, { configFileDir }) => {
28
41
  const pageExtensions = getPageExtensions(program);
29
42
  const extensions = pageExtensions.length > 0 ? pageExtensions : defaultPageExtensions;
30
- const patterns = [...getEntryFilePatterns(extensions), 'next-env.d.ts'];
43
+ const patterns = [...getEntryFilePatterns(extensions, configFileDir), 'next-env.d.ts'];
31
44
  return patterns.map(id => toProductionEntry(join(configFileDir, id)));
32
45
  };
33
46
  const commands = new Set(['dev', 'build', 'start']);
@@ -1,4 +1,5 @@
1
1
  import { toEntry, toProductionEntry } from '../../util/input.js';
2
+ import { getScriptCommands } from '../../util/scripts.js';
2
3
  const title = 'Node.js';
3
4
  const isEnabled = () => true;
4
5
  const patterns = [
@@ -7,7 +8,9 @@ const patterns = [
7
8
  '**/test.{cjs,mjs,js,cts,mts,ts}',
8
9
  '**/test/**/*.{cjs,mjs,js,cts,mts,ts}',
9
10
  ];
10
- const hasNodeTest = (scripts) => scripts && Object.values(scripts).some(script => /(?<=^|\s)(node|nub)\s(.*)--test/.test(script));
11
+ const hasNodeTest = (scripts) => scripts &&
12
+ Object.values(scripts).some(script => typeof script === 'string' &&
13
+ getScriptCommands(script).some(({ binary, args }) => (binary === 'node' || binary === 'nub') && args.includes('--test')));
11
14
  const entry = ['server.js'];
12
15
  const resolve = options => {
13
16
  const entries = entry.map(id => toProductionEntry(id));
@@ -82,10 +82,12 @@ const registerCompilers = async ({ cwd, hasDependency, registerCompiler }) => {
82
82
  if (store)
83
83
  store.push(...components);
84
84
  else
85
- componentMap.set(id, [...components]);
85
+ componentMap.set(id, components);
86
86
  }
87
87
  }
88
88
  const getSyntheticImports = (identifiers, templateTags) => {
89
+ if (importMap.size === 0 && (!templateTags || componentMap.size === 0))
90
+ return [];
89
91
  const syntheticImports = [];
90
92
  for (const [name, specifier] of importMap) {
91
93
  if (identifiers.has(name))
@@ -113,7 +115,7 @@ const registerCompilers = async ({ cwd, hasDependency, registerCompiler }) => {
113
115
  scripts.push(descriptor.script.content);
114
116
  if (descriptor.scriptSetup?.content)
115
117
  scripts.push(descriptor.scriptSetup.content);
116
- const identifiers = collectIdentifiers(scripts.join('\n'), path);
118
+ const identifiers = scripts.length === 0 ? new Set() : collectIdentifiers(scripts.join('\n'), path);
117
119
  let templateTags;
118
120
  if (descriptor.template?.ast) {
119
121
  const info = collectTemplateInfo(descriptor.template.ast);
@@ -1,12 +1,32 @@
1
1
  import { isFile } from '../../util/fs.js';
2
+ import { toDependency, toEntry } from '../../util/input.js';
2
3
  const title = 'pnpm';
4
+ const enablers = 'This plugin is enabled when a `pnpm-lock.yaml` or `pnpm-workspace.yaml` file is found in the root directory, or when `pnpm@` is specified in the `packageManager` field of `package.json`.';
3
5
  const isEnabled = async ({ cwd, manifest }) => manifest.packageManager?.startsWith('pnpm@') || isFile(cwd, 'pnpm-lock.yaml') || isFile(cwd, 'pnpm-workspace.yaml');
4
6
  const isRootOnly = true;
5
- const config = ['.pnpmfile.cjs'];
7
+ const entry = ['.pnpmfile.{cjs,mjs}'];
8
+ const config = ['package.json', 'pnpm-workspace.yaml'];
9
+ const resolveConfig = config => {
10
+ const inputs = entry.map(toEntry);
11
+ const packageExtensions = config?.pnpm?.packageExtensions || config?.packageExtensions;
12
+ if (packageExtensions) {
13
+ for (const extension of Object.values(packageExtensions)) {
14
+ if (extension.peerDependencies) {
15
+ for (const dep of Object.keys(extension.peerDependencies)) {
16
+ inputs.push(toDependency(dep));
17
+ }
18
+ }
19
+ }
20
+ }
21
+ return inputs;
22
+ };
6
23
  const plugin = {
7
24
  title,
25
+ enablers,
8
26
  isEnabled,
9
27
  isRootOnly,
28
+ entry,
10
29
  config,
30
+ resolveConfig,
11
31
  };
12
32
  export default plugin;
@@ -0,0 +1,6 @@
1
+ import type { Dependencies, PackageJson } from '../../types/package-json.ts';
2
+ export type PnpmConfig = PackageJson & {
3
+ packageExtensions?: Record<string, {
4
+ peerDependencies?: Dependencies;
5
+ }>;
6
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -12,9 +12,25 @@ const config = [
12
12
  const resolveConfig = config => {
13
13
  if (typeof config === 'string')
14
14
  return [toDeferResolve(config)];
15
- return Array.isArray(config.plugins)
16
- ? config.plugins.filter((plugin) => typeof plugin === 'string').map(id => toDependency(id))
17
- : [];
15
+ const result = new Set();
16
+ const processOptions = (options) => {
17
+ if (Array.isArray(options.plugins)) {
18
+ for (const plugin of options.plugins) {
19
+ if (typeof plugin === 'string') {
20
+ result.add(toDependency(plugin));
21
+ }
22
+ }
23
+ }
24
+ };
25
+ processOptions(config);
26
+ if (config.overrides) {
27
+ for (const override of config.overrides) {
28
+ if (override.options) {
29
+ processOptions(override.options);
30
+ }
31
+ }
32
+ }
33
+ return Array.from(result);
18
34
  };
19
35
  const args = {
20
36
  config: true,
@@ -1,4 +1,4 @@
1
- export type PrettierConfig = {
1
+ export type PrettierOptions = {
2
2
  plugins?: (string | {
3
3
  parsers?: Record<string, unknown>;
4
4
  printers?: Record<string, unknown>;
@@ -6,3 +6,8 @@ export type PrettierConfig = {
6
6
  options?: Record<string, unknown>;
7
7
  })[];
8
8
  };
9
+ export type PrettierConfig = PrettierOptions & {
10
+ overrides?: {
11
+ options?: PrettierOptions;
12
+ }[];
13
+ };
@@ -1,7 +1,10 @@
1
1
  const directiveMatcher = /generator\s+(?!client)\w+\s*\{\s*provider\s*=\s*"([^"]+)"[^}]*\}/g;
2
2
  const compiler = (text) => {
3
+ if (!text.includes('generator'))
4
+ return '';
3
5
  const imports = [];
4
6
  let match;
7
+ directiveMatcher.lastIndex = 0;
5
8
  while ((match = directiveMatcher.exec(text))) {
6
9
  if (match[1]) {
7
10
  imports.push(`import '${match[1]}';`);
@@ -1,5 +1,6 @@
1
1
  import { hasDependency } from '../../util/plugin.js';
2
2
  import { findWebpackDependenciesFromConfig } from '../webpack/index.js';
3
+ import { createRequireContextVisitor } from '../webpack/visitors/requireContext.js';
3
4
  const title = 'Rspack';
4
5
  const enablers = ['@rspack/core'];
5
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -8,11 +9,15 @@ const resolveConfig = async (localConfig, options) => {
8
9
  const inputs = await findWebpackDependenciesFromConfig(localConfig, options);
9
10
  return inputs.filter(input => !input.specifier.startsWith('builtin:'));
10
11
  };
12
+ const registerVisitors = ({ ctx, registerVisitor }) => {
13
+ registerVisitor(createRequireContextVisitor(ctx));
14
+ };
11
15
  const plugin = {
12
16
  title,
13
17
  enablers,
14
18
  isEnabled,
15
19
  config,
16
20
  resolveConfig,
21
+ registerVisitors,
17
22
  };
18
23
  export default plugin;
@@ -1,3 +1,4 @@
1
+ import { arrayify } from '../../util/array.js';
1
2
  import { toDependency, toProductionEntry } from '../../util/input.js';
2
3
  import { isInternal, join } from '../../util/path.js';
3
4
  import { hasDependency } from '../../util/plugin.js';
@@ -10,13 +11,23 @@ const handlerToEntry = (handler) => {
10
11
  return toProductionEntry(`${handler.slice(0, dot)}.{js,ts}`);
11
12
  };
12
13
  const pluginToInput = (plugin, dir) => isInternal(plugin) ? toProductionEntry(join(dir, plugin)) : toDependency(plugin);
14
+ const getInjectEntries = (esbuild, dir) => esbuild && typeof esbuild === 'object' ? arrayify(esbuild.inject).map(id => toProductionEntry(join(dir, id))) : [];
13
15
  const resolveConfig = async (config, options) => {
14
16
  const functions = config.functions
15
17
  ? Object.values(config.functions).flatMap(fn => (fn.handler ? [handlerToEntry(fn.handler)] : []))
16
18
  : [];
17
19
  const plugins = config.plugins?.filter((plugin) => typeof plugin === 'string') ?? [];
18
20
  const esbuild = config.custom?.esbuild || config.build?.esbuild ? [toDependency('esbuild', { optional: true })] : [];
19
- return [...functions, ...plugins.map(plugin => pluginToInput(plugin, options.configFileDir)), ...esbuild];
21
+ const injectEntries = [
22
+ ...getInjectEntries(config.custom?.esbuild, options.configFileDir),
23
+ ...getInjectEntries(config.build?.esbuild, options.configFileDir),
24
+ ];
25
+ return [
26
+ ...functions,
27
+ ...plugins.map(plugin => pluginToInput(plugin, options.configFileDir)),
28
+ ...esbuild,
29
+ ...injectEntries,
30
+ ];
20
31
  };
21
32
  const plugin = {
22
33
  title,
@@ -1,13 +1,16 @@
1
1
  export type PluginConfig = {
2
2
  build?: {
3
- esbuild?: unknown;
3
+ esbuild?: EsbuildConfig;
4
4
  };
5
5
  custom?: {
6
- esbuild?: unknown;
6
+ esbuild?: EsbuildConfig;
7
7
  };
8
8
  functions?: Record<string, ServerlessFunction>;
9
9
  plugins?: unknown[];
10
10
  };
11
+ export type EsbuildConfig = {
12
+ inject?: string[];
13
+ } | boolean;
11
14
  type ServerlessFunction = {
12
15
  handler?: string;
13
16
  };