knip 6.23.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 (128) hide show
  1. package/LICENSE +1 -1
  2. package/dist/ConfigurationChief.d.ts +13 -1
  3. package/dist/ConfigurationChief.js +3 -0
  4. package/dist/ProjectPrincipal.d.ts +2 -0
  5. package/dist/ProjectPrincipal.js +7 -6
  6. package/dist/WorkspaceWorker.d.ts +3 -1
  7. package/dist/WorkspaceWorker.js +5 -2
  8. package/dist/binaries/bash-parser.js +55 -83
  9. package/dist/binaries/index.js +3 -0
  10. package/dist/binaries/resolvers/yarn.js +4 -3
  11. package/dist/compilers/compilers.d.ts +2 -0
  12. package/dist/compilers/compilers.js +15 -4
  13. package/dist/compilers/index.d.ts +30 -6
  14. package/dist/compilers/index.js +25 -10
  15. package/dist/compilers/less.d.ts +7 -0
  16. package/dist/compilers/less.js +37 -0
  17. package/dist/compilers/mdx.d.ts +1 -2
  18. package/dist/compilers/mdx.js +14 -8
  19. package/dist/compilers/scss.d.ts +3 -2
  20. package/dist/compilers/scss.js +17 -14
  21. package/dist/compilers/shared.d.ts +6 -0
  22. package/dist/compilers/shared.js +9 -0
  23. package/dist/compilers/style-preprocessors.d.ts +2 -0
  24. package/dist/compilers/style-preprocessors.js +41 -0
  25. package/dist/compilers/stylus.d.ts +7 -0
  26. package/dist/compilers/stylus.js +36 -0
  27. package/dist/constants.d.ts +5 -1
  28. package/dist/constants.js +7 -0
  29. package/dist/graph/analyze.js +37 -2
  30. package/dist/graph/build.js +23 -1
  31. package/dist/graph-explorer/explorer.d.ts +1 -0
  32. package/dist/graph-explorer/explorer.js +2 -0
  33. package/dist/graph-explorer/operations/find-all-cycles.d.ts +3 -0
  34. package/dist/graph-explorer/operations/find-all-cycles.js +43 -0
  35. package/dist/graph-explorer/operations/find-cycles.js +3 -9
  36. package/dist/graph-explorer/utils.d.ts +10 -1
  37. package/dist/graph-explorer/utils.js +53 -0
  38. package/dist/plugins/astro/compiler-mdx.js +11 -2
  39. package/dist/plugins/astro/compiler.js +8 -4
  40. package/dist/plugins/bun/index.js +28 -14
  41. package/dist/plugins/eve/index.d.ts +3 -0
  42. package/dist/plugins/eve/index.js +22 -0
  43. package/dist/plugins/execa/visitors/execa.js +10 -18
  44. package/dist/plugins/fumadocs/index.d.ts +3 -0
  45. package/dist/plugins/fumadocs/index.js +18 -0
  46. package/dist/plugins/github-actions/index.js +3 -2
  47. package/dist/plugins/graphql-codegen/index.js +9 -7
  48. package/dist/plugins/index.d.ts +2 -0
  49. package/dist/plugins/index.js +4 -0
  50. package/dist/plugins/jest/index.js +13 -3
  51. package/dist/plugins/next/index.js +23 -10
  52. package/dist/plugins/node/index.js +4 -1
  53. package/dist/plugins/nuxt/index.js +4 -2
  54. package/dist/plugins/pnpm/index.js +21 -1
  55. package/dist/plugins/pnpm/types.d.ts +6 -0
  56. package/dist/plugins/pnpm/types.js +1 -0
  57. package/dist/plugins/prettier/index.js +19 -3
  58. package/dist/plugins/prettier/types.d.ts +6 -1
  59. package/dist/plugins/prisma/compiler.js +3 -0
  60. package/dist/plugins/rspack/index.js +5 -0
  61. package/dist/plugins/serverless-framework/index.js +12 -1
  62. package/dist/plugins/serverless-framework/types.d.ts +5 -2
  63. package/dist/plugins/stencil/index.js +59 -1
  64. package/dist/plugins/storybook/index.js +7 -0
  65. package/dist/plugins/svelte/compiler.d.ts +2 -1
  66. package/dist/plugins/svelte/compiler.js +8 -1
  67. package/dist/plugins/tailwind/compiler.js +3 -0
  68. package/dist/plugins/tailwind/index.js +5 -1
  69. package/dist/plugins/typedoc/index.js +9 -3
  70. package/dist/plugins/typedoc/types.d.ts +2 -0
  71. package/dist/plugins/vite/visitors/importMetaGlob.js +1 -8
  72. package/dist/plugins/vue/compiler.d.ts +2 -1
  73. package/dist/plugins/vue/compiler.js +8 -1
  74. package/dist/plugins/webpack/visitors/requireContext.js +2 -13
  75. package/dist/plugins/yarn/index.js +13 -4
  76. package/dist/plugins/yarn/types.d.ts +10 -0
  77. package/dist/plugins/yarn/types.js +1 -0
  78. package/dist/plugins/zx/visitors/zx.js +4 -4
  79. package/dist/reporters/compact.js +1 -2
  80. package/dist/reporters/cycles.d.ts +3 -0
  81. package/dist/reporters/cycles.js +79 -0
  82. package/dist/reporters/index.d.ts +1 -0
  83. package/dist/reporters/index.js +2 -0
  84. package/dist/reporters/json.d.ts +3 -0
  85. package/dist/reporters/json.js +2 -1
  86. package/dist/reporters/symbols.js +1 -2
  87. package/dist/reporters/util/util.d.ts +3 -1
  88. package/dist/reporters/util/util.js +5 -1
  89. package/dist/schema/configuration.d.ts +40 -6
  90. package/dist/schema/configuration.js +6 -0
  91. package/dist/schema/plugins.d.ts +10 -0
  92. package/dist/schema/plugins.js +2 -0
  93. package/dist/types/PluginNames.d.ts +2 -2
  94. package/dist/types/PluginNames.js +2 -0
  95. package/dist/types/config.d.ts +10 -0
  96. package/dist/types/issues.d.ts +3 -0
  97. package/dist/types/module-graph.d.ts +7 -0
  98. package/dist/types/package-json.d.ts +4 -1
  99. package/dist/types.d.ts +1 -1
  100. package/dist/typescript/SourceFileManager.js +3 -2
  101. package/dist/typescript/ast-nodes.d.ts +4 -1
  102. package/dist/typescript/ast-nodes.js +60 -2
  103. package/dist/typescript/comments.js +22 -3
  104. package/dist/typescript/get-imports-and-exports.js +10 -0
  105. package/dist/typescript/glob-imports.d.ts +3 -0
  106. package/dist/typescript/glob-imports.js +49 -0
  107. package/dist/typescript/resolve-module-names.d.ts +2 -0
  108. package/dist/typescript/resolve-module-names.js +35 -1
  109. package/dist/typescript/visitors/calls.js +4 -6
  110. package/dist/typescript/visitors/imports.js +8 -8
  111. package/dist/typescript/visitors/script-visitors.js +4 -4
  112. package/dist/typescript/visitors/walk.js +6 -1
  113. package/dist/util/cli-arguments.d.ts +2 -1
  114. package/dist/util/cli-arguments.js +4 -2
  115. package/dist/util/create-options.d.ts +32 -5
  116. package/dist/util/create-options.js +4 -1
  117. package/dist/util/get-included-issue-types.d.ts +1 -0
  118. package/dist/util/get-included-issue-types.js +4 -2
  119. package/dist/util/issue-initializers.js +1 -1
  120. package/dist/util/load-tsconfig.js +17 -4
  121. package/dist/util/module-graph.js +1 -0
  122. package/dist/util/modules.js +25 -4
  123. package/dist/util/scripts.d.ts +7 -0
  124. package/dist/util/scripts.js +75 -0
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.js +1 -1
  127. package/package.json +1 -1
  128. package/schema.json +40 -1
