knip 6.43.0 → 6.44.1

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 (168) hide show
  1. package/README.md +2 -4
  2. package/dist/CacheConsultant.d.ts +1 -0
  3. package/dist/CacheConsultant.js +2 -0
  4. package/dist/CatalogCounselor.d.ts +1 -3
  5. package/dist/CatalogCounselor.js +18 -15
  6. package/dist/ConfigurationChief.d.ts +24 -0
  7. package/dist/DependencyDeputy.d.ts +2 -1
  8. package/dist/DependencyDeputy.js +11 -6
  9. package/dist/IssueCollector.js +1 -0
  10. package/dist/ProjectPrincipal.d.ts +4 -2
  11. package/dist/ProjectPrincipal.js +32 -10
  12. package/dist/WorkspaceWorker.d.ts +5 -2
  13. package/dist/WorkspaceWorker.js +20 -7
  14. package/dist/binaries/resolvers/bun.js +7 -2
  15. package/dist/binaries/util.js +2 -1
  16. package/dist/cli.js +6 -1
  17. package/dist/compilers/index.d.ts +5 -0
  18. package/dist/compilers/index.js +1 -1
  19. package/dist/constants.d.ts +2 -0
  20. package/dist/constants.js +2 -0
  21. package/dist/graph/analyze.js +3 -2
  22. package/dist/graph/build.d.ts +2 -0
  23. package/dist/graph/build.js +37 -22
  24. package/dist/graph-explorer/cache.d.ts +2 -1
  25. package/dist/graph-explorer/cache.js +5 -1
  26. package/dist/graph-explorer/explorer.d.ts +3 -5
  27. package/dist/graph-explorer/explorer.js +24 -3
  28. package/dist/plugins/babel/index.js +6 -1
  29. package/dist/plugins/biome/index.js +1 -1
  30. package/dist/plugins/cspell/index.js +10 -2
  31. package/dist/plugins/dependency-cruiser/index.js +2 -2
  32. package/dist/plugins/docusaurus/helpers.js +4 -4
  33. package/dist/plugins/electron-vite/index.js +2 -2
  34. package/dist/plugins/eleventy/index.js +2 -2
  35. package/dist/plugins/expressive-code/index.d.ts +1 -1
  36. package/dist/plugins/expressive-code/index.js +2 -2
  37. package/dist/plugins/gatsby/index.js +6 -6
  38. package/dist/plugins/gatsby/types.d.ts +1 -1
  39. package/dist/plugins/github-actions/index.js +1 -1
  40. package/dist/plugins/i18next-parser/index.js +2 -2
  41. package/dist/plugins/index.d.ts +5 -1
  42. package/dist/plugins/index.js +8 -0
  43. package/dist/plugins/jasmine/index.js +2 -2
  44. package/dist/plugins/karma/index.js +4 -4
  45. package/dist/plugins/kysely-codegen/index.d.ts +3 -0
  46. package/dist/plugins/kysely-codegen/index.js +20 -0
  47. package/dist/plugins/lefthook/index.js +2 -2
  48. package/dist/plugins/lingui/index.d.ts +3 -0
  49. package/dist/plugins/lingui/index.js +16 -0
  50. package/dist/plugins/lockfile-lint/index.js +2 -2
  51. package/dist/plugins/lost-pixel/index.js +2 -2
  52. package/dist/plugins/lunaria/index.js +2 -2
  53. package/dist/plugins/marko/index.js +5 -6
  54. package/dist/plugins/mastra/index.d.ts +3 -0
  55. package/dist/plugins/mastra/index.js +57 -0
  56. package/dist/plugins/mcp/index.js +1 -1
  57. package/dist/plugins/mise/index.js +0 -3
  58. package/dist/plugins/mocha/index.js +43 -4
  59. package/dist/plugins/mocha/types.d.ts +1 -0
  60. package/dist/plugins/npm-package-json-lint/index.js +1 -1
  61. package/dist/plugins/npm-package-json-lint/types.d.ts +1 -1
  62. package/dist/plugins/nx/index.js +3 -8
  63. package/dist/plugins/nyc/index.js +1 -1
  64. package/dist/plugins/openapi-ts/index.js +2 -2
  65. package/dist/plugins/oxfmt/index.js +2 -2
  66. package/dist/plugins/playwright/index.js +6 -11
  67. package/dist/plugins/pnpm/index.js +2 -4
  68. package/dist/plugins/purgecss/index.d.ts +3 -0
  69. package/dist/plugins/purgecss/index.js +16 -0
  70. package/dist/plugins/railway/index.js +1 -4
  71. package/dist/plugins/relay/index.js +1 -1
  72. package/dist/plugins/release-it/index.js +1 -1
  73. package/dist/plugins/remix/index.js +1 -1
  74. package/dist/plugins/rsbuild/index.js +29 -1
  75. package/dist/plugins/rsbuild/types.d.ts +8 -0
  76. package/dist/plugins/rstest/index.js +2 -2
  77. package/dist/plugins/serverless-framework/index.js +1 -1
  78. package/dist/plugins/storybook/index.js +5 -5
  79. package/dist/plugins/sveltekit/resolveFromAST.js +1 -1
  80. package/dist/plugins/svgr/index.js +2 -1
  81. package/dist/plugins/swc/index.js +8 -3
  82. package/dist/plugins/syncpack/index.js +2 -2
  83. package/dist/plugins/tanstack-router/index.js +3 -2
  84. package/dist/plugins/taskfile/index.js +4 -7
  85. package/dist/plugins/textlint/helpers.js +2 -2
  86. package/dist/plugins/typescript/index.js +7 -3
  87. package/dist/plugins/unocss/index.js +2 -2
  88. package/dist/plugins/vite-plugin-pwa/index.js +1 -4
  89. package/dist/plugins/vite-plugin-pwa/resolveFromAST.d.ts +0 -2
  90. package/dist/plugins/vite-plugin-pwa/resolveFromAST.js +2 -2
  91. package/dist/plugins/vite-pwa-assets-generator/index.js +2 -2
  92. package/dist/plugins/vitest/helpers.js +4 -7
  93. package/dist/plugins/vitest/index.js +1 -1
  94. package/dist/plugins/webpack/index.d.ts +2 -0
  95. package/dist/plugins/webpack/index.js +11 -6
  96. package/dist/plugins/yarn/index.js +2 -4
  97. package/dist/reporters/codeclimate.d.ts +2 -2
  98. package/dist/reporters/codeclimate.js +2 -4
  99. package/dist/reporters/codeowners.d.ts +2 -2
  100. package/dist/reporters/codeowners.js +9 -9
  101. package/dist/reporters/compact.d.ts +2 -2
  102. package/dist/reporters/compact.js +8 -7
  103. package/dist/reporters/cycles.d.ts +2 -2
  104. package/dist/reporters/cycles.js +7 -6
  105. package/dist/reporters/disclosure.d.ts +2 -2
  106. package/dist/reporters/disclosure.js +6 -4
  107. package/dist/reporters/github-actions.d.ts +2 -2
  108. package/dist/reporters/github-actions.js +7 -5
  109. package/dist/reporters/index.d.ts +10 -10
  110. package/dist/reporters/json.d.ts +2 -2
  111. package/dist/reporters/json.js +2 -4
  112. package/dist/reporters/markdown.d.ts +2 -2
  113. package/dist/reporters/markdown.js +11 -9
  114. package/dist/reporters/sarif.d.ts +2 -2
  115. package/dist/reporters/sarif.js +2 -3
  116. package/dist/reporters/symbols.d.ts +2 -2
  117. package/dist/reporters/symbols.js +6 -4
  118. package/dist/run.d.ts +1 -1
  119. package/dist/run.js +3 -10
  120. package/dist/schema/configuration.d.ts +60 -0
  121. package/dist/schema/plugins.d.ts +20 -0
  122. package/dist/schema/plugins.js +4 -0
  123. package/dist/session/configuration.d.ts +15 -0
  124. package/dist/session/configuration.js +62 -0
  125. package/dist/session/incremental.d.ts +54 -0
  126. package/dist/session/incremental.js +49 -0
  127. package/dist/session/session.d.ts +1 -1
  128. package/dist/session/session.js +63 -27
  129. package/dist/session/watch.d.ts +2 -0
  130. package/dist/session/watch.js +41 -0
  131. package/dist/types/PluginNames.d.ts +2 -2
  132. package/dist/types/PluginNames.js +4 -0
  133. package/dist/types/config.d.ts +1 -0
  134. package/dist/types/issues.d.ts +4 -0
  135. package/dist/types/package-json.d.ts +0 -3
  136. package/dist/typescript/get-imports-and-exports.js +2 -0
  137. package/dist/typescript/visitors/calls.js +15 -11
  138. package/dist/typescript/visitors/imports.d.ts +3 -1
  139. package/dist/typescript/visitors/imports.js +77 -53
  140. package/dist/typescript/visitors/members.js +23 -26
  141. package/dist/typescript/visitors/walk.d.ts +3 -0
  142. package/dist/typescript/visitors/walk.js +43 -2
  143. package/dist/util/cli-arguments.d.ts +2 -1
  144. package/dist/util/cli-arguments.js +3 -0
  145. package/dist/util/create-input-handler.js +1 -1
  146. package/dist/util/create-options.d.ts +43 -2
  147. package/dist/util/create-options.js +17 -4
  148. package/dist/util/file-entry-cache.d.ts +2 -0
  149. package/dist/util/file-entry-cache.js +19 -1
  150. package/dist/util/gitignore-cache.d.ts +1 -0
  151. package/dist/util/gitignore-cache.js +1 -0
  152. package/dist/util/glob-core.js +4 -2
  153. package/dist/util/glob.d.ts +1 -0
  154. package/dist/util/glob.js +6 -0
  155. package/dist/util/input.d.ts +2 -0
  156. package/dist/util/loader.d.ts +1 -0
  157. package/dist/util/loader.js +29 -1
  158. package/dist/util/modules.js +5 -2
  159. package/dist/util/path.d.ts +1 -0
  160. package/dist/util/path.js +1 -0
  161. package/dist/util/reporter.d.ts +1 -1
  162. package/dist/util/reporter.js +53 -9
  163. package/dist/util/watch.d.ts +5 -11
  164. package/dist/util/watch.js +84 -68
  165. package/dist/version.d.ts +1 -1
  166. package/dist/version.js +1 -1
  167. package/package.json +1 -1
  168. package/schema.json +16 -0
