knip 6.39.0 → 6.41.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 (86) hide show
  1. package/dist/ConfigurationChief.d.ts +24 -0
  2. package/dist/DependencyDeputy.d.ts +1 -0
  3. package/dist/DependencyDeputy.js +28 -2
  4. package/dist/IssueCollector.js +13 -15
  5. package/dist/IssueFixer.js +1 -1
  6. package/dist/WorkspaceWorker.d.ts +3 -4
  7. package/dist/WorkspaceWorker.js +25 -45
  8. package/dist/binaries/bash-parser.js +10 -4
  9. package/dist/binaries/command.d.ts +1 -1
  10. package/dist/binaries/command.js +14 -8
  11. package/dist/compilers/compilers.js +1 -1
  12. package/dist/graph/build.js +33 -17
  13. package/dist/manifest/index.d.ts +1 -0
  14. package/dist/manifest/index.js +5 -0
  15. package/dist/plugins/capacitor/index.js +1 -1
  16. package/dist/plugins/commitlint/index.js +34 -9
  17. package/dist/plugins/eslint/resolveFromAST.d.ts +0 -1
  18. package/dist/plugins/eslint/resolveFromAST.js +1 -1
  19. package/dist/plugins/expo/helpers.js +1 -1
  20. package/dist/plugins/expo/index.js +4 -24
  21. package/dist/plugins/expo-router/index.d.ts +3 -0
  22. package/dist/plugins/expo-router/index.js +32 -0
  23. package/dist/plugins/flue/index.d.ts +3 -0
  24. package/dist/plugins/flue/index.js +42 -0
  25. package/dist/plugins/index.d.ts +4 -0
  26. package/dist/plugins/index.js +8 -0
  27. package/dist/plugins/jasmine/index.d.ts +3 -0
  28. package/dist/plugins/jasmine/index.js +55 -0
  29. package/dist/plugins/jasmine/types.d.ts +7 -0
  30. package/dist/plugins/jasmine/types.js +1 -0
  31. package/dist/plugins/jest/helpers.d.ts +1 -0
  32. package/dist/plugins/jest/helpers.js +2 -0
  33. package/dist/plugins/jest/index.js +20 -11
  34. package/dist/plugins/mise/scripts.js +32 -10
  35. package/dist/plugins/moonrepo/index.js +2 -1
  36. package/dist/plugins/nx/index.js +6 -2
  37. package/dist/plugins/osls/index.d.ts +3 -0
  38. package/dist/plugins/osls/index.js +13 -0
  39. package/dist/plugins/oxlint/index.d.ts +3 -0
  40. package/dist/plugins/oxlint/index.js +4 -31
  41. package/dist/plugins/oxlint/types.d.ts +1 -0
  42. package/dist/plugins/playwright/index.js +17 -0
  43. package/dist/plugins/playwright/types.d.ts +5 -0
  44. package/dist/plugins/postcss/index.js +5 -1
  45. package/dist/plugins/react-native/index.js +1 -1
  46. package/dist/plugins/rsbuild/index.js +58 -6
  47. package/dist/plugins/rsbuild/types.d.ts +24 -1
  48. package/dist/plugins/rspack/index.d.ts +3 -1
  49. package/dist/plugins/rspack/index.js +1 -1
  50. package/dist/plugins/rstest/types.d.ts +1 -5
  51. package/dist/plugins/serverless-framework/index.d.ts +4 -1
  52. package/dist/plugins/serverless-framework/index.js +40 -7
  53. package/dist/plugins/serverless-framework/types.d.ts +4 -2
  54. package/dist/plugins/simple-git-hooks/index.js +1 -1
  55. package/dist/plugins/sveltejs-package/helpers.js +7 -44
  56. package/dist/plugins/vitest/index.js +16 -2
  57. package/dist/plugins/vitest/types.d.ts +2 -0
  58. package/dist/run.js +2 -0
  59. package/dist/schema/configuration.d.ts +60 -0
  60. package/dist/schema/plugins.d.ts +20 -0
  61. package/dist/schema/plugins.js +4 -0
  62. package/dist/types/PluginNames.d.ts +2 -2
  63. package/dist/types/PluginNames.js +4 -0
  64. package/dist/types/workspace.d.ts +1 -0
  65. package/dist/typescript/ast-nodes.js +291 -0
  66. package/dist/typescript/resolve-module-names.js +15 -4
  67. package/dist/typescript/visitors/walk.js +12 -0
  68. package/dist/util/create-options.d.ts +40 -0
  69. package/dist/util/filter-transitive-dependencies.d.ts +2 -0
  70. package/dist/util/filter-transitive-dependencies.js +38 -0
  71. package/dist/util/glob-cache.d.ts +2 -2
  72. package/dist/util/glob-core.js +70 -47
  73. package/dist/util/glob.js +15 -10
  74. package/dist/util/load-tsconfig.d.ts +1 -1
  75. package/dist/util/load-tsconfig.js +21 -11
  76. package/dist/util/module-graph.js +9 -4
  77. package/dist/util/package-json.d.ts +1 -354
  78. package/dist/util/package-json.js +56 -10
  79. package/dist/util/scripts.d.ts +3 -2
  80. package/dist/util/scripts.js +9 -3
  81. package/dist/util/to-source-path.d.ts +1 -1
  82. package/dist/util/to-source-path.js +7 -5
  83. package/dist/version.d.ts +1 -1
  84. package/dist/version.js +1 -1
  85. package/package.json +9 -10
  86. package/schema.json +16 -0
