knip 3.0.1 → 3.1.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/README.md CHANGED
@@ -14,6 +14,6 @@ Special thanks to the wonderful people who have contributed to this project:
14
14
  [![Contributors][4]][3]
15
15
 
16
16
  [1]: https://knip.dev
17
- [2]: https://www.npmjs.com/package/knip
17
+ [2]: https://github.com/webpro/knip
18
18
  [3]: https://github.com/webpro/knip/graphs/contributors
19
19
  [4]: https://contrib.rocks/image?repo=webpro/knip
@@ -59,6 +59,7 @@ export declare class ConfigurationChief {
59
59
  private getAdditionalWorkspaceNames;
60
60
  private getAvailableWorkspaceNames;
61
61
  private getAvailableWorkspaceManifests;
62
+ private getAvailableWorkspacePkgNames;
62
63
  private getEnabledWorkspaces;
63
64
  getWorkspaces(): Workspace[];
64
65
  private getDescendentWorkspaces;
@@ -170,7 +170,7 @@ export class ConfigurationChief {
170
170
  .reverse()
171
171
  .map(dir => join(this.cwd, dir));
172
172
  this.availableWorkspaceManifests = this.getAvailableWorkspaceManifests(this.availableWorkspaceDirs);
173
- this.availableWorkspacePkgNames = new Set(this.availableWorkspaceManifests.map(w => w.manifest.name));
173
+ this.availableWorkspacePkgNames = this.getAvailableWorkspacePkgNames(this.availableWorkspaceManifests);
174
174
  this.workspacesGraph = createPkgGraph(this.availableWorkspaceManifests);
175
175
  this.enabledWorkspaces = this.getEnabledWorkspaces();
176
176
  }
@@ -225,6 +225,17 @@ export class ConfigurationChief {
225
225
  return { dir, manifest };
226
226
  });
227
227
  }
