knip 6.24.0 → 6.25.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 (92) hide show
  1. package/dist/ConfigurationChief.d.ts +13 -1
  2. package/dist/ConfigurationChief.js +3 -0
  3. package/dist/ProjectPrincipal.d.ts +2 -0
  4. package/dist/ProjectPrincipal.js +4 -1
  5. package/dist/binaries/bash-parser.js +55 -83
  6. package/dist/binaries/index.js +3 -0
  7. package/dist/compilers/index.d.ts +29 -5
  8. package/dist/constants.d.ts +5 -1
  9. package/dist/constants.js +5 -0
  10. package/dist/graph/analyze.js +37 -2
  11. package/dist/graph/build.js +9 -0
  12. package/dist/graph-explorer/explorer.d.ts +1 -0
  13. package/dist/graph-explorer/explorer.js +2 -0
  14. package/dist/graph-explorer/operations/find-all-cycles.d.ts +3 -0
  15. package/dist/graph-explorer/operations/find-all-cycles.js +43 -0
  16. package/dist/graph-explorer/operations/find-cycles.js +3 -9
  17. package/dist/graph-explorer/utils.d.ts +10 -1
  18. package/dist/graph-explorer/utils.js +53 -0
  19. package/dist/plugins/bun/index.js +28 -14
  20. package/dist/plugins/eve/index.d.ts +3 -0
  21. package/dist/plugins/eve/index.js +22 -0
  22. package/dist/plugins/execa/visitors/execa.js +10 -18
  23. package/dist/plugins/fumadocs/index.d.ts +3 -0
  24. package/dist/plugins/fumadocs/index.js +18 -0
  25. package/dist/plugins/graphql-codegen/index.js +9 -7
  26. package/dist/plugins/index.d.ts +2 -0
  27. package/dist/plugins/index.js +4 -0
  28. package/dist/plugins/jest/index.js +13 -3
  29. package/dist/plugins/next/index.js +23 -10
  30. package/dist/plugins/node/index.js +4 -1
  31. package/dist/plugins/pnpm/index.js +21 -1
  32. package/dist/plugins/pnpm/types.d.ts +6 -0
  33. package/dist/plugins/pnpm/types.js +1 -0
  34. package/dist/plugins/prettier/index.js +19 -3
  35. package/dist/plugins/prettier/types.d.ts +6 -1
  36. package/dist/plugins/rspack/index.js +5 -0
  37. package/dist/plugins/serverless-framework/index.js +12 -1
  38. package/dist/plugins/serverless-framework/types.d.ts +5 -2
  39. package/dist/plugins/storybook/index.js +7 -0
  40. package/dist/plugins/typedoc/index.js +9 -3
  41. package/dist/plugins/typedoc/types.d.ts +2 -0
  42. package/dist/plugins/vite/visitors/importMetaGlob.js +1 -8
  43. package/dist/plugins/webpack/visitors/requireContext.js +2 -13
  44. package/dist/plugins/yarn/index.js +13 -4
  45. package/dist/plugins/yarn/types.d.ts +10 -0
  46. package/dist/plugins/yarn/types.js +1 -0
  47. package/dist/plugins/zx/visitors/zx.js +4 -4
  48. package/dist/reporters/cycles.d.ts +3 -0
  49. package/dist/reporters/cycles.js +79 -0
  50. package/dist/reporters/index.d.ts +1 -0
  51. package/dist/reporters/index.js +2 -0
  52. package/dist/reporters/json.d.ts +3 -0
  53. package/dist/reporters/json.js +2 -1
  54. package/dist/reporters/util/util.d.ts +3 -1
  55. package/dist/reporters/util/util.js +5 -1
  56. package/dist/schema/configuration.d.ts +40 -6
  57. package/dist/schema/configuration.js +6 -0
  58. package/dist/schema/plugins.d.ts +10 -0
  59. package/dist/schema/plugins.js +2 -0
  60. package/dist/types/PluginNames.d.ts +2 -2
  61. package/dist/types/PluginNames.js +2 -0
  62. package/dist/types/config.d.ts +9 -0
  63. package/dist/types/issues.d.ts +3 -0
  64. package/dist/types/module-graph.d.ts +7 -0
  65. package/dist/types/package-json.d.ts +4 -1
  66. package/dist/typescript/ast-nodes.d.ts +3 -1
  67. package/dist/typescript/ast-nodes.js +9 -1
  68. package/dist/typescript/get-imports-and-exports.js +10 -0
  69. package/dist/typescript/glob-imports.d.ts +3 -0
  70. package/dist/typescript/glob-imports.js +49 -0
  71. package/dist/typescript/resolve-module-names.d.ts +2 -0
  72. package/dist/typescript/resolve-module-names.js +35 -1
  73. package/dist/typescript/visitors/calls.js +4 -6
  74. package/dist/typescript/visitors/imports.js +8 -8
  75. package/dist/typescript/visitors/script-visitors.js +4 -4
  76. package/dist/typescript/visitors/walk.js +2 -3
  77. package/dist/util/cli-arguments.d.ts +2 -1
  78. package/dist/util/cli-arguments.js +4 -2
  79. package/dist/util/create-options.d.ts +32 -5
  80. package/dist/util/create-options.js +4 -1
  81. package/dist/util/get-included-issue-types.d.ts +1 -0
  82. package/dist/util/get-included-issue-types.js +4 -2
  83. package/dist/util/issue-initializers.js +1 -1
  84. package/dist/util/load-tsconfig.js +17 -4
  85. package/dist/util/module-graph.js +1 -0
  86. package/dist/util/modules.js +25 -4
  87. package/dist/util/scripts.d.ts +7 -0
  88. package/dist/util/scripts.js +75 -0
  89. package/dist/version.d.ts +1 -1
  90. package/dist/version.js +1 -1
  91. package/package.json +1 -1
  92. package/schema.json +40 -1