@@ -237,6 +237,11 @@ export declare class ConfigurationChief {
237
237
  entry?: string | string[] | undefined;
238
238
  project?: string | string[] | undefined;
239
239
  } | undefined;
240
+ 'expo-router'?: string | boolean | string[] | {
241
+ config?: string | string[] | undefined;
242
+ entry?: string | string[] | undefined;
243
+ project?: string | string[] | undefined;
244
+ } | undefined;
240
245
  'expressive-code'?: string | boolean | string[] | {
241
246
  config?: string | string[] | undefined;
242
247
  entry?: string | string[] | undefined;
@@ -247,6 +252,11 @@ export declare class ConfigurationChief {
247
252
  entry?: string | string[] | undefined;
248
253
  project?: string | string[] | undefined;
249
254
  } | undefined;
255
+ flue?: string | boolean | string[] | {
256
+ config?: string | string[] | undefined;
257
+ entry?: string | string[] | undefined;
258
+ project?: string | string[] | undefined;
259
+ } | undefined;
250
260
  fumadocs?: string | boolean | string[] | {
251
261
  config?: string | string[] | undefined;
252
262
  entry?: string | string[] | undefined;
@@ -292,6 +302,11 @@ export declare class ConfigurationChief {
292
302
  entry?: string | string[] | undefined;
293
303
  project?: string | string[] | undefined;
294
304
  } | undefined;
305
+ jasmine?: string | boolean | string[] | {
306
+ config?: string | string[] | undefined;
307
+ entry?: string | string[] | undefined;
308
+ project?: string | string[] | undefined;
309
+ } | undefined;
295
310
  jest?: string | boolean | string[] | {
296
311
  config?: string | string[] | undefined;
297
312
  entry?: string | string[] | undefined;
@@ -497,6 +512,11 @@ export declare class ConfigurationChief {
497
512
  entry?: string | string[] | undefined;
498
513
  project?: string | string[] | undefined;
499
514
  } | undefined;
515
+ osls?: string | boolean | string[] | {
516
+ config?: string | string[] | undefined;
517
+ entry?: string | string[] | undefined;
518
+ project?: string | string[] | undefined;
519
+ } | undefined;
500
520
  oxfmt?: string | boolean | string[] | {
501
521
  config?: string | string[] | undefined;
502
522
  entry?: string | string[] | undefined;
@@ -1066,8 +1086,10 @@ export declare class ConfigurationChief {
1066
1086
  eve?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1067
1087
  execa?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1068
1088
  expo?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1089
+ "expo-router"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1069
1090
  "expressive-code"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1070
1091
  fast?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1092
+ flue?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1071
1093
  fumadocs?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1072
1094
  gatsby?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1073
1095
  "github-action"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -1077,6 +1099,7 @@ export declare class ConfigurationChief {
1077
1099
  hardhat?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1078
1100
  husky?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1079
1101
  "i18next-parser"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1102
+ jasmine?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1080
1103
  jest?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1081
1104
  karma?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1082
1105
  knex?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -1118,6 +1141,7 @@ export declare class ConfigurationChief {
1118
1141
  "openapi-ts"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1119
1142
  openclaw?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1120
1143
  orval?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1144
+ osls?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1121
1145
  oxfmt?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1122
1146
  oxlint?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
1123
1147
  "panda-css"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -40,6 +40,7 @@ export declare class DependencyDeputy {
40
40
  peerDependencies: DependencySet;
41
41
  optionalPeerDependencies: DependencySet;
42
42
  requiredPeerDependencies: DependencyArray;
43
+ uninstalledOptionalDependencies: DependencySet;
43
44
  allDependencies: DependencySet;
44
45
  engines: Record<string, string>;
45
46
  isPrivate: boolean;
@@ -38,15 +38,25 @@ export class DependencyDeputy {
38
38
  const requiredPeerDependencies = peerDependencies.filter(dep => !optionalPeerDependencies.has(dep));
39
39
  const devDependencies = Object.keys(manifest.devDependencies ?? {});
40
40
  const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies, ...optionalDependencies];
41
- const packageNames = [...dependencies, ...peerDependencies, ...(this.isProduction ? [] : devDependencies)];
41
+ const uninstalledOptionalDependencies = new Set();
42
+ const packageNames = [
43
+ ...dependencies,
44
+ ...peerDependencies,
45
+ ...optionalDependencies,
46
+ ...(this.isProduction ? [] : devDependencies),
47
+ ];
42
48
  if (this.isReportDependencies) {
43
- const { hostDependencies, installedBinaries, hasTypesIncluded } = getDependencyMetaData({
49
+ const { hostDependencies, installedBinaries, hasTypesIncluded, uninstalledDependencies } = getDependencyMetaData({
44
50
  packageNames,
45
51
  dir,
46
52
  });
47
53
  this.setHostDependencies(name, hostDependencies);
48
54
  this.installedBinaries.set(name, installedBinaries);
49
55
  this.hasTypesIncluded.set(name, hasTypesIncluded);
56
+ for (const dependency of optionalDependencies) {
57
+ if (uninstalledDependencies.has(dependency))
58
+ uninstalledOptionalDependencies.add(dependency);
59
+ }
50
60
  }
51
61
  const ignoreDependencies = id.flatMap(id => filterIsProduction(id, this.isProduction)).map(toRegexOrString);
52
62
  const ignoreBinaries = ib.flatMap(ib => filterIsProduction(ib, this.isProduction)).map(toRegexOrString);
@@ -66,6 +76,7 @@ export class DependencyDeputy {
66
76
  peerDependencies: new Set(peerDependencies),
67
77
  optionalPeerDependencies,
68
78
  requiredPeerDependencies,
79
+ uninstalledOptionalDependencies,
69
80
  allDependencies: new Set(allDependencies),
70
81
  engines: manifest.engines ?? {},
71
82
  isPrivate: Boolean(manifest.private),
@@ -171,6 +182,21 @@ export class DependencyDeputy {
171
182
  }
172
183
  }
173
184
  }
185
+ const optionalDependencies = new Set();
186
+ for (const name of workspaceNames) {
187
+ const manifest = this._manifests.get(name);
188
+ if (!manifest)
189
+ continue;
190
+ for (const dependency of manifest.uninstalledOptionalDependencies) {
191
+ const defaultBinaryName = dependency.replace(/^@[^/]+\//, '');
192
+ if (defaultBinaryName === binaryName) {
193
+ optionalDependencies.add(dependency);
194
+ this.addReferencedDependency(name, dependency);
195
+ }
196
+ }
197
+ }
198
+ if (optionalDependencies.size)
199
+ return optionalDependencies;
174
200
  return;
175
201
  }
176
202
  isInDependencies(workspaceName, packageName, isDevOnly) {
@@ -1,7 +1,6 @@
1
1
  import picomatch from 'picomatch';
2
2
  import { ROOT_WORKSPACE_NAME } from './constants.js';
3
3
  import { partition } from './util/array.js';
4
- import { prependDirToPattern } from './util/glob.js';
5
4
  import { initCounters, initIssues } from './util/issue-initializers.js';
6
5
  import { relative } from './util/path.js';
7
6
  const createMatcher = (patterns) => {
@@ -82,23 +81,22 @@ export class IssueCollector {
82
81
  return;
83
82
  const issueTypePatterns = new Map();
84
83
  for (const [pattern, issueTypes] of Object.entries(ignoreIssues)) {
85
- const id = prependDirToPattern(this.cwd, pattern);
86
84
  for (const issueType of issueTypes) {
87
85
  if (!issueTypePatterns.has(issueType)) {
88
86
  issueTypePatterns.set(issueType, []);
89
87
  }
90
- issueTypePatterns.get(issueType)?.push(id);
88
+ issueTypePatterns.get(issueType)?.push(pattern);
91
89
  }
92
90
  }
93
91
  for (const [issueType, patterns] of issueTypePatterns) {
94
92
  this.issueMatchers.set(issueType, picomatch(patterns, { dot: true }));
95
93
  }
96
94
  }
97
- shouldIgnoreIssue(filePath, issueType) {
95
+ shouldIgnoreIssue(relativePath, issueType) {
98
96
  const matcher = this.issueMatchers.get(issueType);
99
97
  if (!matcher)
100
98
  return false;
101
- return matcher(filePath);
99
+ return matcher(relativePath);
102
100
  }
103
101
  addFileCounts({ processed, unused }) {
104
102
  this.counters.processed += processed;
@@ -110,17 +108,17 @@ export class IssueCollector {
110
108
  continue;
111
109
  if (this.referencedFiles.has(filePath))
112
110
  continue;
113
- if (this.isMatch(filePath)) {
114
- this.markUsedPatterns(filePath, this.unusedIgnorePatterns);
111
+ const symbol = relative(this.cwd, filePath);
112
+ if (this.isMatch(symbol)) {
113
+ this.markUsedPatterns(symbol, this.unusedIgnorePatterns);
115
114
  continue;
116
115
  }
117
- if (this.isFileMatch(filePath)) {
118
- this.markUsedPatterns(filePath, this.unusedIgnoreFilesPatterns);
116
+ if (this.isFileMatch(symbol)) {
117
+ this.markUsedPatterns(symbol, this.unusedIgnoreFilesPatterns);
119
118
  continue;
120
119
  }
121
- if (this.shouldIgnoreIssue(filePath, 'files'))
120
+ if (this.shouldIgnoreIssue(symbol, 'files'))
122
121
  continue;
123
- const symbol = relative(this.cwd, filePath);
124
122
  this.issues.files[symbol] = {
125
123
  [symbol]: { type: 'files', filePath, symbol, workspace: '', severity: this.rules.files, fixes: [] },
126
124
  };
@@ -131,15 +129,15 @@ export class IssueCollector {
131
129
  addIssue(issue) {
132
130
  if (!this.workspaceFilter(issue.filePath))
133
131
  return;
134
- if (this.isMatch(issue.filePath)) {
135
- this.markUsedPatterns(issue.filePath, this.unusedIgnorePatterns);
132
+ const key = relative(this.cwd, issue.filePath);
133
+ if (this.isMatch(key)) {
134
+ this.markUsedPatterns(key, this.unusedIgnorePatterns);
136
135
  return;
137
136
  }
138
- if (this.shouldIgnoreIssue(issue.filePath, issue.type))
137
+ if (this.shouldIgnoreIssue(key, issue.type))
139
138
  return;
140
139
  if (this.rules[issue.type] === 'off')
141
140
  return;
142
- const key = relative(this.cwd, issue.filePath);
143
141
  issue.severity = this.rules[issue.type];
144
142
  const issues = this.issues[issue.type];
145
143
  issues[key] = issues[key] ?? {};
@@ -21,7 +21,7 @@ export const fix = async (issues, counters, options) => {
21
21
  }
22
22
  if (options.isFormat) {
23
23
  const report = await formatly(Array.from(touchedFiles));
24
- if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
24
+ if (report.ran && report.result.runner !== 'dry-run' && report.result.code === 0) {
25
25
  debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
26
26
  }
27
27
  else {
@@ -49,7 +49,7 @@ export declare class WorkspaceWorker {
49
49
  enabledPluginsMap: Partial<Record<PluginName, boolean>>;
50
50
  enabledPlugins: PluginName[];
51
51
  enabledPluginsInAncestors: string[];
52
- cache: CacheConsultant<CacheItem>;
52
+ cache: CacheConsultant<Partial<Record<PluginName, CacheItem>>>;
53
53
  configFilesMap: Map<string, Map<PluginName, Set<string>>>;
54
54
  constructor({ name, dir, config, manifest, dependencies, rootManifest, negatedWorkspacePatterns, ignoredWorkspacePatterns, enabledPluginsInAncestors, handleInput, handleConfigLoadError, findWorkspaceByFilePath, getManifest, readRawFile, configFilesMap, options, }: WorkspaceManagerOptions);
55
55
  init(): Promise<void>;
@@ -61,14 +61,13 @@ export declare class WorkspaceWorker {
61
61
  private getPluginConfig;
62
62
  getPluginConfigPatterns(): string[];
63
63
  getPluginEntryFilePatterns(patterns: string[]): string[];
64
- getProductionEntryFilePatterns(negatedTestFilePatterns: string[]): string[];
65
- getProductionProjectFilePatterns(negatedTestFilePatterns: string[]): string[];
64
+ getProductionEntryFilePatterns(): string[];
65
+ getProductionProjectFilePatterns(): string[];
66
66
  private getConfigurationFilePatterns;
67
67
  registerCompilers(registerCompiler: RegisterCompiler): Promise<void>;
68
68
  resolveSourceMaps(): Promise<SourceMap[]>;
69
69
  registerVisitors(options: RegisterVisitorsOptions): void;
70
70
  runPlugins(): Promise<Input[]>;
71
- private filterTransitiveDependencies;
72
71
  getConfigurationHints(type: 'entry' | 'project', patterns: string[], filePaths: string[], includedPaths: Set<string>, compilerExtensions?: Set<string>): ConfigurationHint[];
73
72
  onDispose(): void;
74
73
  }
@@ -6,15 +6,15 @@ import { DEFAULT_EXTENSIONS, ROOT_WORKSPACE_NAME } from './constants.js';
6
6
  import { getFilteredScripts } from './manifest/helpers.js';
7
7
  import { PluginEntries, Plugins } from './plugins.js';
8
8
  import { createManifest } from './util/package-json.js';
9
- import { collectStringLiterals, isExternalReExportsOnly } from './typescript/ast-helpers.js';
9
+ import { isExternalReExportsOnly } from './typescript/ast-helpers.js';
10
10
  import { _parseFile } from './typescript/ast-nodes.js';
11
11
  import { compact } from './util/array.js';
12
12
  import { debugLogArray, debugLogObject } from './util/debug.js';
13
13
  import { _glob, hasNoProductionSuffix, hasProductionSuffix, negate } from './util/glob.js';
14
- import { isCatalog, isConfig, isDeferResolve, isDependency, toConfig, toDebugString, toEntry, toProductionEntry, } from './util/input.js';
15
- import { getPackageNameFromSpecifier } from './util/modules.js';
14
+ import { isCatalog, isConfig, toConfig, toDebugString, toEntry, toProductionEntry, } from './util/input.js';
15
+ import { filterTransitiveDependencies } from './util/filter-transitive-dependencies.js';
16
16
  import { timerify } from './util/Performance.js';
17
- import { basename, dirname, isInternal, join, toRelative } from './util/path.js';
17
+ import { basename, dirname, join, relative, toRelative } from './util/path.js';
18
18
  import { extractPatternExtensions } from './util/pattern-extensions.js';
19
19
  import { formatCauseMessage } from './util/errors.js';
20
20
  import { logError } from './util/log.js';
@@ -132,17 +132,17 @@ export class WorkspaceWorker {
132
132
  const negateWorkspaces = patterns.some(pattern => pattern.startsWith('**/')) ? this.negatedWorkspacePatterns : [];
133
133
  return [patterns, negateWorkspaces, this.ignoredWorkspacePatterns.map(negate)].flat();
134
134
  }
135
- getProductionEntryFilePatterns(negatedTestFilePatterns) {
135
+ getProductionEntryFilePatterns() {
136
136
  const entry = this.config.entry.filter(hasProductionSuffix);
137
137
  if (entry.length === 0)
138
138
  return [];
139
139
  const negatedEntryFiles = this.config.entry.filter(hasNoProductionSuffix).map(negate);
140
- return [entry, negatedEntryFiles, negatedTestFilePatterns, this.negatedWorkspacePatterns].flat();
140
+ return [entry, negatedEntryFiles, this.negatedWorkspacePatterns].flat();
141
141
  }
142
- getProductionProjectFilePatterns(negatedTestFilePatterns) {
142
+ getProductionProjectFilePatterns() {
143
143
  const project = this.config.project;
144
144
  if (project.length === 0)
145
- return this.getProductionEntryFilePatterns(negatedTestFilePatterns);
145
+ return this.getProductionEntryFilePatterns();
146
146
  const _project = this.config.project.map(pattern => {
147
147
  if (!(pattern.endsWith('!') || pattern.startsWith('!')))
148
148
  return negate(pattern);
@@ -156,7 +156,6 @@ export class WorkspaceWorker {
156
156
  negatedEntryFiles,
157
157
  negatedPluginConfigPatterns,
158
158
  negatedPluginProjectFilePatterns,
159
- negatedTestFilePatterns,
160
159
  this.negatedWorkspacePatterns,
161
160
  ].flat();
162
161
  }
@@ -326,8 +325,8 @@ export class WorkspaceWorker {
326
325
  seenConfigFiles.add(configFilePath);
327
326
  const isManifest = basename(configFilePath) === 'package.json';
328
327
  const fd = isManifest ? undefined : this.cache.getFileDescriptor(configFilePath);
329
- if (fd?.meta?.data && !fd.changed) {
330
- const data = fd.meta.data;
328
+ const data = fd?.changed ? undefined : fd?.meta?.data?.[pluginName];
329
+ if (data) {
331
330
  if (data.resolveConfig)
332
331
  for (const id of data.resolveConfig)
333
332
  addInput(id, configFilePath);
@@ -370,7 +369,7 @@ export class WorkspaceWorker {
370
369
  if (localConfig) {
371
370
  const inputs = await plugin.resolveConfig(localConfig, resolveOpts);
372
371
  if (plugin.isFilterTransitiveDependencies && !isManifest) {
373
- this.filterTransitiveDependencies(inputs, configFilePath);
372
+ filterTransitiveDependencies(inputs, configFilePath, this.readRawFile);
374
373
  }
375
374
  for (const input of inputs)
376
375
  addInput(input, configFilePath);
@@ -405,7 +404,7 @@ export class WorkspaceWorker {
405
404
  this.cache.removeEntry(configFilePath);
406
405
  }
407
406
  else if (fd?.meta) {
408
- fd.meta.data = cache;
407
+ fd.meta.data = { ...fd.meta.data, [pluginName]: cache };
409
408
  }
410
409
  }
411
410
  }
@@ -458,31 +457,6 @@ export class WorkspaceWorker {
458
457
  debugLogArray(wsName, 'Plugin dependencies', () => compact(inputs.map(input => toDebugString(input, rootCwd))));
459
458
  return inputs;
460
459
  }
461
- filterTransitiveDependencies(inputs, configFilePath) {
462
- const literals = new Set();
463
- const visited = new Set();
464
- const collect = (filePath) => {
465
- if (visited.has(filePath))
466
- return;
467
- visited.add(filePath);
468
- const sourceText = this.readRawFile(filePath);
469
- if (!sourceText)
470
- return;
471
- for (const literal of collectStringLiterals(sourceText, filePath)) {
472
- literals.add(literal);
473
- if (isInternal(literal))
474
- collect(join(dirname(filePath), literal));
475
- }
476
- };
477
- collect(configFilePath);
478
- for (const input of inputs) {
479
- if (!input.optional && (isDeferResolve(input) || isDependency(input))) {
480
- const name = getPackageNameFromSpecifier(input.specifier);
481
- if (name && !literals.has(name))
482
- input.optional = true;
483
- }
484
- }
485
- }
486
460
  getConfigurationHints(type, patterns, filePaths, includedPaths, compilerExtensions) {
487
461
  const hints = [];
488
462
  const entries = this.config[type].filter(pattern => !pattern.startsWith('!'));
@@ -495,18 +469,24 @@ export class WorkspaceWorker {
495
469
  hints.push({ type: `${type}-empty`, identifier, workspaceName });
496
470
  return hints;
497
471
  }
472
+ const dir = this.dir;
473
+ const relativePaths = [];
474
+ const hasMatch = (isMatch) => {
475
+ for (let i = 0; i < filePaths.length; i++) {
476
+ if (isMatch((relativePaths[i] ??= relative(dir, filePaths[i]))))
477
+ return true;
478
+ }
479
+ return false;
480
+ };
498
481
  for (const pattern of patterns) {
499
482
  if (pattern.startsWith('!'))
500
483
  continue;
501
- const filePathOrPattern = join(this.dir, pattern.replace(/!$/, ''));
502
- if (includedPaths.has(filePathOrPattern)) {
484
+ const id = pattern.replace(/!$/, '');
485
+ if (includedPaths.has(join(dir, id))) {
503
486
  hints.push({ type: `${type}-redundant`, identifier: pattern, workspaceName });
504
487
  }
505
- else {
506
- const matcher = picomatch(filePathOrPattern);
507
- if (!filePaths.some(filePath => matcher(filePath))) {
508
- hints.push({ type: `${type}-empty`, identifier: pattern, workspaceName });
509
- }
488
+ else if (!hasMatch(picomatch(id))) {
489
+ hints.push({ type: `${type}-empty`, identifier: pattern, workspaceName });
510
490
  }
511
491
  }
512
492
  if (type === 'project' && compilerExtensions) {
@@ -7,6 +7,11 @@ import { walkCommands } from '../util/scripts.js';
7
7
  import { getDependenciesFromCommand } from './command.js';
8
8
  import { toScript } from './util.js';
9
9
  const collectExpansionScripts = (word, out) => {
10
+ if (word.type === 'ArrayValue') {
11
+ for (const element of word.elements)
12
+ collectExpansionScripts(element, out);
13
+ return;
14
+ }
10
15
  if (!word.parts)
11
16
  return;
12
17
  for (const part of word.parts) {
@@ -63,11 +68,12 @@ export const getDependenciesFromScript = (script, options) => {
63
68
  const processCommand = (node, pending) => {
64
69
  if (node.name)
65
70
  collectExpansionScripts(node.name, pending);
66
- for (const prefix of node.prefix)
67
- if (prefix.value)
71
+ for (const prefix of node.prefix) {
72
+ if (prefix.type === 'Assignment')
68
73
  collectExpansionScripts(prefix.value, pending);
69
- for (const suffix of node.suffix)
70
- collectExpansionScripts(suffix, pending);
74
+ }
75
+ for (const arg of node.args)
76
+ collectExpansionScripts(arg.type === 'Assignment' ? arg.value : arg, pending);
71
77
  if (definedFunctions.size && node.name && definedFunctions.has(extractBinary(node.name.value)))
72
78
  return [];
73
79
  return getDependenciesFromCommand(node, { ...options, fromArgs }, fromWords);
@@ -2,4 +2,4 @@ import type { Command, Word } from 'unbash';
2
2
  import type { BinaryResolverOptions, GetInputsFromScriptsOptions } from '../types/config.ts';
3
3
  import { type Input } from '../util/input.ts';
4
4
  export declare const getInputsFromNodeOptions: (prefix: Command['prefix']) => Input[];
5
- export declare const getDependenciesFromCommand: (node: Command, options: BinaryResolverOptions, fromWords?: (words: Word[], options: GetInputsFromScriptsOptions) => Input[]) => Input[];
5
+ export declare const getDependenciesFromCommand: (node: Pick<Command, 'name' | 'prefix' | 'args'>, options: BinaryResolverOptions, fromWords?: (words: Word[], options: GetInputsFromScriptsOptions) => Input[]) => Input[];
@@ -1,17 +1,23 @@
1
1
  import { Plugins, pluginArgsMap } from '../plugins.js';
2
2
  import { toDeferResolve } from '../util/input.js';
3
3
  import { extractBinary, isInNodeModulesBin, isRelativeNodeModulesBin } from '../util/modules.js';
4
+ import { getCommandWords } from '../util/scripts.js';
4
5
  import { resolve as fallbackResolve, spawningBinaries } from './fallback.js';
5
6
  import KnownResolvers, { isPackageManager } from './resolvers/index.js';
6
7
  import { resolve as resolverFromPlugins } from './plugins.js';
7
8
  import { parseNodeArgs, toCommandBinary } from './util.js';
8
- export const getInputsFromNodeOptions = (prefix) => prefix
9
- .filter(a => a.name === 'NODE_OPTIONS' && a.value)
10
- .map(a => a.value.value)
11
- .map(arg => parseNodeArgs(arg.split(' ')))
12
- .filter(args => args.require)
13
- .flatMap(arg => arg.require)
14
- .map(id => toDeferResolve(id));
9
+ export const getInputsFromNodeOptions = (prefix) => {
10
+ const inputs = [];
11
+ for (const item of prefix) {
12
+ if (item.type !== 'Assignment' || item.name !== 'NODE_OPTIONS' || item.value.type !== 'Word')
13
+ continue;
14
+ const args = parseNodeArgs(item.value.value.split(' '));
15
+ if (args.require)
16
+ for (const id of [args.require].flat())
17
+ inputs.push(toDeferResolve(id));
18
+ }
19
+ return inputs;
20
+ };
15
21
  export const getDependenciesFromCommand = (node, options, fromWords = options.fromArgs) => {
16
22
  const text = node.name?.value;
17
23
  if (!text)
@@ -31,7 +37,7 @@ export const getDependenciesFromCommand = (node, options, fromWords = options.fr
31
37
  };
32
38
  }
33
39
  const { fromArgs } = options;
34
- const words = node.suffix;
40
+ const words = getCommandWords(node);
35
41
  if (binary === '!' || binary === 'test')
36
42
  return fromArgs(words);
37
43
  const fromNodeOptions = getInputsFromNodeOptions(node.prefix);
@@ -1,6 +1,6 @@
1
1
  export const fencedCodeBlockMatcher = /```[\s\S]*?```/g;
2
2
  export const inlineCodeMatcher = /`[^`]+`/g;
3
- export const scriptExtractor = /<script\b((?:[^>"']|"[^"]*"|'[^']*')*)>([\s\S]*?)<\/script>/gi;
3
+ export const scriptExtractor = /<script\b((?:[^>"']|"[^"]*"|'[^']*')*)(?<!\/)>([\s\S]*?)<\/script>/gi;
4
4
  export const styleExtractor = /<style\b((?:[^>"']|"[^"]*"|'[^']*')*)>([\s\S]*?)<\/style>/gi;
5
5
  const langAttrMatcher = /\blang\s*=\s*["']([^"']+)["']/i;
6
6
  export const blockCommentMatcher = /\/\*[\s\S]*?\*\//g;
@@ -9,7 +9,7 @@ import { existsSync } from 'node:fs';
9
9
  import picomatch from 'picomatch';
10
10
  import { tryRealpath } from '../util/fs.js';
11
11
  import { createManifest } from '../util/package-json.js';
12
- import { _glob, _syncGlob, negate, prependDirToPattern as prependDir } from '../util/glob.js';
12
+ import { _glob, _syncGlob, prependDirToPattern as prependDir, removeProductionSuffix } from '../util/glob.js';
13
13
  import { isAlias, isCatalog, isConfig, isDeferResolveEntry, isDeferResolveProductionEntry, isEntry, isIgnore, isProductionEntry, isProject, toDeferResolveEntry, toDependency, toProductionEntry, } from '../util/input.js';
14
14
  import { isAmbientDeclarationFile } from '../typescript/ast-nodes.js';
15
15
  import { resolveImportGlobs } from '../typescript/glob-imports.js';
@@ -19,6 +19,7 @@ import { createFileNode, updateImportMap } from '../util/module-graph.js';
19
19
  import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from '../util/modules.js';
20
20
  import { perfObserver } from '../util/Performance.js';
21
21
  import { getEntrySpecifiersFromManifest, getManifestImportDependencies } from '../util/package-json.js';
22
+ import { expandIgnorePatterns } from '../util/parse-and-convert-gitignores.js';
22
23
  import { dirname, extname, isAbsolute, isInNodeModules, isInternal, join, relative } from '../util/path.js';
23
24
  import { extensionAlias } from '../util/resolve.js';
24
25
  import { augmentWorkspace, getToSourcePathsHandler, toSourceMappedSpecifiers } from '../util/to-source-path.js';
@@ -50,8 +51,8 @@ export async function build({ chief, collector, counselor, deputy, principal, is
50
51
  });
51
52
  }
52
53
  deputy.setWorkspacePkgNames(chief.availableWorkspacePkgNames);
53
- collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: prependDir(options.cwd, id), id })));
54
- collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(id => ({ pattern: prependDir(options.cwd, id), id })));
54
+ collector.addIgnorePatterns(chief.config.ignore.map(id => ({ pattern: id, id })));
55
+ collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(id => ({ pattern: id, id })));
55
56
  if (options.configFilePath) {
56
57
  principal.addEntryPath(options.configFilePath, { skipExportsAnalysis: true });
57
58
  }
@@ -78,7 +79,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
78
79
  continue;
79
80
  const dependencies = deputy.getDependencies(name);
80
81
  const tsConfigFilePath = join(dir, options.tsConfigFile ?? 'tsconfig.json');
81
- const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath);
82
+ const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath, options.isUseTscFiles);
82
83
  const [definitionPaths, tscSourcePaths] = partition(fileNames, filePath => IS_DTS.test(filePath));
83
84
  const worker = new WorkspaceWorker({
84
85
  name,
@@ -121,7 +122,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
121
122
  inputs.add(toProductionEntry(tryRealpath(id), { containingFilePath: tsConfigFilePath }));
122
123
  }
123
124
  const sharedGlobOptions = { cwd: options.cwd, dir, gitignore: options.gitignore };
124
- const fn = (id) => ({ pattern: prependDir(options.cwd, prependDir(name, id)), id, workspaceName: name });
125
+ const fn = (id) => ({ pattern: prependDir(name, id), id, workspaceName: name });
125
126
  collector.addIgnorePatterns(config.ignore.map(fn));
126
127
  collector.addIgnoreFilesPatterns(config.ignoreFiles.map(fn));
127
128
  const entrySpecifiersFromManifest = getEntrySpecifiersFromManifest(manifest);
@@ -246,16 +247,30 @@ export async function build({ chief, collector, counselor, deputy, principal, is
246
247
  }
247
248
  }
248
249
  }
249
- const negatedEntryPatterns = [];
250
+ const developmentMatchers = [];
250
251
  if (options.isProduction) {
252
+ const toPattern = (pattern) => {
253
+ const id = removeProductionSuffix(pattern);
254
+ return isAbsolute(id) ? relative(options.cwd, id) : join(name, id);
255
+ };
251
256
  for (const map of [entryPatterns, entryPatternsSkipExports]) {
252
- for (const patterns of map.values())
253
- for (const pattern of patterns)
254
- negatedEntryPatterns.push(negate(pattern));
257
+ for (const patterns of map.values()) {
258
+ const [excluded, included] = partition(patterns, pattern => pattern.startsWith('!'));
259
+ if (included.length === 0)
260
+ continue;
261
+ const ignore = expandIgnorePatterns(excluded.map(pattern => removeProductionSuffix(pattern.slice(1))));
262
+ developmentMatchers.push(picomatch(included.map(toPattern), { ignore: ignore.map(toPattern), dot: true }));
263
+ }
255
264
  }
256
265
  }
266
+ const productionPaths = (paths) => developmentMatchers.length
267
+ ? paths.filter(path => {
268
+ const relativePath = relative(options.cwd, path);
269
+ return !developmentMatchers.some(match => match(relativePath));
270
+ })
271
+ : paths;
257
272
  const userEntryPatterns = options.isProduction
258
- ? worker.getProductionEntryFilePatterns(negatedEntryPatterns)
273
+ ? worker.getProductionEntryFilePatterns()
259
274
  : worker.getEntryFilePatterns();
260
275
  const userEntryPaths = await _glob({
261
276
  ...sharedGlobOptions,
@@ -272,7 +287,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
272
287
  ]);
273
288
  const label = `entry paths from plugins${group !== DEFAULT_GROUP ? ` - ${group}` : ''}`;
274
289
  const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns, label });
275
- principal.addEntryPaths(pluginWorkspaceEntryPaths);
290
+ principal.addEntryPaths(productionPaths(pluginWorkspaceEntryPaths));
276
291
  }
277
292
  {
278
293
  const patterns = worker.getPluginEntryFilePatterns([
@@ -293,7 +308,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
293
308
  collector.addConfigurationHint(hint);
294
309
  }
295
310
  const hasExplicitEntries = config.entry.some(pattern => !isDefaultPattern('entry', pattern));
296
- principal.addEntryPaths(userEntryPaths, hasExplicitEntries ? { skipExportsAnalysis: false } : undefined);
311
+ principal.addEntryPaths(productionPaths(userEntryPaths), hasExplicitEntries ? { skipExportsAnalysis: false } : undefined);
297
312
  if (options.isUseTscFiles && isFile) {
298
313
  const isIgnoredWorkspace = chief.createIgnoredWorkspaceMatcher(name, dir);
299
314
  debugLogArray(name, 'Using tsconfig files as project files', tscSourcePaths);
@@ -306,10 +321,11 @@ export async function build({ chief, collector, counselor, deputy, principal, is
306
321
  }
307
322
  if (extensions.length > 0) {
308
323
  const extPart = extensions.length === 1 ? extensions[0] : `.{${extensions.map(ext => ext.slice(1)).join(',')}}`;
309
- const bases = include ? new Set(include.map(p => picomatch.scan(p).base || dir)) : new Set([dir]);
324
+ const tsConfigDir = relative(dir, dirname(tsConfigFilePath));
325
+ const bases = include ? new Set(include.map(p => join(tsConfigDir, picomatch.scan(p).base))) : new Set(['']);
310
326
  const patterns = [
311
- ...Array.from(bases, base => `${base}/**/*${extPart}`),
312
- ...(exclude?.map(p => `!${p}`) ?? []),
327
+ ...Array.from(bases, base => join(base, `**/*${extPart}`)),
328
+ ...(exclude?.map(p => `!${join(tsConfigDir, p)}`) ?? []),
313
329
  ];
314
330
  const compilerPaths = await _glob({ ...sharedGlobOptions, patterns, label: 'compiler extension paths' });
315
331
  for (const compilerPath of compilerPaths) {
@@ -320,7 +336,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
320
336
  }
321
337
  else {
322
338
  const patterns = options.isProduction
323
- ? worker.getProductionProjectFilePatterns(negatedEntryPatterns)
339
+ ? worker.getProductionProjectFilePatterns()
324
340
  : worker.getProjectFilePatterns([
325
341
  ...(productionPatternsSkipExports.get(DEFAULT_GROUP) ?? []),
326
342
  ...projectFilePatterns,
@@ -332,7 +348,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
332
348
  for (const hint of hints)
333
349
  collector.addConfigurationHint(hint);
334
350
  }
335
- for (const projectPath of projectPaths)
351
+ for (const projectPath of productionPaths(projectPaths))
336
352
  principal.addProjectPath(projectPath);
337
353
  }
338
354
  worker.onDispose();
@@ -7,6 +7,7 @@ declare const getMetaDataFromPackageJson: ({ dir, packageNames }: Options) => {
7
7
  hostDependencies: HostDependencies;
8
8
  installedBinaries: InstalledBinaries;
9
9
  hasTypesIncluded: Set<string>;
10
+ uninstalledDependencies: Set<string>;
10
11
  };
11
12
  export declare const getDependencyMetaData: typeof getMetaDataFromPackageJson;
12
13
  export {};