228
+ getAvailableWorkspacePkgNames(availableWorkspaceManifests) {
229
+ const pkgNames = new Set();
230
+ for (const { dir, manifest } of availableWorkspaceManifests) {
231
+ if (!manifest.name)
232
+ throw new ConfigurationError(`Missing package name in ${join(dir, 'package.json')}`);
233
+ if (pkgNames.has(manifest.name))
234
+ throw new ConfigurationError(`Duplicate package name: ${manifest.name}`);
235
+ pkgNames.add(manifest.name);
236
+ }
237
+ return pkgNames;
238
+ }
228
239
  getEnabledWorkspaces() {
229
240
  if (workspaceArg && !existsSync(workspaceArg)) {
230
241
  throw new ConfigurationError(`Directory does not exist: ${workspaceArg}`);
@@ -17,6 +17,7 @@ export type PrincipalOptions = {
17
17
  compilers: [SyncCompilers, AsyncCompilers];
18
18
  pkgName: string;
19
19
  isGitIgnored: GlobbyFilterFunction;
20
+ isIsolateWorkspaces: boolean;
20
21
  };
21
22
  export declare class PrincipalFactory {
22
23
  principals: Principals;
@@ -16,10 +16,10 @@ const mergePaths = (cwd, compilerOptions, paths = {}) => {
16
16
  export class PrincipalFactory {
17
17
  principals = new Set();
18
18
  getPrincipal(options) {
19
- const { cwd, compilerOptions, paths, pkgName } = options;
19
+ const { cwd, compilerOptions, paths, pkgName, isIsolateWorkspaces } = options;
20
20
  options.compilerOptions = mergePaths(cwd, compilerOptions, paths);
21
21
  const principal = this.findReusablePrincipal(compilerOptions);
22
- if (principal) {
22
+ if (!isIsolateWorkspaces && principal) {
23
23
  this.linkPrincipal(principal, cwd, compilerOptions, pkgName);
24
24
  return principal.principal;
25
25
  }
@@ -11,16 +11,19 @@ import { dirname, extname, isInNodeModules, join } from './util/path.js';
11
11
  import { timerify } from './util/Performance.js';
12
12
  const baseCompilerOptions = {
13
13
  allowJs: true,
14
- jsx: ts.JsxEmit.Preserve,
15
- jsxImportSource: undefined,
16
14
  allowSyntheticDefaultImports: true,
15
+ declaration: false,
16
+ declarationMap: false,
17
17
  esModuleInterop: true,
18
+ inlineSourceMap: false,
19
+ inlineSources: false,
20
+ jsx: ts.JsxEmit.Preserve,
21
+ jsxImportSource: undefined,
22
+ lib: [],
23
+ noEmit: true,
18
24
  skipDefaultLibCheck: true,
19
25
  skipLibCheck: true,
20
- lib: [],
21
- target: ts.ScriptTarget.Latest,
22
- module: ts.ModuleKind.CommonJS,
23
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
26
+ sourceMap: false,
24
27
  };
25
28
  const tsCreateProgram = timerify(ts.createProgram);
26
29
  export class ProjectPrincipal {
@@ -89,16 +89,18 @@ export class WorkspaceWorker {
89
89
  const { entry } = this.config;
90
90
  if (entry.length === 0)
91
91
  return [];
92
- return [entry, this.negatedWorkspacePatterns].flat();
92
+ const excludeProductionNegations = entry.filter(pattern => !(pattern.startsWith('!') && pattern.endsWith('!')));
93
+ return [excludeProductionNegations, this.negatedWorkspacePatterns].flat();
93
94
  }
94
95
  getProjectFilePatterns(testFilePatterns) {
95
96
  const { project } = this.config;
96
97
  if (project.length === 0)
97
98
  return [];
99
+ const excludeProductionNegations = project.filter(pattern => !(pattern.startsWith('!') && pattern.endsWith('!')));
98
100
  const negatedPluginConfigPatterns = this.getPluginConfigPatterns().map(negate);
99
101
  const negatedPluginProjectFilePatterns = this.getPluginProjectFilePatterns().map(negate);
100
102
  return [
101
- project,
103
+ excludeProductionNegations,
102
104
  negatedPluginConfigPatterns,
103
105
  negatedPluginProjectFilePatterns,
104
106
  testFilePatterns,
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { Performance } from './util/Performance.js';
7
7
  import { runPreprocessors, runReporters } from './util/reporter.js';
8
8
  import { version } from './version.js';
9
9
  import { main } from './index.js';
10
- const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, 'include-entry-exports': isIncludeEntryExports = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', 'preprocessor-options': preprocessorOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
10
+ const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, 'include-entry-exports': isIncludeEntryExports = false, 'isolate-workspaces': isIsolateWorkspaces = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', 'preprocessor-options': preprocessorOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
11
11
  if (isHelp) {
12
12
  console.log(helpText);
13
13
  process.exit(0);
@@ -28,6 +28,7 @@ const run = async () => {
28
28
  isStrict,
29
29
  isShowProgress,
30
30
  isIncludeEntryExports,
31
+ isIsolateWorkspaces,
31
32
  });
32
33
  const initialData = {
33
34
  report,
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import { _resolveSpecifier } from './util/require.js';
16
16
  import { loadTSConfig } from './util/tsconfig-loader.js';
17
17
  import { WorkspaceWorker } from './WorkspaceWorker.js';
18
18
  export const main = async (unresolvedConfiguration) => {
19
- const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports } = unresolvedConfiguration;
19
+ const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports, isIsolateWorkspaces, } = unresolvedConfiguration;
20
20
  debugLogObject('*', 'Unresolved configuration (from CLI arguments)', unresolvedConfiguration);
21
21
  const chief = new ConfigurationChief({ cwd, isProduction, isStrict, isIncludeEntryExports });
22
22
  const deputy = new DependencyDeputy({ isStrict });
@@ -87,7 +87,15 @@ export const main = async (unresolvedConfiguration) => {
87
87
  streamer.cast(`Analyzing workspace ${name}...`);
88
88
  deputy.addWorkspace({ name, dir, manifestPath, manifest, ignoreDependencies, ignoreBinaries });
89
89
  const { compilerOptions, definitionPaths } = await loadTSConfig(join(dir, tsConfigFile ?? 'tsconfig.json'));
90
- const principal = factory.getPrincipal({ cwd: dir, paths, compilerOptions, compilers, pkgName, isGitIgnored });
90
+ const principal = factory.getPrincipal({
91
+ cwd: dir,
92
+ paths,
93
+ compilerOptions,
94
+ compilers,
95
+ pkgName,
96
+ isGitIgnored,
97
+ isIsolateWorkspaces,
98
+ });
91
99
  const worker = new WorkspaceWorker({
92
100
  name,
93
101
  dir,
@@ -6,4 +6,5 @@ export interface CommandLineOptions {
6
6
  isProduction: boolean;
7
7
  isShowProgress: boolean;
8
8
  isIncludeEntryExports: boolean;
9
+ isIsolateWorkspaces: boolean;
9
10
  }
@@ -17,7 +17,7 @@ export default visit(() => true, (node, options) => {
17
17
  if (node.importClause?.namedBindings) {
18
18
  if (ts.isNamespaceImport(node.importClause.namedBindings)) {
19
19
  const symbol = node.importClause.namedBindings.symbol;
20
- imports.push({ symbol, specifier, identifier: '*', pos: symbol.declarations[0].pos ?? node.pos });
20
+ imports.push({ symbol, specifier, identifier: '*', pos: symbol?.declarations[0]?.pos ?? node.pos });
21
21
  }
22
22
  if (ts.isNamedImports(node.importClause.namedBindings)) {
23
23
  node.importClause.namedBindings.elements.forEach(element => {
@@ -1,4 +1,4 @@
1
- export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports 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, knip.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 tests, devDependencies, exported types)\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 --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,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --include-entry-exports Include entry files when reporting unused exports\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, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress 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 --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\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\nMore documentation and bug reports: https://github.com/webpro/knip";
1
+ export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports 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, knip.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 tests, devDependencies, exported types)\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 --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 --include-entry-exports Include entry files when reporting unused exports\n --isolate-workspaces Isolated workspaces in monorepo\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, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress 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 --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\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\nMore documentation and bug reports: https://github.com/webpro/knip";
2
2
  declare const _default: {
3
3
  config: string | undefined;
4
4
  debug: boolean | undefined;
@@ -10,6 +10,7 @@ declare const _default: {
10
10
  'ignore-internal': boolean | undefined;
11
11
  include: string[] | undefined;
12
12
  'include-entry-exports': boolean | undefined;
13
+ 'isolate-workspaces': boolean | undefined;
13
14
  'max-issues': string | undefined;
14
15
  'no-config-hints': boolean | undefined;
15
16
  'no-exit-code': boolean | undefined;
@@ -13,9 +13,10 @@ Options:
13
13
  --no-gitignore Don't use .gitignore
14
14
  --include Report only provided issue type(s), can be comma-separated or repeated (1)
15
15
  --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
16
- --dependencies Shortcut for --include dependencies,unlisted,unresolved
16
+ --dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved
17
17
  --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates
18
18
  --include-entry-exports Include entry files when reporting unused exports
19
+ --isolate-workspaces Isolated workspaces in monorepo
19
20
  -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)
20
21
  --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated
21
22
  --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)
@@ -54,6 +55,7 @@ try {
54
55
  'ignore-internal': { type: 'boolean' },
55
56
  include: { type: 'string', multiple: true },
56
57
  'include-entry-exports': { type: 'boolean' },
58
+ 'isolate-workspaces': { type: 'boolean' },
57
59
  'max-issues': { type: 'string' },
58
60
  'no-config-hints': { type: 'boolean' },
59
61
  'no-exit-code': { type: 'boolean' },
@@ -1,5 +1,10 @@
1
1
  import { ISSUE_TYPES } from '../constants.js';
2
+ import { ConfigurationError } from './errors.js';
2
3
  export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
4
+ [...cliArgs.include, ...cliArgs.exclude, ...include, ...exclude].forEach(type => {
5
+ if (!ISSUE_TYPES.includes(type))
6
+ throw new ConfigurationError(`Invalid issue type: ${type}`);
7
+ });
3
8
  if (cliArgs.dependencies) {
4
9
  cliArgs.include = [
5
10
  ...cliArgs.include,
@@ -1,8 +1,9 @@
1
1
  import ts from 'typescript';
2
2
  import { isFile } from './fs.js';
3
+ import { FAKE_PATH } from './loader.js';
3
4
  import { dirname } from './path.js';
4
5
  export const loadTSConfig = async (tsConfigFilePath) => {
5
- if (isFile(tsConfigFilePath)) {
6
+ if (tsConfigFilePath !== FAKE_PATH && isFile(tsConfigFilePath)) {
6
7
  const config = ts.readConfigFile(tsConfigFilePath, ts.sys.readFile);
7
8
  const parsedConfig = ts.parseJsonConfigFileContent(config.config, ts.sys, dirname(tsConfigFilePath));
8
9
  const compilerOptions = parsedConfig.options ?? {};
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "3.0.1";
1
+ export declare const version = "3.1.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '3.0.1';
1
+ export const version = '3.1.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://knip.dev",
6
6
  "repository": {