knip 5.52.0 → 5.54.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 (105) hide show
  1. package/dist/ConfigurationChief.d.ts +1 -0
  2. package/dist/IssueFixer.d.ts +1 -1
  3. package/dist/IssueFixer.js +13 -3
  4. package/dist/PrincipalFactory.js +3 -17
  5. package/dist/ProjectPrincipal.d.ts +2 -2
  6. package/dist/ProjectPrincipal.js +14 -3
  7. package/dist/WorkspaceWorker.d.ts +0 -1
  8. package/dist/WorkspaceWorker.js +4 -19
  9. package/dist/cli.js +10 -6
  10. package/dist/compilers/index.d.ts +10 -0
  11. package/dist/graph/build.js +12 -7
  12. package/dist/index.js +15 -4
  13. package/dist/plugins/ava/index.d.ts +1 -2
  14. package/dist/plugins/ava/index.js +2 -7
  15. package/dist/plugins/bun/index.d.ts +2 -2
  16. package/dist/plugins/bun/index.js +2 -2
  17. package/dist/plugins/cucumber/index.d.ts +1 -2
  18. package/dist/plugins/cucumber/index.js +2 -5
  19. package/dist/plugins/cypress/index.d.ts +1 -2
  20. package/dist/plugins/cypress/index.js +6 -9
  21. package/dist/plugins/cypress/types.d.ts +8 -0
  22. package/dist/plugins/eleventy/helpers.d.ts +10 -2
  23. package/dist/plugins/eleventy/index.d.ts +3 -6
  24. package/dist/plugins/eleventy/index.js +11 -16
  25. package/dist/plugins/eleventy/types.d.ts +9 -7
  26. package/dist/plugins/expo/index.d.ts +2 -5
  27. package/dist/plugins/expo/index.js +4 -6
  28. package/dist/plugins/github-action/index.d.ts +2 -2
  29. package/dist/plugins/github-action/index.js +2 -2
  30. package/dist/plugins/index.d.ts +20 -28
  31. package/dist/plugins/index.js +2 -0
  32. package/dist/plugins/jest/index.d.ts +1 -2
  33. package/dist/plugins/jest/index.js +4 -12
  34. package/dist/plugins/karma/index.d.ts +1 -3
  35. package/dist/plugins/karma/index.js +0 -10
  36. package/dist/plugins/ladle/index.d.ts +1 -2
  37. package/dist/plugins/ladle/index.js +4 -7
  38. package/dist/plugins/metro/index.d.ts +2 -3
  39. package/dist/plugins/metro/index.js +17 -14
  40. package/dist/plugins/mocha/index.d.ts +1 -2
  41. package/dist/plugins/mocha/index.js +2 -6
  42. package/dist/plugins/msw/index.d.ts +2 -2
  43. package/dist/plugins/msw/index.js +2 -2
  44. package/dist/plugins/netlify/index.d.ts +1 -2
  45. package/dist/plugins/netlify/index.js +4 -7
  46. package/dist/plugins/node/index.d.ts +2 -2
  47. package/dist/plugins/node/index.js +2 -2
  48. package/dist/plugins/nuxt/index.d.ts +2 -2
  49. package/dist/plugins/nuxt/index.js +2 -2
  50. package/dist/plugins/playwright/index.d.ts +1 -3
  51. package/dist/plugins/playwright/index.js +5 -7
  52. package/dist/plugins/playwright-ct/index.d.ts +0 -1
  53. package/dist/plugins/playwright-ct/index.js +1 -2
  54. package/dist/plugins/postcss/index.js +3 -1
  55. package/dist/plugins/preconstruct/index.d.ts +1 -1
  56. package/dist/plugins/preconstruct/index.js +2 -2
  57. package/dist/plugins/react-cosmos/index.d.ts +1 -2
  58. package/dist/plugins/react-cosmos/index.js +4 -6
  59. package/dist/plugins/react-router/index.d.ts +2 -2
  60. package/dist/plugins/react-router/index.js +2 -2
  61. package/dist/plugins/relay/index.d.ts +2 -2
  62. package/dist/plugins/relay/index.js +2 -2
  63. package/dist/plugins/rspack/index.js +2 -3
  64. package/dist/plugins/size-limit/index.d.ts +2 -1
  65. package/dist/plugins/size-limit/index.js +10 -0
  66. package/dist/plugins/storybook/index.d.ts +1 -2
  67. package/dist/plugins/storybook/index.js +2 -5
  68. package/dist/plugins/svelte/index.d.ts +2 -1
  69. package/dist/plugins/svelte/index.js +7 -0
  70. package/dist/plugins/svgo/index.d.ts +8 -0
  71. package/dist/plugins/svgo/index.js +11 -0
  72. package/dist/plugins/vite/index.d.ts +0 -1
  73. package/dist/plugins/vite/index.js +1 -2
  74. package/dist/plugins/vitest/index.d.ts +1 -3
  75. package/dist/plugins/vitest/index.js +35 -24
  76. package/dist/plugins/vitest/types.d.ts +12 -0
  77. package/dist/plugins/vue/index.js +2 -5
  78. package/dist/plugins/webpack/index.d.ts +1 -5
  79. package/dist/plugins/webpack/index.js +36 -17
  80. package/dist/plugins/wrangler/index.d.ts +2 -2
  81. package/dist/plugins/wrangler/index.js +2 -2
  82. package/dist/plugins.js +1 -1
  83. package/dist/reporters/watch.js +1 -1
  84. package/dist/schema/configuration.d.ts +56 -0
  85. package/dist/schema/plugins.d.ts +23 -0
  86. package/dist/schema/plugins.js +1 -0
  87. package/dist/types/PluginNames.d.ts +2 -2
  88. package/dist/types/PluginNames.js +1 -0
  89. package/dist/types/cli.d.ts +1 -0
  90. package/dist/types/config.d.ts +0 -2
  91. package/dist/types/project.d.ts +0 -1
  92. package/dist/util/Performance.d.ts +25 -7
  93. package/dist/util/Performance.js +70 -34
  94. package/dist/util/cli-arguments.d.ts +4 -1
  95. package/dist/util/cli-arguments.js +7 -1
  96. package/dist/util/glob-core.d.ts +5 -6
  97. package/dist/util/glob-core.js +30 -29
  98. package/dist/util/input.d.ts +7 -1
  99. package/dist/util/input.js +7 -0
  100. package/dist/util/string.d.ts +1 -0
  101. package/dist/util/string.js +10 -0
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/package.json +2 -2
  105. package/schema.json +4 -0