@@ -0,0 +1,49 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { _syncGlob } from '../util/glob.js';
3
+ import { dirname, isAbsolute, join, toRelative } from '../util/path.js';
4
+ function resolveBaseDir(base, dir, resolveGlobPattern) {
5
+ if (base.startsWith('.'))
6
+ return join(dir, base);
7
+ if (isAbsolute(base))
8
+ return base;
9
+ for (const resolved of resolveGlobPattern(base, dir)) {
10
+ if (resolved !== base && existsSync(resolved))
11
+ return resolved;
12
+ }
13
+ return undefined;
14
+ }
15
+ export function resolveImportGlobs(items, containingFile, resolveGlobPattern, workspaceRoot) {
16
+ const filePaths = [];
17
+ const dir = dirname(containingFile);
18
+ for (const { patterns, base, filter } of items) {
19
+ if (base !== undefined) {
20
+ const cwd = resolveBaseDir(base, dir, resolveGlobPattern);
21
+ if (!cwd)
22
+ continue;
23
+ for (const filePath of _syncGlob({ patterns, cwd })) {
24
+ if (!filter || filter.test(`./${toRelative(filePath, cwd)}`))
25
+ filePaths.push(filePath);
26
+ }
27
+ }
28
+ else {
29
+ const resolved = [];
30
+ for (const pattern of patterns) {
31
+ const isNegated = pattern[0] === '!';
32
+ const specifier = isNegated ? pattern.slice(1) : pattern;
33
+ if (specifier[0] === '/') {
34
+ const rooted = join(workspaceRoot, specifier);
35
+ resolved.push(isNegated ? `!${rooted}` : rooted);
36
+ }
37
+ else {
38
+ for (const p of resolveGlobPattern(pattern, dir))
39
+ resolved.push(p);
40
+ }
41
+ }
42
+ if (resolved.length === 0)
43
+ continue;
44
+ for (const filePath of _syncGlob({ patterns: resolved, cwd: dir }))
45
+ filePaths.push(filePath);
46
+ }
47
+ }
48
+ return filePaths;
49
+ }
@@ -9,6 +9,8 @@ type ScopedRootDirs = Array<{
9
9
  rootDirs: string[];
10
10
  }>;
