knip 6.35.1 → 6.37.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 (109) hide show
  1. package/dist/ConfigurationChief.d.ts +20 -2
  2. package/dist/ConfigurationChief.js +15 -1
  3. package/dist/DependencyDeputy.d.ts +0 -2
  4. package/dist/DependencyDeputy.js +1 -17
  5. package/dist/WorkspaceWorker.js +7 -6
  6. package/dist/binaries/bash-parser.js +1 -1
  7. package/dist/binaries/command.js +21 -10
  8. package/dist/binaries/fallback.js +5 -4
  9. package/dist/binaries/plugins.js +4 -4
  10. package/dist/binaries/resolvers/bun.js +2 -2
  11. package/dist/binaries/resolvers/find.js +5 -4
  12. package/dist/binaries/resolvers/index.d.ts +2 -1
  13. package/dist/binaries/resolvers/index.js +3 -2
  14. package/dist/binaries/resolvers/npm.js +46 -4
  15. package/dist/binaries/resolvers/npx.js +8 -4
  16. package/dist/binaries/resolvers/nub.js +3 -2
  17. package/dist/binaries/resolvers/pnpm.js +17 -10
  18. package/dist/binaries/resolvers/yarn.js +1 -1
  19. package/dist/binaries/util.d.ts +4 -1
  20. package/dist/binaries/util.js +2 -0
  21. package/dist/compilers/compilers.js +1 -1
  22. package/dist/compilers/scss.js +2 -2
  23. package/dist/graph-explorer/cache.d.ts +3 -0
  24. package/dist/graph-explorer/cache.js +6 -0
  25. package/dist/graph-explorer/explorer.d.ts +1 -0
  26. package/dist/graph-explorer/explorer.js +2 -0
  27. package/dist/graph-explorer/operations/build-exports-tree.js +14 -2
  28. package/dist/graph-explorer/operations/get-ambiguous-star-export.d.ts +8 -0
  29. package/dist/graph-explorer/operations/get-ambiguous-star-export.js +11 -0
  30. package/dist/graph-explorer/operations/get-contention.js +265 -122
  31. package/dist/graph-explorer/operations/resolve-export-origins.d.ts +32 -0
  32. package/dist/graph-explorer/operations/resolve-export-origins.js +255 -0
  33. package/dist/graph-explorer/utils.js +8 -0
  34. package/dist/manifest/index.js +1 -3
  35. package/dist/plugins/ava/index.js +1 -1
  36. package/dist/plugins/eslint/helpers.d.ts +2 -1
  37. package/dist/plugins/eslint/helpers.js +59 -14
  38. package/dist/plugins/eslint/index.js +2 -2
  39. package/dist/plugins/eslint/resolveFromAST.js +17 -11
  40. package/dist/plugins/eslint/types.d.ts +3 -3
  41. package/dist/plugins/github-actions/index.js +1 -1
  42. package/dist/plugins/graphql-codegen/index.js +15 -4
  43. package/dist/plugins/graphql-codegen/types.d.ts +11 -1
  44. package/dist/plugins/graphql-codegen/types.js +6 -0
  45. package/dist/plugins/husky/index.js +1 -1
  46. package/dist/plugins/index.d.ts +2 -0
  47. package/dist/plugins/index.js +4 -0
  48. package/dist/plugins/lefthook/index.js +1 -1
  49. package/dist/plugins/mise/scripts.js +5 -5
  50. package/dist/plugins/next/index.js +39 -5
  51. package/dist/plugins/node/index.js +6 -0
  52. package/dist/plugins/tailwind/compiler.js +2 -2
  53. package/dist/plugins/tailwind/index.js +7 -1
  54. package/dist/plugins/taskfile/index.js +1 -1
  55. package/dist/plugins/tauri/index.js +1 -1
  56. package/dist/plugins/textlint/helpers.d.ts +4 -0
  57. package/dist/plugins/textlint/helpers.js +39 -0
  58. package/dist/plugins/textlint/index.d.ts +3 -0
  59. package/dist/plugins/textlint/index.js +52 -0
  60. package/dist/plugins/textlint/types.d.ts +5 -0
  61. package/dist/plugins/textlint/types.js +1 -0
  62. package/dist/plugins/travis/index.js +1 -1
  63. package/dist/plugins/typedoc/index.js +3 -2
  64. package/dist/plugins/typedoc/types.d.ts +2 -2
  65. package/dist/plugins/varlock/index.d.ts +3 -0
  66. package/dist/plugins/varlock/index.js +31 -0
  67. package/dist/plugins/varlock/parse.d.ts +11 -0
  68. package/dist/plugins/varlock/parse.js +185 -0
  69. package/dist/plugins/varlock/scan.d.ts +2 -0
  70. package/dist/plugins/varlock/scan.js +78 -0
  71. package/dist/plugins/vite-plus/resolveFromAST.js +1 -1
  72. package/dist/plugins/vitest/index.js +4 -2
  73. package/dist/reporters/trace.js +30 -1
  74. package/dist/schema/configuration.d.ts +33 -0
  75. package/dist/schema/configuration.js +2 -0
  76. package/dist/schema/plugins.d.ts +10 -0
  77. package/dist/schema/plugins.js +2 -0
  78. package/dist/session/build-maps.js +9 -1
  79. package/dist/session/file-descriptor.js +0 -2
  80. package/dist/session/index.d.ts +1 -1
  81. package/dist/session/types.d.ts +18 -0
  82. package/dist/types/PluginNames.d.ts +2 -2
  83. package/dist/types/PluginNames.js +2 -0
  84. package/dist/types/config.d.ts +5 -1
  85. package/dist/types/module-graph.d.ts +3 -0
  86. package/dist/types/package-json.d.ts +1 -1
  87. package/dist/typescript/get-imports-and-exports.js +43 -9
  88. package/dist/typescript/visitors/exports.js +9 -4
  89. package/dist/typescript/visitors/walk.d.ts +1 -1
  90. package/dist/typescript/visitors/walk.js +4 -1
  91. package/dist/util/array.d.ts +1 -1
  92. package/dist/util/array.js +5 -1
  93. package/dist/util/create-input-handler.js +3 -3
  94. package/dist/util/create-options.d.ts +28 -2
  95. package/dist/util/file-entry-cache.js +1 -1
  96. package/dist/util/glob-core.d.ts +1 -0
  97. package/dist/util/glob-core.js +11 -3
  98. package/dist/util/jiti.js +1 -0
  99. package/dist/util/modules.d.ts +2 -0
  100. package/dist/util/modules.js +3 -1
  101. package/dist/util/package-json.d.ts +185 -183
  102. package/dist/util/parse-args.d.ts +2 -0
  103. package/dist/util/parse-args.js +6 -1
  104. package/dist/util/url.d.ts +1 -0
  105. package/dist/util/url.js +2 -0
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/package.json +5 -5
  109. package/schema.json +20 -0
