knip 6.32.3 → 6.33.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 (47) hide show
  1. package/dist/DependencyDeputy.d.ts +1 -2
  2. package/dist/DependencyDeputy.js +1 -2
  3. package/dist/ProjectPrincipal.js +1 -0
  4. package/dist/config.d.ts +2 -0
  5. package/dist/config.js +1 -0
  6. package/dist/graph/analyze.js +1 -1
  7. package/dist/graph/build.js +0 -1
  8. package/dist/graph-explorer/explorer.d.ts +1 -0
  9. package/dist/graph-explorer/explorer.js +2 -0
  10. package/dist/graph-explorer/operations/is-enumerated.d.ts +2 -0
  11. package/dist/graph-explorer/operations/is-enumerated.js +33 -0
  12. package/dist/manifest/helpers.d.ts +2 -3
  13. package/dist/manifest/helpers.js +6 -42
  14. package/dist/manifest/index.d.ts +1 -2
  15. package/dist/manifest/index.js +2 -2
  16. package/dist/plugins/dotenv/index.js +1 -8
  17. package/dist/plugins/eslint/helpers.d.ts +2 -1
  18. package/dist/plugins/eslint/helpers.js +1 -0
  19. package/dist/plugins/eslint/resolveFromAST.d.ts +1 -0
  20. package/dist/plugins/eslint/resolveFromAST.js +5 -2
  21. package/dist/plugins/eslint/types.d.ts +1 -1
  22. package/dist/plugins/moonrepo/index.js +3 -3
  23. package/dist/plugins/nuxt/index.js +25 -3
  24. package/dist/plugins/nuxt/types.d.ts +5 -1
  25. package/dist/plugins/oxlint/index.js +6 -2
  26. package/dist/plugins/oxlint/types.d.ts +2 -0
  27. package/dist/plugins/typescript/index.js +22 -5
  28. package/dist/plugins/vitest/index.js +18 -11
  29. package/dist/plugins/vitest/types.d.ts +1 -1
  30. package/dist/plugins/vitest/visitors/mock.d.ts +2 -0
  31. package/dist/plugins/vitest/visitors/mock.js +50 -0
  32. package/dist/plugins/webpack/index.js +15 -14
  33. package/dist/types/config.d.ts +1 -0
  34. package/dist/types/tsconfig-json.d.ts +6 -0
  35. package/dist/typescript/get-imports-and-exports.js +3 -0
  36. package/dist/typescript/visitors/calls.js +1 -1
  37. package/dist/typescript/visitors/members.js +56 -8
  38. package/dist/typescript/visitors/walk.d.ts +1 -0
  39. package/dist/typescript/visitors/walk.js +0 -1
  40. package/dist/util/load-config.js +6 -1
  41. package/dist/util/resolve.d.ts +1 -0
  42. package/dist/util/resolve.js +11 -0
  43. package/dist/util/scripts.d.ts +1 -0
  44. package/dist/util/scripts.js +1 -0
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +13 -9
@@ -22,9 +22,8 @@ export declare class DependencyDeputy {
22
22
  installedBinaries: Map<string, InstalledBinaries>;
23
23
  hasTypesIncluded: Map<string, Set<string>>;
24
24
  constructor({ isProduction, isStrict, isReportDependencies }: MainOptions);
25
- addWorkspace({ name, cwd, dir, manifestPath, manifestStr, manifest, ignoreDependencies: id, ignoreBinaries: ib, ignoreUnresolved: iu, }: {
25
+ addWorkspace({ name, dir, manifestPath, manifestStr, manifest, ignoreDependencies: id, ignoreBinaries: ib, ignoreUnresolved: iu, }: {
26
26
  name: string;
27
- cwd: string;
28
27
  dir: string;
29
28
  manifestPath: string;
30
29
  manifestStr: string;
@@ -26,7 +26,7 @@ export class DependencyDeputy {
26
26
  this.installedBinaries = new Map();
27
27
  this.hasTypesIncluded = new Map();
28
28
  }
29
- addWorkspace({ name, cwd, dir, manifestPath, manifestStr, manifest, ignoreDependencies: id, ignoreBinaries: ib, ignoreUnresolved: iu, }) {
29
+ addWorkspace({ name, dir, manifestPath, manifestStr, manifest, ignoreDependencies: id, ignoreBinaries: ib, ignoreUnresolved: iu, }) {
30
30
  const dependencies = Object.keys(manifest.dependencies ?? {});
31
31
  const peerDependencies = Object.keys(manifest.peerDependencies ?? {});
32
32
  const optionalDependencies = Object.keys(manifest.optionalDependencies ?? {});
@@ -45,7 +45,6 @@ export class DependencyDeputy {
45
45
  const { hostDependencies, installedBinaries, hasTypesIncluded } = getDependencyMetaData({
46
46
  packageNames,
47
47
  dir,
48
- cwd,
49
48
  });
50
49
  this.setHostDependencies(name, hostDependencies);
51
50
  this.installedBinaries.set(name, installedBinaries);
@@ -21,6 +21,7 @@ export class ProjectPrincipal {
21
21
  sourceText: '',
22
22
  addScript: () => { },
23
23
  addImport: () => { },
24
+ markImportExpressionHandled: () => { },
24
25
  addImportGlob: () => { },
25
26
  markExportRegistered: () => { },
26
27
  };
@@ -0,0 +1,2 @@
1
+ import type { KnipConfig } from './types.ts';
2
+ export declare const defineConfig: (config: KnipConfig) => KnipConfig;
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ export const defineConfig = (config) => config;
@@ -106,7 +106,7 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
106
106
  exportedItem.members.length > 0 &&
107
107
  exportedItem.type !== 'enum';
108
108
  if ((isEnumMembers || isNsMembers) && exportedItem.members.length > 0) {
109
- if (importsForExport.enumerated?.has(identifier))
109
+ if (explorer.isEnumerated(filePath, identifier))
110
110
  continue;
111
111
  if (!options.includedIssueTypes.nsTypes && importsForExport.refs.has(identifier))
112
112
  continue;
@@ -41,7 +41,6 @@ export async function build({ chief, collector, counselor, deputy, principal, is
41
41
  continue;
42
42
  deputy.addWorkspace({
43
43
  name,
44
- cwd: options.cwd,
45
44
  dir,
46
45
  manifestPath,
47
46
  manifestStr,
@@ -5,6 +5,7 @@ export declare const createGraphExplorer: (graph: ModuleGraph, entryPaths: Set<s
5
5
  treatStarAtEntryAsReferenced?: boolean;
6
6
  }) => readonly [false, string | undefined];
7
7
  hasStrictlyNsReferences: (filePath: string, identifier: string) => [boolean, (string | undefined)?];
8
+ isEnumerated: (filePath: string, identifier: string) => boolean;
8
9
  buildExportsTree: (options: {
9
10
  filePath?: string;
10
11
  identifier?: string;
@@ -6,12 +6,14 @@ import { getContention } from './operations/get-contention.js';
6
6
  import { getDependencyUsage } from './operations/get-dependency-usage.js';
7
7
  import { getUsage } from './operations/get-usage.js';
8
8
  import { hasStrictlyNsReferences } from './operations/has-strictly-ns-references.js';
9
+ import { isEnumerated } from './operations/is-enumerated.js';
9
10
  import { isReferenced } from './operations/is-referenced.js';
10
11
  import { resolveDefinition } from './operations/resolve-definition.js';
11
12
  export const createGraphExplorer = (graph, entryPaths) => {
12
13
  return {
13
14
  isReferenced: (filePath, identifier, options) => isReferenced(graph, entryPaths, filePath, identifier, options),
14
15
  hasStrictlyNsReferences: (filePath, identifier) => hasStrictlyNsReferences(graph, filePath, graph.get(filePath)?.importedBy, identifier),
16
+ isEnumerated: (filePath, identifier) => isEnumerated(graph, filePath, graph.get(filePath)?.importedBy, identifier),
15
17
  buildExportsTree: (options) => buildExportsTree(graph, entryPaths, options),
16
18
  getDependencyUsage: (pattern) => getDependencyUsage(graph, pattern),
17
19
  resolveDefinition: (filePath, identifier) => resolveDefinition(graph, filePath, identifier),
@@ -0,0 +1,2 @@
1
+ import type { ImportMaps, ModuleGraph } from '../../types/module-graph.ts';
2
+ export declare const isEnumerated: (graph: ModuleGraph, filePath: string, importsForExport: ImportMaps | undefined, identifier: string) => boolean;
@@ -0,0 +1,33 @@
1
+ import { getAliasReExportMap, getPassThroughReExportSources, getStarReExportSources } from '../visitors.js';
2
+ export const isEnumerated = (graph, filePath, importsForExport, identifier) => {
3
+ const seen = new Set();
4
+ const walkDown = (path, importMaps, id) => {
5
+ if (!importMaps || seen.has(path))
6
+ return false;
7
+ seen.add(path);
8
+ if (importMaps.enumerated?.has(id))
9
+ return true;
10
+ const follow = (sources, nextId) => {
11
+ for (const source of sources) {
12
+ if (walkDown(source, graph.get(source)?.importedBy, nextId))
13
+ return true;
14
+ }
15
+ return false;
16
+ };
17
+ const directSources = getPassThroughReExportSources(importMaps, id);
18
+ if (directSources && follow(directSources, id))
19
+ return true;
20
+ const starSources = getStarReExportSources(importMaps);
21
+ if (starSources && follow(starSources, id))
22
+ return true;
23
+ const aliasMap = getAliasReExportMap(importMaps, id);
24
+ if (aliasMap) {
25
+ for (const [alias, sources] of aliasMap) {
26
+ if (follow(sources, alias))
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ };
32
+ return walkDown(filePath, importsForExport, identifier);
33
+ };
@@ -1,9 +1,8 @@
1
- import type { Scripts } from '../types/package-json.ts';
1
+ import type { PackageJson, Scripts } from '../types/package-json.ts';
2
2
  type LoadPackageManifestOptions = {
3
3
  dir: string;
4
4
  packageName: string;
5
- cwd: string;
6
5
  };
7
- export declare const loadPackageManifest: ({ dir, packageName, cwd }: LoadPackageManifestOptions) => any;
6
+ export declare const loadPackageManifest: ({ dir, packageName }: LoadPackageManifestOptions) => PackageJson | undefined;
8
7
  export declare const getFilteredScripts: (scripts: Scripts) => Scripts[];
9
8
  export {};
@@ -1,49 +1,13 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { dirname, join } from '../util/path.js';
1
+ import { resolvePackageManifestPath } from '../util/resolve.js';
3
2
  import { _require } from '../util/require.js';
4
- const monorepoRootCache = new Map();
5
- const findMonorepoRootAbove = (startDir) => {
6
- if (monorepoRootCache.has(startDir))
7
- return monorepoRootCache.get(startDir);
8
- let current = dirname(startDir);
9
- let result;
10
- while (current !== dirname(current)) {
11
- if (existsSync(join(current, 'pnpm-workspace.yaml'))) {
12
- result = current;
13
- break;
14
- }
15
- try {
16
- const pkg = JSON.parse(readFileSync(join(current, 'package.json'), 'utf8'));
17
- if (pkg.workspaces) {
18
- result = current;
19
- break;
20
- }
21
- }
22
- catch { }
23
- current = dirname(current);
24
- }
25
- monorepoRootCache.set(startDir, result);
26
- return result;
27
- };
28
- export const loadPackageManifest = ({ dir, packageName, cwd }) => {
3
+ export const loadPackageManifest = ({ dir, packageName }) => {
4
+ const manifestPath = resolvePackageManifestPath(packageName, dir);
5
+ if (!manifestPath)
6
+ return;
29
7
  try {
30
- return _require(join(dir, 'node_modules', packageName, 'package.json'));
8
+ return _require(manifestPath);
31
9
  }
32
10
  catch { }
33
- if (dir !== cwd) {
34
- try {
35
- return _require(join(cwd, 'node_modules', packageName, 'package.json'));
36
- }
37
- catch { }
38
- return;
39
- }
40
- const root = findMonorepoRootAbove(cwd);
41
- if (root) {
42
- try {
43
- return _require(join(root, 'node_modules', packageName, 'package.json'));
44
- }
45
- catch { }
46
- }
47
11
  };
48
12
  export const getFilteredScripts = (scripts) => {
49
13
  if (!scripts)
@@ -2,9 +2,8 @@ import type { HostDependencies, InstalledBinaries } from '../types/workspace.ts'
2
2
  type Options = {
3
3
  packageNames: string[];
4
4
  dir: string;
5
- cwd: string;
6
5
  };
7
- declare const getMetaDataFromPackageJson: ({ cwd, dir, packageNames }: Options) => {
6
+ declare const getMetaDataFromPackageJson: ({ dir, packageNames }: Options) => {
8
7
  hostDependencies: HostDependencies;
9
8
  installedBinaries: InstalledBinaries;
10
9
  hasTypesIncluded: Set<string>;
@@ -1,7 +1,7 @@
1
1
  import { isDefinitelyTyped } from '../util/modules.js';
2
2
  import { timerify } from '../util/Performance.js';
3
3
  import { loadPackageManifest } from './helpers.js';
4
- const getMetaDataFromPackageJson = ({ cwd, dir, packageNames }) => {
4
+ const getMetaDataFromPackageJson = ({ dir, packageNames }) => {
5
5
  const hostDependencies = new Map();
6
6
  const installedBinaries = new Map();
7
7
  const hasTypesIncluded = new Set();
@@ -13,7 +13,7 @@ const getMetaDataFromPackageJson = ({ cwd, dir, packageNames }) => {
13
13
  installedBinaries.set(key, new Set([value]));
14
14
  };
15
15
  for (const packageName of packageNames) {
16
- const manifest = loadPackageManifest({ cwd, dir, packageName });
16
+ const manifest = loadPackageManifest({ dir, packageName });
17
17
  if (manifest) {
18
18
  const defaultBinaryName = packageName.replace(/^@[^/]+\//, '');
19
19
  const binaries = typeof manifest.bin === 'string' ? [defaultBinaryName] : Object.keys(manifest.bin ?? {});
@@ -1,14 +1,7 @@
1
1
  import { argsFrom } from '../../binaries/util.js';
2
2
  const title = 'dotenv';
3
3
  const args = {
4
- fromArgs: (parsed, args) => {
5
- if (parsed._[0])
6
- return argsFrom(args, parsed._[0]);
7
- if (!parsed['--'] || parsed['--'].length === 0)
8
- return [];
9
- const script = parsed['--'].map(arg => (arg.includes(' ') ? `"${arg}"` : arg)).join(' ');
10
- return [script];
11
- },
4
+ fromArgs: (parsed, args) => (parsed._[0] ? argsFrom(args, parsed._[0]) : (parsed['--'] ?? [])),
12
5
  };
13
6
  const plugin = {
14
7
  title,
@@ -1,6 +1,7 @@
1
1
  import type { PluginOptions } from '../../types/config.ts';
2
2
  import { type ConfigInput, type Input } from '../../util/input.ts';
3
- import type { ESLintConfig, ESLintConfigDeprecated, OverrideConfigDeprecated } from './types.ts';
3
+ import type { ESLintConfig, ESLintConfigDeprecated, OverrideConfigDeprecated, Settings } from './types.ts';
4
4
  export declare const isFlatConfig: (fileName: string) => boolean;
5
5
  export declare const getInputs: (config: ESLintConfigDeprecated | OverrideConfigDeprecated | ESLintConfig, options: PluginOptions) => (Input | ConfigInput)[];
6
+ export declare const getInputsFromSettings: (settings?: Settings) => Input[];
6
7
  export declare const resolveFormatters: (formatters: string | string[]) => Set<Input>;
@@ -80,6 +80,7 @@ const getDependenciesFromSettings = (settings = {}) => {
80
80
  }
81
81
  });
82
82
  };
83
+ export const getInputsFromSettings = (settings) => compact(getDependenciesFromSettings(settings)).map(id => toDeferResolve(id, { optional: true }));
83
84
  const builtinFormatters = new Set(['html', 'json-with-metadata', 'json', 'stylish']);
84
85
  export const resolveFormatters = (formatters) => {
85
86
  const inputs = new Set();
@@ -1,3 +1,4 @@
1
1
  import type { Program } from 'oxc-parser';
2
2
  import { type Input } from '../../util/input.ts';
3
+ export declare const getInputsFromSettingsAST: (program: Program) => Input[];
3
4
  export declare const getInputsFromFlatConfigAST: (program: Program) => Input[];
@@ -3,7 +3,7 @@ import { toDeferResolve } from '../../util/input.js';
3
3
  import { findProperty, getPropertyKey } from '../../typescript/ast-helpers.js';
4
4
  import { getStringValue } from '../../typescript/ast-nodes.js';
5
5
  import { isInternal } from '../../util/path.js';
6
- export const getInputsFromFlatConfigAST = (program) => {
6
+ export const getInputsFromSettingsAST = (program) => {
7
7
  const inputs = [];
8
8
  const addResolver = (key, resolver) => {
9
9
  if (!resolver || resolver === 'node' || isInternal(resolver))
@@ -35,6 +35,9 @@ export const getInputsFromFlatConfigAST = (program) => {
35
35
  },
36
36
  });
37
37
  visitor.visit(program);
38
- inputs.push(toDeferResolve('eslint-import-resolver-typescript', { optional: true }));
39
38
  return inputs;
40
39
  };
40
+ export const getInputsFromFlatConfigAST = (program) => [
41
+ ...getInputsFromSettingsAST(program),
42
+ toDeferResolve('eslint-import-resolver-typescript', { optional: true }),
43
+ ];
@@ -6,7 +6,7 @@ type ParserOptions = {
6
6
  presets: string[];
7
7
  };
8
8
  };
9
- type Settings = Record<string, Record<string, unknown> | string>;
9
+ export type Settings = Record<string, Record<string, unknown> | string>;
10
10
  type Rules = Record<string, string | number>;
11
11
  type BaseConfig = {
12
12
  extends?: string | string[];
@@ -1,4 +1,5 @@
1
1
  import { hasDependency } from '../../util/plugin.js';
2
+ import { toShellCommand } from '../../util/scripts.js';
2
3
  const title = 'moonrepo';
3
4
  const enablers = ['@moonrepo/cli'];
4
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -6,12 +7,11 @@ const isRootOnly = true;
6
7
  const config = ['moon.yml', '.moon/tasks.yml', '.moon/tasks/*.yml'];
7
8
  const resolveConfig = async (config, options) => {
8
9
  const tasks = config.tasks ? Object.values(config.tasks) : [];
10
+ const expand = (value) => value.replace('$workspaceRoot', options.rootCwd).replace('$projectRoot', options.cwd);
9
11
  const inputs = tasks
10
12
  .map(task => task.command)
11
13
  .filter(command => command)
12
- .map(command => (Array.isArray(command) ? command.join(' ') : command))
13
- .map(command => command.replace('$workspaceRoot', options.rootCwd))
14
- .map(command => command.replace('$projectRoot', options.cwd))
14
+ .map(command => (Array.isArray(command) ? toShellCommand(command.map(expand)) : expand(command)))
15
15
  .flatMap(command => options.getInputsFromScripts(command));
16
16
  return [...inputs];
17
17
  };
@@ -49,6 +49,26 @@ const resolveAlias = (specifier, srcDir, rootDir) => {
49
49
  return join(srcDir, specifier.slice(2));
50
50
  return specifier;
51
51
  };
52
+ const remoteSourcePrefixes = ['gh:', 'github:', 'gitlab:', 'bitbucket:', 'https://', 'http://'];
53
+ const toLayerSource = (layer) => {
54
+ if (typeof layer === 'string')
55
+ return layer;
56
+ if (Array.isArray(layer))
57
+ return layer[0];
58
+ if (layer && typeof layer === 'object' && 'source' in layer)
59
+ return layer.source;
60
+ };
61
+ const toLayerSources = (extend) => {
62
+ const sources = [];
63
+ if (!extend)
64
+ return sources;
65
+ for (const layer of Array.isArray(extend) ? extend : [extend]) {
66
+ const source = toLayerSource(layer);
67
+ if (typeof source === 'string')
68
+ sources.push(source);
69
+ }
70
+ return sources;
71
+ };
52
72
  const addAppEntries = (inputs, srcDir, serverDir, config, dir) => {
53
73
  for (const id of entry)
54
74
  inputs.push(toEntry(join(srcDir, id)));
@@ -111,15 +131,17 @@ const resolveConfig = async (localConfig, options) => {
111
131
  }
112
132
  }
113
133
  }
114
- for (const ext of localConfig.extends ?? []) {
115
- const target = resolveAlias(ext, srcDir, cwd);
134
+ for (const source of toLayerSources(localConfig.extends)) {
135
+ if (remoteSourcePrefixes.some(prefix => source.startsWith(prefix)))
136
+ continue;
137
+ const target = resolveAlias(source, srcDir, cwd);
116
138
  const resolved = isInternal(target) ? toAbsolute(target, cwd) : target;
117
139
  const configs = _syncGlob({ cwd: resolved, patterns: config });
118
140
  if (configs.length > 0)
119
141
  for (const cfg of configs)
120
142
  inputs.push(toConfig('nuxt', cfg));
121
143
  else
122
- inputs.push(toDependency(ext));
144
+ inputs.push(toDependency(source));
123
145
  }
124
146
  for (const layerConfig of findLayerConfigs(cwd)) {
125
147
  inputs.push(toConfig('nuxt', layerConfig));
@@ -1,3 +1,6 @@
1
+ type NuxtLayer = string | [string, unknown?] | {
2
+ source: string;
3
+ };
1
4
  export interface NuxtConfig {
2
5
  srcDir?: string;
3
6
  buildDir?: string;
@@ -14,7 +17,7 @@ export interface NuxtConfig {
14
17
  autoImport?: boolean;
15
18
  dirs?: string[];
16
19
  };
17
- extends?: string[];
20
+ extends?: NuxtLayer | NuxtLayer[];
18
21
  components?: Array<string | {
19
22
  path: string;
20
23
  }> | {
@@ -25,3 +28,4 @@ export interface NuxtConfig {
25
28
  css?: string[];
26
29
  alias?: Record<string, string>;
27
30
  }
31
+ export {};
@@ -3,10 +3,12 @@ import { findProperty, getPropertyValues } from '../../typescript/ast-helpers.js
3
3
  import { toDependency, toEntry } from '../../util/input.js';
4
4
  import { isInternal } from '../../util/path.js';
5
5
  import { hasDependency } from '../../util/plugin.js';
6
+ import { getInputsFromSettings } from '../eslint/helpers.js';
7
+ import { getInputsFromSettingsAST } from '../eslint/resolveFromAST.js';
6
8
  const title = 'Oxlint';
7
9
  const enablers = ['oxlint', 'vite-plus'];
8
10
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
- const config = ['.oxlintrc.json', 'oxlint.config.{ts,mts}', 'vite.config.{js,mjs,ts,cjs,mts,cts}'];
11
+ const config = ['.oxlintrc.{json,jsonc}', 'oxlint.config.{ts,mts}', 'vite.config.{js,mjs,ts,cjs,mts,cts}'];
10
12
  const isViteConfig = (configFileName) => configFileName.startsWith('vite.config.');
11
13
  const args = {
12
14
  config: true,
@@ -29,6 +31,8 @@ const resolveConfig = config => {
29
31
  for (const input of resolveJsPlugins(override.jsPlugins))
30
32
  inputs.push(input);
31
33
  }
34
+ for (const input of getInputsFromSettings(config.settings))
35
+ inputs.push(input);
32
36
  return inputs;
33
37
  };
34
38
  const resolveFromAST = (program, options) => {
@@ -51,7 +55,7 @@ const resolveFromAST = (program, options) => {
51
55
  },
52
56
  });
53
57
  visitor.visit(program);
54
- return resolveJsPlugins([...jsPlugins]);
58
+ return [...resolveJsPlugins([...jsPlugins]), ...getInputsFromSettingsAST(program)];
55
59
  };
56
60
  const plugin = {
57
61
  title,
@@ -1,3 +1,4 @@
1
+ import type { Settings } from '../eslint/types.ts';
1
2
  type JsPlugin = string | {
2
3
  name: string;
3
4
  specifier: string;
@@ -8,5 +9,6 @@ type Override = {
8
9
  export type OxlintConfig = {
9
10
  jsPlugins?: JsPlugin[];
10
11
  overrides?: Override[];
12
+ settings?: Settings;
11
13
  };
12
14
  export {};
@@ -1,12 +1,21 @@
1
1
  import { compact } from '../../util/array.js';
2
- import { toConfig, toDeferResolve, toProductionDependency } from '../../util/input.js';
2
+ import { toConfig, toDeferResolve, toDependency, toProductionDependency } from '../../util/input.js';
3
3
  import { join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
+ import { toShellCommand } from '../../util/scripts.js';
5
6
  const title = 'TypeScript';
6
7
  const enablers = ['typescript', '@typescript/native', '@typescript/native-preview'];
7
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
8
- const config = ['tsconfig.json'];
9
- const resolveConfig = async (localConfig, options) => {
9
+ const config = ['tsconfig.json', 'package.json'];
10
+ const packageJsonPath = 'typescript.contentMapper';
11
+ const resolveContentMapper = ({ exec }, options) => {
12
+ if (!Array.isArray(exec) || exec.some(arg => typeof arg !== 'string'))
13
+ return [];
14
+ return options
15
+ .getInputsFromScripts(toShellCommand(exec))
16
+ .map(input => input.type === 'entry' || input.type === 'deferResolveEntry' ? { ...input, production: true } : input);
17
+ };
18
+ const resolveTsConfig = (localConfig, options) => {
10
19
  const { compilerOptions } = localConfig;
11
20
  const extend = localConfig.extends
12
21
  ? [localConfig.extends]
@@ -16,8 +25,9 @@ const resolveConfig = async (localConfig, options) => {
16
25
  const references = localConfig.references
17
26
  ?.filter(reference => reference.path.endsWith('.json'))
18
27
  .map(reference => toConfig('typescript', reference.path, { containingFilePath: options.configFilePath })) ?? [];
28
+ const contentMappers = localConfig.contentMappers?.map(contentMapper => toDependency(contentMapper.package)) ?? [];
19
29
  if (!(compilerOptions && localConfig))
20
- return compact([...extend, ...references]);
30
+ return compact([...contentMappers, ...extend, ...references]);
21
31
  const jsx = (compilerOptions?.jsxImportSource ? [compilerOptions.jsxImportSource] : []).map(toProductionDependency);
22
32
  const types = compilerOptions.types ?? [];
23
33
  const plugins = Array.isArray(compilerOptions?.plugins)
@@ -25,6 +35,7 @@ const resolveConfig = async (localConfig, options) => {
25
35
  : [];
26
36
  const importHelpers = compilerOptions?.importHelpers ? ['tslib'] : [];
27
37
  return compact([
38
+ ...contentMappers,
28
39
  ...extend,
29
40
  ...references,
30
41
  ...types.map(id => toDeferResolve(id, { isTypeOnly: true, dir: options.cwd })),
@@ -32,19 +43,25 @@ const resolveConfig = async (localConfig, options) => {
32
43
  ...jsx,
33
44
  ]);
34
45
  };
46
+ const resolveConfig = (localConfig, options) => options.configFileName === 'package.json'
47
+ ? resolveContentMapper(localConfig, options)
48
+ : resolveTsConfig(localConfig, options);
35
49
  const args = {
36
50
  binaries: ['tsc', 'tsgo'],
37
51
  string: ['project'],
38
52
  alias: { project: ['p'] },
39
53
  config: [['project', (p) => (p.endsWith('.json') ? p : join(p, 'tsconfig.json'))]],
40
54
  };
41
- const note = "[What's up with that configurable tsconfig.json location?](/reference/faq#whats-up-with-that-configurable-tsconfigjson-location)";
55
+ const note = `[What's up with that configurable tsconfig.json location?](/reference/faq#whats-up-with-that-configurable-tsconfigjson-location)
56
+
57
+ In a content mapper package, the command in \`package.json#typescript.contentMapper.exec\` is resolved to a production entry.`;
42
58
  export const docs = { note };
43
59
  const plugin = {
44
60
  title,
45
61
  enablers,
46
62
  isEnabled,
47
63
  config,
64
+ packageJsonPath,
48
65
  resolveConfig,
49
66
  args,
50
67
  };
@@ -6,6 +6,7 @@ import { isAbsolute, isInternal, join, toAbsolute } from '../../util/path.js';
6
6
  import { hasDependency } from '../../util/plugin.js';
7
7
  import { getIndexHtmlEntries } from '../vite/helpers.js';
8
8
  import { getAliasInputs, getEnvSpecifier, getExternalReporters } from './helpers.js';
9
+ import { createVitestMockVisitor } from './visitors/mock.js';
9
10
  const title = 'Vitest';
10
11
  const enablers = ['vitest', 'vite-plus'];
11
12
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
@@ -15,7 +16,6 @@ const testEntry = ['**/*.{bench,test,test-d,spec,spec-d}.?(c|m)[jt]s?(x)'];
15
16
  const entry = [...testEntry, ...mocks];
16
17
  const benchmark = ['**/*.bench.?(c|m)[jt]s?(x)'];
17
18
  const findConfigDependencies = (localConfig, options, vitestRoot) => {
18
- const { configFileDir: dir } = options;
19
19
  const testConfig = localConfig.test;
20
20
  if (!testConfig)
21
21
  return [];
@@ -37,7 +37,9 @@ const findConfigDependencies = (localConfig, options, vitestRoot) => {
37
37
  ...toDeferResolve(specifier),
38
38
  dir: vitestRoot,
39
39
  }));
40
- const globalSetup = [testConfig.globalSetup ?? []].flat().map(specifier => ({ ...toDeferResolve(specifier), dir }));
40
+ const globalSetup = [testConfig.globalSetup ?? []]
41
+ .flat()
42
+ .map(specifier => ({ ...toDeferResolve(specifier), dir: vitestRoot }));
41
43
  const workspaceDependencies = [];
42
44
  if (testConfig.workspace !== undefined) {
43
45
  for (const workspaceConfig of testConfig.workspace) {
@@ -75,12 +77,14 @@ const getConfigs = async (localConfig) => {
75
77
  if (typeof config === 'function') {
76
78
  for (const command of ['serve', 'build']) {
77
79
  for (const mode of ['development', 'production']) {
78
- const cfg = await config({ command, mode, ssrBuild: undefined });
79
- configs.push(cfg);
80
- if (cfg.test?.projects) {
81
- for (const project of cfg.test.projects) {
82
- if (typeof project !== 'string') {
83
- configs.push(project);
80
+ for (const ssrBuild of command === 'build' ? [undefined, false, true] : [undefined]) {
81
+ const cfg = await config({ command, mode, ssrBuild });
82
+ configs.push(cfg);
83
+ if (cfg.test?.projects) {
84
+ for (const project of cfg.test.projects) {
85
+ if (typeof project !== 'string') {
86
+ configs.push(project);
87
+ }
84
88
  }
85
89
  }
86
90
  }
@@ -181,9 +185,8 @@ export const resolveConfig = async (localConfig, options) => {
181
185
  for (const dependency of findConfigDependencies(cfg, options, vitestRoot))
182
186
  inputs.add(dependency);
183
187
  const _entry = cfg.build?.lib?.entry ?? [];
184
- const deps = (typeof _entry === 'string' ? [_entry] : Object.values(_entry))
185
- .map(specifier => join(vitestRoot, specifier))
186
- .map(id => toEntry(id));
188
+ const entries = typeof _entry === 'string' ? [_entry] : Array.isArray(_entry) ? _entry : Object.values(_entry).flat();
189
+ const deps = entries.map(specifier => join(vitestRoot, specifier)).map(id => toEntry(id));
187
190
  for (const dependency of deps)
188
191
  inputs.add(dependency);
189
192
  }
@@ -215,6 +218,9 @@ const args = {
215
218
  return inputs;
216
219
  },
217
220
  };
221
+ const registerVisitors = ({ ctx, registerVisitor }) => {
222
+ registerVisitor(createVitestMockVisitor(ctx));
223
+ };
218
224
  const plugin = {
219
225
  title,
220
226
  enablers,
@@ -223,5 +229,6 @@ const plugin = {
223
229
  entry,
224
230
  resolveConfig,
225
231
  args,
232
+ registerVisitors,
226
233
  };
227
234
  export default plugin;
@@ -43,7 +43,7 @@ export interface ViteConfig extends VitestConfig {
43
43
  build?: {
44
44
  lib?: {
45
45
  entry: string | string[] | {
46
- [entryAlias: string]: string;
46
+ [entryAlias: string]: string | string[];
47
47
  };
48
48
  };
49
49
  };
@@ -0,0 +1,2 @@
1
+ import type { PluginVisitorContext, PluginVisitorObject } from '../../../types/config.ts';
2
+ export declare function createVitestMockVisitor(ctx: PluginVisitorContext): PluginVisitorObject;
@@ -0,0 +1,50 @@
1
+ import { IMPORT_FLAGS } from '../../../constants.js';
2
+ import { getStringValue, isStringLiteral } from '../../../typescript/ast-nodes.js';
3
+ import { isShadowed } from '../../../typescript/visitors/walk.js';
4
+ export function createVitestMockVisitor(ctx) {
5
+ const viNames = new Set();
6
+ return {
7
+ Program(node) {
8
+ viNames.clear();
9
+ for (const statement of node.body) {
10
+ if (statement.type !== 'ImportDeclaration' ||
11
+ !isStringLiteral(statement.source) ||
12
+ getStringValue(statement.source) !== 'vitest')
13
+ continue;
14
+ for (const specifier of statement.specifiers ?? []) {
15
+ if (specifier.type === 'ImportSpecifier' &&
16
+ specifier.imported.type === 'Identifier' &&
17
+ specifier.imported.name === 'vi') {
18
+ viNames.add(specifier.local.name);
19
+ }
20
+ }
21
+ }
22
+ },
23
+ CallExpression(node) {
24
+ const argument = node.arguments[0];
25
+ const factory = node.arguments[1];
26
+ const factoryBody = factory?.type === 'ArrowFunctionExpression' &&
27
+ factory.body.type === 'ParenthesizedExpression' &&
28
+ factory.body.expression.type === 'ObjectExpression'
29
+ ? factory.body.expression
30
+ : undefined;
31
+ if (argument?.type !== 'ImportExpression' ||
32
+ !isStringLiteral(argument.source) ||
33
+ factory?.type !== 'ArrowFunctionExpression' ||
34
+ !factoryBody ||
35
+ factory.async ||
36
+ factory.params.length > 0 ||
37
+ factoryBody.properties.some(property => property.type === 'SpreadElement') ||
38
+ node.callee.type !== 'MemberExpression' ||
39
+ node.callee.computed ||
40
+ node.callee.object.type !== 'Identifier' ||
41
+ !viNames.has(node.callee.object.name) ||
42
+ isShadowed(node.callee.object.name, node.callee.object.start) ||
43
+ node.callee.property.type !== 'Identifier' ||
44
+ node.callee.property.name !== 'mock')
45
+ return;
46
+ ctx.markImportExpressionHandled(argument.start);
47
+ ctx.addImport(getStringValue(argument.source), argument.source.start, IMPORT_FLAGS.SIDE_EFFECTS);
48
+ },
49
+ };
50
+ }
@@ -105,20 +105,21 @@ export const findWebpackDependenciesFromConfig = async (config, options) => {
105
105
  }
106
106
  }
107
107
  }
108
- if (typeof opts.entry === 'string')
109
- entries.push(opts.entry);
110
- else if (Array.isArray(opts.entry))
111
- entries.push(...opts.entry);
112
- else if (typeof opts.entry === 'object') {
113
- for (const entry of Object.values(opts.entry)) {
114
- if (typeof entry === 'string')
115
- entries.push(entry);
116
- else if (Array.isArray(entry))
117
- entries.push(...entry);
118
- else if (typeof entry === 'function')
119
- entries.push(entry());
120
- else if (entry && typeof entry === 'object' && 'filename' in entry)
121
- entries.push(entry['filename']);
108
+ const entry = typeof opts.entry === 'function' ? await opts.entry() : opts.entry;
109
+ if (typeof entry === 'string')
110
+ entries.push(entry);
111
+ else if (Array.isArray(entry))
112
+ entries.push(...entry);
113
+ else if (typeof entry === 'object') {
114
+ for (const item of Object.values(entry)) {
115
+ if (typeof item === 'string')
116
+ entries.push(item);
117
+ else if (Array.isArray(item))
118
+ entries.push(...item);
119
+ else if (typeof item === 'function')
120
+ entries.push(item());
121
+ else if (item && typeof item === 'object' && 'import' in item)
122
+ entries.push(...[item.import].flat());
122
123
  }
123
124
  }
124
125
  if (entries.length === 0 && opts.context)
@@ -138,6 +138,7 @@ export type PluginVisitorContext = {
138
138
  sourceText: string;
139
139
  addScript: (script: string) => void;
140
140
  addImport: (specifier: string, pos: number, modifiers: number) => void;
141
+ markImportExpressionHandled: (pos: number) => void;
141
142
  addImportGlob: (patterns: string[], options?: {
142
143
  base?: string;
143
144
  filter?: RegExp;
@@ -8,7 +8,13 @@ export interface TsConfigJson {
8
8
  }>;
9
9
  [key: string]: unknown;
10
10
  };
11
+ contentMappers?: {
12
+ package: string;
13
+ }[];
11
14
  references?: Array<{
12
15
  path: string;
13
16
  }>;
14
17
  }
18
+ export interface ContentMapperManifest {
19
+ exec?: string[];
20
+ }
@@ -25,6 +25,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
25
25
  const specifierExportNames = new Set();
26
26
  const scripts = new Set();
27
27
  const importGlobs = [];
28
+ const handledImportExpressions = new Set();
28
29
  const importAliases = new Map();
29
30
  const addImportAlias = (aliasName, id, importFilePath) => {
30
31
  const aliases = importAliases.get(aliasName);
@@ -278,6 +279,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
278
279
  pluginCtx.sourceText = sourceText;
279
280
  pluginCtx.addScript = (s) => scripts.add(s);
280
281
  pluginCtx.addImport = (spec, pos, mod) => addImport(spec, undefined, undefined, undefined, pos, mod);
282
+ pluginCtx.markImportExpressionHandled = (pos) => handledImportExpressions.add(pos);
281
283
  pluginCtx.addImportGlob = (patterns, opts) => importGlobs.push({ patterns, base: opts?.base, filter: opts?.filter });
282
284
  pluginCtx.markExportRegistered = (name) => registeredCustomElements.add(name);
283
285
  }
@@ -311,6 +313,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
311
313
  resolveModule,
312
314
  programFiles,
313
315
  entryFiles,
316
+ handledImportExpressions,
314
317
  visitor,
315
318
  getJSDocTags,
316
319
  });
@@ -202,7 +202,7 @@ export function handleCallExpression(node, s) {
202
202
  addValue(internalImport.import, OPAQUE, s.filePath);
203
203
  else {
204
204
  internalImport.refs.add(arg.name);
205
- (internalImport.enumerated ??= new Set()).add(arg.name);
205
+ (internalImport.enumerated ??= new Set()).add(_import.importedName);
206
206
  }
207
207
  }
208
208
  }
@@ -2,6 +2,12 @@ import { OPAQUE } from '../../constants.js';
2
2
  import { addValue } from '../../util/module-graph.js';
3
3
  import { getStringValue, isStringLiteral } from '../ast-nodes.js';
4
4
  import { isShadowed } from './walk.js';
5
+ function markWholeObjectRead(internalImport, id) {
6
+ (internalImport.enumerated ??= new Set()).add(id);
7
+ }
8
+ function isNumericKey(value) {
9
+ return value != null && Number.isFinite(Number(value)) && String(Number(value)) === value;
10
+ }
5
11
  export function handleMemberExpression(node, s) {
6
12
  if (node.object.type === 'MemberExpression' && node.object.object.type === 'MemberExpression') {
7
13
  s.chainedMemberExprs.add(node.object);
@@ -18,12 +24,21 @@ export function handleMemberExpression(node, s) {
18
24
  memberName = node.property.name;
19
25
  }
20
26
  else if (node.computed && isStringLiteral(node.property)) {
21
- memberName = getStringValue(node.property);
27
+ const value = getStringValue(node.property);
28
+ if (!_import.isNamespace && isNumericKey(value)) {
29
+ markWholeObjectRead(internalImport, _import.importedName);
30
+ return;
31
+ }
32
+ memberName = value;
22
33
  }
23
34
  else if (node.computed && _import.isNamespace) {
24
35
  addValue(internalImport.import, OPAQUE, s.filePath);
25
36
  return;
26
37
  }
38
+ else if (node.computed) {
39
+ markWholeObjectRead(internalImport, _import.importedName);
40
+ return;
41
+ }
27
42
  if (memberName) {
28
43
  if (_import.isDynamicImport) {
29
44
  addValue(internalImport.import, memberName, s.filePath);
@@ -44,18 +59,51 @@ export function handleMemberExpression(node, s) {
44
59
  if (aliases) {
45
60
  s.accessedAliases.add(localName);
46
61
  let memberName;
62
+ let isWholeRead = false;
47
63
  if (node.computed === false && node.property.type === 'Identifier') {
48
64
  memberName = node.property.name;
49
65
  }
50
66
  else if (node.computed && isStringLiteral(node.property)) {
51
- memberName = getStringValue(node.property);
67
+ const value = getStringValue(node.property);
68
+ if (isNumericKey(value))
69
+ isWholeRead = true;
70
+ else
71
+ memberName = value;
52
72
  }
53
- if (memberName) {
54
- for (const alias of aliases) {
55
- const internalImport = s.internal.get(alias.filePath);
56
- if (internalImport) {
57
- s.addNsMemberRefs(internalImport, alias.id, memberName);
58
- }
73
+ else if (node.computed) {
74
+ isWholeRead = true;
75
+ }
76
+ for (const alias of aliases) {
77
+ const internalImport = s.internal.get(alias.filePath);
78
+ if (!internalImport)
79
+ continue;
80
+ if (isWholeRead) {
81
+ const origin = s.localImportMap.get(alias.id);
82
+ markWholeObjectRead(internalImport, origin?.importedName ?? alias.id);
83
+ }
84
+ else if (memberName) {
85
+ s.addNsMemberRefs(internalImport, alias.id, memberName);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ if (node.computed &&
91
+ node.object.type === 'MemberExpression' &&
92
+ !node.object.computed &&
93
+ node.object.object.type === 'Identifier' &&
94
+ node.object.property.type === 'Identifier') {
95
+ const rootName = node.object.object.name;
96
+ if (!isShadowed(rootName, node.object.object.start)) {
97
+ const _import = s.localImportMap.get(rootName);
98
+ if (_import?.isNamespace) {
99
+ const internalImport = s.internal.get(_import.filePath);
100
+ if (internalImport) {
101
+ const mid = node.object.property.name;
102
+ const value = isStringLiteral(node.property) ? getStringValue(node.property) : undefined;
103
+ if (value !== undefined && !isNumericKey(value))
104
+ s.addNsMemberRefs(internalImport, rootName, `${mid}.${value}`);
105
+ else
106
+ markWholeObjectRead(internalImport, mid);
59
107
  }
60
108
  }
61
109
  }
@@ -43,6 +43,7 @@ interface WalkContext {
43
43
  resolveModule: ResolveModule;
44
44
  programFiles: Set<string>;
45
45
  entryFiles: Set<string>;
46
+ handledImportExpressions: Set<number>;
46
47
  visitor: Visitor;
47
48
  getJSDocTags: (nodeStart: number) => Set<string>;
48
49
  }
@@ -726,7 +726,6 @@ function walkAST(program, sourceText, filePath, hasModuleSyntax, ctx) {
726
726
  sourceText,
727
727
  isJS,
728
728
  isModuleFile: isExternalModule(program, hasModuleSyntax),
729
- handledImportExpressions: new Set(),
730
729
  bareExprRefs: new Set(),
731
730
  accessedAliases: new Set(),
732
731
  nsContainers: new Map(),
@@ -13,12 +13,17 @@ const unwrapFunction = async (maybeFunction, options) => {
13
13
  }
14
14
  return maybeFunction;
15
15
  };
16
+ const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
16
17
  export async function loadResolvedConfigFile(configPath, options) {
17
18
  const loadedValue = await _load(configPath);
19
+ let config;
18
20
  try {
19
- return await unwrapFunction(loadedValue, options);
21
+ config = await unwrapFunction(loadedValue, options);
20
22
  }
21
23
  catch (_error) {
22
24
  throw new ConfigurationError(`Error running the function from ${configPath}`);
23
25
  }
26
+ if (!isObject(config))
27
+ throw new ConfigurationError(`Expected an object as configuration from ${configPath}`);
28
+ return config;
24
29
  }
@@ -1,4 +1,5 @@
1
1
  export declare const extensionAlias: Record<string, string[]>;
2
+ export declare const resolvePackageManifestPath: (packageName: string, baseDir: string) => string | undefined;
2
3
  export declare const _resolveModuleSync: (specifier: string, basePath: string) => string | undefined;
3
4
  declare const resolveDeclarationSync: (specifier: string, containingFile: string) => {
4
5
  path: string;
@@ -23,6 +23,17 @@ const declarationResolver = new ResolverFactory({
23
23
  nodePath: false,
24
24
  });
25
25
  resolverInstances.push(declarationResolver);
26
+ const packageManifestResolver = new ResolverFactory({
27
+ extensions: ['.json'],
28
+ exportsFields: [],
29
+ nodePath: false,
30
+ });
31
+ resolverInstances.push(packageManifestResolver);
32
+ export const resolvePackageManifestPath = (packageName, baseDir) => {
33
+ const resolved = packageManifestResolver.sync(baseDir, `${packageName}/package.json`);
34
+ if (resolved.path)
35
+ return toPosix(resolved.path);
36
+ };
26
37
  const createSyncModuleResolver = (extensions, tsConfigFile) => {
27
38
  const baseOptions = {
28
39
  extensions,
@@ -3,5 +3,6 @@ export interface ScriptCommand {
3
3
  binary: string;
4
4
  args: string[];
5
5
  }
6
+ export declare const toShellCommand: (argv: string[]) => string;
6
7
  export declare function walkCommands(node: Node): Generator<Command>;
7
8
  export declare const getScriptCommands: (script: string) => ScriptCommand[];
@@ -1,6 +1,7 @@
1
1
  import { parse } from 'unbash';
2
2
  import { extractBinary } from './modules.js';
3
3
  const spawningBinaries = new Set(['c8', 'cross-env', 'retry-cli']);
4
+ export const toShellCommand = (argv) => argv.map(arg => `'${arg.replaceAll("'", `'\\''`)}'`).join(' ');
4
5
  export function* walkCommands(node) {
5
6
  switch (node.type) {
6
7
  case 'Command':
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.32.3";
1
+ export declare const version = "6.33.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '6.32.3';
1
+ export const version = '6.33.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "6.32.3",
3
+ "version": "6.33.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "keywords": [
6
6
  "analysis",
@@ -71,6 +71,10 @@
71
71
  "types": "./dist/types.d.ts",
72
72
  "default": "./dist/index.js"
73
73
  },
74
+ "./config": {
75
+ "types": "./dist/config.d.ts",
76
+ "default": "./dist/config.js"
77
+ },
74
78
  "./session": {
75
79
  "types": "./dist/session/index.d.ts",
76
80
  "default": "./dist/session/index.js"
@@ -78,27 +82,27 @@
78
82
  },
79
83
  "dependencies": {
80
84
  "fdir": "^6.5.0",
81
- "formatly": "^0.3.0",
82
- "get-tsconfig": "4.14.1",
85
+ "formatly": "^0.7.0",
86
+ "get-tsconfig": "4.14.3",
83
87
  "jiti": "^2.7.0",
84
- "oxc-parser": "^0.143.0",
88
+ "oxc-parser": "^0.147.0",
85
89
  "oxc-resolver": "11.24.2",
86
- "picomatch": "^4.0.5",
87
- "smol-toml": "^1.7.1",
90
+ "picomatch": "^4.0.7",
91
+ "smol-toml": "^1.8.0",
88
92
  "strip-json-comments": "5.0.3",
89
93
  "tinyglobby": "^0.2.17",
90
- "unbash": "^4.0.9",
94
+ "unbash": "^4.0.10",
91
95
  "yaml": "^2.9.0",
92
96
  "zod": "^4.4.3"
93
97
  },
94
98
  "devDependencies": {
95
99
  "@jest/types": "^30.4.1",
96
- "@types/bun": "^1.3.14",
100
+ "@types/bun": "^1.4.0",
97
101
  "@types/picomatch": "^4.0.3",
98
102
  "@types/webpack": "^5.28.5",
99
103
  "codeclimate-types": "^0.3.1",
100
104
  "prettier": "^3.9.6",
101
- "tsx": "^4.23.11",
105
+ "tsx": "^4.23.12",
102
106
  "typescript": "7.0.2"
103
107
  },
104
108
  "engines": {