knip 2.27.1 → 2.29.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
@@ -253,6 +253,7 @@ Knip contains a growing list of plugins:
253
253
  - [commitlint][plugin-commitlint]
254
254
  - [cspell][plugin-cspell]
255
255
  - [Cypress][plugin-cypress]
256
+ - [Drizzle][plugin-drizzle]
256
257
  - [ESLint][plugin-eslint]
257
258
  - [Gatsby][plugin-gatsby]
258
259
  - [GitHub Actions][plugin-github-actions]
@@ -322,6 +323,21 @@ has them at `e2e-tests/*.spec.ts`. Here's how to configure this:
322
323
  }
323
324
  ```
324
325
 
326
+ When overriding any plugin's configuration, the options object is fully replaced. Look at the plugin's page to find the
327
+ default configuration and use that as a basis. Here's another example to override the test file pattern for Vitest:
328
+
329
+ ```json
330
+ {
331
+ "vitest": {
332
+ "config": ["vitest.config.ts"],
333
+ "entry": ["**/*.vitest.ts"]
334
+ }
335
+ }
336
+ ```
337
+
338
+ This plugin configuration can be set on root and workspace level. If set on root level, it can be disabled on workspace
339
+ level by setting it to `false` there.
340
+
325
341
  #### Multi-project repositories
326
342
 
327
343
  Some repositories have a single `package.json`, but consist of multiple projects with configuration files across the
@@ -875,6 +891,7 @@ Special thanks to the wonderful people who have contributed to this project:
875
891
  [plugin-commitlint]: ./src/plugins/commitlint
876
892
  [plugin-cspell]: ./src/plugins/cspell
877
893
  [plugin-cypress]: ./src/plugins/cypress
894
+ [plugin-drizzle]: ./src/plugins/drizzle
878
895
  [plugin-eslint]: ./src/plugins/eslint
879
896
  [plugin-gatsby]: ./src/plugins/gatsby
880
897
  [plugin-github-actions]: ./src/plugins/github-actions
@@ -6,7 +6,7 @@ import { getJSDocTags, isInModuleBlock } from './typescript/ast-helpers.js';
6
6
  import { createHosts } from './typescript/createHosts.js';
7
7
  import { getImportsAndExports } from './typescript/getImportsAndExports.js';
8
8
  import { SourceFileManager } from './typescript/SourceFileManager.js';
9
- import { isMaybePackageName } from './util/modules.js';
9
+ import { isMaybePackageName, sanitizeSpecifier } from './util/modules.js';
10
10
  import { dirname, extname, isInNodeModules, join } from './util/path.js';
11
11
  import { timerify } from './util/Performance.js';
12
12
  const baseCompilerOptions = {
@@ -128,7 +128,7 @@ export class ProjectPrincipal {
128
128
  }
129
129
  }
130
130
  else {
131
- const sanitizedSpecifier = specifier.replace(/^([?!|-]+)?([^!?]+).*/, '$2');
131
+ const sanitizedSpecifier = sanitizeSpecifier(specifier);
132
132
  if (isMaybePackageName(sanitizedSpecifier)) {
133
133
  external.add(sanitizedSpecifier);
134
134
  }
@@ -50,7 +50,7 @@ export declare class WorkspaceWorker {
50
50
  hostDependencies: HostDependencies;
51
51
  installedBinaries: InstalledBinaries;
52
52
  referencedDependencies: ReferencedDependencies;
53
- enabledPlugins: ("angular" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "tailwind" | "typedoc" | "typescript" | "vite" | "vitest" | "webpack" | "githubActions" | "lintStaged" | "npmPackageJsonLint" | "playwrightCt" | "releaseIt" | "semanticRelease" | "svelte")[];
53
+ enabledPlugins: ("angular" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "tailwind" | "typedoc" | "typescript" | "vite" | "vitest" | "webpack" | "drizzle" | "githubActions" | "lintStaged" | "npmPackageJsonLint" | "playwrightCt" | "releaseIt" | "semanticRelease" | "svelte")[];
54
54
  }>;
55
55
  }
56
56
  export {};
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import { getEntryPathFromManifest, getPackageNameFromFilePath, getPackageNameFro
17
17
  import { dirname, isInNodeModules, join, isInternal, toAbsolute } from './util/path.js';
18
18
  import { _resolveSpecifier, _tryResolve } from './util/require.js';
19
19
  import { _require } from './util/require.js';
20
- import { loadTSConfig as loadCompilerOptions } from './util/tsconfig-loader.js';
20
+ import { loadTSConfig } from './util/tsconfig-loader.js';
21
21
  import { WorkspaceWorker } from './WorkspaceWorker.js';
22
22
  export const main = async (unresolvedConfiguration) => {
23
23
  const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isIgnoreInternal, isShowProgress, isIncludeEntryExports, } = unresolvedConfiguration;
@@ -92,7 +92,7 @@ export const main = async (unresolvedConfiguration) => {
92
92
  if (!manifestPath || !manifest)
93
93
  throw new LoaderError(`Unable to load package.json for ${name}`);
94
94
  deputy.addWorkspace({ name, dir, manifestPath, manifest, ignoreDependencies, ignoreBinaries });
95
- const compilerOptions = await loadCompilerOptions(join(dir, tsConfigFile ?? 'tsconfig.json'));
95
+ const { compilerOptions, definitionPaths } = await loadTSConfig(join(dir, tsConfigFile ?? 'tsconfig.json'));
96
96
  const principal = factory.getPrincipal({ cwd: dir, paths, compilerOptions, compilers, pkgName });
97
97
  const worker = new WorkspaceWorker({
98
98
  name,
@@ -107,6 +107,8 @@ export const main = async (unresolvedConfiguration) => {
107
107
  enabledPluginsInAncestors: ancestors.flatMap(ancestor => enabledPluginsStore.get(ancestor) ?? []),
108
108
  });
109
109
  await worker.init();
110
+ principal.addEntryPaths(definitionPaths);
111
+ debugLogArray(`Found definition paths (${name})`, definitionPaths);
110
112
  const sharedGlobOptions = { cwd, workingDir: dir, gitignore, ignore: worker.getIgnorePatterns() };
111
113
  const entryPathsFromManifest = await getEntryPathFromManifest(cwd, dir, manifest);
112
114
  debugLogArray(`Found entry paths in package.json (${name})`, entryPathsFromManifest);
@@ -0,0 +1,6 @@
1
+ import type { GenericPluginCallback, IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Drizzle";
3
+ export declare const ENABLERS: string[];
4
+ export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
6
+ export declare const findDependencies: GenericPluginCallback;
@@ -0,0 +1,16 @@
1
+ import { _glob } from '../../util/glob.js';
2
+ import { timerify } from '../../util/Performance.js';
3
+ import { hasDependency, load } from '../../util/plugin.js';
4
+ export const NAME = 'Drizzle';
5
+ export const ENABLERS = ['drizzle-kit'];
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
+ export const CONFIG_FILE_PATTERNS = ['drizzle.config.{ts,js,json}'];
8
+ const findDrizzleDependencies = async (configFilePath, { cwd }) => {
9
+ const config = await load(configFilePath);
10
+ if (!config || !config.schema)
11
+ return [];
12
+ const patterns = Array.isArray(config.schema) ? config.schema : [config.schema];
13
+ const paths = await _glob({ cwd, patterns });
14
+ return paths;
15
+ };
16
+ export const findDependencies = timerify(findDrizzleDependencies);
@@ -0,0 +1,3 @@
1
+ export interface DrizzleConfig {
2
+ schema?: string | string[];
3
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -7,6 +7,7 @@ export * as commitizen from './commitizen/index.js';
7
7
  export * as commitlint from './commitlint/index.js';
8
8
  export * as cspell from './cspell/index.js';
9
9
  export * as cypress from './cypress/index.js';
10
+ export * as drizzle from './drizzle/index.js';
10
11
  export * as eslint from './eslint/index.js';
11
12
  export * as gatsby from './gatsby/index.js';
12
13
  export * as githubActions from './github-actions/index.js';
@@ -7,6 +7,7 @@ export * as commitizen from './commitizen/index.js';
7
7
  export * as commitlint from './commitlint/index.js';
8
8
  export * as cspell from './cspell/index.js';
9
9
  export * as cypress from './cypress/index.js';
10
+ export * as drizzle from './drizzle/index.js';
10
11
  export * as eslint from './eslint/index.js';
11
12
  export * as gatsby from './gatsby/index.js';
12
13
  export * as githubActions from './github-actions/index.js';
@@ -40,6 +40,7 @@ const resolveDependencies = (config) => {
40
40
  const moduleNameMapper = (config.moduleNameMapper
41
41
  ? Object.values(config.moduleNameMapper).map(mapper => (typeof mapper === 'string' ? mapper : mapper[0]))
42
42
  : []).filter(value => !/\$[0-9]/.test(value));
43
+ const testResultsProcessor = config.testResultsProcessor ? [config.testResultsProcessor] : [];
43
44
  return [
44
45
  ...presets,
45
46
  ...projects,
@@ -52,6 +53,7 @@ const resolveDependencies = (config) => {
52
53
  ...setupFilesAfterEnv,
53
54
  ...transform,
54
55
  ...moduleNameMapper,
56
+ ...testResultsProcessor,
55
57
  ];
56
58
  };
57
59
  const findJestDependencies = async (configFilePath, { cwd, manifest }) => {
@@ -9,7 +9,7 @@ const productionEntryFilePatternsWithoutSrc = [
9
9
  'app/**/{error,layout,loading,not-found,page,template}.{js,jsx,ts,tsx}',
10
10
  'instrumentation.{js,ts}',
11
11
  'app/{manifest,sitemap,robots}.{js,ts}',
12
- 'app/**/{icon,apple-icon}-image.{js,ts,tsx}',
12
+ 'app/**/{icon,apple-icon}.{js,ts,tsx}',
13
13
  'app/**/{opengraph,twitter}-image.{js,ts,tsx}',
14
14
  'pages/**/*.{js,jsx,ts,tsx}',
15
15
  ];
@@ -22,7 +22,7 @@ const resolveExtensibleConfig = async (configFilePath) => {
22
22
  return config;
23
23
  };
24
24
  export const findTypeScriptDependencies = async (configFilePath) => {
25
- const compilerOptions = await loadTSConfig(configFilePath);
25
+ const { compilerOptions } = await loadTSConfig(configFilePath);
26
26
  const config = await resolveExtensibleConfig(configFilePath);
27
27
  if (!compilerOptions || !config)
28
28
  return [];
@@ -5,7 +5,7 @@ import { getEnvPackageName, getExternalReporters } from './helpers.js';
5
5
  export const NAME = 'Vitest';
6
6
  export const ENABLERS = ['vitest'];
7
7
  export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
8
- export const CONFIG_FILE_PATTERNS = ['vitest.config.ts'];
8
+ export const CONFIG_FILE_PATTERNS = ['vitest.config.ts', 'vitest.{workspace,projects}.{ts,js,json}'];
9
9
  export const ENTRY_FILE_PATTERNS = [];
10
10
  export const findVitestDeps = (config) => {
11
11
  if (!config || !config.test)
@@ -18,8 +18,20 @@ export const findVitestDeps = (config) => {
18
18
  const globalSetup = cfg.globalSetup ? [cfg.globalSetup].flat() : [];
19
19
  return compact([...environments, ...reporters, ...coverage, ...setupFiles, ...globalSetup]);
20
20
  };
21
+ const findVitestWorkspaceDeps = (config) => {
22
+ let deps = [];
23
+ for (const cfg of config) {
24
+ if (typeof cfg === 'string')
25
+ continue;
26
+ deps = [...deps, ...findVitestDeps(cfg)];
27
+ }
28
+ return compact(deps);
29
+ };
21
30
  const findVitestDependencies = async (configFilePath) => {
22
31
  const config = await load(configFilePath);
32
+ if (Array.isArray(config)) {
33
+ return findVitestWorkspaceDeps(config);
34
+ }
23
35
  return findVitestDeps(config);
24
36
  };
25
37
  export const findDependencies = timerify(findVitestDependencies);
@@ -9,3 +9,4 @@ export interface VitestConfig {
9
9
  setupFiles?: string | string[];
10
10
  };
11
11
  }
12
+ export type VitestWorkspaceConfig = (string | VitestConfig)[];
@@ -1,9 +1,7 @@
1
- import { existsSync } from 'node:fs';
2
1
  import { isBuiltin } from 'node:module';
3
- import { resolve, dirname } from 'node:path';
4
2
  import ts from 'typescript';
5
3
  import { getOrSet } from '../util/map.js';
6
- import { isMaybePackageName } from '../util/modules.js';
4
+ import { isMaybePackageName, sanitizeSpecifier } from '../util/modules.js';
7
5
  import { isInNodeModules } from '../util/path.js';
8
6
  import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName, getJSDocTags, } from './ast-helpers.js';
9
7
  import getExportVisitors from './visitors/exports/index.js';
@@ -60,13 +58,14 @@ export const getImportsAndExports = (sourceFile, options) => {
60
58
  if (!isInNodeModules(filePath)) {
61
59
  addInternalImport({ identifier, specifier, symbol, filePath, isReExport });
62
60
  }
63
- if (!isMaybePackageName(specifier))
61
+ const sanitizedSpecifier = sanitizeSpecifier(specifier);
62
+ if (!isMaybePackageName(sanitizedSpecifier))
64
63
  return;
65
64
  if (isDeclarationFileExtension(module.resolvedModule.extension)) {
66
- externalImports.add(specifier);
65
+ externalImports.add(sanitizedSpecifier);
67
66
  }
68
67
  else {
69
- externalImports.add(module.resolvedModule.packageId?.name ?? specifier);
68
+ externalImports.add(module.resolvedModule.packageId?.name ?? sanitizedSpecifier);
70
69
  }
71
70
  }
72
71
  else {
@@ -75,13 +74,7 @@ export const getImportsAndExports = (sourceFile, options) => {
75
74
  }
76
75
  }
77
76
  else {
78
- const filePath = resolve(dirname(sourceFile.fileName), specifier);
79
- if (existsSync(filePath)) {
80
- unresolvedImports.add(filePath);
81
- }
82
- else {
83
- unresolvedImports.add(specifier);
84
- }
77
+ unresolvedImports.add(specifier);
85
78
  }
86
79
  };
87
80
  const maybeAddNamespaceAccessAsImport = ({ namespace, member }) => {
@@ -1,11 +1,29 @@
1
+ import { existsSync } from 'node:fs';
1
2
  import ts from 'typescript';
3
+ import { sanitizeSpecifier } from '../util/modules.js';
4
+ import { dirname, extname, isInternal, join } from '../util/path.js';
2
5
  import { ensureRealFilePath, isVirtualFilePath } from './utils.js';
3
6
  export function createCustomModuleResolver(customSys, compilerOptions, virtualFileExtensions) {
4
7
  function resolveModuleNames(moduleNames, containingFile) {
5
8
  return moduleNames.map(moduleName => resolveModuleName(moduleName, containingFile));
6
9
  }
7
10
  function resolveModuleName(name, containingFile) {
8
- const tsResolvedModule = ts.resolveModuleName(name, containingFile, compilerOptions, ts.sys).resolvedModule;
11
+ const sanitizedSpecifier = sanitizeSpecifier(name);
12
+ const tsResolvedModule = ts.resolveModuleName(sanitizedSpecifier, containingFile, compilerOptions, ts.sys).resolvedModule;
13
+ if (!tsResolvedModule) {
14
+ const extension = extname(sanitizedSpecifier);
15
+ if (extension && isInternal(sanitizedSpecifier) && !virtualFileExtensions.includes(extension)) {
16
+ const resolvedFileName = join(dirname(containingFile), sanitizedSpecifier);
17
+ if (existsSync(resolvedFileName)) {
18
+ return {
19
+ resolvedFileName,
20
+ extension,
21
+ isExternalLibraryImport: false,
22
+ resolvedUsingTsExtension: false,
23
+ };
24
+ }
25
+ }
26
+ }
9
27
  if (virtualFileExtensions.length === 0)
10
28
  return tsResolvedModule;
11
29
  if (tsResolvedModule && !isVirtualFilePath(tsResolvedModule.resolvedFileName, virtualFileExtensions)) {
@@ -6,3 +6,4 @@ export declare const isDefinitelyTyped: (packageName: string) => boolean;
6
6
  export declare const getDefinitelyTypedFor: (packageName: string) => string;
7
7
  export declare const getPackageFromDefinitelyTyped: (typedDependency: string) => string;
8
8
  export declare const getEntryPathFromManifest: (cwd: string, dir: string, manifest: PackageJson) => Promise<string[]>;
9
+ export declare const sanitizeSpecifier: (specifier: string) => string;
@@ -50,3 +50,4 @@ export const getEntryPathFromManifest = (cwd, dir, manifest) => {
50
50
  }
51
51
  return _glob({ cwd, workingDir: dir, patterns: Array.from(entryPaths) });
52
52
  };
53
+ export const sanitizeSpecifier = (specifier) => specifier.replace(/^([?!|-]+)?([^!?]+).*/, '$2');
@@ -1,2 +1,5 @@
1
1
  import ts from 'typescript';
2
- export declare const loadTSConfig: (tsConfigFilePath: string) => Promise<ts.CompilerOptions>;
2
+ export declare const loadTSConfig: (tsConfigFilePath: string) => Promise<{
3
+ compilerOptions: ts.CompilerOptions;
4
+ definitionPaths: string[];
5
+ }>;
@@ -5,7 +5,9 @@ export const loadTSConfig = async (tsConfigFilePath) => {
5
5
  if (isFile(tsConfigFilePath)) {
6
6
  const config = ts.readConfigFile(tsConfigFilePath, ts.sys.readFile);
7
7
  const parsedConfig = ts.parseJsonConfigFileContent(config.config, ts.sys, dirname(tsConfigFilePath));
8
- return parsedConfig.options ?? {};
8
+ const compilerOptions = parsedConfig.options ?? {};
9
+ const definitionPaths = parsedConfig.fileNames.filter(filePath => filePath.endsWith('.d.ts'));
10
+ return { compilerOptions, definitionPaths };
9
11
  }
10
- return {};
12
+ return { compilerOptions: {}, definitionPaths: [] };
11
13
  };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "2.27.1";
1
+ export declare const version = "2.29.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '2.27.1';
1
+ export const version = '2.29.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "2.27.1",
3
+ "version": "2.29.0",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://github.com/webpro/knip",
6
6
  "repository": "github:webpro/knip",
@@ -65,16 +65,16 @@
65
65
  "@npmcli/package-json": "5.0.0",
66
66
  "@release-it/bumper": "5.1.0",
67
67
  "@swc/cli": "0.1.62",
68
- "@swc/core": "1.3.88",
68
+ "@swc/core": "1.3.89",
69
69
  "@types/eslint": "8.44.3",
70
70
  "@types/js-yaml": "4.0.6",
71
71
  "@types/micromatch": "4.0.2",
72
72
  "@types/minimist": "1.2.2",
73
- "@types/node": "20.6.4",
73
+ "@types/node": "20.6.5",
74
74
  "@types/npmcli__map-workspaces": "3.0.2",
75
- "@types/webpack": "5.28.2",
76
- "@typescript-eslint/eslint-plugin": "6.7.2",
77
- "@typescript-eslint/parser": "6.7.2",
75
+ "@types/webpack": "5.28.3",
76
+ "@typescript-eslint/eslint-plugin": "6.7.3",
77
+ "@typescript-eslint/parser": "6.7.3",
78
78
  "c8": "8.0.1",
79
79
  "eslint": "8.50.0",
80
80
  "eslint-import-resolver-typescript": "3.6.1",
package/schema.json CHANGED
@@ -256,6 +256,10 @@
256
256
  "title": "Cypress plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/cypress/README.md)",
257
257
  "$ref": "#/definitions/plugin"
258
258
  },
259
+ "drizzle": {
260
+ "title": "Drizzle plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/drizzle/README.md)",
261
+ "$ref": "#/definitions/plugin"
262
+ },
259
263
  "eslint": {
260
264
  "title": "ESLint plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/eslint/README.md)",
261
265
  "$ref": "#/definitions/plugin"
@@ -312,6 +316,10 @@
312
316
  "title": "Playwright plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/playwright/README.md)",
313
317
  "$ref": "#/definitions/plugin"
314
318
  },
319
+ "playwright-ct": {
320
+ "title": "Playwright for components plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/playwright-ct/README.md)",
321
+ "$ref": "#/definitions/plugin"
322
+ },
315
323
  "postcss": {
316
324
  "title": "PostCSS plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/postcss/README.md)",
317
325
  "$ref": "#/definitions/plugin"