knip 5.80.2 → 5.82.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 (67) hide show
  1. package/dist/ConfigurationChief.d.ts +18 -3
  2. package/dist/ConfigurationChief.js +56 -41
  3. package/dist/DependencyDeputy.d.ts +4 -2
  4. package/dist/DependencyDeputy.js +17 -11
  5. package/dist/IssueCollector.d.ts +3 -1
  6. package/dist/IssueCollector.js +9 -5
  7. package/dist/cli.js +5 -2
  8. package/dist/compilers/astro-mdx.js +2 -2
  9. package/dist/compilers/compilers.d.ts +1 -0
  10. package/dist/compilers/compilers.js +1 -0
  11. package/dist/compilers/index.d.ts +21 -1
  12. package/dist/compilers/index.js +3 -0
  13. package/dist/compilers/mdx.js +2 -2
  14. package/dist/graph/analyze.js +3 -2
  15. package/dist/graph/build.js +3 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/plugins/github-actions/index.js +4 -2
  18. package/dist/plugins/index.d.ts +2 -0
  19. package/dist/plugins/index.js +4 -0
  20. package/dist/plugins/nitro/index.d.ts +6 -0
  21. package/dist/plugins/nitro/index.js +58 -0
  22. package/dist/plugins/nitro/types.d.ts +7 -0
  23. package/dist/plugins/nitro/types.js +1 -0
  24. package/dist/plugins/pnpm/index.js +2 -3
  25. package/dist/plugins/prisma/index.js +1 -1
  26. package/dist/plugins/svelte/index.js +0 -13
  27. package/dist/plugins/sveltekit/index.d.ts +3 -0
  28. package/dist/plugins/sveltekit/index.js +44 -0
  29. package/dist/plugins/taskfile/index.js +13 -4
  30. package/dist/plugins/yarn/index.js +2 -2
  31. package/dist/reporters/trace.d.ts +3 -1
  32. package/dist/reporters/trace.js +3 -4
  33. package/dist/reporters/util/configuration-hints.d.ts +1 -1
  34. package/dist/reporters/util/configuration-hints.js +9 -3
  35. package/dist/run.d.ts +1 -0
  36. package/dist/run.js +3 -1
  37. package/dist/schema/configuration.d.ts +30 -0
  38. package/dist/schema/plugins.d.ts +10 -0
  39. package/dist/schema/plugins.js +2 -0
  40. package/dist/types/PluginNames.d.ts +2 -2
  41. package/dist/types/PluginNames.js +2 -0
  42. package/dist/types/config.d.ts +2 -2
  43. package/dist/types/issues.d.ts +1 -0
  44. package/dist/types/options.d.ts +1 -1
  45. package/dist/types/workspace.d.ts +2 -1
  46. package/dist/typescript/ast-helpers.d.ts +1 -0
  47. package/dist/typescript/ast-helpers.js +3 -0
  48. package/dist/typescript/get-imports-and-exports.js +4 -1
  49. package/dist/util/cli-arguments.d.ts +2 -3
  50. package/dist/util/cli-arguments.js +33 -22
  51. package/dist/util/create-options.d.ts +21 -1
  52. package/dist/util/create-options.js +3 -2
  53. package/dist/util/create-workspace-graph.js +5 -2
  54. package/dist/util/errors.d.ts +1 -0
  55. package/dist/util/errors.js +1 -0
  56. package/dist/util/fs.d.ts +1 -0
  57. package/dist/util/fs.js +17 -3
  58. package/dist/util/glob.d.ts +0 -1
  59. package/dist/util/glob.js +0 -8
  60. package/dist/util/workspace-file-filter.d.ts +2 -0
  61. package/dist/util/workspace-file-filter.js +17 -0
  62. package/dist/util/workspace-selectors.d.ts +12 -0
  63. package/dist/util/workspace-selectors.js +104 -0
  64. package/dist/version.d.ts +1 -1
  65. package/dist/version.js +1 -1
  66. package/package.json +1 -1
  67. package/schema.json +8 -0
@@ -3,6 +3,7 @@ import type { ConfigurationHint } from './types/issues.js';
3
3
  import type { WorkspacePackage } from './types/package-json.js';
4
4
  import type { MainOptions } from './util/create-options.js';
5
5
  import { type WorkspaceGraph } from './util/create-workspace-graph.js';
6
+ import { type WorkspaceFilePathFilter } from './util/workspace-file-filter.js';
6
7
  export declare const isDefaultPattern: (type: "entry" | "project", id: string) => boolean;