@@ -2,11 +2,11 @@ import { parse } from 'unbash';
2
2
  import { getDependenciesFromCommand, getInputsFromNodeOptions } from '../../binaries/command.js';
3
3
  import { spawningBinaries } from '../../binaries/fallback.js';
4
4
  import { isWrapper } from '../../binaries/plugins.js';
5
- import KnownResolvers from '../../binaries/resolvers/index.js';
5
+ import { isPackageManager } from '../../binaries/resolvers/index.js';
6
6
  import { toScript } from '../../binaries/util.js';
7
7
  import { SCRIPT_INTERPOLATION } from '../../constants.js';
8
8
  import { isBinary } from '../../util/input.js';
9
- import { extractBinary } from '../../util/modules.js';
9
+ import { extractBinary, isRelativeNodeModulesBin } from '../../util/modules.js';
10
10
  import { walkCommands } from '../../util/scripts.js';
11
11
  export const getInputsFromMiseScript = (script, options, hasLocalBinPath) => {
12
12
  const inputs = [];
@@ -62,10 +62,10 @@ export const getInputsFromMiseScript = (script, options, hasLocalBinPath) => {
62
62
  if (!name || !word || definedFunctions.has(name))
63
63
  continue;
64
64
  const binary = extractBinary(name);
65
- const isPackageManager = binary in KnownResolvers && binary !== 'find';
66
- const isExplicit = isPackageManager || name.startsWith('./') || /^(?:\.\.?\/)*node_modules\/\.bin\//.test(name);
65
+ const isPackageCommand = isPackageManager(binary);
66
+ const isExplicit = isPackageCommand || name.startsWith('./') || isRelativeNodeModulesBin(name);
67
67
  const isLocal = hasLocalBinPath && !command.prefix.some(assignment => assignment.name === 'PATH');
68
- const isWrapperCommand = !isPackageManager && isWrapper(binary);
68
+ const isWrapperCommand = !isPackageCommand && isWrapper(binary);
69
69
  if (!isExplicit && !isLocal && !isWrapperCommand && binary !== 'node' && binary !== 'find')
70
70
  continue;
71
71
  let commandInputs;
@@ -1,6 +1,8 @@
1
- import { collectPropertyValues } from '../../typescript/ast-helpers.js';
1
+ import { Visitor } from 'oxc-parser';
2
+ import { findProperty, getPropertyValues } from '../../typescript/ast-helpers.js';
3
+ import { getStringValue } from '../../typescript/ast-nodes.js';
2
4
  import { isDirectory } from '../../util/fs.js';
3
- import { toConfig, toProductionEntry } from '../../util/input.js';
5
+ import { toConfig, toDeferResolve, toProductionEntry } from '../../util/input.js';
4
6
  import { join } from '../../util/path.js';
5
7
  import { hasDependency } from '../../util/plugin.js';
6
8
  const title = 'Next.js';
@@ -38,10 +40,42 @@ const getEntryFilePatterns = (pageExtensions = defaultPageExtensions, cwd) => {
38
40
  };
39
41
  const production = getEntryFilePatterns();
40
42
  const resolveFromAST = (program, { configFileDir }) => {
41
- const pageExtensions = [...collectPropertyValues(program, 'pageExtensions')];
42
- const extensions = pageExtensions.length > 0 ? pageExtensions : defaultPageExtensions;
43
+ const pageExtensions = new Set();
44
+ const loaders = new Set();
45
+ const collectLoaders = (node) => {
46
+ if (node?.type === 'ArrayExpression') {
47
+ for (const element of node.elements)
48
+ collectLoaders(element);
49
+ }
50
+ else {
51
+ const loader = getStringValue(node) ?? getStringValue(findProperty(node, 'loader'));
52
+ if (loader)
53
+ loaders.add(loader);
54
+ const nested = findProperty(node, 'loaders');
55
+ if (nested?.type === 'ArrayExpression')
56
+ collectLoaders(nested);
57
+ }
58
+ };
59
+ const visitor = new Visitor({
60
+ ObjectExpression(node) {
61
+ for (const extension of getPropertyValues(node, 'pageExtensions'))
62
+ pageExtensions.add(extension);
63
+ const rules = findProperty(findProperty(node, 'turbopack'), 'rules');
64
+ if (rules?.type !== 'ObjectExpression')
65
+ return;
66
+ for (const rule of rules.properties) {
67
+ if (rule.type === 'Property')
68
+ collectLoaders(rule.value);
69
+ }
70
+ },
71
+ });
72
+ visitor.visit(program);
73
+ const extensions = pageExtensions.size > 0 ? [...pageExtensions] : defaultPageExtensions;
43
74
  const patterns = [...getEntryFilePatterns(extensions, configFileDir), 'next-env.d.ts'];
44
- return patterns.map(id => toProductionEntry(join(configFileDir, id)));
75
+ const inputs = patterns.map(id => toProductionEntry(join(configFileDir, id)));
76
+ for (const loader of loaders)
77
+ inputs.push(toDeferResolve(loader));
78
+ return inputs;
45
79
  };
46
80
  const commands = new Set(['dev', 'build', 'start']);
47
81
  const args = {
@@ -38,12 +38,18 @@ const args = {
38
38
  resolve: ['test-reporter'],
39
39
  boolean: [
40
40
  'deprecation',
41
+ 'enable-source-maps',
42
+ 'experimental-detect-module',
43
+ 'experimental-json-modules',
41
44
  'experimental-strip-types',
42
45
  'experimental-transform-types',
46
+ 'experimental-vm-modules',
47
+ 'expose-gc',
43
48
  'harmony',
44
49
  'inspect-brk',
45
50
  'inspect-wait',
46
51
  'inspect',
52
+ 'openssl-legacy-provider',
47
53
  'test-only',
48
54
  'test',
49
55
  'warnings',
@@ -1,5 +1,5 @@
1
+ import { hasUrlScheme } from '../../util/url.js';
1
2
  const directiveMatcher = /"(?:\\(?:\r\n|[\s\S]|$)|[^"\\\r\n\f])*(?:"|[\r\n\f]|$)|'(?:\\(?:\r\n|[\s\S]|$)|[^'\\\r\n\f])*(?:'|[\r\n\f]|$)|\/\*[\s\S]*?(?:\*\/|$)|@(?:(?:import|config|plugin)\s+['"]([^'"]+)['"]|import\s+url\(\s*(?:['"]([^'"]+)['"]|([^'")\s]+))\s*\))[^;]*;/g;