@@ -1,54 +1,69 @@
1
+ import os from 'node:os';
1
2
  import { PerformanceObserver, performance } from 'node:perf_hooks';
2
- import { constants } from 'node:perf_hooks';
3
3
  import { memoryUsage } from 'node:process';
4
- import prettyMilliseconds from 'pretty-ms';
5
4
  import parsedArgValues from './cli-arguments.js';
6
- import { debugLog } from './debug.js';
7
5
  import { getStats } from './math.js';
8
6
  import { Table } from './table.js';
9
- const { performance: isEnabled = false } = parsedArgValues;
7
+ const { performance: isPerformanceEnabled = false, memory: isMemoryEnabled = false, 'memory-realtime': memoryRealtime = false, } = parsedArgValues;
10
8
  export const timerify = (fn, name = fn.name) => {
11
- if (!isEnabled)
9
+ if (!isPerformanceEnabled)
12
10
  return fn;
13
11
  return performance.timerify(Object.defineProperty(fn, 'name', { get: () => name }));
14
12
  };
13
+ const getMemInfo = () => Object.assign({ freemem: os.freemem() }, memoryUsage());
14
+ const twoFixed = (value) => (typeof value === 'number' ? value.toFixed(2) : value);
15
+ const inMB = (bytes) => bytes / 1024 / 1024;
16
+ const keys = ['heapUsed', 'heapTotal', 'freemem'];
17
+ const logHead = () => console.log(keys.map(key => key.padStart(10)).join(' '));
18
+ const log = (memInfo) => console.log(keys.map(key => twoFixed(inMB(memInfo[key])).padStart(10)).join(' '));
15
19
  class Performance {
16
20
  isEnabled;
21
+ isPerformanceEnabled;
22
+ isMemoryEnabled;
17
23
  startTime = 0;
18
24
  endTime = 0;
19
- entries = [];
20
- instanceId;
25
+ perfEntries = [];
26
+ memEntries = [];
27
+ perfId;
28
+ memId;
21
29
  fnObserver;
22
- gcObserver;
30
+ memObserver;
23
31
  memoryUsageStart;
24
- constructor(isEnabled) {
25
- if (isEnabled) {
26
- this.startTime = performance.now();
27
- this.instanceId = Math.floor(performance.now() * 100);
32
+ freeMemoryStart;
33
+ constructor({ isPerformanceEnabled = false, isMemoryEnabled = false }) {
34
+ this.isEnabled = isPerformanceEnabled || isMemoryEnabled;
35
+ this.isPerformanceEnabled = isPerformanceEnabled;
36
+ this.isMemoryEnabled = isMemoryEnabled;
37
+ this.startTime = performance.now();
38
+ const instanceId = Math.floor(performance.now() * 100);
39
+ this.perfId = `perf-${instanceId}`;
40
+ this.memId = `mem-${instanceId}`;
41
+ if (isPerformanceEnabled) {
28
42
  this.fnObserver = new PerformanceObserver(items => {
29
43
  for (const entry of items.getEntries()) {
30
- this.entries.push(entry);
44
+ this.perfEntries.push(entry);
31
45
  }
32
46
  });
33
- this.fnObserver.observe({ entryTypes: ['function'] });
34
- this.gcObserver = new PerformanceObserver(items => {
35
- for (const item of items.getEntries()) {
36
- if (item.detail?.kind === constants.NODE_PERFORMANCE_GC_MAJOR) {
37
- debugLog('*', `GC (after ${prettyMilliseconds(item.startTime)} in ${prettyMilliseconds(item.duration)})`);
38
- }
47
+ this.fnObserver.observe({ type: 'function' });
48
+ }
49
+ if (isMemoryEnabled) {
50
+ this.memObserver = new PerformanceObserver(items => {
51
+ for (const entry of items.getEntries()) {
52
+ this.memEntries.push(entry);
39
53
  }
40
54
  });
41
- this.gcObserver.observe({ entryTypes: ['gc'] });
42
- this.memoryUsageStart = memoryUsage();
55
+ this.memObserver.observe({ type: 'mark' });
56
+ if (memoryRealtime)
57
+ logHead();
58
+ this.addMemoryMark(0);
43
59
  }
44
- this.isEnabled = isEnabled;
45
60
  }
46
61
  setMark(name) {
47
- const id = `${this.instanceId}:${name}`;
62
+ const id = `${this.perfId}:${name}`;
48
63
  performance.mark(`${id}:start`);
49
64
  }
50
65
  clearMark(name) {
51
- const id = `${this.instanceId}:${name}`;
66
+ const id = `${this.perfId}:${name}`;
52
67
  performance.mark(`${id}:end`);
53
68
  performance.measure(id, `${id}:start`, `${id}:end`);
54
69
  performance.clearMarks(`${id}:start`);
@@ -59,18 +74,17 @@ class Performance {
59
74
  await new Promise(resolve => setTimeout(resolve, 1));
60
75
  this.clearMark('_flush');
61
76
  }
62
- getEntriesByName() {
63
- return this.entries.reduce((entries, entry) => {
64
- const name = entry.name.replace(`${this.instanceId}:`, '');
77
+ getPerfEntriesByName() {
78
+ return this.perfEntries.reduce((entries, entry) => {
79
+ const name = entry.name.replace(`${this.perfId}:`, '');
65
80
  entries[name] = entries[name] ?? [];
66
81
  entries[name].push(entry.duration);
67
82
  return entries;
68
83
  }, {});
69
84
  }
70
- getTable() {
71
- const entriesByName = this.getEntriesByName();
85
+ getPerformanceTable() {
86
+ const entriesByName = this.getPerfEntriesByName();
72
87
  const table = new Table({ header: true });
73
- const twoFixed = (value) => (typeof value === 'number' ? value.toFixed(2) : value);
74
88
  for (const [name, values] of Object.entries(entriesByName)) {
75
89
  const stats = getStats(values);
76
90
  table.newRow();
@@ -82,7 +96,28 @@ class Performance {
82
96
  table.cell('sum', stats.sum, twoFixed);
83
97
  }
84
98
  table.sort('sum|desc');
85
- return table.toString().trim();
99
+ return table.toString();
100
+ }
101
+ addMemoryMark(index) {
102
+ if (!this.isMemoryEnabled)
103
+ return;
104
+ const id = `${this.memId}:${index}`;
105
+ const detail = getMemInfo();
106
+ performance.mark(id, { detail });
107
+ if (memoryRealtime && detail)
108
+ log(detail);
109
+ }
110
+ getMemoryTable() {
111
+ const table = new Table({ header: true });
112
+ for (const entry of this.memEntries) {
113
+ if (!entry.detail)
114
+ continue;
115
+ table.newRow();
116
+ table.cell('heapUsed', inMB(entry.detail.heapUsed), twoFixed);
117
+ table.cell('heapTotal', inMB(entry.detail.heapTotal), twoFixed);
118
+ table.cell('freemem', inMB(entry.detail.freemem), twoFixed);
119
+ }
120
+ return table.toString();
86
121
  }
87
122
  getCurrentDurationInMs(startTime) {
88
123
  return performance.now() - (startTime ?? this.startTime);
@@ -91,7 +126,7 @@ class Performance {
91
126
  return (memoryUsage().heapUsed ?? 0) - (this.memoryUsageStart?.heapUsed ?? 0);
92
127
  }
93
128
  getCurrentMemUsageInMb() {
94
- return Math.round((this.getMemHeapUsage() / 1024 / 1024) * 100) / 100;
129
+ return twoFixed(inMB(this.getMemHeapUsage()));
95
130
  }
96
131
  async finalize() {
97
132
  if (!this.isEnabled)
@@ -99,8 +134,9 @@ class Performance {
99
134
  await this.flush();
100
135
  }
101
136
  reset() {
102
- this.entries = [];
137
+ this.perfEntries = [];
103
138
  this.fnObserver?.disconnect();
139
+ this.memObserver?.disconnect();
104
140
  }
105
141
  }
106
- export const perfObserver = new Performance(isEnabled);
142
+ export const perfObserver = new Performance({ isPerformanceEnabled, isMemoryEnabled });
@@ -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 -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.(js|ts), knip.config.(js|ts) or package.json#knip)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n --production Analyze only production source files (e.g. no test files, devDependencies)\n --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\n --directory [dir] Run process from a different directory (default: cwd)\n --cache Enable caching\n --cache-location Change cache location (default: node_modules/.cache/knip)\n --watch Watch mode\n --no-gitignore Don't use .gitignore\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\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --files Shortcut for --include files\n --fix Fix issues\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 --include-libs Include type definitions from external dependencies (default: false)\n --include-entry-exports Include entry files when reporting unused exports\n --isolate-workspaces Isolate workspaces into separate programs\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\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: symbols, compact, codeowners, json, codeclimate, markdown, disclosure, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --tags Include or exclude tagged exports\n --no-config-hints Suppress configuration hints\n --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints\n --no-exit-code Always exit with code zero (0)\n --max-issues Maximum number of issues before non-zero exit code (default: 0)\n -d, --debug Show debug output\n --trace Show trace output\n --trace-export [name] Show trace output for named export(s)\n --trace-file [file] Show trace output for exports in file\n --performance Measure count and running time of expensive functions and display stats table\n -h, --help Print this help text\n -V, --version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates\n(2) Fixable issue types: dependencies, exports, types\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\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 -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.(js|ts), knip.config.(js|ts) or package.json#knip)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n --production Analyze only production source files (e.g. no test files, devDependencies)\n --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\n --directory [dir] Run process from a different directory (default: cwd)\n --cache Enable caching\n --cache-location Change cache location (default: node_modules/.cache/knip)\n --watch Watch mode\n --no-gitignore Don't use .gitignore\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\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --files Shortcut for --include files\n --fix Fix issues\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --format Format modified files after --fix using the local formatter\n --allow-remove-files Allow Knip to remove files (with --fix)\n --include-libs Include type definitions from external dependencies (default: false)\n --include-entry-exports Include entry files when reporting unused exports\n --isolate-workspaces Isolate workspaces into separate programs\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\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: symbols, compact, codeowners, json, codeclimate, markdown, disclosure, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --tags Include or exclude tagged exports\n --no-config-hints Suppress configuration hints\n --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints\n --no-exit-code Always exit with code zero (0)\n --max-issues Maximum number of issues before non-zero exit code (default: 0)\n -d, --debug Show debug output\n --trace Show trace output\n --trace-export [name] Show trace output for named export(s)\n --trace-file [file] Show trace output for exports in file\n --performance Measure count and running time of key functions and display stats table\n --memory Measure memory usage and display data table\n --memory-realtime Log memory usage in realtime\n -h, --help Print this help text\n -V, --version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates\n(2) Fixable issue types: dependencies, exports, types\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\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
  declare const _default: {
3
3
  cache?: boolean | undefined;
4
4
  'cache-location'?: string | undefined;
@@ -13,6 +13,7 @@ declare const _default: {
13
13
  files?: boolean | undefined;
14
14
  fix?: boolean | undefined;
15
15
  'fix-type'?: string[] | undefined;
16
+ format?: boolean | undefined;
16
17
  'allow-remove-files'?: boolean | undefined;
17
18
  help?: boolean | undefined;
18
19
  'ignore-internal'?: boolean | undefined;
@@ -21,6 +22,8 @@ declare const _default: {
21
22
  'include-entry-exports'?: boolean | undefined;
22
23
  'isolate-workspaces'?: boolean | undefined;
23
24
  'max-issues'?: string | undefined;
25
+ memory?: boolean | undefined;
26
+ 'memory-realtime'?: boolean | undefined;
24
27
  'no-config-hints'?: boolean | undefined;
25
28
  'no-exit-code'?: boolean | undefined;
26
29
  'no-gitignore'?: boolean | undefined;
@@ -21,6 +21,7 @@ Options:
21
21
  --files Shortcut for --include files
22
22
  --fix Fix issues
23
23
  --fix-type Fix only issues of type, can be comma-separated or repeated (2)
24
+ --format Format modified files after --fix using the local formatter
24
25
  --allow-remove-files Allow Knip to remove files (with --fix)
25
26
  --include-libs Include type definitions from external dependencies (default: false)
26
27
  --include-entry-exports Include entry files when reporting unused exports
@@ -39,7 +40,9 @@ Options:
39
40
  --trace Show trace output
40
41
  --trace-export [name] Show trace output for named export(s)
41
42
  --trace-file [file] Show trace output for exports in file
42
- --performance Measure count and running time of expensive functions and display stats table
43
+ --performance Measure count and running time of key functions and display stats table
44
+ --memory Measure memory usage and display data table
45
+ --memory-realtime Log memory usage in realtime
43
46
  -h, --help Print this help text
44
47
  -V, --version Print version
45
48
 
@@ -73,6 +76,7 @@ try {
73
76
  files: { type: 'boolean' },
74
77
  fix: { type: 'boolean' },
75
78
  'fix-type': { type: 'string', multiple: true },
79
+ format: { type: 'boolean' },
76
80
  'allow-remove-files': { type: 'boolean' },
77
81
  help: { type: 'boolean', short: 'h' },
78
82
  'ignore-internal': { type: 'boolean' },
@@ -81,6 +85,8 @@ try {
81
85
  'include-entry-exports': { type: 'boolean' },
82
86
  'isolate-workspaces': { type: 'boolean' },
83
87
  'max-issues': { type: 'string' },
88
+ memory: { type: 'boolean' },
89
+ 'memory-realtime': { type: 'boolean' },
84
90
  'no-config-hints': { type: 'boolean' },
85
91
  'no-exit-code': { type: 'boolean' },
86
92
  'no-gitignore': { type: 'boolean' },
@@ -3,13 +3,12 @@ type Options = {
3
3
  gitignore: boolean;
4
4
  cwd: string;
5
5
  };
6
- type GlobOptions = {
7
- readonly gitignore: boolean;
8
- readonly cwd: string;
9
- readonly dir: string;
6
+ interface GlobOptions extends FastGlobOptions {
7
+ gitignore: boolean;
8
+ cwd: string;
9
+ dir: string;
10
10
  label?: string;
11
- } & FastGlobOptionsWithoutCwd;
12
- type FastGlobOptionsWithoutCwd = Pick<FastGlobOptions, 'onlyDirectories' | 'ignore' | 'absolute' | 'dot'>;
11
+ }
13
12
  export declare const findAndParseGitignores: (cwd: string) => Promise<{
14
13
  gitignoreFiles: string[];
15
14
  ignores: Set<string>;
@@ -48,57 +48,58 @@ export const findAndParseGitignores = async (cwd) => {
48
48
  const dir = dirname(toPosix(filePath));
49
49
  const base = relative(cwd, dir);
50
50
  const ancestor = base.startsWith('..') ? `${relative(dir, cwd)}/` : undefined;
51
- const dirIgnores = new Set(base === '' ? init : []);
52
- const dirUnignores = new Set();
51
+ const ignoresForDir = new Set(base === '' ? init : []);
52
+ const unignoresForDir = new Set();
53
53
  const patterns = readFileSync(filePath, 'utf8');
54
54
  for (const rule of parseAndConvertGitignorePatterns(patterns, ancestor)) {
55
- const [pattern1, pattern2] = rule.patterns;
55
+ const [pattern, extraPattern] = rule.patterns;
56
56
  if (rule.negated) {
57
57
  if (base === '' || base.startsWith('..')) {
58
- if (!unignores.includes(pattern2)) {
58
+ if (!unignores.includes(extraPattern)) {
59
59
  unignores.push(...rule.patterns);
60
- dirUnignores.add(pattern1);
61
- dirUnignores.add(pattern2);
60
+ unignoresForDir.add(pattern);
61
+ unignoresForDir.add(extraPattern);
62
62
  }
63
63
  }
64
64
  else {
65
- if (!unignores.includes(pattern2.startsWith('**/') ? pattern2 : `**/${pattern2}`)) {
66
- const unignore = join(base, pattern1);
67
- const extraUnignore = join(base, pattern2);
65
+ if (!unignores.includes(extraPattern.startsWith('**/') ? extraPattern : `**/${extraPattern}`)) {
66
+ const unignore = join(base, pattern);
67
+ const extraUnignore = join(base, extraPattern);
68
68
  unignores.push(unignore, extraUnignore);
69
- dirUnignores.add(unignore);
70
- dirUnignores.add(extraUnignore);
69
+ unignoresForDir.add(unignore);
70
+ unignoresForDir.add(extraUnignore);
71
71
  }
72
72
  }
73
73
  }
74
74
  else {
75
75
  if (base === '' || base.startsWith('..')) {
76
- ignores.add(pattern1);
77
- ignores.add(pattern2);
78
- dirIgnores.add(pattern1);
79
- dirIgnores.add(pattern2);
76
+ ignores.add(pattern);
77
+ ignores.add(extraPattern);
78
+ ignoresForDir.add(pattern);
79
+ ignoresForDir.add(extraPattern);
80
80
  }
81
- else {
82
- const ignore = join(base, pattern1);
83
- const extraIgnore = join(base, pattern2);
81
+ else if (!unignores.includes(extraPattern.startsWith('**/') ? extraPattern : `**/${extraPattern}`)) {
82
+ const ignore = join(base, pattern);
83
+ const extraIgnore = join(base, extraPattern);
84
84
  ignores.add(ignore);
85
85
  ignores.add(extraIgnore);
86
- dirIgnores.add(ignore);
87
- dirIgnores.add(extraIgnore);
86
+ ignoresForDir.add(ignore);
87
+ ignoresForDir.add(extraIgnore);
88
88
  }
89
89
  }
90
90
  }
91
91
  const cacheDir = ancestor ? cwd : dir;
92
- const cacheForDir = cachedGitIgnores.get(cwd);
92
+ const cacheForDir = cachedGitIgnores.get(cacheDir);
93
93
  if (cacheForDir) {
94
- for (const pattern of dirIgnores)
95
- cacheForDir?.ignores.add(pattern);
96
- cacheForDir.unignores = Array.from(new Set([...cacheForDir.unignores, ...dirUnignores]));
94
+ for (const pattern of ignoresForDir)
95
+ cacheForDir.ignores.add(pattern);
96
+ for (const pattern of unignoresForDir)
97
+ cacheForDir.unignores.add(pattern);
97
98
  }
98
99
  else {
99
- cachedGitIgnores.set(cacheDir, { ignores: dirIgnores, unignores: Array.from(dirUnignores) });
100
+ cachedGitIgnores.set(cacheDir, { ignores: ignoresForDir, unignores: unignoresForDir });
100
101
  }
101
- for (const pattern of dirIgnores)
102
+ for (const pattern of ignoresForDir)
102
103
  matchers.add(_picomatch(pattern, pmOptions));
103
104
  };
104
105
  findAncestorGitignoreFiles(cwd).forEach(addFile);
@@ -150,11 +151,11 @@ export async function glob(patterns, options) {
150
151
  cachedGlobIgnores.set(options.dir, compact(_ignore));
151
152
  const { dir, label, ...fgOptions } = { ...options, ignore };
152
153
  const paths = await fg.glob(patterns, fgOptions);
153
- const name = relative(options.cwd, dir);
154
- debugLogObject(name || ROOT_WORKSPACE_NAME, label ? `Finding ${label}` : 'Finding paths', () => ({
154
+ const name = relative(options.cwd, dir) || ROOT_WORKSPACE_NAME;
155
+ debugLogObject(name, label ? `Finding ${label}` : 'Finding paths', () => ({
155
156
  patterns,
156
157
  ...fgOptions,
157
- ignore: hasCache ? `// identical to ${name}` : ignore,
158
+ ignore: hasCache ? `// using cache from ${name}` : ignore,
158
159
  paths,
159
160
  }));
160
161
  return paths;
@@ -1,5 +1,5 @@
1
1
  import type { PluginName } from '../types/PluginNames.js';
2
- type InputType = 'binary' | 'entry' | 'project' | 'config' | 'dependency' | 'deferResolve' | 'deferResolveEntry';
2
+ type InputType = 'binary' | 'entry' | 'project' | 'config' | 'dependency' | 'deferResolve' | 'deferResolveEntry' | 'alias';
3
3
  export interface Input {
4
4
  type: InputType;
5
5
  specifier: string;
@@ -15,6 +15,10 @@ export interface ConfigInput extends Input {
15
15
  containingFilePath?: string;
16
16
  pluginName: PluginName;
17
17
  }
18
+ interface AliasInput extends Input {
19
+ type: 'alias';
20
+ prefixes: string[];
21
+ }
18
22
  type Options = {
19
23
  optional?: boolean;
20
24
  dir?: string;
@@ -41,5 +45,7 @@ export declare const toDeferResolveProductionEntry: (specifier: string, options?
41
45
  export declare const isDeferResolveProductionEntry: (input: Input) => boolean;
42
46
  export declare const toDeferResolveEntry: (specifier: string, options?: Options) => Input;
43
47
  export declare const isDeferResolveEntry: (input: Input) => boolean;
48
+ export declare const toAlias: (specifier: string, prefixes: string[], options?: Options) => AliasInput;
49
+ export declare const isAlias: (input: Input) => input is AliasInput;
44
50
  export declare const toDebugString: (input: Input) => string;
45
51
  export {};
@@ -50,4 +50,11 @@ export const toDeferResolveEntry = (specifier, options = {}) => ({
50
50
  ...options,
51
51
  });
52
52
  export const isDeferResolveEntry = (input) => input.type === 'deferResolveEntry';
53
+ export const toAlias = (specifier, prefixes, options = {}) => ({
54
+ type: 'alias',
55
+ specifier,
56
+ prefixes,
57
+ ...options,
58
+ });
59
+ export const isAlias = (input) => input.type === 'alias';
53
60
  export const toDebugString = (input) => `${input.type}:${isAbsolute(input.specifier) ? toRelative(input.specifier) : input.specifier}${input.containingFilePath ? ` (${toRelative(input.containingFilePath)})` : ''}`;
@@ -1,3 +1,4 @@
1
1
  export declare const truncate: (text: string, width: number) => string;
2
2
  export declare const truncateStart: (text: string, width: number) => string;
3
3
  export declare const pad: (value: string, width: number, fillString?: string, align?: "left" | "center" | "right") => string;
4
+ export declare const prettyMilliseconds: (ms: number) => string;
@@ -5,3 +5,13 @@ export const pad = (value, width, fillString, align) => align === 'right'
5
5
  : align === 'center'
6
6
  ? value.padStart((value.length + width) / 2, fillString).padEnd(width, fillString)
7
7
  : value.padEnd(width, fillString);
8
+ export const prettyMilliseconds = (ms) => {
9
+ const seconds = ms / 1000;
10
+ const minutes = Math.floor(seconds / 60);
11
+ const hours = Math.floor(minutes / 60);
12
+ if (hours > 0)
13
+ return `${hours}h ${minutes % 60}m ${Math.floor(seconds % 60)}s`;
14
+ if (minutes > 0)
15
+ return `${minutes}m ${Math.floor(seconds % 60)}s`;
16
+ return seconds % 1 ? `${seconds.toFixed(1)}s` : `${Math.floor(seconds)}s`;
17
+ };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.52.0";
1
+ export declare const version = "5.54.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.52.0';
1
+ export const version = '5.54.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "5.52.0",
3
+ "version": "5.54.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://knip.dev",
6
6
  "repository": {
@@ -63,12 +63,12 @@
63
63
  "@nodelib/fs.walk": "^1.2.3",
64
64
  "enhanced-resolve": "^5.18.1",
65
65
  "fast-glob": "^3.3.3",
66
+ "formatly": "^0.2.3",
66
67
  "jiti": "^2.4.2",
67
68
  "js-yaml": "^4.1.0",
68
69
  "minimist": "^1.2.8",
69
70
  "picocolors": "^1.1.0",
70
71
  "picomatch": "^4.0.1",
71
- "pretty-ms": "^9.0.0",
72
72
  "smol-toml": "^1.3.1",
73
73
  "strip-json-comments": "5.0.1",
74
74
  "zod": "^3.22.4",
package/schema.json CHANGED
@@ -607,6 +607,10 @@
607
607
  "title": "svelte plugin configuration (https://knip.dev/reference/plugins/svelte)",
608
608
  "$ref": "#/definitions/plugin"
609
609
  },
610
+ "svgo": {
611
+ "title": "svgo plugin configuration (https://knip.dev/reference/plugins/svgo)",
612
+ "$ref": "#/definitions/plugin"
613
+ },
610
614
  "syncpack": {
611
615
  "title": "syncpack plugin configuration (https://knip.dev/reference/plugins/syncpack)",
612
616
  "$ref": "#/definitions/plugin"