@@ -1,11 +1,13 @@
1
1
  import { ISSUE_TYPES } from '../constants.js';
2
2
  import { ConfigurationError } from './errors.js';
3
- export const defaultExcludedIssueTypes = ['nsExports', 'nsTypes'];
3
+ export const defaultExcludedIssueTypes = ['nsExports', 'nsTypes', 'cycles'];
4
+ const defaultAddOnIssueTypes = ['nsExports', 'nsTypes'];
4
5
  const defaultIssueTypes = ISSUE_TYPES.filter(type => !defaultExcludedIssueTypes.includes(type));
5
6
  const normalize = (values) => values.flatMap(value => value.split(','));
6
7
  export const shorthandDeps = ['dependencies', 'unlisted', 'binaries', 'unresolved', 'catalog'];
7
8
  export const shorthandExports = ['exports', 'types', 'enumMembers', 'namespaceMembers', 'duplicates'];
8
9
  export const shorthandFiles = ['files'];
10
+ export const shorthandCycles = ['cycles'];
9
11
  export const getIncludedIssueTypes = (options) => {
10
12
  const incl = normalize(options.includeOverrides ?? []);
11
13
  const excl = normalize(options.excludeOverrides ?? []);
@@ -28,7 +30,7 @@ export const getIncludedIssueTypes = (options) => {
28
30
  _exclude.push('devDependencies', 'optionalPeerDependencies');
29
31
  }
30
32
  const included = (_include.length > 0
31
- ? _include.some(type => !defaultExcludedIssueTypes.includes(type))
33
+ ? _include.some(type => !defaultAddOnIssueTypes.includes(type))
32
34
  ? _include
33
35
  : [..._include, ...defaultIssueTypes]
34
36
  : defaultIssueTypes).filter(group => !_exclude.includes(group));
@@ -5,4 +5,4 @@ export const initCounters = () => ({
5
5
  processed: 0,
6
6
  total: 0,
7
7
  });
8
- export const defaultRules = Object.fromEntries(ISSUE_TYPES.map(issueType => [issueType, 'error']));
8
+ export const defaultRules = Object.fromEntries(ISSUE_TYPES.map(issueType => [issueType, issueType === 'cycles' ? 'warn' : 'error']));
@@ -2,7 +2,7 @@ import { parseTsconfig } from 'get-tsconfig';
2
2
  import { compact } from './array.js';
3
3
  import { isFile } from './fs.js';
4
4
  import { _syncGlob } from './glob.js';
5
- import { dirname, isAbsolute, join, toAbsolute } from './path.js';
5
+ import { dirname, isAbsolute, join, toAbsolute, toPosix } from './path.js';
6
6
  const hasGlobChar = (p) => p.includes('*') || p.includes('?');
7
7
  const hasExtension = (p) => {
8
8
  const last = p.lastIndexOf('/');
@@ -17,7 +17,20 @@ const resolvePatterns = (patterns, dir, expandDirs = false) => {
17
17
  return expandDirs && !hasGlobChar(p) && !hasExtension(p) ? join(resolved, '**/*') : resolved;
18
18
  });
19
19
  };