2
- const urlSchemeMatcher = /^[a-z][a-z\d+.-]*:/i;
3
3
  const compiler = (text) => {
4
4
  if (!text.includes('@import') && !text.includes('@config') && !text.includes('@plugin'))
5
5
  return '';
@@ -10,7 +10,7 @@ const compiler = (text) => {
10
10
  while ((match = directiveMatcher.exec(text))) {
11
11
  const url = match[2] ?? match[3];
12
12
  const specifier = match[1] ?? url;
13
- if (!specifier || (url && (url.startsWith('//') || urlSchemeMatcher.test(url))))
13
+ if (!specifier || (url && (url.startsWith('//') || hasUrlScheme(url))))
14
14
  continue;
15
15
  imports.push(`import _$${index++} from '${specifier}';`);
16
16
  }
@@ -2,7 +2,13 @@ import { toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
3
  import compiler from './compiler.js';
4
4
  const title = 'Tailwind';
5
- const enablers = ['tailwindcss', '@tailwindcss/vite', '@tailwindcss/postcss', '@tailwindcss/cli'];
5
+ const enablers = [
6
+ 'tailwindcss',
7
+ '@tailwindcss/vite',
8
+ '@tailwindcss/webpack',
9
+ '@tailwindcss/postcss',
10
+ '@tailwindcss/cli',
11
+ ];
6
12
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
13
  const entry = ['tailwind.config.{js,cjs,mjs,ts,cts,mts}'];
8
14
  const registerCompilers = ({ registerCompiler, hasDependency }) => {
@@ -97,7 +97,7 @@ const resolveConfig = async (localConfig, options) => {
97
97
  for (const task of Object.values(localConfig.tasks)) {
98
98
  for (const script of extractScriptsFromTask(task)) {
99
99
  for (const input of getInputsFromScripts([script], {
100
- knownBinsOnly: true,
100
+ optionalBinaries: true,
101
101
  containingFilePath: configFilePath,
102
102
  })) {
103
103
  if (isProduction)
@@ -26,7 +26,7 @@ const resolveConfig = async (localConfig, options) => {
26
26
  continue;
27
27
  const dir = typeof command === 'string' || !command.cwd ? options.cwd : join(options.cwd, command.cwd);
28
28
  const manifest = options.getManifest(dir) ?? options.manifest;
29
- for (const input of options.getInputsFromScripts(script, { knownBinsOnly: true, cwd: dir, manifest })) {
29
+ for (const input of options.getInputsFromScripts(script, { optionalBinaries: true, cwd: dir, manifest })) {
30
30
  inputs.push({ ...input, dir });
31
31
  }
32
32
  }
@@ -0,0 +1,4 @@
1
+ import type { Manifest } from '../../util/package-json.ts';
2
+ export declare const toRuleDependency: (key: string, manifest: Manifest, cwd: string) => import("../../util/input.ts").Input;
3
+ export declare const toFilterRuleDependency: (key: string, manifest: Manifest, cwd: string) => import("../../util/input.ts").Input;
4
+ export declare const toPluginDependency: (key: string, manifest: Manifest, cwd: string) => import("../../util/input.ts").Input;
@@ -0,0 +1,39 @@
1
+ import { toDependency, toDeferResolveEntry } from '../../util/input.js';
2
+ import { isInternal, toAbsolute } from '../../util/path.js';
3
+ const RULE_PREFIX = 'textlint-rule-';
4
+ const PRESET_PREFIX = 'textlint-rule-preset-';
5
+ const FILTER_RULE_PREFIX = 'textlint-filter-rule-';
6
+ const PLUGIN_PREFIX = 'textlint-plugin-';
7
+ const createFullPackageName = (prefix, name) => {
8
+ if (name.charAt(0) === '@') {
9
+ const scopedName = name.slice(name.indexOf('/') + 1);
10
+ if (scopedName !== prefix && !scopedName.startsWith(`${prefix}-`)) {
11
+ return name.replace(/^@([^/]+)\/(.*)$/, `@$1/${prefix}$2`);
12
+ }
13
+ }
14
+ return `${prefix}${name}`;
15
+ };
16
+ const hasPrefix = (prefix, name) => (name.charAt(0) === '@' ? name.slice(name.indexOf('/') + 1) : name).startsWith(prefix);
17
+ const isDeclared = (manifest, name) => Boolean(manifest.dependencies?.[name] ??
18
+ manifest.devDependencies?.[name] ??
19
+ manifest.optionalDependencies?.[name] ??
20
+ manifest.peerDependencies?.[name]);
21
+ const toPackageDependency = (prefix, name, candidates, manifest) => toDependency(candidates.find(candidate => isDeclared(manifest, candidate)) ??
22
+ (hasPrefix(prefix, name) ? name : createFullPackageName(prefix, name)));
23
+ const isPresetRuleKey = (key) => key.startsWith('preset-') ||
24
+ key.startsWith(PRESET_PREFIX) ||
25
+ (key.charAt(0) === '@' && (key.includes('/preset-') || key.includes(`/${PRESET_PREFIX}`)));
26
+ const toPresetDependency = (key, manifest) => {
27
+ const name = key.replace(/^preset-/, '').replace(/^@([^/]+)\/preset-(.*)$/, '@$1/$2');
28
+ const candidates = [`${PRESET_PREFIX}${name}`, name, createFullPackageName(PRESET_PREFIX, name), key];
29
+ return toPackageDependency(PRESET_PREFIX, name, candidates, manifest);
30
+ };
31
+ const toModuleDependency = (prefix, key, manifest) => toPackageDependency(prefix, key, [createFullPackageName(prefix, key), key], manifest);
32
+ const toLocalEntry = (key, cwd) => toDeferResolveEntry(toAbsolute(key, cwd));
33
+ export const toRuleDependency = (key, manifest, cwd) => {
34
+ if (isInternal(key))
35
+ return toLocalEntry(key, cwd);
36
+ return isPresetRuleKey(key) ? toPresetDependency(key, manifest) : toModuleDependency(RULE_PREFIX, key, manifest);
37
+ };
38
+ export const toFilterRuleDependency = (key, manifest, cwd) => isInternal(key) ? toLocalEntry(key, cwd) : toModuleDependency(FILTER_RULE_PREFIX, key, manifest);
39
+ export const toPluginDependency = (key, manifest, cwd) => isInternal(key) ? toLocalEntry(key, cwd) : toModuleDependency(PLUGIN_PREFIX, key, manifest);
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,52 @@
1
+ import { isInternal } from '../../util/path.js';
2
+ import { hasDependency } from '../../util/plugin.js';
3
+ import { toFilterRuleDependency, toPluginDependency, toRuleDependency } from './helpers.js';
4
+ const title = 'textlint';
5
+ const enablers = ['textlint'];
6
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
+ const packageJsonPath = 'textlint';
8
+ const config = ['package.json', '.textlintrc', '.textlintrc.{json,yaml,yml,js,cjs}'];
9
+ const resolveConfig = (config, { cwd, manifest }) => {
10
+ const inputs = [];
11
+ for (const [key, options] of Object.entries(config.rules ?? {})) {
12
+ if (options)
13
+ inputs.push(toRuleDependency(key, manifest, cwd));
14
+ }
15
+ for (const key of Object.keys(config.filters ?? {}))
16
+ inputs.push(toFilterRuleDependency(key, manifest, cwd));
17
+ const plugins = Array.isArray(config.plugins) ? config.plugins : Object.keys(config.plugins ?? {});
18
+ for (const key of plugins)
19
+ inputs.push(toPluginDependency(key, manifest, cwd));
20
+ return inputs;
21
+ };
22
+ const toList = (value) => [value ?? []]
23
+ .flat()
24
+ .flatMap(item => String(item).split(','))
25
+ .map(item => item.trim())
26
+ .filter(Boolean);
27
+ const args = {
28
+ config: true,
29
+ string: ['rule', 'preset', 'plugin'],
30
+ resolveInputs: (parsed, { cwd, manifest }) => {
31
+ const inputs = [];
32
+ for (const rule of toList(parsed.rule))
33
+ inputs.push(toRuleDependency(rule, manifest, cwd));
34
+ for (const preset of toList(parsed.preset)) {
35
+ const key = isInternal(preset) || preset.includes('preset-') ? preset : `preset-${preset}`;
36
+ inputs.push(toRuleDependency(key, manifest, cwd));
37
+ }
38
+ for (const plugin of toList(parsed.plugin))
39
+ inputs.push(toPluginDependency(plugin, manifest, cwd));
40
+ return inputs;
41
+ },
42
+ };
43
+ const plugin = {
44
+ title,
45
+ enablers,
46
+ isEnabled,
47
+ packageJsonPath,
48
+ config,
49
+ resolveConfig,
50
+ args,
51
+ };
52
+ export default plugin;
@@ -0,0 +1,5 @@
1
+ export type TextlintConfig = {
2
+ rules?: Record<string, unknown>;
3
+ filters?: Record<string, unknown>;
4
+ plugins?: string[] | Record<string, unknown>;
5
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -11,7 +11,7 @@ const resolveConfig = async (config, options) => {
11
11
  const beforeInstall = config.before_install ?? [];
12
12
  const beforeScript = config.before_script ?? [];
13
13
  const scripts = [beforeDeploy, beforeInstall, beforeScript].flat();
14
- return options.getInputsFromScripts(scripts, { knownBinsOnly: true });
14
+ return options.getInputsFromScripts(scripts, { optionalBinaries: true });
15
15
  };
16
16
  const plugin = {
17
17
  title,
@@ -1,3 +1,4 @@
1
+ import { arrayify } from '../../util/array.js';
1
2
  import { toDeferResolve, toEntry } from '../../util/input.js';
2
3
  import { join } from '../../util/path.js';
3
4
  import { hasDependency } from '../../util/plugin.js';
@@ -15,8 +16,8 @@ const config = [
15
16
  ];
16
17
  const resolveConfig = (config, options) => {
17
18
  const cfg = 'typedocOptions' in config ? config.typedocOptions : config;
18
- const plugins = cfg?.plugin ?? [];
19
- const themes = cfg?.theme ?? [];
19
+ const plugins = arrayify(cfg?.plugin);
20
+ const themes = arrayify(cfg?.theme);
20
21
  const inputs = [...plugins, ...themes].map(id => toDeferResolve(id));
21
22
  for (const file of [cfg?.customCss, cfg?.customJs]) {
22
23
  if (file)
@@ -1,6 +1,6 @@
1
1
  export type TypeDocConfig = {
2
- plugin?: string[];
3
- theme?: string[];
2
+ plugin?: string | string[];
3
+ theme?: string | string[];
4
4
  customCss?: string;
5
5
  customJs?: string;
6
6
  };
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,31 @@
1
+ import { arrayify } from '../../util/array.js';
2
+ import { get } from '../../util/object.js';
3
+ import { hasDependency } from '../../util/plugin.js';
4
+ import { scanVarlockFiles } from './scan.js';
5
+ const title = 'Varlock';
6
+ const enablers = ['varlock'];
7
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
+ const getLoadPaths = (manifest) => arrayify(get(manifest, 'varlock.loadPath'));
9
+ const resolve = options => {
10
+ const loadPaths = getLoadPaths(options.manifest);
11
+ return scanVarlockFiles(loadPaths.length > 0 ? loadPaths : ['.'], options.cwd);
12
+ };
13
+ const args = {
14
+ alias: { path: ['p'] },
15
+ string: ['path', 'env'],
16
+ fromArgs: parsed => (parsed._[0] === 'run' ? (parsed['--'] ?? []) : []),
17
+ resolveInputs: (parsed, { cwd, manifest }) => {
18
+ const paths = arrayify(parsed.path);
19
+ const loadPaths = getLoadPaths(manifest);
20
+ const environment = arrayify(parsed.env).at(-1);
21
+ return scanVarlockFiles(paths.length > 0 ? paths : environment ? (loadPaths.length > 0 ? loadPaths : ['.']) : [], cwd);
22
+ },
23
+ };
24
+ const plugin = {
25
+ title,
26
+ enablers,
27
+ isEnabled,
28
+ args,
29
+ resolve,
30
+ };
31
+ export default plugin;
@@ -0,0 +1,11 @@
1
+ type Directive = {
2
+ name: 'import' | 'plugin';
3
+ descriptor: string;
4
+ enabled?: boolean | null;
5
+ allowMissing?: boolean | null;
6
+ };
7
+ export declare const parseVarlockFile: (source: string) => {
8
+ directives: Directive[];
9
+ disabled: boolean;
10
+ };
11
+ export {};
@@ -0,0 +1,185 @@
1
+ const pairs = { '(': ')', '[': ']', '{': '}' };
2
+ const getRootComments = (source) => {
3
+ const comments = [];
4
+ let block = [];
5
+ let hasConfigItem = false;
6
+ for (const line of source.replace(/^\uFEFF/, '').split(/\r?\n/)) {
7
+ if (!line.trim()) {
8
+ comments.push(...block);
9
+ block = [];
10
+ continue;
11
+ }
12
+ const match = line.match(/^\s*#(.*)$/);
13
+ if (!match) {
14
+ hasConfigItem = true;
15
+ break;
16
+ }
17
+ const content = match[1].trimStart();
18
+ if (/^[-=*#]{3}/.test(content)) {
19
+ comments.push(...block);
20
+ block = [];
21
+ }
22
+ else {
23
+ block.push(content);
24
+ }
25
+ }
26
+ if (!hasConfigItem)
27
+ comments.push(...block);
28
+ return comments.join('\n');
29
+ };
30
+ const readQuoted = (value, start) => {
31
+ const quote = value[start];
32
+ let result = '';
33
+ for (let index = start + 1; index < value.length; index++) {
34
+ const char = value[index];
35
+ if (char === quote)
36
+ return { value: result, end: index + 1 };
37
+ if (char === '\\' && value[index + 1] === quote) {
38
+ result += quote;
39
+ index++;
40
+ }
41
+ else {
42
+ result += char;
43
+ }
44
+ }
45
+ };
46
+ const readArguments = (value, start) => {
47
+ const args = [];
48
+ const stack = [pairs[value[start]]];
49
+ let argument = '';
50
+ for (let index = start + 1; index < value.length; index++) {
51
+ const char = value[index];
52
+ if (char === '"' || char === "'" || char === '`') {
53
+ const quoted = readQuoted(value, index);
54
+ if (!quoted)
55
+ return;
56
+ argument += value.slice(index, quoted.end);
57
+ index = quoted.end - 1;
58
+ }
59
+ else if (char === '#') {
60
+ index = value.indexOf('\n', index);
61
+ if (index === -1)
62
+ return;
63
+ argument += ' ';
64
+ }
65
+ else if (pairs[char]) {
66
+ stack.push(pairs[char]);
67
+ argument += char;
68
+ }
69
+ else if (char === stack.at(-1)) {
70
+ stack.pop();
71
+ if (stack.length === 0) {
72
+ args.push(argument.trim());
73
+ return { args, end: index + 1 };
74
+ }
75
+ argument += char;
76
+ }
77
+ else if (char === ',' && stack.length === 1) {
78
+ args.push(argument.trim());
79
+ argument = '';
80
+ }
81
+ else {
82
+ argument += char;
83
+ }
84
+ }
85
+ };
86
+ const readValueEnd = (value, start) => {
87
+ let index = start;
88
+ while (index < value.length && !/[\s#]/.test(value[index])) {
89
+ const char = value[index];
90
+ if (char === '"' || char === "'" || char === '`') {
91
+ const quoted = readQuoted(value, index);
92
+ if (!quoted)
93
+ return value.length;
94
+ index = quoted.end;
95
+ }
96
+ else if (pairs[char]) {
97
+ const nested = readArguments(value, index);
98
+ if (!nested)
99
+ return value.length;
100
+ index = nested.end;
101
+ }
102
+ else {
103
+ index++;
104
+ }
105
+ }
106
+ return index;
107
+ };
108
+ const getStaticString = (value) => {
109
+ const trimmed = value.trim();
110
+ const quote = trimmed[0];
111
+ if (quote === '"' || quote === "'" || quote === '`') {
112
+ const quoted = readQuoted(trimmed, 0);
113
+ return quoted?.end === trimmed.length ? quoted.value : undefined;
114
+ }
115
+ if (!trimmed || /[\s,)]/.test(trimmed) || trimmed.includes('$') || /^[a-z][a-z\d_]*\(/i.test(trimmed))
116
+ return;
117
+ if (/^(?:true|false|undefined)$/i.test(trimmed))
118
+ return;
119
+ const number = Number(trimmed);
120
+ return Number.isFinite(number) && String(number) === trimmed ? undefined : trimmed;
121
+ };
122
+ const getBoolean = (value) => {
123
+ const trimmed = value.trim();
124
+ return trimmed === 'true' ? true : trimmed === 'false' ? false : null;
125
+ };
126
+ export const parseVarlockFile = (source) => {
127
+ const directives = [];
128
+ const value = getRootComments(source);
129
+ let disabled = false;
130
+ for (let index = 0; index < value.length;) {
131
+ while (value[index] === ' ' || value[index] === '\t')
132
+ index++;
133
+ if (value[index] !== '@') {
134
+ index = value.indexOf('\n', index) + 1 || value.length;
135
+ continue;
136
+ }
137
+ while (index < value.length && value[index] !== '\n' && value[index] !== '#') {
138
+ if (value[index] !== '@' || !/[a-z]/i.test(value[index + 1] ?? '')) {
139
+ index++;
140
+ continue;
141
+ }
142
+ let nameEnd = index + 2;
143
+ while (/[a-z\d_]/i.test(value[nameEnd] ?? ''))
144
+ nameEnd++;
145
+ const name = value.slice(index + 1, nameEnd);
146
+ let cursor = nameEnd;
147
+ while (value[cursor] === ' ' || value[cursor] === '\t')
148
+ cursor++;
149
+ if (value[cursor] === '(') {
150
+ const result = readArguments(value, cursor);
151
+ if (!result)
152
+ break;
153
+ if (name === 'plugin' || name === 'import') {
154
+ const descriptor = getStaticString(result.args[0] ?? '');
155
+ if (descriptor !== undefined) {
156
+ const directive = { name, descriptor };
157
+ for (const arg of result.args.slice(1)) {
158
+ const separator = arg.indexOf('=');
159
+ if (separator === -1)
160
+ continue;
161
+ const key = arg.slice(0, separator).trim();
162
+ if (key === 'enabled' || key === 'allowMissing')
163
+ directive[key] = getBoolean(arg.slice(separator + 1));
164
+ }
165
+ directives.push(directive);
166
+ }
167
+ }
168
+ index = result.end;
169
+ }
170
+ else if (value[cursor] === '=') {
171
+ const end = readValueEnd(value, cursor + 1);
172
+ if (name === 'disable')
173
+ disabled ||= getBoolean(value.slice(cursor + 1, end)) === true;
174
+ index = end;
175
+ }
176
+ else {
177
+ if (name === 'disable')
178
+ disabled = true;
179
+ index = nameEnd;
180
+ }
181
+ }
182
+ index = value.indexOf('\n', index) + 1 || value.length;
183
+ }
184
+ return { directives, disabled };
185
+ };
@@ -0,0 +1,2 @@
1
+ import type { Input } from '../../util/input.ts';
2
+ export declare const scanVarlockFiles: (paths: string[], cwd: string) => Input[];
@@ -0,0 +1,78 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { toDeferResolve, toDeferResolveProductionEntry, toDependency } from '../../util/input.js';
4
+ import { isDirectory, isFile, tryRealpath } from '../../util/fs.js';
5
+ import { getPackageNameFromModuleSpecifier } from '../../util/modules.js';
6
+ import { dirname, isInternal, join, toAbsolute } from '../../util/path.js';
7
+ import { isGitIgnored } from '../../util/glob-core.js';
8
+ import { debugLog } from '../../util/debug.js';
9
+ import { hasUrlScheme } from '../../util/url.js';
10
+ import { parseVarlockFile } from './parse.js';
11
+ const resolvePath = (path, cwd) => path.startsWith('~/') ? join(homedir(), path.slice(2)) : toAbsolute(path, cwd);
12
+ const isExternalUrl = (path) => path.startsWith('//') || hasUrlScheme(path);
13
+ const isLocalPath = (path) => path.startsWith('~/') || isInternal(path);
14
+ const expandLoadPath = (path) => {
15
+ if (!isDirectory(path))
16
+ return [path];
17
+ try {
18
+ const paths = [];
19
+ for (const name of readdirSync(path))
20
+ if (name === '.env' || name.startsWith('.env.'))
21
+ paths.push(join(path, name));
22
+ return paths;
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ };
28
+ export const scanVarlockFiles = (paths, cwd) => {
29
+ const inputs = [];
30
+ const queue = [];
31
+ for (const path of paths)
32
+ queue.push(...expandLoadPath(resolvePath(path, cwd)));
33
+ const visited = new Set();
34
+ for (const path of queue) {
35
+ if (!isFile(path) || isGitIgnored(path))
36
+ continue;
37
+ const realPath = tryRealpath(path);
38
+ if (visited.has(realPath))
39
+ continue;
40
+ visited.add(realPath);
41
+ let source;
42
+ try {
43
+ source = readFileSync(realPath, 'utf8');
44
+ }
45
+ catch (error) {
46
+ debugLog('Varlock', `Unable to read ${realPath} (${error instanceof Error ? error.message : error})`);
47
+ continue;
48
+ }
49
+ const { directives, disabled } = parseVarlockFile(source);
50
+ if (disabled)
51
+ continue;
52
+ for (const { name, descriptor, enabled, allowMissing } of directives) {
53
+ if (!descriptor || descriptor.includes('$') || isExternalUrl(descriptor) || enabled === false)
54
+ continue;
55
+ if (name === 'plugin') {
56
+ if (isLocalPath(descriptor)) {
57
+ inputs.push(toDeferResolveProductionEntry(descriptor.startsWith('~/') ? resolvePath(descriptor, dirname(realPath)) : descriptor, { containingFilePath: realPath }));
58
+ }
59
+ else {
60
+ const packageName = getPackageNameFromModuleSpecifier(descriptor);
61
+ if (packageName) {
62
+ inputs.push({ ...toDependency(packageName, { containingFilePath: realPath }), production: true });
63
+ }
64
+ }
65
+ continue;
66
+ }
67
+ if (!isLocalPath(descriptor))
68
+ continue;
69
+ const importPath = resolvePath(descriptor, dirname(realPath));
70
+ if (isFile(importPath) || isDirectory(importPath))
71
+ queue.push(...expandLoadPath(importPath));
72
+ else if (allowMissing !== true && allowMissing !== null && enabled !== null) {
73
+ inputs.push(toDeferResolve(descriptor, { containingFilePath: realPath }));
74
+ }
75
+ }
76
+ }
77
+ return inputs;
78
+ };
@@ -30,7 +30,7 @@ export const resolveFromAST = (program, options) => {
30
30
  visitor.visit(program);
31
31
  const inputs = [];
32
32
  for (const command of commands) {
33
- for (const input of options.getInputsFromScripts(command, { knownBinsOnly: true }))
33
+ for (const input of options.getInputsFromScripts(command, { optionalBinaries: true }))
34
34
  inputs.push(input);
35
35
  }
36
36
  return inputs;
@@ -143,7 +143,9 @@ export const resolveConfig = async (localConfig, options) => {
143
143
  for (const entry of await getIndexHtmlEntries(viteRoot, publicDir))
144
144
  inputs.add(entry);
145
145
  }
146
- const vitestRoot = toAbsolute(cfg.test?.root ?? '.', options.cwd);
146
+ const vitestRoot = cfg.test?.root || !options.isResolvedConfigFile
147
+ ? toAbsolute(cfg.test?.root ?? '.', options.cwd)
148
+ : toAbsolute('.', options.configFileDir);
147
149
  const dir = cfg.test?.dir ? toAbsolute(cfg.test.dir, vitestRoot) : vitestRoot;
148
150
  if (cfg.test) {
149
151
  if (cfg.test?.include) {
@@ -189,7 +191,7 @@ export const resolveConfig = async (localConfig, options) => {
189
191
  inputs.add(dependency);
190
192
  const _entry = cfg.build?.lib?.entry ?? [];
191
193
  const entries = typeof _entry === 'string' ? [_entry] : Array.isArray(_entry) ? _entry : Object.values(_entry).flat();
192
- const deps = entries.map(specifier => join(vitestRoot, specifier)).map(id => toEntry(id));
194
+ const deps = entries.map(specifier => join(viteRoot, specifier)).map(id => toEntry(id));
193
195
  for (const dependency of deps)
194
196
  inputs.add(dependency);
195
197
  }