knip 6.11.0 → 6.12.1

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 (39) hide show
  1. package/dist/ConfigurationChief.d.ts +6 -0
  2. package/dist/DependencyDeputy.js +3 -2
  3. package/dist/binaries/bash-parser.js +5 -1
  4. package/dist/cli.js +3 -2
  5. package/dist/compilers/compilers.js +2 -2
  6. package/dist/compilers/index.d.ts +10 -0
  7. package/dist/constants.js +3 -0
  8. package/dist/graph/analyze.js +7 -5
  9. package/dist/plugins/astro/resolveFromAST.js +2 -6
  10. package/dist/plugins/cypress/helpers.js +13 -12
  11. package/dist/plugins/cypress/types.d.ts +9 -10
  12. package/dist/plugins/index.d.ts +1 -0
  13. package/dist/plugins/index.js +2 -0
  14. package/dist/plugins/postcss/index.js +5 -4
  15. package/dist/plugins/taskfile/index.js +5 -5
  16. package/dist/plugins/vercel/index.d.ts +3 -0
  17. package/dist/plugins/vercel/index.js +12 -0
  18. package/dist/plugins/vite/helpers.d.ts +1 -1
  19. package/dist/plugins/vite/helpers.js +11 -8
  20. package/dist/plugins/vite/index.js +3 -3
  21. package/dist/plugins/yarn/index.js +1 -1
  22. package/dist/reporters/util/configuration-hints.js +1 -1
  23. package/dist/schema/configuration.d.ts +15 -0
  24. package/dist/schema/plugins.d.ts +5 -0
  25. package/dist/schema/plugins.js +1 -0
  26. package/dist/types/PluginNames.d.ts +2 -2
  27. package/dist/types/PluginNames.js +1 -0
  28. package/dist/typescript/ast-helpers.d.ts +1 -0
  29. package/dist/typescript/ast-helpers.js +25 -3
  30. package/dist/typescript/comments.js +4 -3
  31. package/dist/typescript/visitors/exports.js +25 -0
  32. package/dist/typescript/visitors/walk.d.ts +13 -1
  33. package/dist/typescript/visitors/walk.js +104 -30
  34. package/dist/util/create-options.d.ts +10 -0
  35. package/dist/util/glob.js +1 -4
  36. package/dist/version.d.ts +1 -1
  37. package/dist/version.js +1 -1
  38. package/package.json +2 -2
  39. package/schema.json +4 -0
@@ -726,6 +726,11 @@ export declare class ConfigurationChief {
726
726
  entry?: string | string[] | undefined;
727
727
  project?: string | string[] | undefined;
728
728
  } | undefined;
