knip 6.29.0 → 6.30.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/CatalogCounselor.d.ts +5 -2
- package/dist/CatalogCounselor.js +26 -8
- package/dist/ConfigurationChief.d.ts +1 -1
- package/dist/ConfigurationChief.js +29 -36
- package/dist/DependencyDeputy.d.ts +8 -1
- package/dist/DependencyDeputy.js +5 -5
- package/dist/PackagePeeker.d.ts +5 -0
- package/dist/PackagePeeker.js +31 -3
- package/dist/WorkspaceWorker.d.ts +1 -1
- package/dist/WorkspaceWorker.js +11 -7
- package/dist/binaries/bash-parser.js +3 -3
- package/dist/binaries/create-script-parser-context.d.ts +7 -0
- package/dist/binaries/create-script-parser-context.js +17 -0
- package/dist/binaries/resolvers/pnpx.js +10 -5
- package/dist/compilers/index.d.ts +5 -5
- package/dist/compilers/scss.js +32 -5
- package/dist/compilers/shared.d.ts +1 -0
- package/dist/compilers/shared.js +1 -1
- package/dist/compilers/svelte.d.ts +2 -0
- package/dist/compilers/svelte.js +22 -0
- package/dist/constants.d.ts +4 -1
- package/dist/constants.js +4 -0
- package/dist/graph/analyze.js +5 -2
- package/dist/graph/build.d.ts +3 -1
- package/dist/graph/build.js +38 -19
- package/dist/graph-explorer/operations/build-exports-tree.js +2 -1
- package/dist/graph-explorer/operations/is-referenced.js +7 -4
- package/dist/graph-explorer/utils.js +2 -2
- package/dist/plugins/_template/index.js +1 -1
- package/dist/plugins/astro-markdoc/index.js +3 -2
- package/dist/plugins/eleventy/index.js +1 -1
- package/dist/plugins/esbuild/index.js +1 -1
- package/dist/plugins/eslint/helpers.js +2 -1
- package/dist/plugins/gatsby/index.js +2 -2
- package/dist/plugins/jest/helpers.js +1 -1
- package/dist/plugins/metro/index.js +1 -1
- package/dist/plugins/nest/index.js +1 -1
- package/dist/plugins/node/index.js +11 -2
- package/dist/plugins/nx/index.js +4 -3
- package/dist/plugins/openclaw/index.js +1 -1
- package/dist/plugins/oxlint/index.js +9 -2
- package/dist/plugins/remark/helpers.d.ts +3 -0
- package/dist/plugins/remark/helpers.js +42 -0
- package/dist/plugins/remark/index.js +4 -5
- package/dist/plugins/rolldown/index.js +1 -1
- package/dist/plugins/rollup/index.js +1 -1
- package/dist/plugins/rslib/index.js +1 -1
- package/dist/plugins/stryker/index.js +6 -1
- package/dist/plugins/svelte/compiler.js +7 -5
- package/dist/plugins/tsdown/index.js +2 -2
- package/dist/plugins/tsup/index.js +1 -1
- package/dist/plugins/vitest/index.js +1 -1
- package/dist/plugins/vitest/types.d.ts +1 -1
- package/dist/reporters/codeclimate.js +1 -5
- package/dist/reporters/github-actions.js +5 -3
- package/dist/reporters/index.d.ts +1 -0
- package/dist/reporters/index.js +2 -0
- package/dist/reporters/json.d.ts +1 -0
- package/dist/reporters/json.js +1 -0
- package/dist/reporters/sarif.d.ts +3 -0
- package/dist/reporters/sarif.js +79 -0
- package/dist/reporters/trace.js +3 -2
- package/dist/reporters/util/util.d.ts +2 -1
- package/dist/reporters/util/util.js +6 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.js +30 -0
- package/dist/schema/configuration.d.ts +6 -6
- package/dist/schema/configuration.js +1 -0
- package/dist/session/build-maps.js +2 -1
- package/dist/types/issues.d.ts +1 -0
- package/dist/types/package-json.d.ts +10 -0
- package/dist/typescript/get-imports-and-exports.js +3 -2
- package/dist/typescript/get-published-type-dependencies.d.ts +13 -0
- package/dist/typescript/get-published-type-dependencies.js +155 -0
- package/dist/typescript/visitors/calls.js +8 -0
- package/dist/util/catalog.d.ts +6 -1
- package/dist/util/catalog.js +16 -2
- package/dist/util/cli-arguments.d.ts +1 -1
- package/dist/util/cli-arguments.js +3 -3
- package/dist/util/codeowners.js +1 -1
- package/dist/util/create-input-handler.js +8 -2
- package/dist/util/create-options.d.ts +6 -5
- package/dist/util/disk-cache.js +1 -1
- package/dist/util/errors.js +3 -2
- package/dist/util/file-entry-cache.js +5 -1
- package/dist/util/fs.js +2 -2
- package/dist/util/get-included-issue-types.js +2 -1
- package/dist/util/gitignore-cache.js +4 -1
- package/dist/util/glob-cache.js +2 -2
- package/dist/util/glob-core.js +3 -1
- package/dist/util/input.d.ts +7 -1
- package/dist/util/input.js +6 -0
- package/dist/util/package-json.d.ts +346 -0
- package/dist/util/package-json.js +123 -0
- package/dist/util/path.d.ts +8 -7
- package/dist/util/resolve.d.ts +6 -0
- package/dist/util/resolve.js +24 -0
- package/dist/util/string.d.ts +2 -0
- package/dist/util/string.js +6 -0
- package/dist/util/table.js +2 -2
- package/dist/util/to-source-path.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/schema.json +4 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { IS_DTS } from '../constants.js';
|
|
3
|
+
import { isFile } from '../util/fs.js';
|
|
4
|
+
import { _syncGlob } from '../util/glob.js';
|
|
5
|
+
import { getDefinitelyTypedFor, getPackageNameFromModuleSpecifier, isDefinitelyTyped, isStartsLikePackageName, sanitizeSpecifier, } from '../util/modules.js';
|
|
6
|
+
import { getPublishedTypeManifest, getPublishedTypeEntrySpecifiers, getPublishedTypeExportSpecifiers, isPublishedTypeExportTarget, toDeclarationSpecifier, } from '../util/package-json.js';
|
|
7
|
+
import { dirname, join, relative } from '../util/path.js';
|
|
8
|
+
import { _resolveDeclarationSync } from '../util/resolve.js';
|
|
9
|
+
import { _getImportsAndExports } from './get-imports-and-exports.js';
|
|
10
|
+
import { buildVisitor } from './visitors/walk.js';
|
|
11
|
+
const options = {
|
|
12
|
+
skipTypeOnly: false,
|
|
13
|
+
isFixExports: false,
|
|
14
|
+
isFixTypes: false,
|
|
15
|
+
isReportExports: false,
|
|
16
|
+
tags: [[], []],
|
|
17
|
+
};
|
|
18
|
+
const resolveNothing = () => undefined;
|
|
19
|
+
const toGlobPattern = (specifier) => {
|
|
20
|
+
const index = specifier.indexOf('*');
|
|
21
|
+
return `${specifier.slice(0, index)}**/*${specifier.slice(index + 1).replaceAll('*', '**')}`;
|
|
22
|
+
};
|
|
23
|
+
const isInWorkspace = (filePath, workspaceDir) => filePath === workspaceDir || filePath.startsWith(`${workspaceDir}/`);
|
|
24
|
+
const toDeclarationPath = (filePath) => {
|
|
25
|
+
if (IS_DTS.test(filePath))
|
|
26
|
+
return filePath;
|
|
27
|
+
const candidate = toDeclarationSpecifier(filePath);
|
|
28
|
+
if (candidate && isFile(candidate))
|
|
29
|
+
return candidate;
|
|
30
|
+
};
|
|
31
|
+
const getDeclarationPaths = (specifiers, workspaceDir) => {
|
|
32
|
+
const paths = new Set();
|
|
33
|
+
const patterns = [];
|
|
34
|
+
for (const specifier of specifiers) {
|
|
35
|
+
if (specifier.includes('*')) {
|
|
36
|
+
patterns.push(toGlobPattern(specifier));
|
|
37
|
+
}
|
|
38
|
+
else if (IS_DTS.test(specifier)) {
|
|
39
|
+
const filePath = join(workspaceDir, specifier);
|
|
40
|
+
if (isFile(filePath))
|
|
41
|
+
paths.add(filePath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (patterns.length > 0) {
|
|
45
|
+
for (const filePath of _syncGlob({ cwd: workspaceDir, patterns })) {
|
|
46
|
+
if (IS_DTS.test(filePath))
|
|
47
|
+
paths.add(filePath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return paths;
|
|
51
|
+
};
|
|
52
|
+
const getPublishedTypeEntryPaths = (manifest, workspaceDir) => {
|
|
53
|
+
const { candidates, versioned } = getPublishedTypeEntrySpecifiers(manifest);
|
|
54
|
+
const paths = getDeclarationPaths(versioned, workspaceDir);
|
|
55
|
+
for (const specifier of candidates) {
|
|
56
|
+
const filePath = join(workspaceDir, specifier);
|
|
57
|
+
if (!isFile(filePath))
|
|
58
|
+
continue;
|
|
59
|
+
paths.add(filePath);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
for (const filePath of getDeclarationPaths(getPublishedTypeExportSpecifiers(manifest.exports), workspaceDir)) {
|
|
63
|
+
if (isPublishedTypeExportTarget(manifest.exports, `./${relative(workspaceDir, filePath)}`))
|
|
64
|
+
paths.add(filePath);
|
|
65
|
+
}
|
|
66
|
+
return paths;
|
|
67
|
+
};
|
|
68
|
+
export const createPublishedTypeDependencyAnalyzer = () => {
|
|
69
|
+
const visitor = buildVisitor([]);
|
|
70
|
+
const packageJsonCache = new Map();
|
|
71
|
+
const packageTypesCache = new Map();
|
|
72
|
+
const loadPackageJson = (filePath) => {
|
|
73
|
+
if (packageJsonCache.has(filePath))
|
|
74
|
+
return packageJsonCache.get(filePath);
|
|
75
|
+
let manifest;
|
|
76
|
+
try {
|
|
77
|
+
manifest = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
78
|
+
}
|
|
79
|
+
catch { }
|
|
80
|
+
packageJsonCache.set(filePath, manifest);
|
|
81
|
+
return manifest;
|
|
82
|
+
};
|
|
83
|
+
const packageProvidesTypes = (packageJsonPath, resolvedPath) => {
|
|
84
|
+
const cached = packageTypesCache.get(packageJsonPath);
|
|
85
|
+
if (cached !== undefined)
|
|
86
|
+
return cached;
|
|
87
|
+
const manifest = loadPackageJson(packageJsonPath);
|
|
88
|
+
const hasTypes = toDeclarationPath(resolvedPath) !== undefined ||
|
|
89
|
+
Boolean(manifest && (manifest.types || manifest.typings || manifest.typesVersions)) ||
|
|
90
|
+
isFile(join(dirname(packageJsonPath), 'index.d.ts'));
|
|
91
|
+
packageTypesCache.set(packageJsonPath, hasTypes);
|
|
92
|
+
return hasTypes;
|
|
93
|
+
};
|
|
94
|
+
const getExternalDependency = (packageName, containingFile, declaredDependencies) => {
|
|
95
|
+
const resolved = _resolveDeclarationSync(packageName, containingFile);
|
|
96
|
+
if (isDefinitelyTyped(packageName))
|
|
97
|
+
return { packageName, isResolved: resolved !== undefined };
|
|
98
|
+
if (resolved?.packageJsonPath) {
|
|
99
|
+
const installedName = loadPackageJson(resolved.packageJsonPath)?.name;
|
|
100
|
+
if (installedName && isDefinitelyTyped(installedName))
|
|
101
|
+
return { packageName: installedName, isResolved: true };
|
|
102
|
+
if (packageProvidesTypes(resolved.packageJsonPath, resolved.path))
|
|
103
|
+
return { packageName, isResolved: true };
|
|
104
|
+
}
|
|
105
|
+
const typesPackageName = getDefinitelyTypedFor(packageName);
|
|
106
|
+
if (_resolveDeclarationSync(typesPackageName, containingFile) || declaredDependencies.has(typesPackageName))
|
|
107
|
+
return { packageName: typesPackageName, isResolved: true };
|
|
108
|
+
return { packageName, isResolved: resolved !== undefined };
|
|
109
|
+
};
|
|
110
|
+
return (workspace, manifest) => {
|
|
111
|
+
const dependencies = [];
|
|
112
|
+
const declaredDependencies = new Set([
|
|
113
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
114
|
+
...Object.keys(manifest.devDependencies ?? {}),
|
|
115
|
+
...Object.keys(manifest.peerDependencies ?? {}),
|
|
116
|
+
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
117
|
+
]);
|
|
118
|
+
const files = getPublishedTypeEntryPaths(getPublishedTypeManifest(manifest), workspace.dir);
|
|
119
|
+
for (const filePath of files) {
|
|
120
|
+
let file;
|
|
121
|
+
try {
|
|
122
|
+
file = _getImportsAndExports(filePath, readFileSync(filePath, 'utf8'), resolveNothing, options, false, true, visitor, undefined);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const _import of file.imports.unresolved) {
|
|
128
|
+
const specifier = sanitizeSpecifier(_import.specifier);
|
|
129
|
+
const packageName = isStartsLikePackageName(specifier)
|
|
130
|
+
? getPackageNameFromModuleSpecifier(specifier)
|
|
131
|
+
: undefined;
|
|
132
|
+
if (!packageName || packageName === workspace.pkgName) {
|
|
133
|
+
if (!packageName && !specifier.startsWith('.'))
|
|
134
|
+
continue;
|
|
135
|
+
const resolved = _resolveDeclarationSync(specifier, filePath);
|
|
136
|
+
const declarationPath = resolved && toDeclarationPath(resolved.path);
|
|
137
|
+
if (declarationPath && isInWorkspace(declarationPath, workspace.dir))
|
|
138
|
+
files.add(declarationPath);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const external = getExternalDependency(packageName, filePath, declaredDependencies);
|
|
142
|
+
dependencies.push({
|
|
143
|
+
containingFilePath: filePath,
|
|
144
|
+
packageName: external.packageName,
|
|
145
|
+
specifier,
|
|
146
|
+
pos: _import.pos,
|
|
147
|
+
line: _import.line,
|
|
148
|
+
col: _import.col,
|
|
149
|
+
isResolved: external.isResolved,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return dependencies;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
@@ -221,6 +221,14 @@ export function handleCallExpression(node, s) {
|
|
|
221
221
|
for (const arg of node.arguments) {
|
|
222
222
|
if (arg.type === 'Identifier')
|
|
223
223
|
markRefIfNs(arg.name);
|
|
224
|
+
else if (arg.type === 'ArrowFunctionExpression' && arg.expression) {
|
|
225
|
+
const body = arg.body.type === 'AwaitExpression' ? arg.body.argument : arg.body;
|
|
226
|
+
if (body.type === 'ImportExpression' && isStringLiteral(body.source)) {
|
|
227
|
+
s.handledImportExpressions.add(body.start);
|
|
228
|
+
const specifier = getStringValue(body.source);
|
|
229
|
+
s.addImport(specifier, undefined, undefined, undefined, body.source.start, IMPORT_FLAGS.DYNAMIC | IMPORT_FLAGS.LOADER);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
224
232
|
else if (arg.type === 'ArrayExpression') {
|
|
225
233
|
for (const el of arg.elements ?? []) {
|
|
226
234
|
if (el?.type === 'Identifier')
|
package/dist/util/catalog.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { CatalogContainer } from '../CatalogCounselor.ts';
|
|
2
2
|
import type { PackageJson } from '../types/package-json.ts';
|
|
3
3
|
export declare const DEFAULT_CATALOG = "default";
|
|
4
|
+
export type CatalogReference = {
|
|
5
|
+
catalogName: string;
|
|
6
|
+
packageName: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const getCatalogReference: (specifier: string) => CatalogReference | undefined;
|
|
4
9
|
export declare const getCatalogContainer: (cwd: string, manifest: PackageJson, manifestPath: string, pnpmWorkspacePath?: string, pnpmWorkspace?: any) => Promise<CatalogContainer>;
|
|
5
10
|
export declare const parseCatalog: (container: CatalogContainer) => Set<string>;
|
|
6
|
-
export declare const extractCatalogReferences: (manifest: PackageJson) =>
|
|
11
|
+
export declare const extractCatalogReferences: (manifest: PackageJson) => CatalogReference[];
|
package/dist/util/catalog.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import { isFile } from './fs.js';
|
|
2
2
|
import { _load } from './loader.js';
|
|
3
|
+
import { getPackageNameFromModuleSpecifier } from './modules.js';
|
|
3
4
|
import { basename, join } from './path.js';
|
|
4
5
|
export const DEFAULT_CATALOG = 'default';
|
|
6
|
+
const CATALOG_PROTOCOL = '@catalog:';
|
|
7
|
+
export const getCatalogReference = (specifier) => {
|
|
8
|
+
const protocolIndex = specifier.lastIndexOf(CATALOG_PROTOCOL);
|
|
9
|
+
if (protocolIndex <= 0)
|
|
10
|
+
return;
|
|
11
|
+
const packageName = specifier.slice(0, protocolIndex);
|
|
12
|
+
if (getPackageNameFromModuleSpecifier(packageName) !== packageName)
|
|
13
|
+
return;
|
|
14
|
+
return {
|
|
15
|
+
catalogName: specifier.slice(protocolIndex + CATALOG_PROTOCOL.length) || DEFAULT_CATALOG,
|
|
16
|
+
packageName,
|
|
17
|
+
};
|
|
18
|
+
};
|
|
5
19
|
export const getCatalogContainer = async (cwd, manifest, manifestPath, pnpmWorkspacePath, pnpmWorkspace) => {
|
|
6
20
|
const filePath = pnpmWorkspacePath ?? (isFile(cwd, '.yarnrc.yml') ? join(cwd, '.yarnrc.yml') : manifestPath);
|
|
7
21
|
const yarnWorkspace = basename(filePath) === '.yarnrc.yml' ? await _load(filePath) : undefined;
|
|
@@ -43,14 +57,14 @@ export const parseCatalog = (container) => {
|
|
|
43
57
|
return entries;
|
|
44
58
|
};
|
|
45
59
|
export const extractCatalogReferences = (manifest) => {
|
|
46
|
-
const catalogReferences =
|
|
60
|
+
const catalogReferences = [];
|
|
47
61
|
const checkDependencies = (dependencies) => {
|
|
48
62
|
if (!dependencies)
|
|
49
63
|
return;
|
|
50
64
|
for (const [name, version] of Object.entries(dependencies)) {
|
|
51
65
|
if (typeof version === 'string' && version.startsWith('catalog:')) {
|
|
52
66
|
const catalogName = version.slice('catalog:'.length) || DEFAULT_CATALOG;
|
|
53
|
-
catalogReferences.
|
|
67
|
+
catalogReferences.push({ catalogName, packageName: name });
|
|
54
68
|
}
|
|
55
69
|
}
|
|
56
70
|
};
|
|
@@ -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\n --exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates\n --files Shortcut for --include files\n --cycles Shortcut for --include cycles (circular dependencies)\n --tags Include or exclude tagged exports\n\nFix\n -f, --fix Fix issues (modifies files in your repo)\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --allow-remove-files Allow Knip to remove files (with --fix)\n -F, --format Format modified files after --fix using the local formatter\n\nOutput\n --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated\n --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)\n --reporter Select reporter (default: symbols), can be repeated (3)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress configuration hints\n --no-tag-hints Suppress tag hints\n --treat-config-hints-as-errors Exit with non-zero code (1) if there are any configuration hints\n --treat-tag-hints-as-errors Exit with non-zero code (1) if there are any tag hints\n --max-issues Maximum number of total issues before non-zero exit code (default: 0)\n --max-show-issues Maximum number of issues to display per type\n --no-exit-code Always exit with code zero (0)\n\nTroubleshooting\n -d, --debug Show debug output\n --memory Measure memory usage and display data table\n --memory-realtime Log memory usage in realtime\n --performance Measure count and running time of key functions and display stats table\n --performance-fn [name] Measure only function [name]\n -u, --duration Print total running time (zero overhead, no instrumentation)\n --trace Show trace output\n --trace-dependency [name] Show files that import the named dependency\n --trace-export [name] Show trace output for named export(s)\n --trace-file [file] Show trace output for exports in file\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog, cycles\n(2) Fixable issue types: dependencies, exports, types, files, catalog\n(3) Built-in reporters: symbols (default), compact, codeowners, cycles, json, codeclimate, markdown, disclosure, github-actions\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip --workspace @myorg/* --workspace '!@myorg/legacy'\n$ knip --workspace './apps/*' --workspace '@shared/utils'\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --tags=-lintignore\n\nWebsite: https://knip.dev";
|
|
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";
|
|
2
2
|
export type ParsedCLIArgs = ReturnType<typeof parseCLIArgs>;
|
|
3
3
|
export default function parseCLIArgs(): {
|
|
4
4
|
cache?: boolean | undefined;
|
|
@@ -26,7 +26,7 @@ Scope
|
|
|
26
26
|
-D, --directory [dir] Run process from a different directory (default: cwd)
|
|
27
27
|
--include Include provided issue type(s), can be comma-separated or repeated (1)
|
|
28
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
|
|
29
|
+
--dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved,catalog,catalogReferences
|
|
30
30
|
--exports Shortcut for --include exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates
|
|
31
31
|
--files Shortcut for --include files
|
|
32
32
|
--cycles Shortcut for --include cycles (circular dependencies)
|
|
@@ -63,9 +63,9 @@ Troubleshooting
|
|
|
63
63
|
--trace-export [name] Show trace output for named export(s)
|
|
64
64
|
--trace-file [file] Show trace output for exports in file
|
|
65
65
|
|
|
66
|
-
(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog, cycles
|
|
66
|
+
(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, types, nsTypes, enumMembers, namespaceMembers, duplicates, catalog, catalogReferences, cycles
|
|
67
67
|
(2) Fixable issue types: dependencies, exports, types, files, catalog
|
|
68
|
-
(3) Built-in reporters: symbols (default), compact, codeowners, cycles, json, codeclimate, markdown, disclosure, github-actions
|
|
68
|
+
(3) Built-in reporters: symbols (default), compact, codeowners, cycles, json, codeclimate, markdown, disclosure, github-actions, sarif
|
|
69
69
|
|
|
70
70
|
Examples:
|
|
71
71
|
|
package/dist/util/codeowners.js
CHANGED
|
@@ -12,7 +12,7 @@ export function parseCodeowners(content) {
|
|
|
12
12
|
return { owners, match: picomatch(expandIgnorePatterns([pattern], true)) };
|
|
13
13
|
});
|
|
14
14
|
return (filePath) => {
|
|
15
|
-
for (const matcher of
|
|
15
|
+
for (const matcher of matchers.toReversed()) {
|
|
16
16
|
if (matcher.match(filePath)) {
|
|
17
17
|
return matcher.owners;
|
|
18
18
|
}
|
|
@@ -55,11 +55,17 @@ export const createInputHandler = (deputy, chief, isGitIgnored, addIssue, extern
|
|
|
55
55
|
const isWorkspace = chief.workspacesByPkgName.has(packageName);
|
|
56
56
|
const inputWorkspace = getWorkspaceFor(input, chief, workspace);
|
|
57
57
|
if (inputWorkspace) {
|
|
58
|
-
let isHandled = deputy.maybeAddReferencedExternalDependency(inputWorkspace, packageName,
|
|
58
|
+
let isHandled = deputy.maybeAddReferencedExternalDependency(inputWorkspace, packageName, {
|
|
59
|
+
isDevOnly: isConfig(input),
|
|
60
|
+
isTypeOnly: input.isTypeOnly,
|
|
61
|
+
});
|
|
59
62
|
if (input.isTypeOnly && input.containingFilePath) {
|
|
60
63
|
const owningWorkspace = chief.findWorkspaceByFilePath(input.containingFilePath);
|
|
61
64
|
if (owningWorkspace && owningWorkspace !== inputWorkspace) {
|
|
62
|
-
const isOwnerHandled = deputy.maybeAddReferencedExternalDependency(owningWorkspace, packageName,
|
|
65
|
+
const isOwnerHandled = deputy.maybeAddReferencedExternalDependency(owningWorkspace, packageName, {
|
|
66
|
+
isDevOnly: isConfig(input),
|
|
67
|
+
isTypeOnly: input.isTypeOnly,
|
|
68
|
+
});
|
|
63
69
|
isHandled = isHandled || isOwnerHandled;
|
|
64
70
|
}
|
|
65
71
|
}
|
|
@@ -936,7 +936,7 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
936
936
|
project?: string | string[] | undefined;
|
|
937
937
|
} | undefined;
|
|
938
938
|
$schema?: string | undefined;
|
|
939
|
-
rules?: Partial<Record<"binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved", "error" | "off" | "warn">> | undefined;
|
|
939
|
+
rules?: Partial<Record<"binaries" | "catalog" | "catalogReferences" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved", "error" | "off" | "warn">> | undefined;
|
|
940
940
|
entry?: string | string[] | undefined;
|
|
941
941
|
project?: string | string[] | undefined;
|
|
942
942
|
paths?: Record<string, string[]> | undefined;
|
|
@@ -947,7 +947,7 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
947
947
|
ignoreMembers?: (string | RegExp)[] | undefined;
|
|
948
948
|
ignoreUnresolved?: (string | RegExp)[] | undefined;
|
|
949
949
|
ignoreExportsUsedInFile?: boolean | Record<string, boolean | undefined> | undefined;
|
|
950
|
-
ignoreIssues?: Record<string, ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
|
|
950
|
+
ignoreIssues?: Record<string, ("binaries" | "catalog" | "catalogReferences" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
|
|
951
951
|
cycles?: {
|
|
952
952
|
allow?: string[][] | undefined;
|
|
953
953
|
dynamicImports?: boolean | undefined;
|
|
@@ -960,8 +960,8 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
960
960
|
tags?: string[] | undefined;
|
|
961
961
|
treatConfigHintsAsErrors?: boolean | undefined;
|
|
962
962
|
treatTagHintsAsErrors?: boolean | undefined;
|
|
963
|
-
include?: ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
|
|
964
|
-
exclude?: ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
|
|
963
|
+
include?: ("binaries" | "catalog" | "catalogReferences" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
|
|
964
|
+
exclude?: ("binaries" | "catalog" | "catalogReferences" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[] | undefined;
|
|
965
965
|
workspaces?: Record<string, {
|
|
966
966
|
angular?: string | boolean | string[] | {
|
|
967
967
|
config?: string | string[] | undefined;
|
|
@@ -1863,13 +1863,14 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
1863
1863
|
ignoreMembers?: (string | RegExp)[] | undefined;
|
|
1864
1864
|
ignoreUnresolved?: (string | RegExp)[] | undefined;
|
|
1865
1865
|
ignoreExportsUsedInFile?: boolean | Record<string, boolean | undefined> | undefined;
|
|
1866
|
-
ignoreIssues?: Record<string, ("binaries" | "catalog" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
|
|
1866
|
+
ignoreIssues?: Record<string, ("binaries" | "catalog" | "catalogReferences" | "cycles" | "dependencies" | "devDependencies" | "duplicates" | "enumMembers" | "exports" | "files" | "namespaceMembers" | "nsExports" | "nsTypes" | "optionalPeerDependencies" | "types" | "unlisted" | "unresolved")[]> | undefined;
|
|
1867
1867
|
includeEntryExports?: boolean | undefined;
|
|
1868
1868
|
}> | undefined;
|
|
1869
1869
|
};
|
|
1870
1870
|
rules: {
|
|
1871
1871
|
binaries: import("../types/issues.ts").IssueSeverity;
|
|
1872
1872
|
catalog: import("../types/issues.ts").IssueSeverity;
|
|
1873
|
+
catalogReferences: import("../types/issues.ts").IssueSeverity;
|
|
1873
1874
|
cycles: import("../types/issues.ts").IssueSeverity;
|
|
1874
1875
|
dependencies: import("../types/issues.ts").IssueSeverity;
|
|
1875
1876
|
devDependencies: import("../types/issues.ts").IssueSeverity;
|
package/dist/util/disk-cache.js
CHANGED
|
@@ -7,7 +7,7 @@ import { isDirectory, isFile } from './fs.js';
|
|
|
7
7
|
import { dirname } from './path.js';
|
|
8
8
|
export const mtimeMatches = (filePath, mtimeMs) => {
|
|
9
9
|
try {
|
|
10
|
-
return fs.statSync(filePath)
|
|
10
|
+
return fs.statSync(filePath, { throwIfNoEntry: false })?.mtimeMs === mtimeMs;
|
|
11
11
|
}
|
|
12
12
|
catch {
|
|
13
13
|
return false;
|
package/dist/util/errors.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { core } from 'zod/mini';
|
|
2
|
+
import { substringBefore } from './string.js';
|
|
2
3
|
const isZodErrorLike = (error) => error instanceof core.$ZodError;
|
|
3
4
|
export class ConfigurationError extends Error {
|
|
4
5
|
}
|
|
@@ -13,11 +14,11 @@ export const formatCauseMessage = (error, cwd) => {
|
|
|
13
14
|
let root = error;
|
|
14
15
|
while (root.cause instanceof Error)
|
|
15
16
|
root = root.cause;
|
|
16
|
-
return root.message
|
|
17
|
+
return substringBefore(root.message, '\n').replace(`${cwd}/`, '');
|
|
17
18
|
};
|
|
18
19
|
export const getKnownErrors = (error) => {
|
|
19
20
|
if (isZodErrorLike(error))
|
|
20
|
-
return
|
|
21
|
+
return Array.from(error.issues, error => {
|
|
21
22
|
let message = error.message;
|
|
22
23
|
const details = [];
|
|
23
24
|
if (error.path.length > 0)
|
|
@@ -31,12 +31,16 @@ export class FileEntryCache {
|
|
|
31
31
|
return existing;
|
|
32
32
|
let fstat;
|
|
33
33
|
try {
|
|
34
|
-
fstat = fs.statSync(filePath);
|
|
34
|
+
fstat = fs.statSync(filePath, { throwIfNoEntry: false });
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
37
|
this.removeEntry(filePath);
|
|
38
38
|
return { key: filePath, notFound: true, err: error };
|
|
39
39
|
}
|
|
40
|
+
if (!fstat) {
|
|
41
|
+
this.removeEntry(filePath);
|
|
42
|
+
return { key: filePath, notFound: true };
|
|
43
|
+
}
|
|
40
44
|
let meta = this.cache.get(filePath);
|
|
41
45
|
const cSize = fstat.size;
|
|
42
46
|
const cTime = fstat.mtime.getTime();
|
package/dist/util/fs.js
CHANGED
|
@@ -7,7 +7,7 @@ import { LoaderError } from './errors.js';
|
|
|
7
7
|
import { extname, join, toPosix } from './path.js';
|
|
8
8
|
export const isDirectory = (cwdOrPath, name) => {
|
|
9
9
|
try {
|
|
10
|
-
return statSync(name ? join(cwdOrPath, name) : cwdOrPath)
|
|
10
|
+
return statSync(name ? join(cwdOrPath, name) : cwdOrPath, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
11
11
|
}
|
|
12
12
|
catch {
|
|
13
13
|
return false;
|
|
@@ -15,7 +15,7 @@ export const isDirectory = (cwdOrPath, name) => {
|
|
|
15
15
|
};
|
|
16
16
|
export const isFile = (cwdOrPath, name) => {
|
|
17
17
|
try {
|
|
18
|
-
return statSync(name ? join(cwdOrPath, name) : cwdOrPath)
|
|
18
|
+
return statSync(name ? join(cwdOrPath, name) : cwdOrPath, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
19
19
|
}
|
|
20
20
|
catch {
|
|
21
21
|
return false;
|
|
@@ -4,7 +4,7 @@ export const defaultExcludedIssueTypes = ['nsExports', 'nsTypes', 'cycles'];
|
|
|
4
4
|
const defaultAddOnIssueTypes = ['nsExports', 'nsTypes'];
|
|
5
5
|
const defaultIssueTypes = ISSUE_TYPES.filter(type => !defaultExcludedIssueTypes.includes(type));
|
|
6
6
|
const normalize = (values) => values.flatMap(value => value.split(','));
|
|
7
|
-
export const shorthandDeps = ['dependencies', 'unlisted', 'binaries', 'unresolved', 'catalog'];
|
|
7
|
+
export const shorthandDeps = ['dependencies', 'unlisted', 'binaries', 'unresolved', 'catalog', 'catalogReferences'];
|
|
8
8
|
export const shorthandExports = ['exports', 'types', 'enumMembers', 'namespaceMembers', 'duplicates'];
|
|
9
9
|
export const shorthandFiles = ['files'];
|
|
10
10
|
export const shorthandCycles = ['cycles'];
|
|
@@ -22,6 +22,7 @@ export const getIncludedIssueTypes = (options) => {
|
|
|
22
22
|
if (options.isProduction) {
|
|
23
23
|
_exclude.push('devDependencies');
|
|
24
24
|
_exclude.push('catalog');
|
|
25
|
+
_exclude.push('catalogReferences');
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
28
|
if (_include.includes('dependencies'))
|
|
@@ -50,7 +50,10 @@ export const setCachedGitignore = (cwd, workspaceDirs, gitignoreFiles, ignores,
|
|
|
50
50
|
for (const file of gitignoreFiles) {
|
|
51
51
|
const abs = path.isAbsolute(file) ? file : path.resolve(cwd, file);
|
|
52
52
|
try {
|
|
53
|
-
|
|
53
|
+
const stat = fs.statSync(abs, { throwIfNoEntry: false });
|
|
54
|
+
if (!stat)
|
|
55
|
+
continue;
|
|
56
|
+
mtimes.push(stat.mtimeMs);
|
|
54
57
|
validFiles.push(file);
|
|
55
58
|
}
|
|
56
59
|
catch {
|
package/dist/util/glob-cache.js
CHANGED
|
@@ -33,8 +33,8 @@ const statDirMtime = (dir) => {
|
|
|
33
33
|
let mtime = dirMtimeCache.get(dir);
|
|
34
34
|
if (mtime === undefined) {
|
|
35
35
|
try {
|
|
36
|
-
const stat = fs.statSync(dir);
|
|
37
|
-
mtime = stat
|
|
36
|
+
const stat = fs.statSync(dir, { throwIfNoEntry: false });
|
|
37
|
+
mtime = stat?.isDirectory() ? stat.mtimeMs : Number.NaN;
|
|
38
38
|
}
|
|
39
39
|
catch {
|
|
40
40
|
mtime = Number.NaN;
|
package/dist/util/glob-core.js
CHANGED
|
@@ -293,7 +293,9 @@ export async function getGitIgnoredHandler(options, workspaceDirs) {
|
|
|
293
293
|
return () => false;
|
|
294
294
|
const { ignores, unignores } = await _parseFindGitignores(options.cwd, workspaceDirs);
|
|
295
295
|
gitignoreFingerprint = hashIgnores(ignores, unignores);
|
|
296
|
-
const
|
|
296
|
+
const ignoreMatcher = picomatch(expandIgnorePatterns(ignores));
|
|
297
|
+
const unignoreMatcher = unignores.size > 0 ? picomatch(expandIgnorePatterns(unignores)) : undefined;
|
|
298
|
+
const matcher = unignoreMatcher ? (path) => ignoreMatcher(path) && !unignoreMatcher(path) : ignoreMatcher;
|
|
297
299
|
const cache = new Map();
|
|
298
300
|
const isGitIgnored = (filePath) => {
|
|
299
301
|
let result = cache.get(filePath);
|
package/dist/util/input.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IssueType } from '../types/issues.ts';
|
|
2
2
|
import type { PluginName } from '../types/PluginNames.ts';
|
|
3
|
-
type InputType = 'binary' | 'entry' | 'project' | 'config' | 'dependency' | 'deferResolve' | 'deferResolveEntry' | 'alias' | 'ignore';
|
|
3
|
+
type InputType = 'binary' | 'catalog' | 'entry' | 'project' | 'config' | 'dependency' | 'deferResolve' | 'deferResolveEntry' | 'alias' | 'ignore';
|
|
4
4
|
export interface Input {
|
|
5
5
|
type: InputType;
|
|
6
6
|
specifier: string;
|
|
@@ -18,6 +18,10 @@ export interface ConfigInput extends Input {
|
|
|
18
18
|
containingFilePath?: string;
|
|
19
19
|
pluginName: PluginName;
|
|
20
20
|
}
|
|
21
|
+
export interface CatalogInput extends Input {
|
|
22
|
+
type: 'catalog';
|
|
23
|
+
catalogName: string;
|
|
24
|
+
}
|
|
21
25
|
interface AliasInput extends Input {
|
|
22
26
|
type: 'alias';
|
|
23
27
|
prefixes: string[];
|
|
@@ -36,6 +40,8 @@ type Options = {
|
|
|
36
40
|
export declare const fromBinary: (input: Input) => string;
|
|
37
41
|
export declare const toBinary: (specifier: string, options?: Options) => Input;
|
|
38
42
|
export declare const isBinary: (input: Input) => boolean;
|
|
43
|
+
export declare const toCatalog: (specifier: string, catalogName: string) => CatalogInput;
|
|
44
|
+
export declare const isCatalog: (input: Input) => input is CatalogInput;
|
|
39
45
|
export declare const toEntry: (specifier: string) => Input;
|
|
40
46
|
export declare const isEntry: (input: Input) => boolean;
|
|
41
47
|
export declare const toProject: (specifier: string) => Input;
|
package/dist/util/input.js
CHANGED
|
@@ -6,6 +6,12 @@ export const toBinary = (specifier, options = {}) => ({
|
|
|
6
6
|
...options,
|
|
7
7
|
});
|
|
8
8
|
export const isBinary = (input) => input.type === 'binary';
|
|
9
|
+
export const toCatalog = (specifier, catalogName) => ({
|
|
10
|
+
type: 'catalog',
|
|
11
|
+
specifier,
|
|
12
|
+
catalogName,
|
|
13
|
+
});
|
|
14
|
+
export const isCatalog = (input) => input.type === 'catalog';
|
|
9
15
|
export const toEntry = (specifier) => ({ type: 'entry', specifier });
|
|
10
16
|
export const isEntry = (input) => input.type === 'entry' && !input.production;
|
|
11
17
|
export const toProject = (specifier) => ({ type: 'project', specifier });
|