@@ -2,6 +2,7 @@ import { OPAQUE } from '../../constants.js';
2
2
  import { addValue } from '../../util/module-graph.js';
3
3
  import { getStringValue, isStringLiteral } from '../ast-nodes.js';
4
4
  import { isShadowed } from './walk.js';
5
+ const chainNames = [];
5
6
  function markWholeObjectRead(internalImport, id) {
6
7
  (internalImport.enumerated ??= new Set()).add(id);
7
8
  }
@@ -9,7 +10,10 @@ function isNumericKey(value) {
9
10
  return value != null && Number.isFinite(Number(value)) && String(Number(value)) === value;
10
11
  }
11
12
  export function handleMemberExpression(node, s) {
12
- if (node.object.type === 'MemberExpression' && node.object.object.type === 'MemberExpression') {
13
+ if (node.object.type === 'MemberExpression' &&
14
+ node.object.object.type === 'MemberExpression' &&
15
+ !node.computed &&
16
+ node.property.type === 'Identifier') {
13
17
  s.chainedMemberExprs.add(node.object);
14
18
  }
15
19
  if (node.object.type === 'Identifier') {
@@ -143,34 +147,27 @@ export function handleMemberExpression(node, s) {
143
147
  }
144
148
  }
145
149
  if (node.object.type === 'MemberExpression' &&
146
- !node.object.computed &&
147
150
  node.object.object.type === 'MemberExpression' &&
148
- !node.object.object.computed &&
149
- node.object.object.object.type === 'Identifier' &&
150
- node.object.object.property.type === 'Identifier' &&
151
- node.object.property.type === 'Identifier' &&
152
- !node.computed &&
153
- node.property.type === 'Identifier') {
154
- const rootName = node.object.object.object.name;
155
- if (!isShadowed(rootName, node.object.object.object.start)) {
156
- const _import = s.localImportMap.get(rootName);
157
- if (_import) {
158
- const internalImport = s.internal.get(_import.filePath);
159
- if (internalImport) {
160
- const a = node.object.object.property.name;
161
- const b = node.object.property.name;
162
- const c = node.property.name;
163
- s.addNsMemberRefs(internalImport, rootName, a);
164
- s.addNsMemberRefs(internalImport, rootName, `${a}.${b}`);
165
- s.addNsMemberRefs(internalImport, rootName, `${a}.${b}.${c}`);
151
+ !s.chainedMemberExprs.has(node)) {
152
+ chainNames.length = 0;
153
+ let root = node;
154
+ while (root.type === 'MemberExpression' && !root.computed && root.property.type === 'Identifier') {
155
+ chainNames.push(root.property.name);
156
+ root = root.object;
157
+ }
158
+ if (root.type === 'Identifier' && !isShadowed(root.name, root.start)) {
159
+ const _import = s.localImportMap.get(root.name);
160
+ const internalImport = _import && s.internal.get(_import.filePath);
161
+ if (internalImport || !_import) {
162
+ let path = '';
163
+ for (let i = chainNames.length - 1; i >= 0; i--) {
164
+ path = path ? `${path}.${chainNames[i]}` : chainNames[i];
165
+ if (internalImport)
166
+ s.addNsMemberRefs(internalImport, root.name, path);
167
+ else
168
+ s.memberRefsInFile.push(root.name, path);
166
169
  }
167
170
  }
168
- else {
169
- const a = node.object.object.property.name;
170
- const b = node.object.property.name;
171
- const c = node.property.name;
172
- s.memberRefsInFile.push(rootName, a, rootName, `${a}.${b}`, rootName, `${a}.${b}.${c}`);
173
- }
174
171
  }
175
172
  }
176
173
  if (node.object.type === 'MemberExpression' &&
@@ -44,6 +44,7 @@ interface WalkContext {
44
44
  programFiles: Set<string>;
45
45
  entryFiles: Set<string>;
46
46
  handledImportExpressions: Set<number>;
47
+ caughtImportExpressions: Set<number>;
47
48
  visitor: Visitor;
48
49
  getJSDocTags: (nodeStart: number) => Set<string>;
49
50
  }
@@ -53,6 +54,8 @@ export interface WalkState extends WalkContext {
53
54
  isJS: boolean;
54
55
  isModuleFile: boolean;
55
56
  handledImportExpressions: Set<number>;
57
+ caughtTryBlockEnds: number[];
58
+ functionCaughtTryBlockEnds: number[][];
56
59
  bareExprRefs: Set<string>;
57
60
  accessedAliases: Set<string>;
58
61
  nsContainers: Map<string, Map<string, string>>;
@@ -7,7 +7,7 @@ import { collectAugmentationRefs, getLineAndCol, getStringValue, isStringLiteral
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';
10
- import { handleImportExpression, handleVariableDeclarator } from './imports.js';
10
+ import { getPromiseAllElements, handleImportExpression, handleImportThen, handleVariableDeclarator, } from './imports.js';
11
11
  import { handleJSXMemberExpression, handleMemberExpression } from './members.js';
12
12
  let state;
13
13
  const _getFix = (start, end, flags) => state.options.isFixExports ? [start, end, flags ?? FIX_FLAGS.NONE] : undefined;
@@ -267,8 +267,10 @@ const coreVisitorObject = {
267
267
  state.scopeEnds[state.scopeDepth] = node.end;
268
268
  state.scopeDepth++;
269
269
  },
270
- 'BlockStatement:exit'() {
270
+ 'BlockStatement:exit'(node) {
271
271
  state.scopeDepth--;
272
+ if (state.caughtTryBlockEnds[state.caughtTryBlockEnds.length - 1] === node.end)
273
+ state.caughtTryBlockEnds.pop();
272
274
  },
273
275
  TSModuleDeclaration(node) {
274
276
  state.nsRanges.push([node.start, node.end]);
@@ -319,6 +321,8 @@ const coreVisitorObject = {
319
321
  state.staticBlockDepth--;
320
322
  },
321
323
  FunctionDeclaration(node) {
324
+ state.functionCaughtTryBlockEnds.push(state.caughtTryBlockEnds);
325
+ state.caughtTryBlockEnds = [];
322
326
  if (node.id?.name) {
323
327
  state.localDeclarationTypes.set(node.id.name, SYMBOL_TYPE.FUNCTION);
324
328
  state.localDeclarations.set(node.id.name, node);
@@ -327,12 +331,25 @@ const coreVisitorObject = {
327
331
  }
328
332
  _addParamShadows(node.params, node.body);
329
333
  },
334
+ 'FunctionDeclaration:exit'() {
335
+ state.caughtTryBlockEnds = state.functionCaughtTryBlockEnds.pop();
336
+ },
330
337
  FunctionExpression(node) {
338
+ state.functionCaughtTryBlockEnds.push(state.caughtTryBlockEnds);
339
+ state.caughtTryBlockEnds = [];
331
340
  _addParamShadows(node.params, node.body);
332
341
  },
342
+ 'FunctionExpression:exit'() {
343
+ state.caughtTryBlockEnds = state.functionCaughtTryBlockEnds.pop();
344
+ },
333
345
  ArrowFunctionExpression(node) {
346
+ state.functionCaughtTryBlockEnds.push(state.caughtTryBlockEnds);
347
+ state.caughtTryBlockEnds = [];
334
348
  _addParamShadows(node.params, node.body);
335
349
  },
350
+ 'ArrowFunctionExpression:exit'() {
351
+ state.caughtTryBlockEnds = state.functionCaughtTryBlockEnds.pop();
352
+ },
336
353
  CatchClause(node) {
337
354
  if (node.param?.type === 'Identifier' && node.body) {
338
355
  _addShadowRange(node.param.name, [node.body.start, node.body.end]);
@@ -380,7 +397,29 @@ const coreVisitorObject = {
380
397
  ImportExpression(node) {
381
398
  handleImportExpression(node, state);
382
399
  },
400
+ TryStatement(node) {
401
+ if (node.handler)
402
+ state.caughtTryBlockEnds.push(node.block.end);
403
+ },
404
+ AwaitExpression(node) {
405
+ if (state.caughtTryBlockEnds.length === 0)
406
+ return;
407
+ const { argument } = node;
408
+ if (argument.type === 'ImportExpression') {
409
+ state.caughtImportExpressions.add(argument.start);
410
+ }
411
+ else {
412
+ const elements = getPromiseAllElements(argument);
413
+ if (!elements)
414
+ return;
415
+ for (const element of elements) {
416
+ if (element?.type === 'ImportExpression')
417
+ state.caughtImportExpressions.add(element.start);
418
+ }
419
+ }
420
+ },
383
421
  CallExpression(node) {
422
+ handleImportThen(node, state);
384
423
  handleCallExpression(node, state);
385
424
  },
386
425
  NewExpression(node) {
@@ -833,6 +872,8 @@ function walkAST(program, sourceText, filePath, hasModuleSyntax, ctx) {
833
872
  localToExports: new Map(),
834
873
  customElementRegistries: new Set(),
835
874
  classNameStack: [],
875
+ caughtTryBlockEnds: [],
876
+ functionCaughtTryBlockEnds: [],
836
877
  staticBlockDepth: 0,
837
878
  addExport: _addExport,
838
879
  getFix: _getFix,
@@ -1,4 +1,4 @@
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 Include 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,catalogReferences\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, catalogReferences, 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, sarif\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 Include 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,catalogReferences\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 --output-file Write reporter output to a file instead of stdout ([reporter=]path), can be repeated\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, catalogReferences, 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, sarif\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 --reporter symbols --reporter json --output-file json=knip.json\n$ knip --tags=-lintignore\n\nWebsite: https://knip.dev";
2
2
  export type ParsedCLIArgs = ReturnType<typeof parseCLIArgs>;
3
3
  export declare const parseNumericOption: (value: string | undefined, option: string) => number | undefined;
4
4
  export default function parseCLIArgs(): {
@@ -29,6 +29,7 @@ export default function parseCLIArgs(): {
29
29
  'no-gitignore'?: boolean | undefined;
30
30
  'no-progress'?: boolean | undefined;
31
31
  'no-tag-hints'?: boolean | undefined;
32
+ 'output-file'?: string[] | undefined;
32
33
  performance?: boolean | undefined;
33
34
  'performance-fn'?: string | undefined;
34
35
  production?: boolean | undefined;
@@ -44,6 +44,7 @@ Output
44
44
  --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)
45
45
  --reporter Select reporter (default: symbols), can be repeated (3)
46
46
  --reporter-options Pass extra options to the reporter (as JSON string, see example)
47
+ --output-file Write reporter output to a file instead of stdout ([reporter=]path), can be repeated
47
48
  --no-config-hints Suppress configuration hints
48
49
  --no-tag-hints Suppress tag hints
49
50
  --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints
@@ -77,6 +78,7 @@ $ knip --workspace @myorg/* --workspace '!@myorg/legacy'
77
78
  $ knip --workspace './apps/*' --workspace '@shared/utils'
78
79
  $ knip -c ./config/knip.json --reporter compact
79
80
  $ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
81
+ $ knip --reporter symbols --reporter json --output-file json=knip.json
80
82
  $ knip --tags=-lintignore
81
83
 
82
84
  Website: https://knip.dev`;
@@ -118,6 +120,7 @@ export default function parseCLIArgs() {
118
120
  'no-gitignore': { type: 'boolean' },
119
121
  'no-progress': { type: 'boolean', short: 'n' },
120
122
  'no-tag-hints': { type: 'boolean' },
123
+ 'output-file': { type: 'string', multiple: true },
121
124
  performance: { type: 'boolean' },
122
125
  'performance-fn': { type: 'string' },
123
126
  production: { type: 'boolean', short: 'p' },
@@ -60,7 +60,7 @@ export const createInputHandler = (deputy, chief, isGitIgnored, addIssue, extern
60
60
  isDevOnly: isConfig(input),
61
61
  isTypeOnly: input.isTypeOnly,
62
62
  });
63
- if (input.isTypeOnly && input.containingFilePath) {
63
+ if (input.alsoReferenceOwner && input.containingFilePath) {
64
64
  const owningWorkspace = chief.findWorkspaceByFilePath(input.containingFilePath);
65
65
  if (owningWorkspace && owningWorkspace !== inputWorkspace) {
66
66
  const isOwnerHandled = deputy.maybeAddReferencedExternalDependency(owningWorkspace, packageName, {
@@ -3,9 +3,10 @@ import { type ParsedCLIArgs } from './cli-arguments.ts';
3
3
  interface CreateOptions extends Partial<Options> {
4
4
  args?: ParsedCLIArgs;
5
5
  }
6
- export declare const createOptions: (options: CreateOptions) => Promise<{
6
+ export declare const createOptions: (options: CreateOptions, isReload?: boolean) => Promise<{
7
+ createdFrom: CreateOptions;
7
8
  cacheLocation: string;
8
- catalog: import("../CatalogCounselor.ts").CatalogContainer;
9
+ catalog: import("../CatalogCounselor.ts").CatalogContainer[];
9
10
  config: string | undefined;
10
11
  configFilePath: string | undefined;
11
12
  cwd: string;
@@ -326,6 +327,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
326
327
  entry?: string | string[] | undefined;
327
328
  project?: string | string[] | undefined;
328
329
  } | undefined;
330
+ 'kysely-codegen'?: string | boolean | string[] | {
331
+ config?: string | string[] | undefined;
332
+ entry?: string | string[] | undefined;
333
+ project?: string | string[] | undefined;
334
+ } | undefined;
329
335
  ladle?: string | boolean | string[] | {
330
336
  config?: string | string[] | undefined;
331
337
  entry?: string | string[] | undefined;
@@ -341,6 +347,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
341
347
  entry?: string | string[] | undefined;
342
348
  project?: string | string[] | undefined;
343
349
  } | undefined;
350
+ lingui?: string | boolean | string[] | {
351
+ config?: string | string[] | undefined;
352
+ entry?: string | string[] | undefined;
353
+ project?: string | string[] | undefined;
354
+ } | undefined;
344
355
  'lint-staged'?: string | boolean | string[] | {
345
356
  config?: string | string[] | undefined;
346
357
  entry?: string | string[] | undefined;
@@ -381,6 +392,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
381
392
  entry?: string | string[] | undefined;
382
393
  project?: string | string[] | undefined;
383
394
  } | undefined;
395
+ mastra?: string | boolean | string[] | {
396
+ config?: string | string[] | undefined;
397
+ entry?: string | string[] | undefined;
398
+ project?: string | string[] | undefined;
399
+ } | undefined;
384
400
  mcp?: string | boolean | string[] | {
385
401
  config?: string | string[] | undefined;
386
402
  entry?: string | string[] | undefined;
@@ -611,6 +627,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
611
627
  entry?: string | string[] | undefined;
612
628
  project?: string | string[] | undefined;
613
629
  } | undefined;
630
+ purgecss?: string | boolean | string[] | {
631
+ config?: string | string[] | undefined;
632
+ entry?: string | string[] | undefined;
633
+ project?: string | string[] | undefined;
634
+ } | undefined;
614
635
  quasar?: string | boolean | string[] | {
615
636
  config?: string | string[] | undefined;
616
637
  entry?: string | string[] | undefined;
@@ -1348,6 +1369,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1348
1369
  entry?: string | string[] | undefined;
1349
1370
  project?: string | string[] | undefined;
1350
1371
  } | undefined;
1372
+ 'kysely-codegen'?: string | boolean | string[] | {
1373
+ config?: string | string[] | undefined;
1374
+ entry?: string | string[] | undefined;
1375
+ project?: string | string[] | undefined;
1376
+ } | undefined;
1351
1377
  ladle?: string | boolean | string[] | {
1352
1378
  config?: string | string[] | undefined;
1353
1379
  entry?: string | string[] | undefined;
@@ -1363,6 +1389,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1363
1389
  entry?: string | string[] | undefined;
1364
1390
  project?: string | string[] | undefined;
1365
1391
  } | undefined;
1392
+ lingui?: string | boolean | string[] | {
1393
+ config?: string | string[] | undefined;
1394
+ entry?: string | string[] | undefined;
1395
+ project?: string | string[] | undefined;
1396
+ } | undefined;
1366
1397
  'lint-staged'?: string | boolean | string[] | {
1367
1398
  config?: string | string[] | undefined;
1368
1399
  entry?: string | string[] | undefined;
@@ -1403,6 +1434,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1403
1434
  entry?: string | string[] | undefined;
1404
1435
  project?: string | string[] | undefined;
1405
1436
  } | undefined;
1437
+ mastra?: string | boolean | string[] | {
1438
+ config?: string | string[] | undefined;
1439
+ entry?: string | string[] | undefined;
1440
+ project?: string | string[] | undefined;
1441
+ } | undefined;
1406
1442
  mcp?: string | boolean | string[] | {
1407
1443
  config?: string | string[] | undefined;
1408
1444
  entry?: string | string[] | undefined;
@@ -1633,6 +1669,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
1633
1669
  entry?: string | string[] | undefined;
1634
1670
  project?: string | string[] | undefined;
1635
1671
  } | undefined;
1672
+ purgecss?: string | boolean | string[] | {
1673
+ config?: string | string[] | undefined;
1674
+ entry?: string | string[] | undefined;
1675
+ project?: string | string[] | undefined;
1676
+ } | undefined;
1636
1677
  quasar?: string | boolean | string[] | {
1637
1678
  config?: string | string[] | undefined;
1638
1679
  entry?: string | string[] | undefined;
@@ -8,12 +8,12 @@ import { findFile, loadJSON } from './fs.js';
8
8
  import { getIncludedIssueTypes, shorthandCycles, shorthandDeps, shorthandExports, shorthandFiles, } from './get-included-issue-types.js';
9
9
  import { defaultRules } from './issue-initializers.js';
10
10
  import { loadResolvedConfigFile } from './load-config.js';
11
- import { _load } from './loader.js';
11
+ import { _load, unload } from './loader.js';
12
12
  import { logWarning } from './log.js';
13
13
  import { getKeysByValue } from './object.js';
14
14
  import { isAbsolute, isInternal, join, resolveCwd, toAbsolute } from './path.js';
15
15
  import { splitTags } from './tag.js';
16
- export const createOptions = async (options) => {
16
+ export const createOptions = async (options, isReload = false) => {
17
17
  const { args = {} } = options;
18
18
  const cwd = resolveCwd(options.cwd ?? args.directory ?? '.');
19
19
  const manifestPath = findFile(cwd, 'package.json');
@@ -32,6 +32,8 @@ export const createOptions = async (options) => {
32
32
  if (args.config && !configFilePath && !manifest.knip) {
33
33
  throw new ConfigurationError(`Unable to find ${args.config} or package.json#knip`);
34
34
  }
35
+ if (options.isSession && !isReload && configFilePath)
36
+ unload([configFilePath]);
35
37
  const loadedConfig = Object.assign({}, manifest.knip, configFilePath ? await loadResolvedConfigFile(configFilePath, args) : {});
36
38
  const validIssueTypes = new Set(ISSUE_TYPES);
37
39
  for (const key of ['rules', 'include', 'exclude']) {
@@ -60,6 +62,16 @@ export const createOptions = async (options) => {
60
62
  configFilePath = manifestPath;
61
63
  const pnpmWorkspacePath = findFile(cwd, 'pnpm-workspace.yaml');
62
64
  const pnpmWorkspace = pnpmWorkspacePath && (await _load(pnpmWorkspacePath));
65
+ const catalog = [await getCatalogContainer(cwd, manifest, manifestPath, pnpmWorkspacePath, pnpmWorkspace)];
66
+ for (const source in pnpmWorkspace?.include) {
67
+ if (!source.startsWith('.'))
68
+ continue;
69
+ const filePath = join(cwd, source);
70
+ const included = await _load(filePath);
71
+ if (!included)
72
+ continue;
73
+ catalog.push({ filePath, catalog: included.catalog, catalogs: included.catalogs, overrides: included.overrides });
74
+ }
63
75
  const workspaces = pnpmWorkspace?.packages ??
64
76
  (manifest.workspaces
65
77
  ? Array.isArray(manifest.workspaces)
@@ -102,8 +114,9 @@ export const createOptions = async (options) => {
102
114
  const preprocessorOptions = args['preprocessor-options'] ??
103
115
  (parsedConfig.preprocessorOptions ? JSON.stringify(parsedConfig.preprocessorOptions) : '');
104
116
  return {
117
+ createdFrom: options,
105
118
  cacheLocation: args['cache-location'] ?? join(cwd, 'node_modules', '.cache', 'knip'),
106
- catalog: await getCatalogContainer(cwd, manifest, manifestPath, pnpmWorkspacePath, pnpmWorkspace),
119
+ catalog,
107
120
  config: args.config,
108
121
  configFilePath,
109
122
  cwd,
@@ -145,7 +158,7 @@ export const createOptions = async (options) => {
145
158
  includedIssueTypes.enumMembers ||
146
159
  includedIssueTypes.namespaceMembers,
147
160
  isReportValues: includedIssueTypes.exports || includedIssueTypes.nsExports,
148
- isSession: options.isSession ?? false,
161
+ isSession: options.isSession ?? args.watch ?? options.isWatch ?? false,
149
162
  isShowProgress: !isDebug &&
150
163
  !isTrace &&
151
164
  args['no-progress'] !== true &&
@@ -14,8 +14,10 @@ export declare class FileEntryCache<T> {
14
14
  filePath: string;
15
15
  cache: Map<string, MetaData<T>>;
16
16
  normalizedEntries: Map<string, FileDescriptor<T>>;
17
+ private isDirty;
17
18
  constructor(cacheId: string, _path: string);
18
19
  getFileDescriptor(filePath: string): FileDescriptor<T>;
20
+ setFileData(filePath: string, data: T): void;
19
21
  removeEntry(entryName: string): void;
20
22
  reconcile(): void;
21
23
  }
@@ -18,6 +18,7 @@ export class FileEntryCache {
18
18
  filePath;
19
19
  cache = new Map();
20
20
  normalizedEntries = new Map();
21
+ isDirty = false;
21
22
  constructor(cacheId, _path) {
22
23
  this.filePath = path.resolve(_path, cacheId);
23
24
  if (isFile(this.filePath))
@@ -58,22 +59,39 @@ export class FileEntryCache {
58
59
  meta = { size: cSize, mtime: cTime };
59
60
  this.cache.set(filePath, meta);
60
61
  }
62
+ if (changed)
63
+ this.isDirty = true;
61
64
  const fd = { key: filePath, changed, meta };
62
65
  this.normalizedEntries.set(filePath, fd);
63
66
  return fd;
64
67
  }
68
+ setFileData(filePath, data) {
69
+ const fd = this.getFileDescriptor(filePath);
70
+ if (!fd.meta)
71
+ return;
72
+ fd.meta.data = data;
73
+ this.isDirty = true;
74
+ }
65
75
  removeEntry(entryName) {
66
76
  if (!isAbsolute(entryName))
67
77
  entryName = resolve(entryName);
68
78
  this.normalizedEntries.delete(entryName);
69
- this.cache.delete(entryName);
79
+ if (this.cache.delete(entryName))
80
+ this.isDirty = true;
70
81
  }
71
82
  reconcile() {
83
+ for (const filePath of this.cache.keys()) {
84
+ if (!this.normalizedEntries.has(filePath))
85
+ this.removeEntry(filePath);
86
+ }
87
+ if (!this.isDirty)
88
+ return;
72
89
  try {
73
90
  const dir = path.dirname(this.filePath);
74
91
  if (!isDirectory(dir))
75
92
  fs.mkdirSync(dir, { recursive: true });
76
93
  fs.writeFileSync(this.filePath, serialize(this.cache));
94
+ this.isDirty = false;
77
95
  }
78
96
  catch (_err) {
79
97
  debugLog('*', `Error writing cache to ${this.filePath}`);
@@ -5,6 +5,7 @@ export interface CachedGitignoreResult {
5
5
  gitignoreFiles: string[];
6
6
  perDirIgnores: Map<string, Gitignores>;
7
7
  }
8
+ export declare const clearGitignoreCache: () => void;
8
9
  export declare const initGitignoreCache: (cacheLocation: string) => void;
9
10
  export declare const isGitignoreCacheEnabled: () => boolean;
10
11
  export declare const flushGitignoreCache: () => void;
@@ -2,6 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { createDiskCache, mtimeMatches } from './disk-cache.js';
4
4
  const store = createDiskCache('gitignore');
5
+ export const clearGitignoreCache = store.clear;
5
6
  export const initGitignoreCache = store.init;
6
7
  export const isGitignoreCacheEnabled = store.isEnabled;
7
8
  export const flushGitignoreCache = store.flush;
@@ -1,6 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { readdir, readFileSync } from 'node:fs';
3
- import { escapePath, glob as tinyGlob } from 'tinyglobby';
3
+ import { escapePath, glob as tinyGlob, isDynamicPattern } from 'tinyglobby';
4
4
  import picomatch from 'picomatch';
5
5
  import { GLOBAL_IGNORE_PATTERNS } from '../constants.js';
6
6
  import { compact, partition } from './array.js';
@@ -292,7 +292,9 @@ export async function glob(_patterns, options) {
292
292
  }
293
293
  cachedGlobIgnores.set(options.dir, compact(_ignore));
294
294
  }
295
- const ignorePatterns = (cachedIgnores ?? _ignore).concat(negatedPatterns.map(pattern => pattern.slice(1)));
295
+ const ignores = cachedIgnores ?? _ignore;
296
+ const isStatic = options.gitignore && !patterns.some(pattern => isDynamicPattern(pattern));
297
+ const ignorePatterns = (isStatic ? expandIgnorePatterns(ignores) : ignores).concat(negatedPatterns.map(pattern => pattern.slice(1)));
296
298
  const { dir, label, ...fgOptions } = {
297
299
  ...options,
298
300
  ignore: ignorePatterns,
@@ -8,6 +8,7 @@ interface GlobOptions {
8
8
  }
9
9
  export declare const removeProductionSuffix: (pattern: string) => string;
10
10
  export declare const prependDirToPattern: (dir: string, pattern: string) => string;
11
+ export declare const rebasePattern: (pattern: string, base: string, dir: string) => string;
11
12
  export declare const negate: (pattern: string) => string;
12
13
  export declare const hasProductionSuffix: (pattern: string) => boolean;
13
14
  export declare const hasNoProductionSuffix: (pattern: string) => boolean;
package/dist/util/glob.js CHANGED
@@ -23,6 +23,12 @@ export const prependDirToPattern = (dir, pattern) => {
23
23
  return `!${join(dir, pattern.slice(1))}`;
24
24
  return join(dir, pattern);
25
25
  };
26
+ export const rebasePattern = (pattern, base, dir) => {
27
+ const isNegated = pattern.startsWith('!');
28
+ const id = isNegated ? pattern.slice(1) : pattern;
29
+ const rebased = relative(dir, isAbsolute(id) ? id : join(base, id));
30
+ return isNegated ? `!${rebased}` : rebased;
31
+ };
26
32
  export const negate = (pattern) => pattern.replace(/^!?/, '!');
27
33
  export const hasProductionSuffix = (pattern) => pattern.endsWith('!');
28
34
  export const hasNoProductionSuffix = (pattern) => !pattern.endsWith('!');
@@ -7,6 +7,7 @@ export interface Input {
7
7
  production?: boolean;
8
8
  optional?: boolean;
9
9
  isTypeOnly?: boolean;
10
+ alsoReferenceOwner?: boolean;
10
11
  dir?: string;
11
12
  containingFilePath?: string;
12
13
  allowIncludeExports?: boolean;
@@ -33,6 +34,7 @@ interface IgnoreInput extends Input {
33
34
  type Options = {
34
35
  optional?: boolean;
35
36
  isTypeOnly?: boolean;
37
+ alsoReferenceOwner?: boolean;
36
38
  dir?: string;
37
39
  containingFilePath?: string;
38
40
  allowIncludeExports?: boolean;
@@ -1,3 +1,4 @@
1
1
  declare const load: (filePath: string) => Promise<any>;
2
2
  export declare const _load: typeof load;
3
+ export declare const unload: (filePaths: Iterable<string>) => void;
3
4
  export {};
@@ -6,11 +6,25 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
+ import { createRequire } from 'node:module';
10
+ import { pathToFileURL } from 'node:url';
9
11
  import { LoaderError } from './errors.js';
10
12
  import { loadFile, loadJSON, loadJSONC, loadTOML, loadYAML, parseJSONC, parseYAML } from './fs.js';
11
13
  import { jiti } from './jiti.js';
12
14
  import { timerify } from './Performance.js';
13
- import { extname, isInternal } from './path.js';
15
+ import { extname, isInternal, toNative } from './path.js';
16
+ const versions = new Map();
17
+ const isReloadable = (ext) => ext === '.js' || ext === '.mjs' || ext === '.cjs';
18
+ const reload = async (filePath, version) => {
19
+ let imported;
20
+ try {
21
+ imported = jiti(filePath);
22
+ }
23
+ catch {
24
+ imported = await import(__rewriteRelativeImportExtension(`${pathToFileURL(filePath).href}?v=${version}`));
25
+ }
26
+ return imported.default ?? imported;
27
+ };
14
28
  const load = async (filePath) => {
15
29
  try {
16
30
  const ext = extname(filePath);
@@ -42,6 +56,10 @@ const load = async (filePath) => {
42
56
  if (ext === '.toml') {
43
57
  return await loadTOML(filePath);
44
58
  }
59
+ const version = versions.get(filePath) ?? 0;
60
+ versions.set(filePath, version);
61
+ if (version && isReloadable(ext))
62
+ return await reload(filePath, version);
45
63
  return await jiti.import(filePath, { default: true });
46
64
  }
47
65
  catch (error) {
@@ -49,3 +67,13 @@ const load = async (filePath) => {
49
67
  }
50
68
  };
51
69
  export const _load = timerify(load);
70
+ const { cache } = createRequire(import.meta.url);
71
+ export const unload = (filePaths) => {
72
+ for (const filePath of filePaths) {
73
+ delete cache[filePath];
74
+ delete cache[toNative(filePath)];
75
+ const version = versions.get(filePath);
76
+ if (version !== undefined)
77
+ versions.set(filePath, version + 1);
78
+ }
79
+ };
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { DT_SCOPE, PROTOCOL_VIRTUAL } from '../constants.js';
2
+ import { DT_SCOPE, PROTOCOL_CLOUDFLARE, PROTOCOL_VIRTUAL } from '../constants.js';
3
3
  import { isAbsolute, isInNodeModules, join, toPosix } from './path.js';
4
4
  export const getPackageNameFromModuleSpecifier = (specifier) => {
5
5
  if (!isStartsLikePackageName(specifier) && !isTildePackageName(specifier))
@@ -53,7 +53,9 @@ const isPackageNameStart = (ch) => (ch >= 65 && ch <= 90) || (ch >= 97 && ch <=
53
53
  const isPackageScopeStart = (ch) => isPackageNameStart(ch) || ch === 46 || ch === 95 || ch === 126;
54
54
  export const isStartsLikePackageName = (specifier) => {
55
55
  const ch = specifier.charCodeAt(0);
56
- return ch === 64 ? isPackageScopeStart(specifier.charCodeAt(1)) : isPackageNameStart(ch);
56
+ return ch === 64
57
+ ? isPackageScopeStart(specifier.charCodeAt(1))
58
+ : isPackageNameStart(ch) && specifier.charCodeAt(1) !== 58;
57
59
  };
58
60
  const isTildePackageName = (specifier) => specifier.charCodeAt(0) === 126 && isPackageNameStart(specifier.charCodeAt(1));
59
61
  export const stripVersionFromSpecifier = (specifier) => specifier.replace(/(\S+)@.*/, '$1');
@@ -87,6 +89,7 @@ const CHAR_HASH = 35;
87
89
  const CHAR_QUESTION = 63;
88
90
  export const sanitizeSpecifier = (specifier) => {
89
91
  if (specifier.startsWith('node:') ||
92
+ specifier.startsWith(PROTOCOL_CLOUDFLARE) ||
90
93
  isAbsolute(specifier) ||
91
94
  specifier.charCodeAt(0) === CHAR_COLON ||
92
95
  specifier.startsWith(PROTOCOL_VIRTUAL)) {