knip 6.13.0 → 6.14.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.
- package/dist/CacheConsultant.d.ts +3 -3
- package/dist/CacheConsultant.js +13 -16
- package/dist/ConfigurationChief.d.ts +1 -0
- package/dist/ConfigurationChief.js +11 -2
- package/dist/DependencyDeputy.d.ts +3 -0
- package/dist/DependencyDeputy.js +28 -8
- package/dist/ProjectPrincipal.d.ts +1 -0
- package/dist/ProjectPrincipal.js +43 -52
- package/dist/WorkspaceWorker.js +3 -3
- package/dist/cli.js +1 -1
- package/dist/graph/analyze.js +4 -3
- package/dist/graph/build.js +1 -0
- package/dist/graph-explorer/explorer.d.ts +2 -1
- package/dist/graph-explorer/operations/is-referenced.d.ts +2 -1
- package/dist/graph-explorer/operations/is-referenced.js +6 -3
- package/dist/plugins/docusaurus/helpers.js +12 -5
- package/dist/plugins/docusaurus/index.js +2 -1
- package/dist/plugins/hardhat/index.js +1 -1
- package/dist/plugins/jest/index.js +1 -1
- package/dist/plugins/nitro/index.js +1 -1
- package/dist/plugins/nuxt/helpers.js +3 -3
- package/dist/plugins/nuxt/index.js +1 -1
- package/dist/plugins/nx/index.js +8 -2
- package/dist/plugins/sst/resolveFromAST.js +2 -2
- package/dist/plugins/tailwind/index.js +1 -1
- package/dist/plugins/wxt/index.js +1 -1
- package/dist/reporters/trace.js +6 -2
- package/dist/run.js +7 -2
- package/dist/typescript/ast-helpers.js +2 -2
- package/dist/typescript/ast-nodes.d.ts +1 -1
- package/dist/typescript/ast-nodes.js +3 -1
- package/dist/typescript/get-imports-and-exports.js +4 -4
- package/dist/typescript/visitors/walk.d.ts +2 -1
- package/dist/typescript/visitors/walk.js +3 -1
- package/dist/util/Performance.d.ts +3 -1
- package/dist/util/Performance.js +6 -2
- package/dist/util/cli-arguments.d.ts +2 -1
- package/dist/util/cli-arguments.js +52 -50
- package/dist/util/disk-cache.d.ts +10 -0
- package/dist/util/disk-cache.js +62 -0
- package/dist/util/file-entry-cache.d.ts +0 -7
- package/dist/util/file-entry-cache.js +15 -53
- package/dist/util/gitignore-cache.d.ts +12 -0
- package/dist/util/gitignore-cache.js +77 -0
- package/dist/util/glob-cache.d.ts +2 -2
- package/dist/util/glob-cache.js +9 -57
- package/dist/util/glob-core.d.ts +4 -0
- package/dist/util/glob-core.js +14 -1
- package/dist/util/glob.js +12 -6
- package/dist/util/module-graph.js +17 -13
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Visitor } from 'oxc-parser';
|
|
2
2
|
import { collectPropertyValues, getImportMap } from '../../typescript/ast-helpers.js';
|
|
3
|
-
import {
|
|
3
|
+
import { _parseFile } from '../../typescript/ast-nodes.js';
|
|
4
4
|
import { toDeferResolveProductionEntry } from '../../util/input.js';
|
|
5
5
|
import { dirname } from '../../util/path.js';
|
|
6
6
|
import { _resolveSync } from '../../util/resolve.js';
|
|
@@ -27,7 +27,7 @@ export const getInputsFromHandlers = (program, options) => {
|
|
|
27
27
|
if (resolvedPath) {
|
|
28
28
|
const stackText = options.readFile(resolvedPath);
|
|
29
29
|
if (stackText) {
|
|
30
|
-
const stackResult =
|
|
30
|
+
const stackResult = _parseFile('stack.ts', stackText);
|
|
31
31
|
addHandlers(collectPropertyValues(stackResult.program, 'handler'));
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -3,7 +3,7 @@ import compiler from './compiler.js';
|
|
|
3
3
|
const title = 'Tailwind';
|
|
4
4
|
const enablers = ['tailwindcss', '@tailwindcss/vite', '@tailwindcss/postcss', '@tailwindcss/cli'];
|
|
5
5
|
const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
|
|
6
|
-
const entry = ['tailwind.config.{js,cjs,mjs,ts}'];
|
|
6
|
+
const entry = ['tailwind.config.{js,cjs,mjs,ts,cts,mts}'];
|
|
7
7
|
const registerCompilers = ({ registerCompiler, hasDependency }) => {
|
|
8
8
|
if (enablers.some(enabler => hasDependency(enabler)))
|
|
9
9
|
registerCompiler({ extension: '.css', compiler });
|
|
@@ -3,7 +3,7 @@ import { hasDependency } from '../../util/plugin.js';
|
|
|
3
3
|
const title = 'WXT';
|
|
4
4
|
const enablers = ['wxt'];
|
|
5
5
|
const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
|
|
6
|
-
const config = ['wxt.config.{js,mjs,ts}'];
|
|
6
|
+
const config = ['wxt.config.{js,cjs,mjs,ts,cts,mts}'];
|
|
7
7
|
const production = ['entrypoints/**/*'];
|
|
8
8
|
const resolveConfig = async (localConfig) => {
|
|
9
9
|
const inputs = [];
|
package/dist/reporters/trace.js
CHANGED
|
@@ -35,7 +35,7 @@ export default ({ graph, explorer, options, workspaceFilePathFilter }) => {
|
|
|
35
35
|
nodes.sort((a, b) => a.filePath.localeCompare(b.filePath) || a.identifier.localeCompare(b.identifier));
|
|
36
36
|
const toRel = (path) => toRelative(path, options.cwd);
|
|
37
37
|
const isReferenced = (node) => {
|
|
38
|
-
if (explorer.isReferenced(node.filePath, node.identifier, {
|
|
38
|
+
if (explorer.isReferenced(node.filePath, node.identifier, { traverseEntries: false })[0])
|
|
39
39
|
return true;
|
|
40
40
|
if (explorer.hasStrictlyNsReferences(node.filePath, node.identifier)[0])
|
|
41
41
|
return true;
|
|
@@ -48,7 +48,11 @@ export default ({ graph, explorer, options, workspaceFilePathFilter }) => {
|
|
|
48
48
|
memberStatuses = [];
|
|
49
49
|
for (const m of exp.members) {
|
|
50
50
|
const id = `${node.identifier}.${m.identifier}`;
|
|
51
|
-
const referenced = m.hasRefsInFile ||
|
|
51
|
+
const referenced = m.hasRefsInFile ||
|
|
52
|
+
explorer.isReferenced(node.filePath, id, {
|
|
53
|
+
traverseEntries: true,
|
|
54
|
+
treatStarAtEntryAsReferenced: true,
|
|
55
|
+
})[0];
|
|
52
56
|
memberStatuses.push({ identifier: m.identifier, referenced });
|
|
53
57
|
}
|
|
54
58
|
}
|
package/dist/run.js
CHANGED
|
@@ -9,6 +9,7 @@ import { IssueCollector } from './IssueCollector.js';
|
|
|
9
9
|
import { ProjectPrincipal } from './ProjectPrincipal.js';
|
|
10
10
|
import watchReporter from './reporters/watch.js';
|
|
11
11
|
import { debugLogObject } from './util/debug.js';
|
|
12
|
+
import { flushGitignoreCache, initGitignoreCache } from './util/gitignore-cache.js';
|
|
12
13
|
import { flushGlobCache, initGlobCache } from './util/glob-cache.js';
|
|
13
14
|
import { getGitIgnoredHandler } from './util/glob-core.js';
|
|
14
15
|
import { getModuleSourcePathHandler, getWorkspaceManifestHandler } from './util/to-source-path.js';
|
|
@@ -16,8 +17,10 @@ import { getSessionHandler } from './util/watch.js';
|
|
|
16
17
|
export const run = async (options) => {
|
|
17
18
|
debugLogObject('*', 'Unresolved configuration', options);
|
|
18
19
|
debugLogObject('*', 'Included issue types', options.includedIssueTypes);
|
|
19
|
-
if (options.isCache)
|
|
20
|
+
if (options.isCache) {
|
|
20
21
|
initGlobCache(options.cacheLocation);
|
|
22
|
+
initGitignoreCache(options.cacheLocation);
|
|
23
|
+
}
|
|
21
24
|
const chief = new ConfigurationChief(options);
|
|
22
25
|
const deputy = new DependencyDeputy(options);
|
|
23
26
|
const streamer = new ConsoleStreamer(options);
|
|
@@ -83,8 +86,10 @@ export const run = async (options) => {
|
|
|
83
86
|
const { issues, counters, tagHints, configurationHints } = collector.getIssues();
|
|
84
87
|
if (!options.isWatch)
|
|
85
88
|
streamer.clear();
|
|
86
|
-
if (options.isCache)
|
|
89
|
+
if (options.isCache) {
|
|
87
90
|
flushGlobCache();
|
|
91
|
+
flushGitignoreCache();
|
|
92
|
+
}
|
|
88
93
|
return {
|
|
89
94
|
results: {
|
|
90
95
|
issues,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Visitor } from 'oxc-parser';
|
|
2
2
|
import stripJsonComments from 'strip-json-comments';
|
|
3
3
|
import { extname, isInternal } from '../util/path.js';
|
|
4
|
-
import { getStringValue, isStringLiteral
|
|
4
|
+
import { _parseFile, getStringValue, isStringLiteral } from './ast-nodes.js';
|
|
5
5
|
export const getPropertyKey = (prop) => prop?.key?.type === 'Identifier' ? prop.key.name : getStringValue(prop?.key);
|
|
6
6
|
export const getImportMap = (program) => {
|
|
7
7
|
const importMap = new Map();
|
|
@@ -191,7 +191,7 @@ export const collectStringLiterals = (sourceText, filePath) => {
|
|
|
191
191
|
collectJsonStringLiterals(JSON.parse(stripJsonComments(sourceText, { trailingCommas: true })), literals);
|
|
192
192
|
return literals;
|
|
193
193
|
}
|
|
194
|
-
const result =
|
|
194
|
+
const result = _parseFile(filePath, sourceText);
|
|
195
195
|
const visitor = new Visitor({
|
|
196
196
|
Literal(node) {
|
|
197
197
|
if (typeof node.value === 'string')
|
|
@@ -2,7 +2,7 @@ import { type TSEnumDeclaration, type TSModuleDeclaration } from 'oxc-parser';
|
|
|
2
2
|
import type { GetImportsAndExportsOptions, IgnoreExportsUsedInFile } from '../types/config.ts';
|
|
3
3
|
import type { SymbolType } from '../types/issues.ts';
|
|
4
4
|
import type { ExportMember } from '../types/module-graph.ts';
|
|
5
|
-
export declare const
|
|
5
|
+
export declare const _parseFile: (filePath: string, sourceText: string) => import("oxc-parser").ParseResult;
|
|
6
6
|
export type ResolveModule = (specifier: string, containingFile: string) => ResolvedModule | undefined;
|
|
7
7
|
export interface ResolvedModule {
|
|
8
8
|
resolvedFileName: string;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { parseSync, rawTransferSupported, } from 'oxc-parser';
|
|
2
2
|
import { DEFAULT_EXTENSIONS, FIX_FLAGS, SYMBOL_TYPE } from '../constants.js';
|
|
3
3
|
import { extname } from '../util/path.js';
|
|
4
|
+
import { timerify } from '../util/Performance.js';
|
|
4
5
|
import { EMPTY_TAGS } from './visitors/jsdoc.js';
|
|
5
6
|
const defaultParseOptions = {
|
|
6
7
|
sourceType: 'unambiguous',
|
|
7
8
|
experimentalRawTransfer: rawTransferSupported(),
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
+
const parseFile = (filePath, sourceText) => {
|
|
10
11
|
const ext = extname(filePath);
|
|
11
12
|
const parseFileName = DEFAULT_EXTENSIONS.has(ext) ? filePath : `${filePath}.ts`;
|
|
12
13
|
return parseSync(parseFileName, sourceText, defaultParseOptions);
|
|
13
14
|
};
|
|
15
|
+
export const _parseFile = timerify(parseFile);
|
|
14
16
|
export const buildLineStarts = (sourceText) => {
|
|
15
17
|
const starts = [0];
|
|
16
18
|
for (let i = 0; i < sourceText.length; i++) {
|
|
@@ -6,9 +6,9 @@ import { timerify } from '../util/Performance.js';
|
|
|
6
6
|
import { dirname, isInNodeModules, resolve } from '../util/path.js';
|
|
7
7
|
import { shouldIgnore } from '../util/tag.js';
|
|
8
8
|
import { extractImportsFromComments } from './comments.js';
|
|
9
|
-
import { buildLineStarts, getLineAndCol,
|
|
9
|
+
import { _parseFile, buildLineStarts, getLineAndCol, shouldCountRefs, } from './ast-nodes.js';
|
|
10
10
|
import { buildJSDocTagLookup } from './visitors/jsdoc.js';
|
|
11
|
-
import {
|
|
11
|
+
import { _walkAST } from './visitors/walk.js';
|
|
12
12
|
const getImportsAndExports = (filePath, sourceText, resolveModule, options, ignoreExportsUsedInFile, skipExportsForFile, visitor, pluginCtx, cachedParseResult) => {
|
|
13
13
|
const skipExports = skipExportsForFile || !options.isReportExports;
|
|
14
14
|
const isDts = filePath.endsWith('.d.ts') || filePath.endsWith('.d.cts') || filePath.endsWith('.d.mts');
|
|
@@ -159,7 +159,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
};
|
|
162
|
-
const result = cachedParseResult ??
|
|
162
|
+
const result = cachedParseResult ?? _parseFile(filePath, sourceText);
|
|
163
163
|
const lineStarts = buildLineStarts(sourceText);
|
|
164
164
|
const getJSDocTags = buildJSDocTagLookup(result.comments, sourceText);
|
|
165
165
|
let hasNodeModuleImport = false;
|
|
@@ -255,7 +255,7 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
|
|
|
255
255
|
pluginCtx.addScript = (s) => scripts.add(s);
|
|
256
256
|
pluginCtx.addImport = (spec, pos, mod) => addImport(spec, undefined, undefined, undefined, pos, mod);
|
|
257
257
|
}
|
|
258
|
-
const localRefs =
|
|
258
|
+
const localRefs = _walkAST(result.program, sourceText, filePath, {
|
|
259
259
|
lineStarts,
|
|
260
260
|
skipExports,
|
|
261
261
|
options,
|
|
@@ -81,5 +81,6 @@ export interface WalkState extends WalkContext {
|
|
|
81
81
|
}
|
|
82
82
|
export declare const isShadowed: (name: string, pos: number) => boolean;
|
|
83
83
|
export declare function buildVisitor(pluginVisitorObjects: PluginVisitorObject[], includeLocalRefs?: boolean): Visitor;
|
|
84
|
-
|
|
84
|
+
declare function walkAST(program: Program, sourceText: string, filePath: string, ctx: WalkContext): Set<string> | undefined;
|
|
85
|
+
export declare const _walkAST: typeof walkAST;
|
|
85
86
|
export {};
|
|
@@ -2,6 +2,7 @@ import { Visitor, visitorKeys, } from 'oxc-parser';
|
|
|
2
2
|
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
|
+
import { timerify } from '../../util/Performance.js';
|
|
5
6
|
import { getLineAndCol, getStringValue, isStringLiteral } from '../ast-nodes.js';
|
|
6
7
|
import { EMPTY_TAGS } from './jsdoc.js';
|
|
7
8
|
import { handleCallExpression, handleNewExpression } from './calls.js';
|
|
@@ -673,7 +674,7 @@ export function buildVisitor(pluginVisitorObjects, includeLocalRefs) {
|
|
|
673
674
|
}
|
|
674
675
|
return new Visitor(merged);
|
|
675
676
|
}
|
|
676
|
-
|
|
677
|
+
function walkAST(program, sourceText, filePath, ctx) {
|
|
677
678
|
const isJS = filePath.endsWith('.js') || filePath.endsWith('.mjs') || filePath.endsWith('.cjs') || filePath.endsWith('.jsx');
|
|
678
679
|
state = {
|
|
679
680
|
...ctx,
|
|
@@ -780,3 +781,4 @@ export function walkAST(program, sourceText, filePath, ctx) {
|
|
|
780
781
|
state = undefined;
|
|
781
782
|
return localRefs;
|
|
782
783
|
}
|
|
784
|
+
export const _walkAST = timerify(walkAST);
|
|
@@ -13,6 +13,7 @@ declare class Performance {
|
|
|
13
13
|
isEnabled: boolean;
|
|
14
14
|
isTimerifyFunctions: boolean;
|
|
15
15
|
isMemoryUsageEnabled: boolean;
|
|
16
|
+
isDurationEnabled: boolean;
|
|
16
17
|
startTime: number;
|
|
17
18
|
endTime: number;
|
|
18
19
|
perfEntries: PerformanceEntry[];
|
|
@@ -21,7 +22,8 @@ declare class Performance {
|
|
|
21
22
|
memId?: string;
|
|
22
23
|
fnObserver?: PerformanceObserver;
|
|
23
24
|
memObserver?: PerformanceObserver;
|
|
24
|
-
constructor({ isTimerifyFunctions, isMemoryUsageEnabled }: {
|
|
25
|
+
constructor({ isTimerifyFunctions, isMemoryUsageEnabled, isDurationEnabled }: {
|
|
26
|
+
isDurationEnabled?: boolean | undefined;
|
|
25
27
|
isMemoryUsageEnabled?: boolean | undefined;
|
|
26
28
|
isTimerifyFunctions?: boolean | undefined;
|
|
27
29
|
});
|
package/dist/util/Performance.js
CHANGED
|
@@ -10,12 +10,14 @@ const { values } = parseArgs({
|
|
|
10
10
|
'performance-fn': { type: 'string', multiple: true },
|
|
11
11
|
memory: { type: 'boolean' },
|
|
12
12
|
'memory-realtime': { type: 'boolean' },
|
|
13
|
+
duration: { type: 'boolean' },
|
|
13
14
|
},
|
|
14
15
|
});
|
|
15
16
|
const timerifyOnlyFnName = values['performance-fn'];
|
|
16
17
|
const isMemoryRealtime = !!values['memory-realtime'];
|
|
17
18
|
const isTimerifyFunctions = !!values.performance || !!timerifyOnlyFnName;
|
|
18
19
|
const isMemoryUsageEnabled = !!values.memory || isMemoryRealtime;
|
|
20
|
+
const isDurationEnabled = !!values.duration;
|
|
19
21
|
export const timerify = (fn, name = fn.name) => {
|
|
20
22
|
if (!isTimerifyFunctions)
|
|
21
23
|
return fn;
|
|
@@ -36,6 +38,7 @@ class Performance {
|
|
|
36
38
|
isEnabled;
|
|
37
39
|
isTimerifyFunctions;
|
|
38
40
|
isMemoryUsageEnabled;
|
|
41
|
+
isDurationEnabled;
|
|
39
42
|
startTime = 0;
|
|
40
43
|
endTime = 0;
|
|
41
44
|
perfEntries = [];
|
|
@@ -44,10 +47,11 @@ class Performance {
|
|
|
44
47
|
memId;
|
|
45
48
|
fnObserver;
|
|
46
49
|
memObserver;
|
|
47
|
-
constructor({ isTimerifyFunctions = false, isMemoryUsageEnabled = false }) {
|
|
50
|
+
constructor({ isTimerifyFunctions = false, isMemoryUsageEnabled = false, isDurationEnabled = false }) {
|
|
48
51
|
this.isEnabled = isTimerifyFunctions || isMemoryUsageEnabled;
|
|
49
52
|
this.isTimerifyFunctions = isTimerifyFunctions;
|
|
50
53
|
this.isMemoryUsageEnabled = isMemoryUsageEnabled;
|
|
54
|
+
this.isDurationEnabled = isDurationEnabled;
|
|
51
55
|
this.startTime = performance.now();
|
|
52
56
|
const instanceId = Math.floor(performance.now() * 100);
|
|
53
57
|
this.perfId = `perf-${instanceId}`;
|
|
@@ -172,4 +176,4 @@ class Performance {
|
|
|
172
176
|
this.memObserver?.disconnect();
|
|
173
177
|
}
|
|
174
178
|
}
|
|
175
|
-
export const perfObserver = new Performance({ isTimerifyFunctions, isMemoryUsageEnabled });
|
|
179
|
+
export const perfObserver = new Performance({ isTimerifyFunctions, isMemoryUsageEnabled, isDurationEnabled });
|
|
@@ -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
|
|
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 --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration 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";
|
|
2
2
|
export type ParsedCLIArgs = ReturnType<typeof parseCLIArgs>;
|
|
3
3
|
export default function parseCLIArgs(): {
|
|
4
4
|
cache?: boolean | undefined;
|
|
@@ -33,6 +33,7 @@ export default function parseCLIArgs(): {
|
|
|
33
33
|
'preprocessor-options'?: string | undefined;
|
|
34
34
|
reporter?: string[] | undefined;
|
|
35
35
|
'reporter-options'?: string | undefined;
|
|
36
|
+
duration?: boolean | undefined;
|
|
36
37
|
strict?: boolean | undefined;
|
|
37
38
|
trace?: boolean | undefined;
|
|
38
39
|
'trace-dependency'?: string | undefined;
|
|
@@ -4,60 +4,61 @@ export const helpText = `✂️ Find unused dependencies, exports and files in
|
|
|
4
4
|
Usage: knip [options]
|
|
5
5
|
|
|
6
6
|
Options:
|
|
7
|
-
-h, --help
|
|
8
|
-
-V, --version
|
|
9
|
-
-n, --no-progress
|
|
10
|
-
-c, --config [file]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-t, --tsConfig [file]
|
|
7
|
+
-h, --help Print this help text
|
|
8
|
+
-V, --version Print version
|
|
9
|
+
-n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)
|
|
10
|
+
-c, --config [file] Configuration file path
|
|
11
|
+
(default: [.]knip.json[c], knip.(js|ts), knip.config.(js|ts) or package.json#knip)
|
|
12
|
+
--use-tsconfig-files Use tsconfig.json to define project files (override \`project\` patterns)
|
|
13
|
+
-t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)
|
|
14
14
|
|
|
15
15
|
Mode
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
--production Analyze only production source files (e.g. no test files, devDependencies)
|
|
21
|
-
--strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
|
|
22
|
-
--watch Watch mode
|
|
16
|
+
--cache Enable caching
|
|
17
|
+
--cache-location Change cache location (default: node_modules/.cache/knip)
|
|
18
|
+
--include-entry-exports Include entry files when reporting unused exports
|
|
19
|
+
--no-gitignore Don't respect .gitignore
|
|
20
|
+
-p, --production Analyze only production source files (e.g. no test files, devDependencies)
|
|
21
|
+
-s, --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
|
|
22
|
+
-w, --watch Watch mode
|
|
23
23
|
|
|
24
24
|
Scope
|
|
25
|
-
-W, --workspace [filter]
|
|
26
|
-
--directory [dir] Run process from a different directory (default: cwd)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
-W, --workspace [filter] Filter workspaces by name, directory, or glob (can be repeated)
|
|
26
|
+
-D, --directory [dir] Run process from a different directory (default: cwd)
|
|
27
|
+
--include Report only provided issue type(s), can be comma-separated or repeated (1)
|
|
28
|
+
--exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
|
|
29
|
+
--dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved,catalog
|
|
30
|
+
--exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates
|
|
31
|
+
--files Shortcut for --include files
|
|
32
|
+
--tags Include or exclude tagged exports
|
|
33
33
|
|
|
34
34
|
Fix
|
|
35
|
-
--fix Fix issues (modifies files in your repo)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
--format Format modified files after --fix using the local formatter
|
|
35
|
+
-f, --fix Fix issues (modifies files in your repo)
|
|
36
|
+
--fix-type Fix only issues of type, can be comma-separated or repeated (2)
|
|
37
|
+
--allow-remove-files Allow Knip to remove files (with --fix)
|
|
38
|
+
-F, --format Format modified files after --fix using the local formatter
|
|
39
39
|
|
|
40
40
|
Output
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
--preprocessor Preprocess the results before providing it to the reporter(s), can be repeated
|
|
42
|
+
--preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)
|
|
43
|
+
--reporter Select reporter (default: symbols), can be repeated (3)
|
|
44
|
+
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
45
|
+
--no-config-hints Suppress configuration hints
|
|
46
|
+
--treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints
|
|
47
|
+
--max-issues Maximum number of total issues before non-zero exit code (default: 0)
|
|
48
|
+
--max-show-issues Maximum number of issues to display per type
|
|
49
|
+
--no-exit-code Always exit with code zero (0)
|
|
50
50
|
|
|
51
51
|
Troubleshooting
|
|
52
|
-
-d, --debug
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
--
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
-d, --debug Show debug output
|
|
53
|
+
--memory Measure memory usage and display data table
|
|
54
|
+
--memory-realtime Log memory usage in realtime
|
|
55
|
+
--performance Measure count and running time of key functions and display stats table
|
|
56
|
+
--performance-fn [name] Measure only function [name]
|
|
57
|
+
-u, --duration Print total running time (zero overhead, no instrumentation)
|
|
58
|
+
--trace Show trace output
|
|
59
|
+
--trace-dependency [name] Show files that import the named dependency
|
|
60
|
+
--trace-export [name] Show trace output for named export(s)
|
|
61
|
+
--trace-file [file] Show trace output for exports in file
|
|
61
62
|
|
|
62
63
|
(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog
|
|
63
64
|
(2) Fixable issue types: dependencies, exports, types, files, catalog
|
|
@@ -83,14 +84,14 @@ export default function parseCLIArgs() {
|
|
|
83
84
|
config: { type: 'string', short: 'c' },
|
|
84
85
|
debug: { type: 'boolean', short: 'd' },
|
|
85
86
|
dependencies: { type: 'boolean' },
|
|
86
|
-
directory: { type: 'string' },
|
|
87
|
+
directory: { type: 'string', short: 'D' },
|
|
87
88
|
exclude: { type: 'string', multiple: true },
|
|
88
89
|
exports: { type: 'boolean' },
|
|
89
90
|
tags: { type: 'string', multiple: true },
|
|
90
91
|
files: { type: 'boolean' },
|
|
91
|
-
fix: { type: 'boolean' },
|
|
92
|
+
fix: { type: 'boolean', short: 'f' },
|
|
92
93
|
'fix-type': { type: 'string', multiple: true },
|
|
93
|
-
format: { type: 'boolean' },
|
|
94
|
+
format: { type: 'boolean', short: 'F' },
|
|
94
95
|
'allow-remove-files': { type: 'boolean' },
|
|
95
96
|
help: { type: 'boolean', short: 'h' },
|
|
96
97
|
include: { type: 'string', multiple: true },
|
|
@@ -105,12 +106,13 @@ export default function parseCLIArgs() {
|
|
|
105
106
|
'no-progress': { type: 'boolean', short: 'n' },
|
|
106
107
|
performance: { type: 'boolean' },
|
|
107
108
|
'performance-fn': { type: 'string' },
|
|
108
|
-
production: { type: 'boolean' },
|
|
109
|
+
production: { type: 'boolean', short: 'p' },
|
|
109
110
|
preprocessor: { type: 'string', multiple: true },
|
|
110
111
|
'preprocessor-options': { type: 'string' },
|
|
111
112
|
reporter: { type: 'string', multiple: true },
|
|
112
113
|
'reporter-options': { type: 'string' },
|
|
113
|
-
|
|
114
|
+
duration: { type: 'boolean', short: 'u' },
|
|
115
|
+
strict: { type: 'boolean', short: 's' },
|
|
114
116
|
trace: { type: 'boolean' },
|
|
115
117
|
'trace-dependency': { type: 'string' },
|
|
116
118
|
'trace-export': { type: 'string' },
|
|
@@ -119,7 +121,7 @@ export default function parseCLIArgs() {
|
|
|
119
121
|
tsConfig: { type: 'string', short: 't' },
|
|
120
122
|
'use-tsconfig-files': { type: 'boolean' },
|
|
121
123
|
version: { type: 'boolean', short: 'V' },
|
|
122
|
-
watch: { type: 'boolean' },
|
|
124
|
+
watch: { type: 'boolean', short: 'w' },
|
|
123
125
|
workspace: { type: 'string', short: 'W', multiple: true },
|
|
124
126
|
},
|
|
125
127
|
}).values;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface DiskCache<V> {
|
|
2
|
+
init: (cacheLocation: string) => void;
|
|
3
|
+
isEnabled: () => boolean;
|
|
4
|
+
get: (key: string) => V | undefined;
|
|
5
|
+
set: (key: string, value: V) => void;
|
|
6
|
+
delete: (key: string) => void;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
flush: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const createDiskCache: <V>(name: string) => DiskCache<V>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { deserialize, serialize } from 'node:v8';
|
|
4
|
+
import { version } from '../version.js';
|
|
5
|
+
import { debugLog } from './debug.js';
|
|
6
|
+
import { isDirectory, isFile } from './fs.js';
|
|
7
|
+
import { dirname } from './path.js';
|
|
8
|
+
export const createDiskCache = (name) => {
|
|
9
|
+
const filename = `${name}-${version}.cache`;
|
|
10
|
+
let cacheFilePath;
|
|
11
|
+
let cache;
|
|
12
|
+
let isDirty = false;
|
|
13
|
+
return {
|
|
14
|
+
init(cacheLocation) {
|
|
15
|
+
cacheFilePath = path.resolve(cacheLocation, filename);
|
|
16
|
+
if (isFile(cacheFilePath)) {
|
|
17
|
+
try {
|
|
18
|
+
cache = deserialize(fs.readFileSync(cacheFilePath));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
debugLog('*', `Error reading cache from ${cacheFilePath}`);
|
|
22
|
+
cache = new Map();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
cache = new Map();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
isEnabled: () => cache !== undefined,
|
|
30
|
+
get: key => cache?.get(key),
|
|
31
|
+
set(key, value) {
|
|
32
|
+
if (!cache)
|
|
33
|
+
return;
|
|
34
|
+
cache.set(key, value);
|
|
35
|
+
isDirty = true;
|
|
36
|
+
},
|
|
37
|
+
delete(key) {
|
|
38
|
+
if (cache?.delete(key))
|
|
39
|
+
isDirty = true;
|
|
40
|
+
},
|
|
41
|
+
clear() {
|
|
42
|
+
if (cache && cache.size > 0) {
|
|
43
|
+
cache.clear();
|
|
44
|
+
isDirty = true;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
flush() {
|
|
48
|
+
if (!cache || !cacheFilePath || !isDirty)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const dir = dirname(cacheFilePath);
|
|
52
|
+
if (!isDirectory(dir))
|
|
53
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
fs.writeFileSync(cacheFilePath, serialize(cache));
|
|
55
|
+
isDirty = false;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
debugLog('*', `Error writing cache to ${cacheFilePath}`);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
type MetaData<T> = {
|
|
3
2
|
size: number;
|
|
4
3
|
mtime: number;
|
|
@@ -16,14 +15,8 @@ export declare class FileEntryCache<T> {
|
|
|
16
15
|
cache: Map<string, MetaData<T>>;
|
|
17
16
|
normalizedEntries: Map<string, FileDescriptor<T>>;
|
|
18
17
|
constructor(cacheId: string, _path: string);
|
|
19
|
-
removeNotFoundFiles(): void;
|
|
20
18
|
getFileDescriptor(filePath: string): FileDescriptor<T>;
|
|
21
|
-
_getFileDescriptorUsingMtimeAndSize(filePath: string, fstat: fs.Stats): FileDescriptor<T>;
|
|
22
19
|
removeEntry(entryName: string): void;
|
|
23
|
-
_getMetaForFileUsingMtimeAndSize(cacheEntry: FileDescriptor<T>): {
|
|
24
|
-
size: number;
|
|
25
|
-
mtime: number;
|
|
26
|
-
};
|
|
27
20
|
reconcile(): void;
|
|
28
21
|
}
|
|
29
22
|
export {};
|