11
11
  export declare function clearModuleResolutionCaches(): void;
12
+ export type ResolveGlobPattern = (pattern: string, dir: string) => string[];
13
+ export declare function createGlobAliasResolver(scopedPaths: ScopedPaths | undefined): ResolveGlobPattern;
12
14
  export declare function createCustomModuleResolver(compilerOptions: {
13
15
  scopedPaths?: ScopedPaths;
14
16
  scopedRootDirs?: ScopedRootDirs;
@@ -3,7 +3,7 @@ import { isBuiltin } from 'node:module';
3
3
  import { DEFAULT_EXTENSIONS, DTS_EXTENSIONS } from '../constants.js';
4
4
  import { sanitizeSpecifier } from '../util/modules.js';
5
5
  import { timerify } from '../util/Performance.js';
6
- import { dirname, extname, isAbsolute, isInNodeModules, join } from '../util/path.js';
6
+ import { dirname, extname, isAbsolute, isInNodeModules, join, toPosix } from '../util/path.js';
7
7
  import { _createSyncModuleResolver, _resolveModuleSync } from '../util/resolve.js';
8
8
  function pickStringTarget(value) {
9
9
  if (typeof value === 'string')
@@ -56,6 +56,40 @@ function compileRootDirs(scopedRootDirs) {
56
56
  scoped.sort((a, b) => b.scope.length - a.scope.length);
57
57
  return scoped;
58
58
  }
59
+ export function createGlobAliasResolver(scopedPaths) {
60
+ const mappings = compilePathMappings(scopedPaths);
61
+ return (pattern, dir) => {
62
+ if (!mappings)
63
+ return [pattern];
64
+ const isNegated = pattern[0] === '!';
65
+ const specifier = isNegated ? pattern.slice(1) : pattern;
66
+ let best;
67
+ for (const mapping of mappings) {
68
+ const { prefix, wildcard, scope } = mapping;
69
+ if (dir !== scope && !dir.startsWith(`${scope}/`))
70
+ continue;
71
+ const matches = wildcard
72
+ ? specifier.startsWith(prefix)
73
+ : specifier === prefix || specifier.startsWith(`${prefix}/`);
74
+ if (!matches)
75
+ continue;
76
+ if (!best ||
77
+ scope.length > best.scope.length ||
78
+ (scope.length === best.scope.length && prefix.length > best.prefix.length))
79
+ best = mapping;
80
+ }
81
+ if (!best)
82
+ return [pattern];
83
+ const captured = specifier.slice(best.prefix.length);
84
+ const resolved = [];
85
+ for (const value of best.values) {
86
+ const starIdx = value.indexOf('*');
87
+ const mapped = toPosix(starIdx >= 0 ? value.slice(0, starIdx) + captured + value.slice(starIdx + 1) : value + captured);
88
+ resolved.push(isNegated ? `!${mapped}` : mapped);
89
+ }
90
+ return resolved;
91
+ };
92
+ }
59
93
  export function createCustomModuleResolver(compilerOptions, customCompilerExtensions, toSourceFilePath, findWorkspaceManifestImports, tsConfigFile) {
60
94
  const customCompilerExtensionsSet = new Set(customCompilerExtensions);
61
95
  const hasCustomExts = customCompilerExtensionsSet.size > 0;
@@ -1,6 +1,6 @@
1
1
  import { IMPORT_FLAGS, OPAQUE } from '../../constants.js';
2
2
  import { addValue } from '../../util/module-graph.js';
3
- import { getSafeScriptFromArgs, getStringValue, isStringLiteral } from '../ast-nodes.js';
3
+ import { getSafeScriptFromArgs, getScriptFromArg, getStringValue, isStringLiteral } from '../ast-nodes.js';
4
4
  import { isShadowed } from './walk.js';
5
5
  function getRegisteredCustomElement(node, s) {
6
6
  const callee = node.callee;
@@ -162,11 +162,9 @@ export function handleCallExpression(node, s) {
162
162
  if (method) {
163
163
  const arg = node.arguments[0];
164
164
  if (CHILD_PROCESS_COMMAND_METHODS.has(method)) {
165
- if (isStringLiteral(arg)) {
166
- const command = getStringValue(arg);
167
- if (command)
168
- s.scripts.add(command);
169
- }
165
+ const command = getScriptFromArg(arg);
166
+ if (command)
167
+ s.scripts.add(command);
170
168
  return;
171
169
  }
172
170
  if (CHILD_PROCESS_FILE_METHODS.has(method)) {
@@ -26,16 +26,16 @@ export function handleVariableDeclarator(node, s) {
26
26
  : undefined;
27
27
  const localName = prop.value?.type === 'Identifier' ? prop.value.name : importedName;
28
28
  const alias = localName !== importedName ? localName : undefined;
29
- s.addImport(specifier, importedName, alias, undefined, prop.key?.start ?? prop.start, IMPORT_FLAGS.NONE);
29
+ s.addImport(specifier, importedName, alias, undefined, prop.key?.start ?? prop.start, IMPORT_FLAGS.DYNAMIC);
30
30
  }
31
31
  else if (prop.type === 'RestElement' && prop.argument?.type === 'Identifier') {
32
- s.addImport(specifier, IMPORT_STAR, prop.argument.name, undefined, prop.start, IMPORT_FLAGS.NONE);
32
+ s.addImport(specifier, IMPORT_STAR, prop.argument.name, undefined, prop.start, IMPORT_FLAGS.DYNAMIC);
33
33
  }
34
34
  }
35
35
  }
36
36
  else if (node.id.type === 'Identifier') {
37
37
  if (init.type === 'AwaitExpression') {
38
- s.addImport(specifier, 'default', node.id.name, undefined, importExpr.source.start, IMPORT_FLAGS.NONE);
38
+ s.addImport(specifier, 'default', node.id.name, undefined, importExpr.source.start, IMPORT_FLAGS.DYNAMIC);
39
39
  const resolved = s.resolveModule(specifier, s.filePath);
40
40
  if (resolved && !resolved.isExternalLibraryImport && !isInNodeModules(resolved.resolvedFileName)) {
41
41
  s.localImportMap.set(node.id.name, {
@@ -47,11 +47,11 @@ export function handleVariableDeclarator(node, s) {
47
47
  }
48
48
  }
49
49
  else {
50
- s.addImport(specifier, undefined, undefined, undefined, importExpr.source.start, IMPORT_FLAGS.OPAQUE);
50
+ s.addImport(specifier, undefined, undefined, undefined, importExpr.source.start, IMPORT_FLAGS.DYNAMIC | IMPORT_FLAGS.OPAQUE);
51
51
  }
52
52
  }
53
53
  else {
54
- s.addImport(specifier, undefined, undefined, undefined, importExpr.source.start, IMPORT_FLAGS.OPAQUE);
54
+ s.addImport(specifier, undefined, undefined, undefined, importExpr.source.start, IMPORT_FLAGS.DYNAMIC | IMPORT_FLAGS.OPAQUE);
55
55
  }
56
56
  return;
57
57
  }
@@ -117,10 +117,10 @@ export function handleVariableDeclarator(node, s) {
117
117
  }
118
118
  }
119
119
  else if (binding?.type === 'Identifier') {
120
- s.addImport(specifier, 'default', binding.name, undefined, imp.source.start, IMPORT_FLAGS.NONE);
120
+ s.addImport(specifier, 'default', binding.name, undefined, imp.source.start, IMPORT_FLAGS.DYNAMIC);
121
121
  }
122
122
  else {
123
- s.addImport(specifier, undefined, undefined, undefined, imp.source.start, IMPORT_FLAGS.SIDE_EFFECTS);
123
+ s.addImport(specifier, undefined, undefined, undefined, imp.source.start, IMPORT_FLAGS.DYNAMIC | IMPORT_FLAGS.SIDE_EFFECTS);
124
124
  }
125
125
  }
126
126
  }
@@ -257,6 +257,6 @@ export function handleImportExpression(node, s) {
257
257
  return;
258
258
  const specifier = getStringValue(node.source);
259
259
  if (specifier) {
260
- s.addImport(specifier, undefined, undefined, undefined, node.source.start, IMPORT_FLAGS.OPAQUE);
260
+ s.addImport(specifier, undefined, undefined, undefined, node.source.start, IMPORT_FLAGS.DYNAMIC | IMPORT_FLAGS.OPAQUE);
261
261
  }
262
262
  }
@@ -1,12 +1,12 @@
1
+ import { getScriptFromTemplate } from '../ast-nodes.js';
1
2
  export function createBunShellVisitor(ctx) {
2
3
  return {
3
4
  TaggedTemplateExpression(node) {
4
5
  const tag = node.tag;
5
6
  if (tag.type === 'Identifier' && tag.name === '$') {
6
- for (const q of node.quasi.quasis) {
7
- if (q.value.raw)
8
- ctx.addScript(q.value.raw);
9
- }
7
+ const script = getScriptFromTemplate(node.quasi);
8
+ if (script)
9
+ ctx.addScript(script);
10
10
  }
11
11
  },
12
12
  };
@@ -3,7 +3,7 @@ import { FIX_FLAGS, IMPORT_FLAGS, OPAQUE, SYMBOL_TYPE } from '../../constants.js
3
3
  import { addValue } from '../../util/module-graph.js';
4
4
  import { isInNodeModules } from '../../util/path.js';
5
5
  import { timerify } from '../../util/Performance.js';
6
- import { getLineAndCol, getStringValue, isStringLiteral } from '../ast-nodes.js';
6
+ import { collectAugmentationRefs, getLineAndCol, getStringValue, isStringLiteral, } from '../ast-nodes.js';
7
7
  import { EMPTY_TAGS } from './jsdoc.js';
8
8
  import { handleCallExpression, handleNewExpression, trackCustomElementRegistry } from './calls.js';
9
9
  import { handleExportAssignment, handleExportDefault, handleExportNamed, handleExpressionStatement, } from './exports.js';
@@ -211,6 +211,11 @@ const coreVisitorObject = {
211
211
  },
212
212
  TSModuleDeclaration(node) {
213
213
  state.nsRanges.push([node.start, node.end]);
214
+ if (node.kind !== 'global' && isStringLiteral(node.id)) {
215
+ const specifier = getStringValue(node.id);
216
+ for (const name of collectAugmentationRefs(node))
217
+ state.addImport(specifier, name, undefined, undefined, node.id.start, IMPORT_FLAGS.TYPE_ONLY | IMPORT_FLAGS.AUGMENT);
218
+ }
214
219
  },
215
220
  ClassDeclaration(node) {
216
221
  state.classNameStack.push(node.id?.name ?? '');
@@ -1,9 +1,10 @@
1
- export declare const helpText = "\u2702\uFE0F Find unused dependencies, exports and files in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -h, --help Print this help text\n -V, --version Print version\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\n -c, --config [file] Configuration file path\n (default: [.]knip.json[c], knip.(js|ts), knip.config.(js|ts) or package.json#knip)\n --use-tsconfig-files Use tsconfig.json to define project files (override `project` patterns)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n\nMode\n --cache Enable caching\n --cache-location Change cache location (default: node_modules/.cache/knip)\n --include-entry-exports Include entry files when reporting unused exports\n --no-gitignore Don't respect .gitignore\n -p, --production Analyze only production source files (e.g. no test files, devDependencies)\n -s, --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n -w, --watch Watch mode\n\nScope\n -W, --workspace [filter] Filter workspaces by name, directory, or glob (can be repeated)\n -D, --directory [dir] Run process from a different directory (default: cwd)\n --include Report only provided issue type(s), can be comma-separated or repeated (1)\n --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)\n --dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved,catalog\n --exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates\n --files Shortcut for --include files\n --tags Include or exclude tagged exports\n\nFix\n -f, --fix Fix issues (modifies files in your repo)\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --allow-remove-files Allow Knip to remove files (with --fix)\n -F, --format Format modified files after --fix using the local formatter\n\nOutput\n --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated\n --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)\n --reporter Select reporter (default: symbols), can be repeated (3)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress configuration hints\n --no-tag-hints Suppress tag hints\n --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints\n --treat-tag-hints-as-errors Exit with non-zero code (1) if there are any tag hints\n --max-issues Maximum number of total issues before non-zero exit code (default: 0)\n --max-show-issues Maximum number of issues to display per type\n --no-exit-code Always exit with code zero (0)\n\nTroubleshooting\n -d, --debug Show debug output\n --memory Measure memory usage and display data table\n --memory-realtime Log memory usage in realtime\n --performance Measure count and running time of key functions and display stats table\n --performance-fn [name] Measure only function [name]\n -u, --duration Print total running time (zero overhead, no instrumentation)\n --trace Show trace output\n --trace-dependency [name] Show files that import the named dependency\n --trace-export [name] Show trace output for named export(s)\n --trace-file [file] Show trace output for exports in file\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog\n(2) Fixable issue types: dependencies, exports, types, files, catalog\n(3) Built-in reporters: symbols (default), compact, codeowners, json, codeclimate, markdown, disclosure, github-actions\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip --workspace @myorg/* --workspace '!@myorg/legacy'\n$ knip --workspace './apps/*' --workspace '@shared/utils'\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --tags=-lintignore\n\nWebsite: https://knip.dev";
1
+ export declare const helpText = "\u2702\uFE0F Find unused dependencies, exports and files in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -h, --help Print this help text\n -V, --version Print version\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\n -c, --config [file] Configuration file path\n (default: [.]knip.json[c], knip.(js|ts), knip.config.(js|ts) or package.json#knip)\n --use-tsconfig-files Use tsconfig.json to define project files (override `project` patterns)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n\nMode\n --cache Enable caching\n --cache-location Change cache location (default: node_modules/.cache/knip)\n --include-entry-exports Include entry files when reporting unused exports\n --no-gitignore Don't respect .gitignore\n -p, --production Analyze only production source files (e.g. no test files, devDependencies)\n -s, --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n -w, --watch Watch mode\n\nScope\n -W, --workspace [filter] Filter workspaces by name, directory, or glob (can be repeated)\n -D, --directory [dir] Run process from a different directory (default: cwd)\n --include Report only provided issue type(s), can be comma-separated or repeated (1)\n --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)\n --dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved,catalog\n --exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates\n --files Shortcut for --include files\n --cycles Shortcut for --include cycles (circular dependencies)\n --tags Include or exclude tagged exports\n\nFix\n -f, --fix Fix issues (modifies files in your repo)\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --allow-remove-files Allow Knip to remove files (with --fix)\n -F, --format Format modified files after --fix using the local formatter\n\nOutput\n --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated\n --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)\n --reporter Select reporter (default: symbols), can be repeated (3)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress configuration hints\n --no-tag-hints Suppress tag hints\n --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints\n --treat-tag-hints-as-errors Exit with non-zero code (1) if there are any tag hints\n --max-issues Maximum number of total issues before non-zero exit code (default: 0)\n --max-show-issues Maximum number of issues to display per type\n --no-exit-code Always exit with code zero (0)\n\nTroubleshooting\n -d, --debug Show debug output\n --memory Measure memory usage and display data table\n --memory-realtime Log memory usage in realtime\n --performance Measure count and running time of key functions and display stats table\n --performance-fn [name] Measure only function [name]\n -u, --duration Print total running time (zero overhead, no instrumentation)\n --trace Show trace output\n --trace-dependency [name] Show files that import the named dependency\n --trace-export [name] Show trace output for named export(s)\n --trace-file [file] Show trace output for exports in file\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog, cycles\n(2) Fixable issue types: dependencies, exports, types, files, catalog\n(3) Built-in reporters: symbols (default), compact, codeowners, cycles, json, codeclimate, markdown, disclosure, github-actions\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip --workspace @myorg/* --workspace '!@myorg/legacy'\n$ knip --workspace './apps/*' --workspace '@shared/utils'\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --tags=-lintignore\n\nWebsite: https://knip.dev";
2
2
  export type ParsedCLIArgs = ReturnType<typeof parseCLIArgs>;
3
3
  export default function parseCLIArgs(): {
4
4
  cache?: boolean | undefined;
5
5
  'cache-location'?: string | undefined;
6
6
  config?: string | undefined;
7
+ cycles?: boolean | undefined;
7
8
  debug?: boolean | undefined;
8
9
  dependencies?: boolean | undefined;
9
10
  directory?: string | undefined;
@@ -29,6 +29,7 @@ Scope
29
29
  --dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved,catalog
30
30
  --exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates
31
31
  --files Shortcut for --include files
32
+ --cycles Shortcut for --include cycles (circular dependencies)
32
33
  --tags Include or exclude tagged exports
33
34
 
34
35
  Fix
@@ -62,9 +63,9 @@ Troubleshooting
62
63
  --trace-export [name] Show trace output for named export(s)
63
64
  --trace-file [file] Show trace output for exports in file
64
65
 
65
- (1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog
66
+ (1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog, cycles
66
67
  (2) Fixable issue types: dependencies, exports, types, files, catalog
67
- (3) Built-in reporters: symbols (default), compact, codeowners, json, codeclimate, markdown, disclosure, github-actions
68
+ (3) Built-in reporters: symbols (default), compact, codeowners, cycles, json, codeclimate, markdown, disclosure, github-actions
68
69
 
69
70
  Examples:
70
71
 
@@ -84,6 +85,7 @@ export default function parseCLIArgs() {
84
85
  cache: { type: 'boolean' },
85
86
  'cache-location': { type: 'string' },
86
87
  config: { type: 'string', short: 'c' },
88
+ cycles: { type: 'boolean' },
87
89
  debug: { type: 'boolean', short: 'd' },
88
90
  dependencies: { type: 'boolean' },
89
91
  directory: { type: 'string', short: 'D' },
@@ -9,6 +9,7 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
9
9
  config: string | undefined;
10
10
  configFilePath: string | undefined;
11
11
  cwd: string;
12
+ cycles: boolean;
12
13
  dependencies: boolean;
13
14
  exports: boolean;
14
15
  files: boolean;
@@ -30,6 +31,7 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
30
31
  isProduction: boolean;
31
32
  isReportDependencies: boolean;
32
33
  isReportExports: boolean;
34
+ isReportCycles: boolean;
33
35
  isReportFiles: boolean;
34
36
  isReportTypes: boolean;
35
37
  isReportValues: boolean;
@@ -193,6 +195,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
193
195
  entry?: string | string[] | undefined;
194
196
  project?: string | string[] | undefined;
195
197
  } | undefined;
198
+ eve?: string | boolean | string[] | {
199
+ config?: string | string[] | undefined;
200
+ entry?: string | string[] | undefined;
201
+ project?: string | string[] | undefined;
202
+ } | undefined;
196
203
  execa?: string | boolean | string[] | {
197
204
  config?: string | string[] | undefined;
198
205
  entry?: string | string[] | undefined;
@@ -213,6 +220,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
213
220
  entry?: string | string[] | undefined;
214
221
  project?: string | string[] | undefined;
215
222
  } | undefined;
223
+ fumadocs?: string | boolean | string[] | {
224
+ config?: string | string[] | undefined;
225
+ entry?: string | string[] | undefined;
226
+ project?: string | string[] | undefined;
227
+ } | undefined;
216
228
  gatsby?: string | boolean | string[] | {
217
229
  config?: string | string[] | undefined;
218
230
  entry?: string | string[] | undefined;
@@ -829,7 +841,7 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
829
841
  project?: string | string[] | undefined;
830
842
  } | undefined;
831
843
  $schema?: string | undefined;
832
- rules?: Partial<Record<"binaries" | "catalog" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved", "error" | "off" | "warn">> | undefined;
844
+ rules?: Partial<Record<"binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved", "error" | "off" | "warn">> | undefined;
833
845
  entry?: string | string[] | undefined;
834
846
  project?: string | string[] | undefined;
835
847
  paths?: Record<string, string[]> | undefined;
@@ -840,7 +852,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
840
852
  ignoreMembers?: (string | RegExp)[] | undefined;
841
853
  ignoreUnresolved?: (string | RegExp)[] | undefined;
842
854
  ignoreExportsUsedInFile?: boolean | Record<string, boolean | undefined> | undefined;
843
- ignoreIssues?: Record<string, ("binaries" | "catalog" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
855
+ ignoreIssues?: Record<string, ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
856
+ cycles?: {
857
+ allow?: string[][] | undefined;
858
+ dynamicImports?: boolean | undefined;
859
+ } | undefined;
844
860
  ignoreWorkspaces?: string[] | undefined;
845
861
  includeEntryExports?: boolean | undefined;
846
862
  compilers?: Record<string, true | import("../compilers/types.ts").CompilerAsync | import("../compilers/types.ts").CompilerSync> | undefined;
@@ -849,8 +865,8 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
849
865
  tags?: string[] | undefined;
850
866
  treatConfigHintsAsErrors?: boolean | undefined;
851
867
  treatTagHintsAsErrors?: boolean | undefined;
852
- include?: ("binaries" | "catalog" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
853
- exclude?: ("binaries" | "catalog" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
868
+ include?: ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
869
+ exclude?: ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
854
870
  workspaces?: Record<string, {
855
871
  angular?: string | boolean | string[] | {
856
872
  config?: string | string[] | undefined;
@@ -1002,6 +1018,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1002
1018
  entry?: string | string[] | undefined;
1003
1019
  project?: string | string[] | undefined;
1004
1020
  } | undefined;
1021
+ eve?: string | boolean | string[] | {
1022
+ config?: string | string[] | undefined;
1023
+ entry?: string | string[] | undefined;
1024
+ project?: string | string[] | undefined;
1025
+ } | undefined;
1005
1026
  execa?: string | boolean | string[] | {
1006
1027
  config?: string | string[] | undefined;
1007
1028
  entry?: string | string[] | undefined;
@@ -1022,6 +1043,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1022
1043
  entry?: string | string[] | undefined;
1023
1044
  project?: string | string[] | undefined;
1024
1045
  } | undefined;
1046
+ fumadocs?: string | boolean | string[] | {
1047
+ config?: string | string[] | undefined;
1048
+ entry?: string | string[] | undefined;
1049
+ project?: string | string[] | undefined;
1050
+ } | undefined;
1025
1051
  gatsby?: string | boolean | string[] | {
1026
1052
  config?: string | string[] | undefined;
1027
1053
  entry?: string | string[] | undefined;
@@ -1647,13 +1673,14 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1647
1673
  ignoreMembers?: (string | RegExp)[] | undefined;
1648
1674
  ignoreUnresolved?: (string | RegExp)[] | undefined;
1649
1675
  ignoreExportsUsedInFile?: boolean | Record<string, boolean | undefined> | undefined;
1650
- ignoreIssues?: Record<string, ("binaries" | "catalog" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
1676
+ ignoreIssues?: Record<string, ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
1651
1677
  includeEntryExports?: boolean | undefined;
1652
1678
  }> | undefined;
1653
1679
  };
1654
1680
  rules: {
1655
1681
  binaries: import("../types/issues.ts").IssueSeverity;
1656
1682
  catalog: import("../types/issues.ts").IssueSeverity;
1683
+ cycles: import("../types/issues.ts").IssueSeverity;
1657
1684
  dependencies: import("../types/issues.ts").IssueSeverity;
1658
1685
  devDependencies: import("../types/issues.ts").IssueSeverity;
1659
1686
  duplicates: import("../types/issues.ts").IssueSeverity;
@@ -4,7 +4,7 @@ import { knipConfigurationSchema } from '../schema/configuration.js';
4
4
  import { getCatalogContainer } from './catalog.js';
5
5
  import { ConfigurationError } from './errors.js';
6
6
  import { findFile, loadJSON } from './fs.js';
7
- import { getIncludedIssueTypes, shorthandDeps, shorthandExports, shorthandFiles } from './get-included-issue-types.js';
7
+ import { getIncludedIssueTypes, shorthandCycles, shorthandDeps, shorthandExports, shorthandFiles, } from './get-included-issue-types.js';
8
8
  import { defaultRules } from './issue-initializers.js';
9
9
  import { loadResolvedConfigFile } from './load-config.js';
10
10
  import { _load } from './loader.js';
@@ -82,6 +82,7 @@ export const createOptions = async (options) => {
82
82
  ...(args.dependencies ? shorthandDeps : []),
83
83
  ...(args.exports ? shorthandExports : []),
84
84
  ...(args.files ? shorthandFiles : []),
85
+ ...(args.cycles ? shorthandCycles : []),
85
86
  ],
86
87
  });
87
88
  for (const [key, value] of Object.entries(includedIssueTypes)) {
@@ -98,6 +99,7 @@ export const createOptions = async (options) => {
98
99
  config: args.config,
99
100
  configFilePath,
100
101
  cwd,
102
+ cycles: args.cycles ?? false,
101
103
  dependencies: args.dependencies ?? false,
102
104
  exports: args.exports ?? false,
103
105
  files: args.files ?? false,
@@ -128,6 +130,7 @@ export const createOptions = async (options) => {
128
130
  includedIssueTypes.enumMembers ||
129
131
  includedIssueTypes.namespaceMembers ||
130
132
  includedIssueTypes.duplicates,
133
+ isReportCycles: includedIssueTypes.cycles,
131
134
  isReportFiles: includedIssueTypes.files,
132
135
  isReportTypes: includedIssueTypes.types ||
133
136
  includedIssueTypes.nsTypes ||
@@ -10,5 +10,6 @@ export declare const defaultExcludedIssueTypes: string[];
10
10
  export declare const shorthandDeps: string[];
11
11
  export declare const shorthandExports: string[];
12
12
  export declare const shorthandFiles: string[];
13
+ export declare const shorthandCycles: string[];
13
14
  export declare const getIncludedIssueTypes: (options: GetIncludedIssueTypesOptions) => Report;
14
15
  export {};
@@ -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[];