7
8
  export type Workspace = {
8
9
  name: string;
@@ -23,18 +24,19 @@ export declare class ConfigurationChief {
23
24
  isStrict: boolean;
24
25
  isIncludeEntryExports: boolean;
25
26
  config: Configuration;
26
- workspace: string | undefined;
27
+ workspace: string | string[] | undefined;
28
+ selectedWorkspaces: Set<string> | undefined;
29
+ workspaceFilePathFilter: WorkspaceFilePathFilter;
27
30
  workspaces: string[];
28
31
  ignoredWorkspacePatterns: string[];
29
32
  workspacePackages: Map<string, WorkspacePackage>;
30
33
  workspacesByPkgName: Map<string, Workspace>;
31
- workspacesByName: Map<string, Workspace>;
34
+ workspacesByDir: Map<string, Workspace>;
32
35
  additionalWorkspaceNames: Set<string>;
33
36
  availableWorkspaceNames: string[];
34
37
  availableWorkspacePkgNames: Set<string>;
35
38
  availableWorkspaceDirs: string[];
36
39
  workspaceGraph: WorkspaceGraph;
37
- includedWorkspaces: Workspace[];
38
40
  constructor(options: MainOptions);
39
41
  getConfigurationHints(): ConfigurationHint[];
40
42
  private normalize;
@@ -52,6 +54,7 @@ export declare class ConfigurationChief {
52
54
  createIgnoredWorkspaceMatcher(name: string, dir: string): (filePath: string) => boolean;
53
55
  getNegatedWorkspacePatterns(name: string): string[];
54
56
  private getConfigKeyForWorkspace;
57
+ private getSelectedWorkspaces;
55
58
  getWorkspaceConfig(workspaceName: string): {
56
59
  angular?: string | boolean | string[] | {
57
60
  config?: string | string[] | undefined;
@@ -348,6 +351,11 @@ export declare class ConfigurationChief {
348
351
  entry?: string | string[] | undefined;
349
352
  project?: string | string[] | undefined;
350
353
  } | undefined;
354
+ nitro?: string | boolean | string[] | {
355
+ config?: string | string[] | undefined;
356
+ entry?: string | string[] | undefined;
357
+ project?: string | string[] | undefined;
358
+ } | undefined;
351
359
  node?: string | boolean | string[] | {
352
360
  config?: string | string[] | undefined;
353
361
  entry?: string | string[] | undefined;
@@ -548,6 +556,11 @@ export declare class ConfigurationChief {
548
556
  entry?: string | string[] | undefined;
549
557
  project?: string | string[] | undefined;
550
558
  } | undefined;
559
+ sveltekit?: string | boolean | string[] | {
560
+ config?: string | string[] | undefined;
561
+ entry?: string | string[] | undefined;
562
+ project?: string | string[] | undefined;
563
+ } | undefined;
551
564
  svgo?: string | boolean | string[] | {
552
565
  config?: string | string[] | undefined;
553
566
  entry?: string | string[] | undefined;
@@ -773,6 +786,7 @@ export declare class ConfigurationChief {
773
786
  next?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
774
787
  "next-intl"?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
775
788
  "next-mdx"?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
789
+ nitro?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
776
790
  "node-modules-inspector"?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
777
791
  nodemon?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
778
792
  "npm-package-json-lint"?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
@@ -811,6 +825,7 @@ export declare class ConfigurationChief {
811
825
  stryker?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
812
826
  stylelint?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
813
827
  svelte?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
828
+ sveltekit?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
814
829
  svgo?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
815
830
  svgr?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
816
831
  swc?: (boolean | import("./types/config.js").EnsuredPluginConfiguration) | undefined;
@@ -4,7 +4,6 @@ import { DEFAULT_EXTENSIONS, ROOT_WORKSPACE_NAME } from './constants.js';
4
4
  import { pluginNames } from './types/PluginNames.js';
5
5
  import { arrayify, compact, partition } from './util/array.js';
6
6
  import { createWorkspaceGraph } from './util/create-workspace-graph.js';
7
- import { ConfigurationError } from './util/errors.js';
8
7
  import { isDirectory, isFile } from './util/fs.js';
9
8
  import { _dirGlob, removeProductionSuffix } from './util/glob.js';
10
9
  import { graphSequencer } from './util/graph-sequencer.js';
@@ -14,6 +13,8 @@ import { normalizePluginConfig } from './util/plugin.js';
14
13
  import { toRegexOrString } from './util/regex.js';
15
14
  import { ELLIPSIS } from './util/string.js';
16
15
  import { byPathDepth } from './util/workspace.js';
16
+ import { createWorkspaceFilePathFilter } from './util/workspace-file-filter.js';
17
+ import { selectWorkspaces } from './util/workspace-selectors.js';
17
18
  const defaultBaseFilenamePattern = '{index,cli,main}';
18
19
  export const isDefaultPattern = (type, id) => {
19
20
  if (type === 'project')
@@ -31,9 +32,10 @@ const getDefaultWorkspaceConfig = (extensions = []) => {
31
32
  const isPluginName = (name) => pluginNames.includes(name);
32
33
  const defaultConfig = {
33
34
  ignore: [],
34
- ignoreFiles: [],
35
35
  ignoreBinaries: [],
36
36
  ignoreDependencies: [],
37
+ ignoreFiles: [],
38
+ ignoreIssues: {},
37
39
  ignoreMembers: [],
38
40
  ignoreUnresolved: [],
39
41
  ignoreWorkspaces: [],
@@ -51,17 +53,18 @@ export class ConfigurationChief {
51
53
  isIncludeEntryExports;
52
54
  config;
53
55
  workspace;
56
+ selectedWorkspaces;
57
+ workspaceFilePathFilter = () => true;
54
58
  workspaces;
55
59
  ignoredWorkspacePatterns = [];
56
60
  workspacePackages = new Map();
57
61
  workspacesByPkgName = new Map();
58
- workspacesByName = new Map();
62
+ workspacesByDir = new Map();
59
63
  additionalWorkspaceNames = new Set();
60
64
  availableWorkspaceNames = [];
61
65
  availableWorkspacePkgNames = new Set();
62
66
  availableWorkspaceDirs = [];
63
67
  workspaceGraph = new Map();
64
- includedWorkspaces = [];
65
68
  constructor(options) {
66
69
  this.cwd = options.cwd;
67
70
  this.isProduction = options.isProduction;
@@ -98,7 +101,7 @@ export class ConfigurationChief {
98
101
  const ignoreMembers = rawConfig.ignoreMembers ?? [];
99
102
  const ignoreUnresolved = rawConfig.ignoreUnresolved ?? [];
100
103
  const ignoreExportsUsedInFile = rawConfig.ignoreExportsUsedInFile ?? false;
101
- const ignoreIssues = rawConfig.ignoreIssues;
104
+ const ignoreIssues = rawConfig.ignoreIssues ?? {};
102
105
  const ignoreWorkspaces = rawConfig.ignoreWorkspaces ?? defaultConfig.ignoreWorkspaces;
103
106
  const isIncludeEntryExports = rawConfig.includeEntryExports ?? this.isIncludeEntryExports;
104
107
  const { syncCompilers, asyncCompilers } = rawConfig;
@@ -137,14 +140,16 @@ export class ConfigurationChief {
137
140
  .reverse()
138
141
  .map(dir => join(this.cwd, dir));
139
142
  this.workspaceGraph = createWorkspaceGraph(this.cwd, this.availableWorkspaceNames, wsPkgNames, packages);
140
- this.includedWorkspaces = this.getIncludedWorkspaces();
141
- for (const workspace of this.includedWorkspaces) {
143
+ this.selectedWorkspaces = this.getSelectedWorkspaces();
144
+ this.workspaceFilePathFilter = createWorkspaceFilePathFilter(this.cwd, this.selectedWorkspaces, this.availableWorkspaceNames);
145
+ const includedWorkspaces = this.getIncludedWorkspaces();
146
+ for (const workspace of includedWorkspaces) {
142
147
  this.workspacesByPkgName.set(workspace.pkgName, workspace);
143
- this.workspacesByName.set(workspace.name, workspace);
148
+ this.workspacesByDir.set(workspace.dir, workspace);
144
149
  }
145
- const sorted = graphSequencer(this.workspaceGraph, this.includedWorkspaces.map(workspace => workspace.dir));
150
+ const sorted = graphSequencer(this.workspaceGraph, Array.from(this.workspacesByDir.keys()).filter(dir => this.workspaceGraph.has(dir)));
146
151
  const [root, rest] = partition(sorted.chunks.flat(), dir => dir === this.cwd);
147
- return [...root, ...rest.reverse()].map(dir => this.includedWorkspaces.find(w => w.dir === dir));
152
+ return [...root, ...rest.reverse()].map(dir => this.workspacesByDir.get(dir));
148
153
  }
149
154
  getListedWorkspaces() {
150
155
  return this.workspaces.map(pattern => pattern.replace(/(?<=!?)\.\//, ''));
@@ -180,53 +185,48 @@ export class ConfigurationChief {
180
185
  getAvailableWorkspaceNames(names) {
181
186
  const availableWorkspaceNames = [];
182
187
  const [ignore, patterns] = partition(this.ignoredWorkspacePatterns, pattern => pattern.startsWith('!'));
188
+ const ignoreSliced = ignore.map(pattern => pattern.slice(1));
183
189
  for (const name of names) {
184
- if (!picomatch.isMatch(name, patterns, { ignore: ignore.map(pattern => pattern.slice(1)) })) {
190
+ if (!picomatch.isMatch(name, patterns, { ignore: ignoreSliced })) {
185
191
  availableWorkspaceNames.push(name);
186
192
  }
187
193
  }
188
194
  return availableWorkspaceNames;
189
195
  }
190
196
  getIncludedWorkspaces() {
191
- if (this.workspace) {
192
- const dir = path.resolve(this.cwd, this.workspace);
193
- if (!isDirectory(dir))
194
- throw new ConfigurationError('Workspace is not a directory');
195
- if (!isFile(dir, 'package.json'))
196
- throw new ConfigurationError('Unable to find package.json in workspace');
197
- }
198
- const getAncestors = (name) => (ancestors, ancestorName) => {
199
- if (name === ancestorName)
200
- return ancestors;
201
- if (ancestorName === ROOT_WORKSPACE_NAME || name.startsWith(`${ancestorName}/`))
202
- ancestors.push(ancestorName);
203
- return ancestors;
204
- };
205
- const workspaceNames = this.workspace
206
- ? [...this.availableWorkspaceNames.reduce(getAncestors(this.workspace), []), this.workspace]
197
+ const selectedWorkspaces = this.selectedWorkspaces;
198
+ const isAncestor = (name, ancestor) => ancestor !== name && (ancestor === ROOT_WORKSPACE_NAME || name.startsWith(`${ancestor}/`));
199
+ const getAncestors = (name) => this.availableWorkspaceNames.filter(a => isAncestor(name, a));
200
+ const workspaceNames = selectedWorkspaces
201
+ ? Array.from(selectedWorkspaces).flatMap(name => [...getAncestors(name), name])
207
202
  : this.availableWorkspaceNames;
208
203
  const ws = new Set();
209
- if (this.workspace && this.isStrict) {
210
- ws.add(this.workspace);
204
+ if (selectedWorkspaces && this.isStrict) {
205
+ for (const name of selectedWorkspaces)
206
+ ws.add(name);
211
207
  }
212
- else if (this.workspace) {
208
+ else if (selectedWorkspaces) {
213
209
  const graph = this.workspaceGraph;
214
210
  if (graph) {
215
211
  const seen = new Set();
216
- const initialWorkspaces = workspaceNames.map(name => join(this.cwd, name));
212
+ const initialWorkspaces = new Set(workspaceNames.map(name => join(this.cwd, name)));
217
213
  const workspaceDirsWithDependents = new Set(initialWorkspaces);
218
214
  const addDependents = (dir) => {
219
215
  seen.add(dir);
220
216
  const dirs = graph.get(dir);
221
217
  if (!dirs || dirs.size === 0)
222
218
  return;
223
- if (initialWorkspaces.some(dir => dirs.has(dir)))
224
- workspaceDirsWithDependents.add(dir);
219
+ for (const d of dirs)
220
+ if (initialWorkspaces.has(d)) {
221
+ workspaceDirsWithDependents.add(dir);
222
+ break;
223
+ }
225
224
  for (const dir of dirs)
226
225
  if (!seen.has(dir))
227
226
  addDependents(dir);
228
227
  };
229
- this.availableWorkspaceDirs.forEach(addDependents);
228
+ for (const dir of this.availableWorkspaceDirs)
229
+ addDependents(dir);
230
230
  for (const dir of workspaceDirsWithDependents)
231
231
  ws.add(relative(this.cwd, dir) || ROOT_WORKSPACE_NAME);
232
232
  }
@@ -250,7 +250,7 @@ export class ConfigurationChief {
250
250
  pkgName,
251
251
  dir,
252
252
  config: this.getConfigForWorkspace(name),
253
- ancestors: this.availableWorkspaceNames.reduce(getAncestors(name), []),
253
+ ancestors: getAncestors(name),
254
254
  manifestPath,
255
255
  manifestStr,
256
256
  ignoreMembers,
@@ -261,9 +261,8 @@ export class ConfigurationChief {
261
261
  return this.workspacePackages.get(name)?.manifest;
262
262
  }
263
263
  getDescendentWorkspaces(name) {
264
- return this.availableWorkspaceNames
265
- .filter(workspaceName => workspaceName !== name)
266
- .filter(workspaceName => name === ROOT_WORKSPACE_NAME || workspaceName.startsWith(`${name}/`));
264
+ const prefix = `${name}/`;
265
+ return this.availableWorkspaceNames.filter(workspaceName => workspaceName !== name && (name === ROOT_WORKSPACE_NAME || workspaceName.startsWith(prefix)));
267
266
  }
268
267
  getIgnoredWorkspacesFor(name) {
269
268
  return this.ignoredWorkspacePatterns
@@ -294,6 +293,12 @@ export class ConfigurationChief {
294
293
  .reverse()
295
294
  .find(pattern => picomatch.isMatch(workspaceName, pattern));
296
295
  }
296
+ getSelectedWorkspaces() {
297
+ if (!this.workspace)
298
+ return;
299
+ const workspaceSelectors = Array.isArray(this.workspace) ? this.workspace : [this.workspace];
300
+ return selectWorkspaces(workspaceSelectors, this.cwd, this.workspacePackages, this.availableWorkspaceNames);
301
+ }
297
302
  getWorkspaceConfig(workspaceName) {
298
303
  const key = this.getConfigKeyForWorkspace(workspaceName);
299
304
  const workspaces = this.rawConfig?.workspaces ?? {};
@@ -341,13 +346,23 @@ export class ConfigurationChief {
341
346
  }
342
347
  findWorkspaceByFilePath(filePath) {
343
348
  const workspaceDir = this.availableWorkspaceDirs.find(workspaceDir => filePath.startsWith(`${workspaceDir}/`));
344
- return this.includedWorkspaces.find(workspace => workspace.dir === workspaceDir);
349
+ if (!workspaceDir)
350
+ return undefined;
351
+ return this.workspacesByDir.get(workspaceDir);
345
352
  }
346
353
  getUnusedIgnoredWorkspaces() {
347
354
  const ignoredWorkspaceNames = this.config.ignoreWorkspaces.map(removeProductionSuffix);
348
- const workspaceNames = [...this.workspacePackages.keys(), ...this.additionalWorkspaceNames];
355
+ const matchesWorkspace = (pattern) => {
356
+ for (const name of this.workspacePackages.keys())
357
+ if (picomatch.isMatch(name, pattern))
358
+ return true;
359
+ for (const name of this.additionalWorkspaceNames)
360
+ if (picomatch.isMatch(name, pattern))
361
+ return true;
362
+ return false;
363
+ };
349
364
  return ignoredWorkspaceNames
350
- .filter(ignoredWorkspaceName => !workspaceNames.some(name => picomatch.isMatch(name, ignoredWorkspaceName)))
365
+ .filter(ignoredWorkspaceName => !matchesWorkspace(ignoredWorkspaceName))
351
366
  .filter(ignoredWorkspaceName => {
352
367
  const dir = join(this.cwd, ignoredWorkspaceName);
353
368
  return !isDirectory(dir) || isFile(dir, 'package.json');
@@ -32,7 +32,8 @@ export declare class DependencyDeputy {
32
32
  dependencies: DependencyArray;
33
33
  devDependencies: DependencyArray;
34
34
  peerDependencies: DependencySet;
35
- optionalPeerDependencies: DependencyArray;
35
+ optionalPeerDependencies: DependencySet;
36
+ requiredPeerDependencies: DependencyArray;
36
37
  allDependencies: DependencySet;
37
38
  ignoreDependencies: (string | RegExp)[];
38
39
  ignoreBinaries: (string | RegExp)[];
@@ -55,7 +56,7 @@ export declare class DependencyDeputy {
55
56
  name: string;
56
57
  isPeerOptional: boolean;
57
58
  }[];
58
- getOptionalPeerDependencies(workspaceName: string): DependencyArray;
59
+ getOptionalPeerDependencies(workspaceName: string): DependencySet;
59
60
  maybeAddReferencedExternalDependency(workspace: Workspace, packageName: string): boolean;
60
61
  maybeAddReferencedBinary(workspace: Workspace, binaryName: string): Set<string> | undefined;
61
62
  private isInDependencies;
@@ -74,4 +75,5 @@ export declare class DependencyDeputy {
74
75
  getConfigurationHints(): ConfigurationHint[];
75
76
  addIgnoredDependencies(workspaceName: string, identifier: string): void;
76
77
  addIgnoredBinaries(workspaceName: string, identifier: string): void;
78
+ addIgnoredUnresolved(workspaceName: string, identifier: string): void;
77
79
  }
@@ -29,11 +29,14 @@ export class DependencyDeputy {
29
29
  const dependencies = Object.keys(manifest.dependencies ?? {});
30
30
  const peerDependencies = Object.keys(manifest.peerDependencies ?? {});
31
31
  const optionalDependencies = Object.keys(manifest.optionalDependencies ?? {});
32
- const optionalPeerDependencies = manifest.peerDependenciesMeta
33
- ? peerDependencies.filter(peerDependency => manifest.peerDependenciesMeta &&
34
- peerDependency in manifest.peerDependenciesMeta &&
35
- manifest.peerDependenciesMeta[peerDependency].optional)
36
- : [];
32
+ const optionalPeerDependencies = new Set();
33
+ if (manifest.peerDependenciesMeta) {
34
+ for (const dep of peerDependencies) {
35
+ if (manifest.peerDependenciesMeta[dep]?.optional)
36
+ optionalPeerDependencies.add(dep);
37
+ }
38
+ }
39
+ const requiredPeerDependencies = peerDependencies.filter(dep => !optionalPeerDependencies.has(dep));
37
40
  const devDependencies = Object.keys(manifest.devDependencies ?? {});
38
41
  const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies, ...optionalDependencies];
39
42
  const packageNames = [
@@ -68,6 +71,7 @@ export class DependencyDeputy {
68
71
  devDependencies,
69
72
  peerDependencies: new Set(peerDependencies),
70
73
  optionalPeerDependencies,
74
+ requiredPeerDependencies,
71
75
  allDependencies: new Set(allDependencies),
72
76
  });
73
77
  }
@@ -79,7 +83,7 @@ export class DependencyDeputy {
79
83
  if (!manifest)
80
84
  return [];
81
85
  if (this.isStrict)
82
- return [...manifest.dependencies, ...manifest.peerDependencies];
86
+ return [...manifest.dependencies, ...manifest.requiredPeerDependencies];
83
87
  return manifest.dependencies;
84
88
  }
85
89
  getDevDependencies(workspaceName) {
@@ -122,10 +126,7 @@ export class DependencyDeputy {
122
126
  return this.hostDependencies.get(workspaceName)?.get(dependency) ?? [];
123
127
  }
124
128
  getOptionalPeerDependencies(workspaceName) {
125
- const manifest = this._manifests.get(workspaceName);
126
- if (!manifest)
127
- return [];
128
- return manifest.optionalPeerDependencies;
129
+ return this._manifests.get(workspaceName)?.optionalPeerDependencies ?? new Set();
129
130
  }
130
131
  maybeAddReferencedExternalDependency(workspace, packageName) {
131
132
  if (!this.isReportDependencies)
@@ -227,7 +228,9 @@ export class DependencyDeputy {
227
228
  const position = peeker.getLocation('devDependencies', symbol);
228
229
  devDependencyIssues.push({ type: 'devDependencies', filePath, workspace, symbol, fixes: [], ...position });
229
230
  }
230
- for (const symbol of this.getOptionalPeerDependencies(workspace).filter(d => isReferencedDependency(d))) {
231
+ for (const symbol of this.getOptionalPeerDependencies(workspace)) {
232
+ if (!isReferencedDependency(symbol))
233
+ continue;
231
234
  const pos = peeker.getLocation('optionalPeerDependencies', symbol);
232
235
  optionalPeerDependencyIssues.push({
233
236
  type: 'optionalPeerDependencies',
@@ -369,4 +372,7 @@ export class DependencyDeputy {
369
372
  addIgnoredBinaries(workspaceName, identifier) {
370
373
  this._manifests.get(workspaceName)?.ignoreBinaries.push(toRegexOrString(identifier));
371
374
  }
375
+ addIgnoredUnresolved(workspaceName, identifier) {
376
+ this._manifests.get(workspaceName)?.ignoreUnresolved.push(toRegexOrString(identifier));
377
+ }
372
378
  }
@@ -1,11 +1,12 @@
1
1
  import type { IgnoreIssues } from './types/config.js';
2
2
  import type { ConfigurationHint, Issue, TagHint } from './types/issues.js';
3
3
  import type { MainOptions } from './util/create-options.js';
4
+ import type { WorkspaceFilePathFilter } from './util/workspace-file-filter.js';
4
5
  export type CollectorIssues = ReturnType<IssueCollector['getIssues']>;
5
6
  export declare class IssueCollector {
6
7
  private cwd;
7
8
  private rules;
8
- private filter;
9
+ private workspaceFilter;
9
10
  private issues;
10
11
  private counters;
11
12
  private referencedFiles;
@@ -17,6 +18,7 @@ export declare class IssueCollector {
17
18
  private isFileMatch;
18
19
  private issueMatchers;
19
20
  constructor(options: MainOptions);
21
+ setWorkspaceFilter(workspaceFilePathFilter: WorkspaceFilePathFilter | undefined): void;
20
22
  addIgnorePatterns(patterns: string[]): void;
21
23
  addIgnoreFilesPatterns(patterns: string[]): void;
22
24
  setIgnoreIssues(ignoreIssues?: IgnoreIssues): void;
@@ -1,7 +1,7 @@
1
1
  import picomatch from 'picomatch';
2
2
  import { partition } from './util/array.js';
3
3
  import { initCounters, initIssues } from './util/issue-initializers.js';
4
- import { join, relative } from './util/path.js';
4
+ import { relative } from './util/path.js';
5
5
  const createMatcher = (patterns) => {
6
6
  const [negated, positive] = partition(patterns, p => p[0] === '!');
7
7
  if (positive.length === 0) {
@@ -14,7 +14,7 @@ const createMatcher = (patterns) => {
14
14
  export class IssueCollector {
15
15
  cwd;
16
16
  rules;
17
- filter;
17
+ workspaceFilter;
18
18
  issues = initIssues();
19
19
  counters = initCounters();
20
20
  referencedFiles = new Set();
@@ -28,10 +28,14 @@ export class IssueCollector {
28
28
  constructor(options) {
29
29
  this.cwd = options.cwd;
30
30
  this.rules = options.rules;
31
- this.filter = options.workspace ? join(options.cwd, options.workspace) : undefined;
31
+ this.workspaceFilter = () => true;
32
32
  this.isMatch = () => false;
33
33
  this.isFileMatch = () => false;
34
34
  }
35
+ setWorkspaceFilter(workspaceFilePathFilter) {
36
+ if (workspaceFilePathFilter)
37
+ this.workspaceFilter = workspaceFilePathFilter;
38
+ }
35
39
  addIgnorePatterns(patterns) {
36
40
  for (const pattern of patterns)
37
41
  this.ignorePatterns.add(pattern);
@@ -71,7 +75,7 @@ export class IssueCollector {
71
75
  }
72
76
  addFilesIssues(filePaths) {
73
77
  for (const filePath of filePaths) {
74
- if (this.filter && !filePath.startsWith(`${this.filter}/`))
78
+ if (!this.workspaceFilter(filePath))
75
79
  continue;
76
80
  if (this.referencedFiles.has(filePath))
77
81
  continue;
@@ -89,7 +93,7 @@ export class IssueCollector {
89
93
  }
90
94
  }
91
95
  addIssue(issue) {
92
- if (this.filter && !issue.filePath.startsWith(`${this.filter}/`))
96
+ if (!this.workspaceFilter(issue.filePath))
93
97
  return;
94
98
  if (this.isMatch(issue.filePath))
95
99
  return;
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@ import { fix } from './IssueFixer.js';
2
2
  import { run } from './run.js';
3
3
  import parseArgs, { helpText } from './util/cli-arguments.js';
4
4
  import { createOptions } from './util/create-options.js';
5
- import { getKnownErrors, hasErrorCause, isConfigurationError, isKnownError, isModuleNotFoundError, } from './util/errors.js';
5
+ import { getKnownErrors, hasErrorCause, isConfigurationError, isKnownError, isLoaderError, isModuleNotFoundError, } from './util/errors.js';
6
6
  import { logError, logWarning } from './util/log.js';
7
7
  import { perfObserver } from './util/Performance.js';
8
8
  import { runPreprocessors, runReporters } from './util/reporter.js';
@@ -32,7 +32,7 @@ const main = async () => {
32
32
  }
33
33
  const options = await createOptions({ args });
34
34
  const { results } = await run(options);
35
- const { issues, counters, tagHints, configurationHints, includedWorkspaceDirs, enabledPlugins } = results;
35
+ const { issues, counters, tagHints, configurationHints, includedWorkspaceDirs, enabledPlugins, selectedWorkspaces, } = results;
36
36
  if (options.isWatch || options.isTrace)
37
37
  return;
38
38
  const initialData = {
@@ -52,6 +52,7 @@ const main = async () => {
52
52
  maxShowIssues: args['max-show-issues'] ? Number(args['max-show-issues']) : undefined,
53
53
  options: args['reporter-options'] ?? '',
54
54
  preprocessorOptions: args['preprocessor-options'] ?? '',
55
+ selectedWorkspaces,
55
56
  };
56
57
  const finalData = await runPreprocessors(args.preprocessor ?? [], initialData);
57
58
  if (options.isFix)
@@ -92,6 +93,8 @@ const main = async () => {
92
93
  console.error('Reason:', knownErrors[0].cause.message);
93
94
  if (isModuleNotFoundError(knownErrors[0].cause))
94
95
  console.log('Module load error? Visit https://knip.dev/reference/known-issues');
96
+ if (isLoaderError(knownErrors[0]))
97
+ console.log('Configuration file load error? Visit https://knip.dev/reference/known-issues');
95
98
  }
96
99
  if (isConfigurationError(knownErrors[0]))
97
100
  console.log('\nRun `knip --help` or visit https://knip.dev for help');
@@ -1,9 +1,9 @@
1
- import { fencedCodeBlockMatcher, importMatcher, importsWithinFrontmatter } from './compilers.js';
1
+ import { fencedCodeBlockMatcher, importMatcher, importsWithinFrontmatter, inlineCodeMatcher } from './compilers.js';
2
2
  const astroMDXDependencies = ['@astrojs/mdx', '@astrojs/starlight'];
3
3
  const frontmatterImportFields = ['layout'];
4
4
  const condition = (hasDependency) => astroMDXDependencies.some(hasDependency);
5
5
  const compiler = (text) => {
6
- const imports = text.replace(fencedCodeBlockMatcher, '').matchAll(importMatcher);
6
+ const imports = text.replace(fencedCodeBlockMatcher, '').replace(inlineCodeMatcher, '').matchAll(importMatcher);
7
7
  const frontmatterImports = importsWithinFrontmatter(text, frontmatterImportFields);
8
8
  return [...imports, frontmatterImports].join('\n');
9
9
  };
@@ -1,5 +1,6 @@
1
1
  import type { SyncCompilerFn } from './types.js';
2
2
  export declare const fencedCodeBlockMatcher: RegExp;
3
+ export declare const inlineCodeMatcher: RegExp;
3
4
  export declare const importMatcher: RegExp;
4
5
  export declare const importsWithinScripts: SyncCompilerFn;
5
6
  export declare const scriptBodies: SyncCompilerFn;
@@ -1,4 +1,5 @@
1
1
  export const fencedCodeBlockMatcher = /```[\s\S]*?```/g;
2
+ export const inlineCodeMatcher = /`[^`]+`/g;
2
3
  const scriptExtractor = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
3
4
  export const importMatcher = /import[^'"]+['"][^'"]+['"]/g;
4
5
  export const importsWithinScripts = (text) => {
@@ -2,7 +2,7 @@ import type { RawConfiguration } from '../types/config.js';
2
2
  import type { DependencySet } from '../types/workspace.js';
3
3
  import type { AsyncCompilerFn, AsyncCompilers, RawSyncCompilers, SyncCompilerFn, SyncCompilers } from './types.js';
4
4
  export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
5
- syncCompilers: Record<string, SyncCompilerFn>;
5
+ syncCompilers: Record<string, true | SyncCompilerFn>;
6
6
  asyncCompilers: Record<string, AsyncCompilerFn>;
7
7
  angular?: string | boolean | string[] | {
8
8
  config?: string | string[] | undefined;
@@ -299,6 +299,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
299
299
  entry?: string | string[] | undefined;
300
300
  project?: string | string[] | undefined;
301
301
  } | undefined;
302
+ nitro?: string | boolean | string[] | {
303
+ config?: string | string[] | undefined;
304
+ entry?: string | string[] | undefined;
305
+ project?: string | string[] | undefined;
306
+ } | undefined;
302
307
  node?: string | boolean | string[] | {
303
308
  config?: string | string[] | undefined;
304
309
  entry?: string | string[] | undefined;
@@ -499,6 +504,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
499
504
  entry?: string | string[] | undefined;
500
505
  project?: string | string[] | undefined;
501
506
  } | undefined;
507
+ sveltekit?: string | boolean | string[] | {
508
+ config?: string | string[] | undefined;
509
+ entry?: string | string[] | undefined;
510
+ project?: string | string[] | undefined;
511
+ } | undefined;
502
512
  svgo?: string | boolean | string[] | {
503
513
  config?: string | string[] | undefined;
504
514
  entry?: string | string[] | undefined;
@@ -940,6 +950,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
940
950
  entry?: string | string[] | undefined;
941
951
  project?: string | string[] | undefined;
942
952
  } | undefined;
953
+ nitro?: string | boolean | string[] | {
954
+ config?: string | string[] | undefined;
955
+ entry?: string | string[] | undefined;
956
+ project?: string | string[] | undefined;
957
+ } | undefined;
943
958
  node?: string | boolean | string[] | {
944
959
  config?: string | string[] | undefined;
945
960
  entry?: string | string[] | undefined;
@@ -1140,6 +1155,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
1140
1155
  entry?: string | string[] | undefined;
1141
1156
  project?: string | string[] | undefined;
1142
1157
  } | undefined;
1158
+ sveltekit?: string | boolean | string[] | {
1159
+ config?: string | string[] | undefined;
1160
+ entry?: string | string[] | undefined;
1161
+ project?: string | string[] | undefined;
1162
+ } | undefined;
1143
1163
  svgo?: string | boolean | string[] | {
1144
1164
  config?: string | string[] | undefined;
1145
1165
  entry?: string | string[] | undefined;
@@ -22,6 +22,9 @@ export const partitionCompilers = (rawLocalConfig) => {
22
22
  syncCompilers[ext] = compilerFn;
23
23
  }
24
24
  }
25
+ else if (compilerFn === true) {
26
+ syncCompilers[ext] = true;
27
+ }
25
28
  }
26
29
  for (const extension in rawLocalConfig.asyncCompilers) {
27
30
  const ext = normalizeExt(extension);
@@ -1,4 +1,4 @@
1
- import { fencedCodeBlockMatcher, importMatcher } from './compilers.js';
1
+ import { fencedCodeBlockMatcher, importMatcher, inlineCodeMatcher } from './compilers.js';
2
2
  const mdxDependencies = [
3
3
  '@mdx-js/esbuild',
4
4
  '@mdx-js/loader',
@@ -11,5 +11,5 @@ const mdxDependencies = [
11
11
  'remark-mdx',
12
12
  ];
13
13
  const condition = (hasDependency) => mdxDependencies.some(hasDependency);
14
- const compiler = (text) => [...text.replace(fencedCodeBlockMatcher, '').matchAll(importMatcher)].join('\n');
14
+ const compiler = (text) => [...text.replace(fencedCodeBlockMatcher, '').replace(inlineCodeMatcher, '').matchAll(importMatcher)].join('\n');
15
15
  export default { condition, compiler };
@@ -234,7 +234,8 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
234
234
  collector.addConfigurationHint(hint);
235
235
  };
236
236
  await analyzeGraph();
237
- if (options.isTrace)
238
- traceReporter({ graph, explorer, options });
237
+ if (options.isTrace) {
238
+ traceReporter({ graph, explorer, options, workspaceFilePathFilter: chief.workspaceFilePathFilter });
239
+ }
239
240
  return analyzeGraph;
240
241
  };
@@ -150,6 +150,9 @@ export async function build({ chief, collector, counselor, deputy, factory, isGi
150
150
  else if (input.issueType === 'binaries') {
151
151
  deputy.addIgnoredBinaries(name, input.specifier);
152
152
  }
153
+ else if (input.issueType === 'unresolved') {
154
+ deputy.addIgnoredUnresolved(name, input.specifier);
155
+ }
153
156
  }
154
157
  else if (!isConfig(input)) {
155
158
  const ws = (input.containingFilePath && chief.findWorkspaceByFilePath(input.containingFilePath)) || workspace;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export declare const main: (options: MainOptions) => Promise<{
4
4
  counters: import("./types/issues.js").Counters;
5
5
  tagHints: Set<import("./types/issues.js").TagHint>;
6
6
  configurationHints: import("./types/issues.js").ConfigurationHint[];
7
+ selectedWorkspaces: string[] | undefined;
7
8
  includedWorkspaceDirs: string[];
8
9
  enabledPlugins: {
9
10
  [k: string]: string[];
@@ -1,10 +1,12 @@
1
- import { _firstGlob } from '../../util/glob.js';
1
+ import { hasFilesWithExtensions } from '../../util/fs.js';
2
2
  import { isDeferResolveEntry, toEntry } from '../../util/input.js';
3
3
  import { findByKeyDeep } from '../../util/object.js';
4
4
  import { join, relative } from '../../util/path.js';
5
5
  const title = 'GitHub Actions';
6
6
  const enablers = 'This plugin is enabled when a `.yml` or `.yaml` file is found in the `.github/workflows` folder.';
7
- const isEnabled = async ({ cwd }) => Boolean(await _firstGlob({ cwd, patterns: ['.github/workflows/*.{yml,yaml}'] }));
7
+ const isEnabled = ({ cwd }) => {
8
+ return hasFilesWithExtensions(cwd, '.github/workflows', ['yml', 'yaml']);
9
+ };
8
10
  const isRootOnly = true;
9
11
  const config = ['.github/workflows/*.{yml,yaml}', '.github/**/action.{yml,yaml}'];
10
12
  const isString = (value) => typeof value === 'string';