20
- const pathsBaseDir = (baseUrl, dir) => (baseUrl ? toAbsolute(baseUrl, dir) : dir);
20
+ const getImplicitBaseUrl = (compilerOptions) => {
21
+ for (const symbol of Object.getOwnPropertySymbols(compilerOptions)) {
22
+ if (symbol.description === 'implicitBaseUrl') {
23
+ const value = Reflect.get(compilerOptions, symbol);
24
+ if (typeof value === 'string')
25
+ return toPosix(value);
26
+ }
27
+ }
28
+ };
29
+ const pathsBaseDir = (compilerOptions, dir) => {
30
+ if (compilerOptions?.baseUrl)
31
+ return toAbsolute(compilerOptions.baseUrl, dir);
32
+ return (compilerOptions && getImplicitBaseUrl(compilerOptions)) ?? dir;
33
+ };
21
34
  const collectPaths = (acc, paths, baseDir) => {
22
35
  if (!paths)
23
36
  return;
@@ -74,7 +87,7 @@ const walkReferences = (target, references, dir, visited, pairs, paths) => {
74
87
  const refConfig = parseTsconfig(refPath);
75
88
  const refDir = dirname(refPath);
76
89
  const refOpts = refConfig.compilerOptions;
77
- collectPaths(paths, refOpts?.paths, pathsBaseDir(refOpts?.baseUrl, refDir));
90
+ collectPaths(paths, refOpts?.paths, pathsBaseDir(refOpts, refDir));
78
91
  const refOutDir = refOpts?.outDir ? absDir(refOpts.outDir, refDir) : undefined;
79
92
  const refRootDir = refOpts?.rootDir ? absDir(refOpts.rootDir, refDir) : undefined;
80
93
  if (refOutDir && refRootDir && refOutDir !== refRootDir)
@@ -109,7 +122,7 @@ export const loadTSConfig = async (tsConfigFilePath) => {
109
122
  if (compilerOptions.rootDirs)
110
123
  compilerOptions.rootDirs = compilerOptions.rootDirs.map(d => absDir(d, dir));
111
124
  const tsconfigPaths = {};
112
- collectPaths(tsconfigPaths, compilerOptions.paths, pathsBaseDir(compilerOptions.baseUrl, dir));
125
+ collectPaths(tsconfigPaths, compilerOptions.paths, pathsBaseDir(compilerOptions, dir));
113
126
  const sourceMapPairs = [];
114
127
  if (config.references?.length) {
115
128
  walkReferences(compilerOptions, config.references, dir, new Set([tsConfigFilePath]), sourceMapPairs, tsconfigPaths);
@@ -47,6 +47,7 @@ export const createFileNode = () => ({
47
47
  exports: new Map(),
48
48
  duplicates: new Set(),
49
49
  scripts: new Set(),
50
+ importGlobs: [],
50
51
  importedBy: undefined,
51
52
  internalImportCache: undefined,
52
53
  });
@@ -1,5 +1,6 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import { DT_SCOPE, PROTOCOL_VIRTUAL } from '../constants.js';
2
- import { isAbsolute, isInNodeModules, toPosix } from './path.js';
3
+ import { isAbsolute, isInNodeModules, join, toPosix } from './path.js';
3
4
  export const getPackageNameFromModuleSpecifier = (specifier) => {
4
5
  if (!isStartsLikePackageName(specifier))
5
6
  return;
@@ -18,13 +19,33 @@ export const getPackageNameFromModuleSpecifier = (specifier) => {
18
19
  return specifier;
19
20
  };
20
21
  const lastPackageNameMatch = /(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/g;
22
+ const yarnPnpmStorePackageRoot = /^(.*\/node_modules\/\.store\/[^/]+\/package)(?:\/|$)/;
23
+ const yarnPnpmStoreNameCache = new Map();
24
+ const getPackageNameFromYarnPnpmStore = (posixPath) => {
25
+ const match = posixPath.match(yarnPnpmStorePackageRoot);
26
+ if (!match)
27
+ return;
28
+ const root = match[1];
29
+ if (yarnPnpmStoreNameCache.has(root))
30
+ return yarnPnpmStoreNameCache.get(root);
31
+ let name;
32
+ try {
33
+ name = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')).name;
34
+ }
35
+ catch { }
36
+ yarnPnpmStoreNameCache.set(root, name);
37
+ return name;
38
+ };
21
39
  export const getPackageNameFromFilePath = (value) => {
22
40
  const name = value.startsWith('file://') ? value.slice(7) : value;
23
41
  if (name.includes('node_modules/.bin/'))
24
42
  return extractBinary(name);
25
- const match = toPosix(name).match(lastPackageNameMatch);
26
- if (match)
27
- return match[match.length - 1];
43
+ const posixPath = toPosix(name);
44
+ const match = posixPath.match(lastPackageNameMatch);
45
+ if (match) {
46
+ const last = match[match.length - 1];
47
+ return last === '.store' ? (getPackageNameFromYarnPnpmStore(posixPath) ?? last) : last;
48
+ }
28
49
  return name;
29
50
  };
30
51
  export const getPackageNameFromSpecifier = (specifier) => isInNodeModules(specifier) ? getPackageNameFromFilePath(specifier) : getPackageNameFromModuleSpecifier(specifier);
@@ -0,0 +1,7 @@
1
+ import { type Command, type Node } from 'unbash';
2
+ export interface ScriptCommand {
3
+ binary: string;
4
+ args: string[];
5
+ }
6
+ export declare function walkCommands(node: Node): Generator<Command>;
7
+ export declare const getScriptCommands: (script: string) => ScriptCommand[];
@@ -0,0 +1,75 @@
1
+ import { parse } from 'unbash';
2
+ import { extractBinary } from './modules.js';
3
+ const spawningBinaries = new Set(['cross-env', 'retry-cli']);
4
+ export function* walkCommands(node) {
5
+ switch (node.type) {
6
+ case 'Command':
7
+ yield node;
8
+ break;
9
+ case 'AndOr':
10
+ case 'Pipeline':
11
+ for (const command of node.commands)
12
+ yield* walkCommands(command);
13
+ break;
14
+ case 'If':
15
+ for (const statement of node.clause.commands)
16
+ yield* walkCommands(statement.command);
17
+ for (const statement of node.then.commands)
18
+ yield* walkCommands(statement.command);
19
+ if (node.else)
20
+ yield* walkCommands(node.else);
21
+ break;
22
+ case 'While':
23
+ for (const statement of node.clause.commands)
24
+ yield* walkCommands(statement.command);
25
+ for (const statement of node.body.commands)
26
+ yield* walkCommands(statement.command);
27
+ break;
28
+ case 'For':
29
+ case 'Select':
30
+ case 'Subshell':
31
+ case 'BraceGroup':
32
+ for (const statement of node.body.commands)
33
+ yield* walkCommands(statement.command);
34
+ break;
35
+ case 'CompoundList':
36
+ for (const statement of node.commands)
37
+ yield* walkCommands(statement.command);
38
+ break;
39
+ case 'Function':
40
+ case 'Coproc':
41
+ yield* walkCommands(node.body);
42
+ break;
43
+ case 'Statement':
44
+ yield* walkCommands(node.command);
45
+ break;
46
+ }
47
+ }
48
+ export const getScriptCommands = (script) => {
49
+ if (!script)
50
+ return [];
51
+ let parsed;
52
+ try {
53
+ parsed = parse(script);
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ if (!parsed.commands)
59
+ return [];
60
+ const out = [];
61
+ for (const statement of parsed.commands) {
62
+ for (const node of walkCommands(statement.command)) {
63
+ const text = node.name?.value;
64
+ if (!text)
65
+ continue;
66
+ const binary = extractBinary(text);
67
+ const args = node.suffix.map(word => word.value);
68
+ if (spawningBinaries.has(binary))
69
+ out.push(...getScriptCommands(args.filter(arg => arg !== '--').join(' ')));
70
+ else
71
+ out.push({ binary, args });
72
+ }
73
+ }
74
+ return out;
75
+ };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.24.0";
1
+ export declare const version = "6.25.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '6.24.0';
1
+ export const version = '6.25.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "6.24.0",
3
+ "version": "6.25.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "keywords": [
6
6
  "analysis",
package/schema.json CHANGED
@@ -67,6 +67,33 @@
67
67
  "$ref": "#/definitions/issueTypes"
68
68
  }
69
69
  },
70
+ "cycles": {
71
+ "title": "Configure circular dependency (cycles) detection",
72
+ "examples": [
73
+ {
74
+ "dynamicImports": true,
75
+ "allow": [["src/a.ts", "src/b.ts"]]
76
+ }
77
+ ],
78
+ "type": "object",
79
+ "additionalProperties": false,
80
+ "properties": {
81
+ "dynamicImports": {
82
+ "title": "Include dynamic import() edges in cycle detection (excluded by default)",
83
+ "type": "boolean"
84
+ },
85
+ "allow": {
86
+ "title": "Allow (accept) specific cycles by exact path, relative to the root and omitting the closing repeat of the first file",
87
+ "type": "array",
88
+ "items": {
89
+ "type": "array",
90
+ "items": {
91
+ "type": "string"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ },
70
97
  "includeEntryExports": {
71
98
  "$ref": "#/definitions/includeEntryExports"
72
99
  },
@@ -99,6 +126,9 @@
99
126
  "catalog": {
100
127
  "$ref": "#/definitions/ruleValue"
101
128
  },
129
+ "cycles": {
130
+ "$ref": "#/definitions/ruleValue"
131
+ },
102
132
  "dependencies": {
103
133
  "$ref": "#/definitions/ruleValue"
104
134
  },
@@ -251,7 +281,8 @@
251
281
  "duplicates",
252
282
  "enumMembers",
253
283
  "namespaceMembers",
254
- "catalog"
284
+ "catalog",
285
+ "cycles"
255
286
  ]
256
287
  }
257
288
  },
@@ -483,6 +514,10 @@
483
514
  "title": "ESLint plugin configuration (https://knip.dev/reference/plugins/eslint)",
484
515
  "$ref": "#/definitions/plugin"
485
516
  },
517
+ "eve": {
518
+ "title": "eve plugin configuration (https://knip.dev/reference/plugins/eve)",
519
+ "$ref": "#/definitions/plugin"
520
+ },
486
521
  "execa": {
487
522
  "title": "execa plugin configuration (https://knip.dev/reference/plugins/execa)",
488
523
  "$ref": "#/definitions/plugin"
@@ -499,6 +534,10 @@
499
534
  "title": "fast plugin configuration (https://knip.dev/reference/plugins/fast)",
500
535
  "$ref": "#/definitions/plugin"
501
536
  },
537
+ "fumadocs": {
538
+ "title": "fumadocs plugin configuration (https://knip.dev/reference/plugins/fumadocs)",
539
+ "$ref": "#/definitions/plugin"
540
+ },
502
541
  "gatsby": {
503
542
  "title": "Gatsby plugin configuration (https://knip.dev/reference/plugins/gatsby)",
504
543
  "$ref": "#/definitions/plugin"