729
+ vercel?: string | boolean | string[] | {
730
+ config?: string | string[] | undefined;
731
+ entry?: string | string[] | undefined;
732
+ project?: string | string[] | undefined;
733
+ } | undefined;
729
734
  'vercel-og'?: string | boolean | string[] | {
730
735
  config?: string | string[] | undefined;
731
736
  entry?: string | string[] | undefined;
@@ -958,6 +963,7 @@ export declare class ConfigurationChief {
958
963
  typescript?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
959
964
  unbuild?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
960
965
  unocss?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
966
+ vercel?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
961
967
  "vercel-og"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
962
968
  vike?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
963
969
  vite?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -139,9 +139,10 @@ export class DependencyDeputy {
139
139
  if (packageName === workspace.pkgName)
140
140
  return true;
141
141
  const workspaceNames = this.isStrict ? [workspace.name] : [workspace.name, ...[...workspace.ancestors].reverse()];
142
- const closestWorkspaceName = workspaceNames.find(name => this.isInDependencies(name, packageName, isDevOnly));
142
+ const isDevOrTypeOnly = isDevOnly || isTypeOnly;
143
+ const closestWorkspaceName = workspaceNames.find(name => this.isInDependencies(name, packageName, isDevOrTypeOnly));
143
144
  const typesPackageName = !isDefinitelyTyped(packageName) && getDefinitelyTypedFor(packageName);
144
- const closestWorkspaceNameForTypes = typesPackageName && workspaceNames.find(name => this.isInDependencies(name, typesPackageName, isDevOnly));
145
+ const closestWorkspaceNameForTypes = typesPackageName && workspaceNames.find(name => this.isInDependencies(name, typesPackageName, isDevOrTypeOnly));
145
146
  if (closestWorkspaceNameForTypes && !this.hasTypesIncluded.get(closestWorkspaceNameForTypes)?.has(packageName))
146
147
  this.addReferencedDependency(closestWorkspaceNameForTypes, typesPackageName);
147
148
  if (closestWorkspaceName) {
@@ -94,7 +94,11 @@ export const getDependenciesFromScript = (script, options) => {
94
94
  return [toBinary(binary), ...getDependenciesFromScript(rest, options)];
95
95
  }
96
96
  if (binary in Plugins) {
97
- return [...fallbackResolve(binary, args, { ...options, fromArgs }), ...fromNodeOptions];
97
+ const inputs = fallbackResolve(binary, args, { ...options, fromArgs });
98
+ if (options.knownBinsOnly)
99
+ for (const input of inputs)
100
+ input.optional = true;
101
+ return [...inputs, ...fromNodeOptions];
98
102
  }
99
103
  if (options.knownBinsOnly && !text?.startsWith('.'))
100
104
  return [];
package/dist/cli.js CHANGED
@@ -73,8 +73,9 @@ const main = async () => {
73
73
  console.log('\nTotal running time:', prettyMilliseconds(duration));
74
74
  perfObserver.reset();
75
75
  }
76
- if ((!args['no-exit-code'] && totalErrorCount > Number(args['max-issues'] ?? 0)) ||
77
- (!options.isDisableConfigHints && options.isTreatConfigHintsAsErrors && configurationHints.length > 0)) {
76
+ if (!args['no-exit-code'] &&
77
+ (totalErrorCount > Number(args['max-issues'] ?? 0) ||
78
+ (!options.isDisableConfigHints && options.isTreatConfigHintsAsErrors && configurationHints.length > 0))) {
78
79
  process.exitCode = 1;
79
80
  return;
80
81
  }
@@ -1,6 +1,6 @@
1
1
  export const fencedCodeBlockMatcher = /```[\s\S]*?```/g;
2
2
  export const inlineCodeMatcher = /`[^`]+`/g;
3
- const scriptExtractor = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
3
+ const scriptExtractor = /<script\b(?:[^>"']|"[^"]*"|'[^']*')*>([\s\S]*?)<\/script>/gm;
4
4
  export const importMatcher = /import[^'"]+['"][^'"]+['"]/g;
5
5
  export const importsWithinScripts = (text) => {
6
6
  const scripts = [];
@@ -12,7 +12,7 @@ export const importsWithinScripts = (text) => {
12
12
  }
13
13
  return scripts.join(';\n');
14
14
  };
15
- const scriptBodyExtractor = /<script\b[^>]*>(?<body>[\s\S]*?)<\/script>/gm;
15
+ const scriptBodyExtractor = /<script\b(?:[^>"']|"[^"]*"|'[^']*')*>(?<body>[\s\S]*?)<\/script>/gm;
16
16
  export const scriptBodies = (text) => {
17
17
  const scripts = [];
18
18
  let scriptMatch;
@@ -673,6 +673,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
673
673
  entry?: string | string[] | undefined;
674
674
  project?: string | string[] | undefined;
675
675
  } | undefined;
676
+ vercel?: string | boolean | string[] | {
677
+ config?: string | string[] | undefined;
678
+ entry?: string | string[] | undefined;
679
+ project?: string | string[] | undefined;
680
+ } | undefined;
676
681
  'vercel-og'?: string | boolean | string[] | {
677
682
  config?: string | string[] | undefined;
678
683
  entry?: string | string[] | undefined;
@@ -1439,6 +1444,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
1439
1444
  entry?: string | string[] | undefined;
1440
1445
  project?: string | string[] | undefined;
1441
1446
  } | undefined;
1447
+ vercel?: string | boolean | string[] | {
1448
+ config?: string | string[] | undefined;
1449
+ entry?: string | string[] | undefined;
1450
+ project?: string | string[] | undefined;
1451
+ } | undefined;
1442
1452
  'vercel-og'?: string | boolean | string[] | {
1443
1453
  config?: string | string[] | undefined;
1444
1454
  entry?: string | string[] | undefined;
package/dist/constants.js CHANGED
@@ -75,6 +75,7 @@ export const IGNORED_GLOBAL_BINARIES = new Set([
75
75
  'mkdir',
76
76
  'mknod',
77
77
  'mv',
78
+ 'nc',
78
79
  'nice',
79
80
  'nl',
80
81
  'node',
@@ -100,6 +101,7 @@ export const IGNORED_GLOBAL_BINARIES = new Set([
100
101
  'sha512sum',
101
102
  'shred',
102
103
  'shuf',
104
+ 'sleep',
103
105
  'sort',
104
106
  'split',
105
107
  'ssh',
@@ -113,6 +115,7 @@ export const IGNORED_GLOBAL_BINARIES = new Set([
113
115
  'time',
114
116
  'timeout',
115
117
  'touch',
118
+ 'trap',
116
119
  'tr',
117
120
  'true',
118
121
  'tsort',
@@ -22,12 +22,14 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
22
22
  const inExport = file.exports.get(containingExport);
23
23
  if (!inExport)
24
24
  continue;
25
- if (shouldCountRefs(ignoreExportsUsedInFile, inExport.type)) {
26
- if (inExport.hasRefsInFile)
27
- return true;
28
- if (explorer.isReferenced(filePath, containingExport, { includeEntryExports })[0])
29
- return true;
25
+ if ((inExport.type === 'type' || inExport.type === 'interface' || inExport.type === 'enum') &&
26
+ !shouldCountRefs(ignoreExportsUsedInFile, inExport.type)) {
27
+ continue;
30
28
  }
29
+ if (inExport.hasRefsInFile)
30
+ return true;
31
+ if (explorer.isReferenced(filePath, containingExport, { includeEntryExports })[0])
32
+ return true;
31
33
  if (inExport.referencedIn) {
32
34
  const v = visited ?? new Set();
33
35
  if (!v.has(containingExport)) {
@@ -1,4 +1,4 @@
1
- import { collectPropertyValues, findProperty, getPropertyKey, getStringValue, hasImportSpecifier, } from '../../typescript/ast-helpers.js';
1
+ import { collectPropertyValues, findProperty, getPropertyKey, getStringValue, hasImportSpecifier, resolveObjectArg, } from '../../typescript/ast-helpers.js';
2
2
  export const getSrcDir = (program) => {
3
3
  const values = collectPropertyValues(program, 'srcDir');
4
4
  return values.size > 0 ? Array.from(values)[0] : 'src';
@@ -22,11 +22,7 @@ export const getViteAliases = (program) => {
22
22
  if (node.type !== 'ExportDefaultDeclaration')
23
23
  continue;
24
24
  const decl = node.declaration;
25
- const root = decl?.type === 'ObjectExpression'
26
- ? decl
27
- : decl?.type === 'CallExpression' && decl.arguments?.[0]?.type === 'ObjectExpression'
28
- ? decl.arguments[0]
29
- : undefined;
25
+ const root = decl?.type === 'CallExpression' ? resolveObjectArg(decl.arguments?.[0]) : resolveObjectArg(decl);
30
26
  const aliasNode = findProperty(findProperty(findProperty(root, 'vite'), 'resolve'), 'alias');
31
27
  if (aliasNode?.type !== 'ObjectExpression')
32
28
  continue;
@@ -1,19 +1,20 @@
1
1
  import { isInternal, toAbsolute } from '../../util/path.js';
2
2
  import { load } from '../../util/plugin.js';
3
3
  export const resolveDependencies = async (config, options) => {
4
- const { reporter } = config;
5
4
  const { configFileDir } = options;
6
- const reporters = reporter ? new Set([reporter]) : new Set();
7
- if (reporter === 'cypress-multi-reporters' && config.reporterOptions?.configFile) {
8
- const { configFile } = config.reporterOptions;
9
- const configFilePath = toAbsolute(configFile, configFileDir);
10
- if (isInternal(configFilePath)) {
11
- const reporterConfig = await load(configFilePath);
12
- if (typeof reporterConfig === 'object' && reporterConfig.reporterEnabled) {
13
- const { reporterEnabled: reporterConcatenatedNames } = reporterConfig;
14
- const reporterNames = reporterConcatenatedNames.split(',');
15
- for (const reporterName of reporterNames) {
16
- reporters.add(reporterName.trim());
5
+ const reporters = new Set();
6
+ for (const scope of [config, config.e2e, config.component]) {
7
+ const reporter = scope?.reporter;
8
+ if (!reporter)
9
+ continue;
10
+ reporters.add(reporter);
11
+ if (reporter === 'cypress-multi-reporters' && scope?.reporterOptions?.configFile) {
12
+ const configFilePath = toAbsolute(scope.reporterOptions.configFile, configFileDir);
13
+ if (isInternal(configFilePath)) {
14
+ const reporterConfig = await load(configFilePath);
15
+ if (typeof reporterConfig === 'object' && reporterConfig.reporterEnabled) {
16
+ for (const name of reporterConfig.reporterEnabled.split(','))
17
+ reporters.add(name.trim());
17
18
  }
18
19
  }
19
20
  }
@@ -1,14 +1,13 @@
1
- export interface CypressConfig {
2
- reporter: string;
1
+ interface CypressTestingTypeConfig {
2
+ specPattern?: string[];
3
+ supportFile?: string;
4
+ reporter?: string;
3
5
  reporterOptions?: {
4
6
  configFile?: string;
5
7
  };
6
- component?: {
7
- specPattern?: string[];
8
- supportFile?: string;
9
- };
10
- e2e?: {
11
- specPattern?: string[];
12
- supportFile?: string;
13
- };
14
8
  }
9
+ export interface CypressConfig extends CypressTestingTypeConfig {
10
+ component?: CypressTestingTypeConfig;
11
+ e2e?: CypressTestingTypeConfig;
12
+ }
13
+ export {};
@@ -138,6 +138,7 @@ export declare const Plugins: {
138
138
  typescript: import("../types/config.ts").Plugin;
139
139
  unbuild: import("../types/config.ts").Plugin;
140
140
  unocss: import("../types/config.ts").Plugin;
141
+ vercel: import("../types/config.ts").Plugin;
141
142
  'vercel-og': import("../types/config.ts").Plugin;
142
143
  vike: import("../types/config.ts").Plugin;
143
144
  vite: import("../types/config.ts").Plugin;
@@ -132,6 +132,7 @@ import { default as typedoc } from './typedoc/index.js';
132
132
  import { default as typescript } from './typescript/index.js';
133
133
  import { default as unbuild } from './unbuild/index.js';
134
134
  import { default as unocss } from './unocss/index.js';
135
+ import { default as vercel } from './vercel/index.js';
135
136
  import { default as vercelOg } from './vercel-og/index.js';
136
137
  import { default as vike } from './vike/index.js';
137
138
  import { default as vite } from './vite/index.js';
@@ -282,6 +283,7 @@ export const Plugins = {
282
283
  typescript,
283
284
  unbuild,
284
285
  unocss,
286
+ vercel,
285
287
  'vercel-og': vercelOg,
286
288
  vike,
287
289
  vite,
@@ -2,7 +2,7 @@ import { toDeferResolve, toDependency } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
3
  import { toLilconfig } from '../../util/plugin-config.js';
4
4
  const title = 'PostCSS';
5
- const enablers = ['postcss', 'postcss-cli', 'next'];
5
+ const enablers = ['postcss', 'postcss-cli', 'next', '@tailwindcss/postcss'];
6
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
7
  const config = [
8
8
  'package.json',
@@ -20,9 +20,10 @@ const resolveConfig = config => {
20
20
  })
21
21
  : [];
22
22
  const inputs = plugins.map(id => toDeferResolve(id));
23
- return ['tailwindcss', '@tailwindcss/postcss'].some(tailwindPlugin => plugins.includes(tailwindPlugin))
24
- ? [...inputs, toDependency('postcss')]
25
- : inputs;
23
+ if (plugins.includes('tailwindcss')) {
24
+ return [...inputs, toDependency('postcss')];
25
+ }
26
+ return plugins.includes('@tailwindcss/postcss') ? [...inputs, toDependency('postcss', { optional: true })] : inputs;
26
27
  };
27
28
  const plugin = {
28
29
  title,
@@ -4,7 +4,7 @@ import { join, relative } from '../../util/path.js';
4
4
  const title = 'Taskfile';
5
5
  const enablers = 'This plugin is enabled when a Taskfile is found (Taskfile.yml, taskfile.yml, Taskfile.yaml, taskfile.yaml, etc.).';
6
6
  const isRootOnly = true;
7
- const taskFiles = [
7
+ const config = [
8
8
  'Taskfile.yml',
9
9
  'taskfile.yml',
10
10
  'Taskfile.yaml',
@@ -14,10 +14,10 @@ const taskFiles = [
14
14
  'Taskfile.dist.yaml',
15
15
  'taskfile.dist.yaml',
16
16
  ];
17
- const isEnabled = async ({ cwd, config }) => {
18
- if (config.taskfile)
17
+ const isEnabled = ({ cwd, config: wsConfig }) => {
18
+ if (wsConfig.taskfile)
19
19
  return true;
20
- return taskFiles.some(file => isFile(cwd, file));
20
+ return config.some(file => isFile(cwd, file));
21
21
  };
22
22
  const extractScriptsFromCommand = (command) => {
23
23
  const scripts = [];
@@ -113,7 +113,7 @@ const plugin = {
113
113
  title,
114
114
  enablers,
115
115
  isEnabled,
116
- config: taskFiles,
116
+ config,
117
117
  resolveConfig,
118
118
  isRootOnly,
119
119
  };
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,12 @@
1
+ import { hasDependency } from '../../util/plugin.js';
2
+ const title = 'Vercel';
3
+ const enablers = ['@vercel/config'];
4
+ const entry = ['vercel.{js,mjs,cjs,ts,mts}'];
5
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
+ const plugin = {
7
+ title,
8
+ enablers,
9
+ isEnabled,
10
+ entry,
11
+ };
12
+ export default plugin;
@@ -1,4 +1,4 @@
1
1
  import type { Program } from 'oxc-parser';
2
2
  import { type Input } from '../../util/input.ts';
3
- export declare const getReactBabelPlugins: (program: Program) => string[];
3
+ export declare const getReactBabelInputs: (program: Program) => string[];
4
4
  export declare const getIndexHtmlEntries: (rootDir: string) => Promise<Input[]>;
@@ -1,10 +1,10 @@
1
1
  import { Visitor } from 'oxc-parser';
2
- import { findProperty, getDefaultImportName, getImportMap, getStringValues } from '../../typescript/ast-helpers.js';
2
+ import { findProperty, getDefaultImportName, getImportMap, getStringValues, resolveObjectArg, } from '../../typescript/ast-helpers.js';
3
3
  import { isFile, loadFile } from '../../util/fs.js';
4
4
  import { toProductionEntry } from '../../util/input.js';
5
5
  import { join } from '../../util/path.js';
6
- export const getReactBabelPlugins = (program) => {
7
- const babelPlugins = [];
6
+ export const getReactBabelInputs = (program) => {
7
+ const inputs = [];
8
8
  const importMap = getImportMap(program);
9
9
  const reactPluginNames = new Set();
10
10
  for (const [importName, importPath] of importMap) {
@@ -22,7 +22,8 @@ export const getReactBabelPlugins = (program) => {
22
22
  CallExpression(node) {
23
23
  if (node.callee?.type !== 'Identifier' || node.callee.name !== 'defineConfig')
24
24
  return;
25
- const plugins = findProperty(node.arguments?.[0], 'plugins');
25
+ const config = resolveObjectArg(node.arguments?.[0]);
26
+ const plugins = findProperty(config, 'plugins');
26
27
  if (plugins?.type !== 'ArrayExpression')
27
28
  return;
28
29
  for (const el of plugins.elements ?? []) {
@@ -30,14 +31,16 @@ export const getReactBabelPlugins = (program) => {
30
31
  continue;
31
32
  if (!reactPluginNames.has(el.callee.name))
32
33
  continue;
33
- const babelPluginsArray = findProperty(findProperty(el.arguments?.[0], 'babel'), 'plugins');
34
- for (const v of getStringValues(babelPluginsArray))
35
- babelPlugins.push(v);
34
+ const babel = findProperty(el.arguments?.[0], 'babel');
35
+ for (const key of ['plugins', 'presets']) {
36
+ for (const v of getStringValues(findProperty(babel, key)))
37
+ inputs.push(v);
38
+ }
36
39
  }
37
40
  },
38
41
  });
39
42
  visitor.visit(program);
40
- return babelPlugins;
43
+ return inputs;
41
44
  };
42
45
  const moduleScriptPattern = /<script\b(?=[^>]*\btype\s*=\s*["']?module["']?)(?=[^>]*\bsrc\s*=\s*["']?([^"' >]+)["']?)[^>]*>/gi;
43
46
  const normalizeModuleScriptSrc = (value) => value.trim().replace(/^\//, '');
@@ -1,15 +1,15 @@
1
1
  import { toDependency } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
3
  import { resolveConfig } from '../vitest/index.js';
4
- import { getIndexHtmlEntries, getReactBabelPlugins } from './helpers.js';
4
+ import { getIndexHtmlEntries, getReactBabelInputs } from './helpers.js';
5
5
  import { createImportMetaGlobVisitor } from './visitors/importMetaGlob.js';
6
6
  const title = 'Vite';
7
7
  const enablers = ['vite', 'vitest'];
8
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
9
  export const config = ['vite.config.{js,mjs,ts,cjs,mts,cts}'];
10
10
  const resolveFromAST = program => {
11
- const babelPlugins = getReactBabelPlugins(program);
12
- return babelPlugins.map(plugin => toDependency(plugin));
11
+ const inputs = getReactBabelInputs(program);
12
+ return inputs.map(id => toDependency(id));
13
13
  };
14
14
  const registerVisitors = ({ ctx, registerVisitor }) => {
15
15
  registerVisitor(createImportMetaGlobVisitor(ctx));
@@ -2,7 +2,7 @@ import { isFile } from '../../util/fs.js';
2
2
  import { toEntry } from '../../util/input.js';
3
3
  const title = 'Yarn';
4
4
  const enablers = 'This plugin is enabled when a `yarn.lock` file is found in the root folder.';
5
- const isEnabled = async ({ cwd }) => isFile(cwd, 'yarn.lock');
5
+ const isEnabled = ({ cwd }) => isFile(cwd, 'yarn.lock');
6
6
  const isRootOnly = true;
7
7
  const config = ['.yarnrc.yml'];
8
8
  const entry = ['yarn.config.cjs'];
@@ -124,7 +124,7 @@ export const printConfigurationHints = ({ cwd, counters, issues, tagHints, confi
124
124
  const rows = finalizeConfigurationHints({ issues, counters, configurationHints, tagHints, includedWorkspaceDirs, selectedWorkspaces, enabledPlugins }, { cwd, configFilePath });
125
125
  if (rows.length > 0) {
126
126
  const getTitle = isTreatConfigHintsAsErrors ? getColoredTitle : getDimmedTitle;
127
- console.log(getTitle('Configuration hints', configurationHints.length));
127
+ console.warn(getTitle('Configuration hints', configurationHints.length));
128
128
  console.warn(getTableForHints(rows).toString());
129
129
  }
130
130
  };
@@ -671,6 +671,11 @@ export declare const workspaceConfigurationSchema: z.ZodMiniObject<{
671
671
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
672
672
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
673
673
  }, z.core.$strip>]>>;
674
+ vercel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
675
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
676
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
677
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
678
+ }, z.core.$strip>]>>;
674
679
  'vercel-og': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
675
680
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
676
681
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -1428,6 +1433,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
1428
1433
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1429
1434
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1430
1435
  }, z.core.$strip>]>>;
1436
+ vercel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1437
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1438
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1439
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1440
+ }, z.core.$strip>]>>;
1431
1441
  'vercel-og': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1432
1442
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1433
1443
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -2202,6 +2212,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
2202
2212
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2203
2213
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2204
2214
  }, z.core.$strip>]>>;
2215
+ vercel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
2216
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2217
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2218
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2219
+ }, z.core.$strip>]>>;
2205
2220
  'vercel-og': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
2206
2221
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
2207
2222
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -676,6 +676,11 @@ export declare const pluginsSchema: z.ZodMiniObject<{
676
676
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
677
677
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
678
678
  }, z.core.$strip>]>;
679
+ vercel: z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
680
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
681
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
682
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
683
+ }, z.core.$strip>]>;
679
684
  'vercel-og': z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
680
685
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
681
686
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -144,6 +144,7 @@ export const pluginsSchema = z.object({
144
144
  typescript: pluginSchema,
145
145
  unbuild: pluginSchema,
146
146
  unocss: pluginSchema,
147
+ vercel: pluginSchema,
147
148
  'vercel-og': pluginSchema,
148
149
  vike: pluginSchema,
149
150
  vite: pluginSchema,
@@ -1,2 +1,2 @@
1
- export type PluginName = 'angular' | 'astro' | 'astro-db' | 'astro-og-canvas' | 'ava' | 'babel' | 'biome' | 'bumpp' | 'bun' | 'c8' | 'capacitor' | 'changelogen' | 'changelogithub' | 'changesets' | 'commitizen' | 'commitlint' | 'convex' | 'create-typescript-app' | 'cspell' | 'cucumber' | 'cypress' | 'danger' | 'dependency-cruiser' | 'docusaurus' | 'dotenv' | 'drizzle' | 'eleventy' | 'eslint' | 'execa' | 'expo' | 'expressive-code' | 'gatsby' | 'github-action' | 'github-actions' | 'glob' | 'graphql-codegen' | 'hardhat' | 'husky' | 'i18next-parser' | 'jest' | 'karma' | 'knex' | 'ladle' | 'lefthook' | 'lint-staged' | 'linthtml' | 'lockfile-lint' | 'lost-pixel' | 'markdownlint' | 'mdx' | 'mdxlint' | 'metro' | 'mocha' | 'moonrepo' | 'msw' | 'nano-staged' | 'nest' | 'netlify' | 'next' | 'next-intl' | 'next-mdx' | 'nitro' | 'node' | 'node-modules-inspector' | 'nodemon' | 'npm-package-json-lint' | 'nuxt' | 'nx' | 'nyc' | 'oclif' | 'openapi-ts' | 'oxfmt' | 'oxlint' | 'panda-css' | 'parcel' | 'payload' | 'pino' | 'playwright' | 'playwright-ct' | 'playwright-test' | 'plop' | 'pm2' | 'pnpm' | 'postcss' | 'preconstruct' | 'prettier' | 'prisma' | 'qwik' | 'raycast' | 'react-cosmos' | 'react-email' | 'react-native' | 'react-router' | 'relay' | 'release-it' | 'remark' | 'remix' | 'rolldown' | 'rollup' | 'rsbuild' | 'rslib' | 'rspack' | 'rstest' | 'sanity' | 'semantic-release' | 'sentry' | 'serverless-framework' | 'simple-git-hooks' | 'size-limit' | 'sst' | 'starlight' | 'stencil' | 'storybook' | 'stryker' | 'stylelint' | 'svelte' | 'sveltejs-package' | 'sveltekit' | 'svgo' | 'svgr' | 'swc' | 'syncpack' | 'tailwind' | 'tanstack-router' | 'taskfile' | 'travis' | 'ts-node' | 'tsdown' | 'tsup' | 'tsx' | 'typedoc' | 'typescript' | 'unbuild' | 'unocss' | 'vercel-og' | 'vike' | 'vite' | 'vitepress' | 'vitest' | 'vue' | 'webdriver-io' | 'webpack' | 'wireit' | 'wrangler' | 'wxt' | 'xo' | 'yarn' | 'yorkie' | 'zx';
2
- export declare const pluginNames: readonly ['angular', 'astro', 'astro-db', 'astro-og-canvas', 'ava', 'babel', 'biome', 'bumpp', 'bun', 'c8', 'capacitor', 'changelogen', 'changelogithub', 'changesets', 'commitizen', 'commitlint', 'convex', 'create-typescript-app', 'cspell', 'cucumber', 'cypress', 'danger', 'dependency-cruiser', 'docusaurus', 'dotenv', 'drizzle', 'eleventy', 'eslint', 'execa', 'expo', 'expressive-code', 'gatsby', 'github-action', 'github-actions', 'glob', 'graphql-codegen', 'hardhat', 'husky', 'i18next-parser', 'jest', 'karma', 'knex', 'ladle', 'lefthook', 'lint-staged', 'linthtml', 'lockfile-lint', 'lost-pixel', 'markdownlint', 'mdx', 'mdxlint', 'metro', 'mocha', 'moonrepo', 'msw', 'nano-staged', 'nest', 'netlify', 'next', 'next-intl', 'next-mdx', 'nitro', 'node', 'node-modules-inspector', 'nodemon', 'npm-package-json-lint', 'nuxt', 'nx', 'nyc', 'oclif', 'openapi-ts', 'oxfmt', 'oxlint', 'panda-css', 'parcel', 'payload', 'pino', 'playwright', 'playwright-ct', 'playwright-test', 'plop', 'pm2', 'pnpm', 'postcss', 'preconstruct', 'prettier', 'prisma', 'qwik', 'raycast', 'react-cosmos', 'react-email', 'react-native', 'react-router', 'relay', 'release-it', 'remark', 'remix', 'rolldown', 'rollup', 'rsbuild', 'rslib', 'rspack', 'rstest', 'sanity', 'semantic-release', 'sentry', 'serverless-framework', 'simple-git-hooks', 'size-limit', 'sst', 'starlight', 'stencil', 'storybook', 'stryker', 'stylelint', 'svelte', 'sveltejs-package', 'sveltekit', 'svgo', 'svgr', 'swc', 'syncpack', 'tailwind', 'tanstack-router', 'taskfile', 'travis', 'ts-node', 'tsdown', 'tsup', 'tsx', 'typedoc', 'typescript', 'unbuild', 'unocss', 'vercel-og', 'vike', 'vite', 'vitepress', 'vitest', 'vue', 'webdriver-io', 'webpack', 'wireit', 'wrangler', 'wxt', 'xo', 'yarn', 'yorkie', 'zx'];
1
+ export type PluginName = 'angular' | 'astro' | 'astro-db' | 'astro-og-canvas' | 'ava' | 'babel' | 'biome' | 'bumpp' | 'bun' | 'c8' | 'capacitor' | 'changelogen' | 'changelogithub' | 'changesets' | 'commitizen' | 'commitlint' | 'convex' | 'create-typescript-app' | 'cspell' | 'cucumber' | 'cypress' | 'danger' | 'dependency-cruiser' | 'docusaurus' | 'dotenv' | 'drizzle' | 'eleventy' | 'eslint' | 'execa' | 'expo' | 'expressive-code' | 'gatsby' | 'github-action' | 'github-actions' | 'glob' | 'graphql-codegen' | 'hardhat' | 'husky' | 'i18next-parser' | 'jest' | 'karma' | 'knex' | 'ladle' | 'lefthook' | 'lint-staged' | 'linthtml' | 'lockfile-lint' | 'lost-pixel' | 'markdownlint' | 'mdx' | 'mdxlint' | 'metro' | 'mocha' | 'moonrepo' | 'msw' | 'nano-staged' | 'nest' | 'netlify' | 'next' | 'next-intl' | 'next-mdx' | 'nitro' | 'node' | 'node-modules-inspector' | 'nodemon' | 'npm-package-json-lint' | 'nuxt' | 'nx' | 'nyc' | 'oclif' | 'openapi-ts' | 'oxfmt' | 'oxlint' | 'panda-css' | 'parcel' | 'payload' | 'pino' | 'playwright' | 'playwright-ct' | 'playwright-test' | 'plop' | 'pm2' | 'pnpm' | 'postcss' | 'preconstruct' | 'prettier' | 'prisma' | 'qwik' | 'raycast' | 'react-cosmos' | 'react-email' | 'react-native' | 'react-router' | 'relay' | 'release-it' | 'remark' | 'remix' | 'rolldown' | 'rollup' | 'rsbuild' | 'rslib' | 'rspack' | 'rstest' | 'sanity' | 'semantic-release' | 'sentry' | 'serverless-framework' | 'simple-git-hooks' | 'size-limit' | 'sst' | 'starlight' | 'stencil' | 'storybook' | 'stryker' | 'stylelint' | 'svelte' | 'sveltejs-package' | 'sveltekit' | 'svgo' | 'svgr' | 'swc' | 'syncpack' | 'tailwind' | 'tanstack-router' | 'taskfile' | 'travis' | 'ts-node' | 'tsdown' | 'tsup' | 'tsx' | 'typedoc' | 'typescript' | 'unbuild' | 'unocss' | 'vercel' | 'vercel-og' | 'vike' | 'vite' | 'vitepress' | 'vitest' | 'vue' | 'webdriver-io' | 'webpack' | 'wireit' | 'wrangler' | 'wxt' | 'xo' | 'yarn' | 'yorkie' | 'zx';
2
+ export declare const pluginNames: readonly ['angular', 'astro', 'astro-db', 'astro-og-canvas', 'ava', 'babel', 'biome', 'bumpp', 'bun', 'c8', 'capacitor', 'changelogen', 'changelogithub', 'changesets', 'commitizen', 'commitlint', 'convex', 'create-typescript-app', 'cspell', 'cucumber', 'cypress', 'danger', 'dependency-cruiser', 'docusaurus', 'dotenv', 'drizzle', 'eleventy', 'eslint', 'execa', 'expo', 'expressive-code', 'gatsby', 'github-action', 'github-actions', 'glob', 'graphql-codegen', 'hardhat', 'husky', 'i18next-parser', 'jest', 'karma', 'knex', 'ladle', 'lefthook', 'lint-staged', 'linthtml', 'lockfile-lint', 'lost-pixel', 'markdownlint', 'mdx', 'mdxlint', 'metro', 'mocha', 'moonrepo', 'msw', 'nano-staged', 'nest', 'netlify', 'next', 'next-intl', 'next-mdx', 'nitro', 'node', 'node-modules-inspector', 'nodemon', 'npm-package-json-lint', 'nuxt', 'nx', 'nyc', 'oclif', 'openapi-ts', 'oxfmt', 'oxlint', 'panda-css', 'parcel', 'payload', 'pino', 'playwright', 'playwright-ct', 'playwright-test', 'plop', 'pm2', 'pnpm', 'postcss', 'preconstruct', 'prettier', 'prisma', 'qwik', 'raycast', 'react-cosmos', 'react-email', 'react-native', 'react-router', 'relay', 'release-it', 'remark', 'remix', 'rolldown', 'rollup', 'rsbuild', 'rslib', 'rspack', 'rstest', 'sanity', 'semantic-release', 'sentry', 'serverless-framework', 'simple-git-hooks', 'size-limit', 'sst', 'starlight', 'stencil', 'storybook', 'stryker', 'stylelint', 'svelte', 'sveltejs-package', 'sveltekit', 'svgo', 'svgr', 'swc', 'syncpack', 'tailwind', 'tanstack-router', 'taskfile', 'travis', 'ts-node', 'tsdown', 'tsup', 'tsx', 'typedoc', 'typescript', 'unbuild', 'unocss', 'vercel', 'vercel-og', 'vike', 'vite', 'vitepress', 'vitest', 'vue', 'webdriver-io', 'webpack', 'wireit', 'wrangler', 'wxt', 'xo', 'yarn', 'yorkie', 'zx'];
@@ -133,6 +133,7 @@ export const pluginNames = [
133
133
  'typescript',
134
134
  'unbuild',
135
135
  'unocss',
136
+ 'vercel',
136
137
  'vercel-og',
137
138
  'vike',
138
139
  'vite',
@@ -5,6 +5,7 @@ export declare const getImportMap: (program: Program) => Map<string, string>;
5
5
  export declare const getDefaultImportName: (importMap: Map<string, string>, specifier: string) => string | undefined;
6
6
  export declare const getPropertyValues: (node: any, propertyName: string) => Set<string>;
7
7
  export declare const collectPropertyValues: (program: Program, propertyName: string) => Set<string>;
8
+ export declare const resolveObjectArg: (arg: any) => any | undefined;
8
9
  export declare const findCallArg: (program: Program, fnName: string) => any | undefined;
9
10
  export declare const findProperty: (node: any, name: string) => any | undefined;
10
11
  export declare const getStringValues: (node: any) => Set<string>;
@@ -82,6 +82,28 @@ export const collectPropertyValues = (program, propertyName) => {
82
82
  visitor.visit(program);
83
83
  return values;
84
84
  };
85
+ const unwrapParens = (node) => node?.type === 'ParenthesizedExpression' ? unwrapParens(node.expression) : node;
86
+ export const resolveObjectArg = (arg) => {
87
+ const node = unwrapParens(arg);
88
+ if (!node)
89
+ return;
90
+ if (node.type === 'ObjectExpression')
91
+ return node;
92
+ if (node.type !== 'ArrowFunctionExpression' && node.type !== 'FunctionExpression')
93
+ return;
94
+ const body = unwrapParens(node.body);
95
+ if (body?.type === 'ObjectExpression')
96
+ return body;
97
+ if (body?.type !== 'BlockStatement')
98
+ return;
99
+ for (const stmt of body.body ?? []) {
100
+ if (stmt.type === 'ReturnStatement') {
101
+ const ret = unwrapParens(stmt.argument);
102
+ if (ret?.type === 'ObjectExpression')
103
+ return ret;
104
+ }
105
+ }
106
+ };
85
107
  export const findCallArg = (program, fnName) => {
86
108
  let result;
87
109
  const visitor = new Visitor({
@@ -89,9 +111,9 @@ export const findCallArg = (program, fnName) => {
89
111
  if (result)
90
112
  return;
91
113
  if (node.callee?.type === 'Identifier' && node.callee.name === fnName) {
92
- const arg = node.arguments?.[0];
93
- if (arg?.type === 'ObjectExpression')
94
- result = arg;
114
+ const obj = resolveObjectArg(node.arguments?.[0]);
115
+ if (obj)
116
+ result = obj;
95
117
  }
96
118
  },
97
119
  });
@@ -2,7 +2,7 @@ import { IMPORT_FLAGS } from '../constants.js';
2
2
  const jsDocImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)(?:\.(\w+))?/g;
3
3
  const jsDocImportTagRe = /@import\s+(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+['"]([^'"]+)['"]/g;
4
4
  const jsxImportSourceRe = /@jsxImportSource\s+(\S+)/;
5
- const referenceTypesRe = /\s*<reference\s+types\s*=\s*"([^"]+)"[^/]*\/>/;
5
+ const referenceRe = /\s*<reference\s+(types|path)\s*=\s*"([^"]+)"[^/]*\/>/;
6
6
  const envPragmaRe = /@(vitest|jest)-environment\s+([@\w./-]+)/g;
7
7
  const resolveEnvironmentPragma = (tool, value) => {
8
8
  if (value === 'node')
@@ -55,9 +55,10 @@ export const extractImportsFromComments = (comments, firstStmtStart, addImport)
55
55
  }
56
56
  }
57
57
  if (comment.type === 'Line') {
58
- const refMatch = comment.value.match(referenceTypesRe);
58
+ const refMatch = comment.value.match(referenceRe);
59
59
  if (refMatch) {
60
- addImport(refMatch[1], undefined, undefined, undefined, comment.start, IMPORT_FLAGS.TYPE_ONLY);
60
+ const flags = IMPORT_FLAGS.TYPE_ONLY | (refMatch[1] === 'path' ? IMPORT_FLAGS.OPTIONAL : 0);
61
+ addImport(refMatch[2], undefined, undefined, undefined, comment.start, flags);
61
62
  }
62
63
  }
63
64
  }
@@ -3,6 +3,11 @@ import { addNsValue, addValue } from '../../util/module-graph.js';
3
3
  import { extractEnumMembers, extractNamespaceMembers, getLineAndCol, getStringValue, isStringLiteral, } from './helpers.js';
4
4
  import { EMPTY_TAGS } from './jsdoc.js';
5
5
  const getName = (n) => (n?.type === 'Identifier' ? n.name : undefined);
6
+ const hasExplicitFunctionReturnType = (node) => !!node &&
7
+ (node.type === 'ArrowFunctionExpression' ||
8
+ node.type === 'FunctionExpression' ||
9
+ node.type === 'FunctionDeclaration') &&
10
+ Boolean(node.returnType);
6
11
  export function handleExportNamed(node, s) {
7
12
  if (s.skipExports || s.isInNamespace(node))
8
13
  return;
@@ -34,18 +39,24 @@ export function handleExportNamed(node, s) {
34
39
  const name = p.argument.name;
35
40
  const fix = s.options.isFixExports ? [p.start, p.end, FIX_FLAGS.OBJECT_BINDING] : undefined;
36
41
  s.addExport(name, SYMBOL_TYPE.UNKNOWN, p.argument.start, [], fix, false, s.getJSDocTags(exportStart));
42
+ if (declarator.init)
43
+ s.collectRefsInType(declarator.init, name, false);
37
44
  s.destructuredExports.add(name);
38
45
  }
39
46
  else if (p.value?.type === 'Identifier') {
40
47
  const name = p.value.name;
41
48
  const fix = s.options.isFixExports ? [p.start, p.end, FIX_FLAGS.OBJECT_BINDING] : undefined;
42
49
  s.addExport(name, SYMBOL_TYPE.UNKNOWN, p.value.start, [], fix, false, s.getJSDocTags(exportStart));
50
+ if (declarator.init)
51
+ s.collectRefsInType(declarator.init, name, false);
43
52
  s.destructuredExports.add(name);
44
53
  }
45
54
  else if (p.value?.type === 'AssignmentPattern' && p.value.left?.type === 'Identifier') {
46
55
  const name = p.value.left.name;
47
56
  const fix = s.options.isFixExports ? [p.start, p.end, FIX_FLAGS.OBJECT_BINDING] : undefined;
48
57
  s.addExport(name, SYMBOL_TYPE.UNKNOWN, p.value.left.start, [], fix, false, s.getJSDocTags(exportStart));
58
+ if (declarator.init)
59
+ s.collectRefsInType(declarator.init, name, false);
49
60
  s.destructuredExports.add(name);
50
61
  }
51
62
  }
@@ -55,11 +66,15 @@ export function handleExportNamed(node, s) {
55
66
  if (el?.type === 'Identifier') {
56
67
  const fix = s.options.isFixExports ? [el.start, el.end, FIX_FLAGS.NONE] : undefined;
57
68
  s.addExport(el.name, SYMBOL_TYPE.UNKNOWN, el.start, [], fix, false, s.getJSDocTags(exportStart));
69
+ if (declarator.init)
70
+ s.collectRefsInType(declarator.init, el.name, false);
58
71
  s.destructuredExports.add(el.name);
59
72
  }
60
73
  else if (el?.type === 'RestElement' && el.argument?.type === 'Identifier') {
61
74
  const fix = s.options.isFixExports ? [el.start, el.end, FIX_FLAGS.NONE] : undefined;
62
75
  s.addExport(el.argument.name, SYMBOL_TYPE.UNKNOWN, el.argument.start, [], fix, false, s.getJSDocTags(exportStart));
76
+ if (declarator.init)
77
+ s.collectRefsInType(declarator.init, el.argument.name, false);
63
78
  s.destructuredExports.add(el.argument.name);
64
79
  }
65
80
  }
@@ -111,6 +126,12 @@ export function handleExportNamed(node, s) {
111
126
  findSpreads(declarator.init, [name]);
112
127
  }
113
128
  s.addExport(name, SYMBOL_TYPE.UNKNOWN, declarator.id.start, [], fix, isReExport, jsDocTags);
129
+ if (declarator.id.typeAnnotation) {
130
+ s.collectRefsInType(declarator.id.typeAnnotation, name, true);
131
+ }
132
+ else if (declarator.init) {
133
+ s.collectRefsInType(declarator.init, name, hasExplicitFunctionReturnType(declarator.init));
134
+ }
114
135
  if (!jsDocTags.has(ALIAS_TAG) && declarator.init?.type === 'Identifier') {
115
136
  const initName = declarator.init.name;
116
137
  const existingExport = s.exports.get(initName);
@@ -133,10 +154,12 @@ export function handleExportNamed(node, s) {
133
154
  else if ((decl.type === 'FunctionDeclaration' || decl.type === 'TSDeclareFunction') && decl.id) {
134
155
  const fix = s.getFix(exportStart, exportStart + 7);
135
156
  s.addExport(decl.id.name, SYMBOL_TYPE.FUNCTION, decl.id.start, [], fix, false, s.getJSDocTags(exportStart));
157
+ s.collectRefsInType(decl, decl.id.name, hasExplicitFunctionReturnType(decl));
136
158
  }
137
159
  else if (decl.type === 'ClassDeclaration' && decl.id) {
138
160
  const fix = s.getFix(exportStart, exportStart + 7);
139
161
  s.addExport(decl.id.name, SYMBOL_TYPE.CLASS, decl.id.start, [], fix, false, s.getJSDocTags(exportStart));
162
+ s.collectRefsInType(decl, decl.id.name, true);
140
163
  }
141
164
  else if (decl.type === 'TSTypeAliasDeclaration') {
142
165
  const fix = s.getTypeFix(exportStart, exportStart + 7);
@@ -210,11 +233,13 @@ export function handleExportDefault(node, s) {
210
233
  if (decl.type === 'FunctionDeclaration') {
211
234
  type = SYMBOL_TYPE.FUNCTION;
212
235
  pos = decl.id?.start ?? decl.start;
236
+ s.collectRefsInType(decl, 'default', hasExplicitFunctionReturnType(decl));
213
237
  }
214
238
  else if (decl.type === 'ClassDeclaration') {
215
239
  type = SYMBOL_TYPE.CLASS;
216
240
  pos = decl.id?.start ?? decl.start;
217
241
  members = [];
242
+ s.collectRefsInType(decl, 'default', true);
218
243
  }
219
244
  else if (decl.type === 'TSInterfaceDeclaration') {
220
245
  type = SYMBOL_TYPE.INTERFACE;
@@ -1,4 +1,4 @@
1
- import { Visitor, type Program, type Span } from 'oxc-parser';
1
+ import { Visitor, type Class, type Function as FunctionNode, type Program, type Span, type VariableDeclarator } from 'oxc-parser';
2
2
  import type { PluginVisitorObject } from '../../types/config.ts';
3
3
  import type { GetImportsAndExportsOptions } from '../../types/config.ts';
4
4
  import type { Fix } from '../../types/exports.ts';
@@ -60,6 +60,18 @@ export interface WalkState extends WalkContext {
60
60
  scopeStarts: number[];
61
61
  scopeEnds: number[];
62
62
  shadowScopes: Map<string, [number, number][]>;
63
+ localDeclarations: Map<string, FunctionNode | Class | VariableDeclarator>;
64
+ pendingCallRefs: Array<{
65
+ name: string;
66
+ exportName: string;
67
+ seen: Set<string>;
68
+ }>;
69
+ pendingMemberCallRefs: Array<{
70
+ objectName: string;
71
+ propertyName: string;
72
+ exportName: string;
73
+ seen: Set<string>;
74
+ }>;
63
75
  addExport: (identifier: string, type: SymbolType, pos: number, members: ExportMember[], fix: Fix, isReExport: boolean, jsDocTags: Set<string>) => void;
64
76
  getFix: (start: number, end: number, flags?: number) => Fix;
65
77
  getTypeFix: (start: number, end: number) => Fix;
@@ -1,4 +1,4 @@
1
- import { Visitor } from 'oxc-parser';
1
+ import { Visitor, visitorKeys, } from 'oxc-parser';
2
2
  import { FIX_FLAGS, IMPORT_FLAGS, OPAQUE, SYMBOL_TYPE } from '../../constants.js';
3
3
  import { addValue } from '../../util/module-graph.js';
4
4
  import { isInNodeModules } from '../../util/path.js';
@@ -47,42 +47,79 @@ const _addExport = (identifier, type, pos, members, fix, isReExport, jsDocTags)
47
47
  });
48
48
  }
49
49
  };
50
- const _collectRefsInType = (node, exportName, signatureOnly) => {
51
- if (!node || typeof node !== 'object')
50
+ const _collectRefsInType = (node, exportName, signatureOnly, seen = new Set(), inBody = false) => {
51
+ if (!node)
52
52
  return;
53
- if (node.type === 'TSTypeQuery') {
54
- const name = node.exprName.type === 'Identifier' ? node.exprName.name : undefined;
55
- if (name) {
56
- const refs = state.referencedInExport.get(name);
57
- if (refs)
58
- refs.add(exportName);
59
- else
60
- state.referencedInExport.set(name, new Set([exportName]));
61
- }
53
+ const type = node.type;
54
+ if (!type)
62
55
  return;
56
+ switch (type) {
57
+ case 'TSTypeQuery':
58
+ if (node.exprName?.type === 'Identifier')
59
+ _addRefInExport(node.exprName.name, exportName);
60
+ return;
61
+ case 'TSTypeReference':
62
+ if (node.typeName?.type === 'Identifier')
63
+ _addRefInExport(node.typeName.name, exportName);
64
+ break;
65
+ case 'CallExpression': {
66
+ const callee = node.callee;
67
+ if (callee?.type === 'Identifier') {
68
+ state.pendingCallRefs.push({ name: callee.name, exportName, seen });
69
+ }
70
+ else if (callee?.type === 'MemberExpression' &&
71
+ !callee.computed &&
72
+ callee.object?.type === 'Identifier' &&
73
+ callee.property?.type === 'Identifier') {
74
+ state.pendingMemberCallRefs.push({
75
+ objectName: callee.object.name,
76
+ propertyName: callee.property.name,
77
+ exportName,
78
+ seen,
79
+ });
80
+ }
81
+ if (!inBody) {
82
+ const args = node.arguments;
83
+ if (args) {
84
+ for (const arg of args) {
85
+ if (arg?.type === 'Identifier')
86
+ state.pendingCallRefs.push({ name: arg.name, exportName, seen });
87
+ }
88
+ }
89
+ }
90
+ break;
91
+ }
92
+ case 'FunctionBody':
93
+ case 'BlockStatement':
94
+ if (signatureOnly)
95
+ return;
96
+ break;
97
+ case 'TSAsExpression':
98
+ case 'TSTypeAssertion':
99
+ case 'TSSatisfiesExpression':
100
+ if (inBody) {
101
+ if (node.expression)
102
+ _collectRefsInType(node.expression, exportName, signatureOnly, seen, inBody);
103
+ return;
104
+ }
105
+ break;
63
106
  }
64
- if (signatureOnly && (node.type === 'FunctionBody' || node.type === 'BlockStatement'))
107
+ const keys = visitorKeys[type];
108
+ if (!keys)
65
109
  return;
66
- if (node.type === 'TSTypeReference' && node.typeName.type === 'Identifier') {
67
- const name = node.typeName.name;
68
- const refs = state.referencedInExport.get(name);
69
- if (refs)
70
- refs.add(exportName);
71
- else
72
- state.referencedInExport.set(name, new Set([exportName]));
73
- }
74
- for (const key in node) {
75
- if (key === 'type' || key === 'parent')
76
- continue;
110
+ const childInBody = inBody || type === 'FunctionBody' || type === 'BlockStatement';
111
+ for (const key of keys) {
77
112
  const val = node[key];
113
+ if (!val)
114
+ continue;
78
115
  if (Array.isArray(val)) {
79
116
  for (const item of val) {
80
- if (item && typeof item === 'object' && item.type)
81
- _collectRefsInType(item, exportName, signatureOnly);
117
+ if (item)
118
+ _collectRefsInType(item, exportName, signatureOnly, seen, childInBody);
82
119
  }
83
120
  }
84
- else if (val && typeof val === 'object' && val.type) {
85
- _collectRefsInType(val, exportName, signatureOnly);
121
+ else {
122
+ _collectRefsInType(val, exportName, signatureOnly, seen, childInBody);
86
123
  }
87
124
  }
88
125
  };
@@ -167,12 +204,15 @@ const coreVisitorObject = {
167
204
  state.nsRanges.push([node.start, node.end]);
168
205
  },
169
206
  ClassDeclaration(node) {
170
- if (node.id?.name)
207
+ if (node.id?.name) {
171
208
  state.localDeclarationTypes.set(node.id.name, SYMBOL_TYPE.CLASS);
209
+ state.localDeclarations.set(node.id.name, node);
210
+ }
172
211
  },
173
212
  FunctionDeclaration(node) {
174
213
  if (node.id?.name) {
175
214
  state.localDeclarationTypes.set(node.id.name, SYMBOL_TYPE.FUNCTION);
215
+ state.localDeclarations.set(node.id.name, node);
176
216
  if (state.scopeDepth > 0)
177
217
  _addShadow(node.id.name);
178
218
  }
@@ -201,8 +241,10 @@ const coreVisitorObject = {
201
241
  }
202
242
  else {
203
243
  for (const decl of node.declarations) {
204
- if (decl.id.type === 'Identifier')
244
+ if (decl.id.type === 'Identifier') {
205
245
  state.localDeclarationTypes.set(decl.id.name, SYMBOL_TYPE.VARIABLE);
246
+ state.localDeclarations.set(decl.id.name, decl);
247
+ }
206
248
  }
207
249
  }
208
250
  },
@@ -651,6 +693,9 @@ export function walkAST(program, sourceText, filePath, ctx) {
651
693
  scopeStarts: [],
652
694
  scopeEnds: [],
653
695
  shadowScopes: new Map(),
696
+ localDeclarations: new Map(),
697
+ pendingCallRefs: [],
698
+ pendingMemberCallRefs: [],
654
699
  addExport: _addExport,
655
700
  getFix: _getFix,
656
701
  getTypeFix: _getTypeFix,
@@ -659,6 +704,35 @@ export function walkAST(program, sourceText, filePath, ctx) {
659
704
  isInNamespace: _isInNamespace,
660
705
  };
661
706
  ctx.visitor.visit(program);
707
+ while (state.pendingCallRefs.length > 0 || state.pendingMemberCallRefs.length > 0) {
708
+ while (state.pendingCallRefs.length > 0) {
709
+ const { name, exportName, seen } = state.pendingCallRefs.pop();
710
+ if (seen.has(name))
711
+ continue;
712
+ const decl = state.localDeclarations.get(name);
713
+ if (!decl)
714
+ continue;
715
+ seen.add(name);
716
+ _collectRefsInType(decl, exportName, true, seen);
717
+ }
718
+ while (state.pendingMemberCallRefs.length > 0) {
719
+ const { objectName, propertyName, exportName, seen } = state.pendingMemberCallRefs.pop();
720
+ const key = `${objectName}.${propertyName}`;
721
+ if (seen.has(key))
722
+ continue;
723
+ const decl = state.localDeclarations.get(objectName);
724
+ if (decl?.type !== 'VariableDeclarator' || decl.init?.type !== 'ObjectExpression')
725
+ continue;
726
+ const prop = decl.init.properties.find(p => p.type === 'Property' && p.key?.type === 'Identifier' && p.key.name === propertyName);
727
+ if (prop?.type !== 'Property')
728
+ continue;
729
+ const fn = prop.value;
730
+ if (fn.type !== 'ArrowFunctionExpression' && fn.type !== 'FunctionExpression')
731
+ continue;
732
+ seen.add(key);
733
+ _collectRefsInType(fn, exportName, true, seen);
734
+ }
735
+ }
662
736
  for (let i = 0; i < state.memberRefsInFile.length; i += 2) {
663
737
  const exp = state.exports.get(state.memberRefsInFile[i]);
664
738
  if (exp) {
@@ -712,6 +712,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
712
712
  entry?: string | string[] | undefined;
713
713
  project?: string | string[] | undefined;
714
714
  } | undefined;
715
+ vercel?: string | boolean | string[] | {
716
+ config?: string | string[] | undefined;
717
+ entry?: string | string[] | undefined;
718
+ project?: string | string[] | undefined;
719
+ } | undefined;
715
720
  'vercel-og'?: string | boolean | string[] | {
716
721
  config?: string | string[] | undefined;
717
722
  entry?: string | string[] | undefined;
@@ -1480,6 +1485,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1480
1485
  entry?: string | string[] | undefined;
1481
1486
  project?: string | string[] | undefined;
1482
1487
  } | undefined;
1488
+ vercel?: string | boolean | string[] | {
1489
+ config?: string | string[] | undefined;
1490
+ entry?: string | string[] | undefined;
1491
+ project?: string | string[] | undefined;
1492
+ } | undefined;
1483
1493
  'vercel-og'?: string | boolean | string[] | {
1484
1494
  config?: string | string[] | undefined;
1485
1495
  entry?: string | string[] | undefined;
package/dist/util/glob.js CHANGED
@@ -5,10 +5,7 @@ import { glob } from './glob-core.js';
5
5
  import { timerify } from './Performance.js';
6
6
  import { isAbsolute, join, relative } from './path.js';
7
7
  const prepend = (pattern, relativePath) => isAbsolute(pattern.replace(/^!/, '')) ? pattern : prependDirToPattern(relativePath, pattern);
8
- const prependDirToPatterns = (cwd, dir, patterns) => {
9
- const relativePath = relative(cwd, dir);
10
- return compact([patterns].flat().map(p => removeProductionSuffix(prepend(p, relativePath)))).sort(negatedLast);
11
- };
8
+ const prependDirToPatterns = (cwd, dir, patterns) => compact([patterns].flat().map(p => removeProductionSuffix(prepend(p, relative(cwd, dir))))).sort(negatedLast);
12
9
  export const removeProductionSuffix = (pattern) => pattern.replace(/!$/, '');
13
10
  const negatedLast = (pattern) => (pattern.startsWith('!') ? 1 : -1);
14
11
  export const prependDirToPattern = (dir, pattern) => {
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.11.0";
1
+ export declare const version = "6.12.1";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '6.11.0';
1
+ export const version = '6.12.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "6.11.0",
3
+ "version": "6.12.1",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "keywords": [
6
6
  "analysis",
@@ -80,7 +80,7 @@
80
80
  "fdir": "^6.5.0",
81
81
  "formatly": "^0.3.0",
82
82
  "get-tsconfig": "4.14.0",
83
- "jiti": "^2.6.0",
83
+ "jiti": "^2.7.0",
84
84
  "minimist": "^1.2.8",
85
85
  "oxc-parser": "^0.128.0",
86
86
  "oxc-resolver": "^11.19.1",
package/schema.json CHANGED
@@ -864,6 +864,10 @@
864
864
  "title": "unocss plugin configuration (https://knip.dev/reference/plugins/unocss)",
865
865
  "$ref": "#/definitions/plugin"
866
866
  },
867
+ "vercel": {
868
+ "title": "vercel plugin configuration (https://knip.dev/reference/plugins/vercel)",
869
+ "$ref": "#/definitions/plugin"
870
+ },
867
871
  "vercel-og": {
868
872
  "title": "vercel-og plugin configuration (https://knip.dev/reference/plugins/vercel-og)",
869
873
  "$ref": "#/definitions/plugin"