knip 0.0.0-graph.3 → 0.0.0-node-types.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +7 -915
  2. package/bin/knip.js +2 -0
  3. package/dist/ConfigurationChief.d.ts +14 -6
  4. package/dist/ConfigurationChief.js +104 -70
  5. package/dist/ConfigurationValidator.d.ts +553 -321
  6. package/dist/ConfigurationValidator.js +7 -1
  7. package/dist/DependencyDeputy.d.ts +4 -1
  8. package/dist/DependencyDeputy.js +13 -11
  9. package/dist/PrincipalFactory.d.ts +5 -2
  10. package/dist/PrincipalFactory.js +11 -7
  11. package/dist/ProjectPrincipal.d.ts +18 -15
  12. package/dist/ProjectPrincipal.js +43 -25
  13. package/dist/WorkspaceWorker.d.ts +9 -7
  14. package/dist/WorkspaceWorker.js +45 -63
  15. package/dist/binaries/bash-parser.js +1 -1
  16. package/dist/binaries/index.js +12 -3
  17. package/dist/binaries/resolvers/c8.js +2 -1
  18. package/dist/binaries/resolvers/dotenv.js +2 -1
  19. package/dist/binaries/resolvers/fallback.js +4 -2
  20. package/dist/binaries/resolvers/index.d.ts +1 -0
  21. package/dist/binaries/resolvers/index.js +1 -0
  22. package/dist/binaries/resolvers/node.js +1 -1
  23. package/dist/binaries/resolvers/nodemon.js +2 -1
  24. package/dist/binaries/resolvers/npx.js +2 -1
  25. package/dist/binaries/resolvers/nx.js +1 -1
  26. package/dist/binaries/resolvers/pnpm.js +1 -1
  27. package/dist/binaries/resolvers/rollup.js +2 -1
  28. package/dist/binaries/resolvers/tsx.d.ts +2 -0
  29. package/dist/binaries/resolvers/tsx.js +6 -0
  30. package/dist/binaries/resolvers/yarn.js +1 -1
  31. package/dist/binaries/util.d.ts +0 -3
  32. package/dist/binaries/util.js +1 -3
  33. package/dist/cli.d.ts +0 -1
  34. package/dist/cli.js +10 -9
  35. package/dist/constants.d.ts +0 -1
  36. package/dist/constants.js +5 -4
  37. package/dist/index.js +101 -65
  38. package/dist/manifest/index.js +8 -4
  39. package/dist/plugins/_template/index.js +15 -3
  40. package/dist/plugins/_template/types.d.ts +1 -0
  41. package/dist/plugins/angular/index.js +11 -11
  42. package/dist/plugins/astro/index.d.ts +7 -0
  43. package/dist/plugins/astro/index.js +19 -0
  44. package/dist/plugins/ava/index.d.ts +1 -1
  45. package/dist/plugins/ava/index.js +28 -7
  46. package/dist/plugins/ava/types.d.ts +5 -1
  47. package/dist/plugins/babel/helpers.d.ts +1 -2
  48. package/dist/plugins/babel/helpers.js +28 -20
  49. package/dist/plugins/babel/index.js +17 -14
  50. package/dist/plugins/capacitor/index.js +7 -3
  51. package/dist/plugins/changesets/index.js +10 -6
  52. package/dist/plugins/commitizen/index.d.ts +1 -0
  53. package/dist/plugins/commitizen/index.js +8 -4
  54. package/dist/plugins/commitizen/types.d.ts +1 -1
  55. package/dist/plugins/commitlint/index.js +7 -3
  56. package/dist/plugins/cspell/index.js +7 -3
  57. package/dist/plugins/cspell/types.d.ts +1 -1
  58. package/dist/plugins/cypress/index.d.ts +3 -1
  59. package/dist/plugins/cypress/index.js +17 -4
  60. package/dist/plugins/drizzle/index.js +5 -7
  61. package/dist/plugins/eslint/fallback.js +6 -1
  62. package/dist/plugins/eslint/helpers.d.ts +4 -11
  63. package/dist/plugins/eslint/helpers.js +24 -26
  64. package/dist/plugins/eslint/index.d.ts +1 -1
  65. package/dist/plugins/eslint/index.js +14 -4
  66. package/dist/plugins/gatsby/index.js +11 -5
  67. package/dist/plugins/github-actions/index.d.ts +1 -1
  68. package/dist/plugins/github-actions/index.js +7 -4
  69. package/dist/plugins/graphql-codegen/index.d.ts +7 -0
  70. package/dist/plugins/graphql-codegen/index.js +46 -0
  71. package/dist/plugins/graphql-codegen/types.d.ts +25 -0
  72. package/dist/plugins/graphql-codegen/types.js +3 -0
  73. package/dist/plugins/husky/index.js +9 -4
  74. package/dist/plugins/index.d.ts +4 -0
  75. package/dist/plugins/index.js +4 -0
  76. package/dist/plugins/jest/index.d.ts +1 -1
  77. package/dist/plugins/jest/index.js +21 -12
  78. package/dist/plugins/jest/types.d.ts +3 -0
  79. package/dist/plugins/lefthook/index.js +12 -8
  80. package/dist/plugins/lint-staged/index.d.ts +1 -0
  81. package/dist/plugins/lint-staged/index.js +10 -7
  82. package/dist/plugins/markdownlint/index.js +7 -4
  83. package/dist/plugins/mocha/index.d.ts +1 -0
  84. package/dist/plugins/mocha/index.js +12 -7
  85. package/dist/plugins/mocha/types.d.ts +4 -0
  86. package/dist/plugins/mocha/types.js +1 -0
  87. package/dist/plugins/next/index.d.ts +2 -1
  88. package/dist/plugins/next/index.js +7 -0
  89. package/dist/plugins/node-test-runner/index.d.ts +6 -0
  90. package/dist/plugins/node-test-runner/index.js +19 -0
  91. package/dist/plugins/npm-package-json-lint/index.d.ts +1 -0
  92. package/dist/plugins/npm-package-json-lint/index.js +8 -4
  93. package/dist/plugins/nx/index.js +13 -10
  94. package/dist/plugins/nyc/index.js +6 -3
  95. package/dist/plugins/nyc/types.d.ts +3 -0
  96. package/dist/plugins/nyc/types.js +1 -0
  97. package/dist/plugins/playwright/index.d.ts +5 -1
  98. package/dist/plugins/playwright/index.js +25 -2
  99. package/dist/plugins/playwright-ct/index.d.ts +3 -1
  100. package/dist/plugins/playwright-ct/index.js +18 -2
  101. package/dist/plugins/postcss/index.js +12 -9
  102. package/dist/plugins/prettier/index.js +11 -6
  103. package/dist/plugins/prettier/types.d.ts +8 -0
  104. package/dist/plugins/prettier/types.js +1 -0
  105. package/dist/plugins/release-it/index.d.ts +1 -0
  106. package/dist/plugins/release-it/index.js +14 -10
  107. package/dist/plugins/remark/index.d.ts +1 -0
  108. package/dist/plugins/remark/index.js +20 -4
  109. package/dist/plugins/remark/types.d.ts +3 -0
  110. package/dist/plugins/remark/types.js +1 -0
  111. package/dist/plugins/remix/index.d.ts +2 -1
  112. package/dist/plugins/remix/index.js +9 -0
  113. package/dist/plugins/rollup/index.d.ts +2 -1
  114. package/dist/plugins/rollup/index.js +8 -1
  115. package/dist/plugins/semantic-release/index.d.ts +1 -0
  116. package/dist/plugins/semantic-release/index.js +10 -4
  117. package/dist/plugins/semantic-release/types.d.ts +1 -1
  118. package/dist/plugins/sentry/index.d.ts +2 -1
  119. package/dist/plugins/sentry/index.js +7 -0
  120. package/dist/plugins/storybook/index.js +28 -10
  121. package/dist/plugins/storybook/types.d.ts +7 -0
  122. package/dist/plugins/stryker/index.js +13 -9
  123. package/dist/plugins/stylelint/index.js +8 -5
  124. package/dist/plugins/svelte/index.d.ts +2 -1
  125. package/dist/plugins/svelte/index.js +6 -0
  126. package/dist/plugins/tsup/index.d.ts +6 -0
  127. package/dist/plugins/tsup/index.js +23 -0
  128. package/dist/plugins/tsup/types.d.ts +7 -0
  129. package/dist/plugins/tsup/types.js +1 -0
  130. package/dist/plugins/typedoc/index.d.ts +1 -0
  131. package/dist/plugins/typedoc/index.js +8 -4
  132. package/dist/plugins/typedoc/types.d.ts +1 -1
  133. package/dist/plugins/typescript/index.js +16 -11
  134. package/dist/plugins/vite/index.js +7 -5
  135. package/dist/plugins/vitest/helpers.d.ts +2 -2
  136. package/dist/plugins/vitest/index.d.ts +4 -4
  137. package/dist/plugins/vitest/index.js +55 -26
  138. package/dist/plugins/vitest/types.d.ts +23 -2
  139. package/dist/plugins/webpack/index.js +31 -19
  140. package/dist/plugins/webpack/types.d.ts +2 -1
  141. package/dist/reporters/codeowners.js +2 -2
  142. package/dist/reporters/json.js +14 -9
  143. package/dist/reporters/symbols.js +3 -2
  144. package/dist/reporters/util.d.ts +8 -2
  145. package/dist/reporters/util.js +7 -1
  146. package/dist/types/cli.d.ts +1 -1
  147. package/dist/types/config.d.ts +9 -4
  148. package/dist/types/exports.d.ts +1 -0
  149. package/dist/types/imports.d.ts +6 -0
  150. package/dist/types/issues.d.ts +11 -1
  151. package/dist/types/package-json.d.ts +41 -0
  152. package/dist/types/package-json.js +1 -0
  153. package/dist/types/plugins.d.ts +5 -7
  154. package/dist/types/util.d.ts +16 -0
  155. package/dist/types/util.js +1 -0
  156. package/dist/types/workspace.d.ts +4 -1
  157. package/dist/typescript/SourceFile.d.ts +5 -0
  158. package/dist/typescript/SourceFileManager.js +3 -3
  159. package/dist/typescript/ast-helpers.d.ts +7 -14
  160. package/dist/typescript/ast-helpers.js +11 -9
  161. package/dist/typescript/createHosts.d.ts +1 -0
  162. package/dist/typescript/createHosts.js +1 -1
  163. package/dist/typescript/getImportsAndExports.d.ts +7 -5
  164. package/dist/typescript/getImportsAndExports.js +35 -18
  165. package/dist/typescript/resolveModuleNames.d.ts +1 -1
  166. package/dist/typescript/resolveModuleNames.js +38 -12
  167. package/dist/typescript/visitors/exports/exportDeclaration.js +14 -1
  168. package/dist/typescript/visitors/exports/exportKeyword.js +5 -2
  169. package/dist/typescript/visitors/exports/moduleExportsAccessExpression.js +29 -21
  170. package/dist/typescript/visitors/imports/importCall.js +1 -1
  171. package/dist/typescript/visitors/imports/importDeclaration.js +3 -3
  172. package/dist/typescript/visitors/imports/importEqualsDeclaration.js +1 -1
  173. package/dist/typescript/visitors/imports/jsDocType.js +37 -5
  174. package/dist/typescript/visitors/imports/propertyAccessCall.js +1 -1
  175. package/dist/typescript/visitors/imports/reExportDeclaration.js +8 -3
  176. package/dist/typescript/visitors/imports/requireCall.js +5 -5
  177. package/dist/util/array.d.ts +3 -1
  178. package/dist/util/cli-arguments.d.ts +3 -2
  179. package/dist/util/cli-arguments.js +6 -6
  180. package/dist/util/compilers.d.ts +122 -80
  181. package/dist/util/debug.d.ts +3 -3
  182. package/dist/util/debug.js +12 -18
  183. package/dist/util/fs.d.ts +2 -0
  184. package/dist/util/fs.js +22 -3
  185. package/dist/util/get-included-issue-types.js +14 -18
  186. package/dist/util/git.js +1 -1
  187. package/dist/util/glob.js +1 -1
  188. package/dist/util/loader.d.ts +2 -0
  189. package/dist/util/loader.js +23 -3
  190. package/dist/util/modules.d.ts +7 -1
  191. package/dist/util/modules.js +20 -10
  192. package/dist/util/object.d.ts +1 -0
  193. package/dist/util/object.js +3 -0
  194. package/dist/util/parse-args.d.ts +3 -0
  195. package/dist/util/parse-args.js +8 -0
  196. package/dist/util/path.d.ts +1 -0
  197. package/dist/util/path.js +5 -3
  198. package/dist/util/plugin.d.ts +4 -3
  199. package/dist/util/plugin.js +11 -4
  200. package/dist/util/protocols.d.ts +9 -0
  201. package/dist/util/protocols.js +9 -0
  202. package/dist/util/register.d.ts +2 -1
  203. package/dist/util/register.js +9 -13
  204. package/dist/util/require.js +7 -5
  205. package/dist/util/tsconfig-loader.js +2 -1
  206. package/dist/util/unwrap-function.d.ts +1 -0
  207. package/dist/util/unwrap-function.js +13 -0
  208. package/dist/version.d.ts +1 -1
  209. package/dist/version.js +1 -1
  210. package/package.json +86 -85
  211. package/schema-jsonc.json +11 -0
  212. package/schema.json +27 -3
  213. package/dist/plugins/vite/types.d.ts +0 -4
  214. /package/dist/plugins/{vite → jest}/types.js +0 -0
@@ -3,7 +3,7 @@ import ts from 'typescript';
3
3
  import { getOrSet } from '../util/map.js';
4
4
  import { isMaybePackageName, sanitizeSpecifier } from '../util/modules.js';
5
5
  import { isInNodeModules } from '../util/path.js';
6
- import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName, getJSDocTags, } from './ast-helpers.js';
6
+ import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName, getJSDocTags, getLineAndCharacterOfPosition, } from './ast-helpers.js';
7
7
  import getExportVisitors from './visitors/exports/index.js';
8
8
  import { getJSXImplicitImportBase } from './visitors/helpers.js';
9
9
  import getImportVisitors from './visitors/imports/index.js';
@@ -13,12 +13,12 @@ const getVisitors = (sourceFile) => ({
13
13
  import: getImportVisitors(sourceFile),
14
14
  script: getScriptVisitors(sourceFile),
15
15
  });
16
- export const getImportsAndExports = (sourceFile, options) => {
16
+ export const getImportsAndExports = (sourceFile, getResolvedModule, options) => {
17
17
  const internalImports = new Map();
18
18
  const externalImports = new Set();
19
19
  const unresolvedImports = new Set();
20
20
  const exports = new Map();
21
- const aliasedExports = {};
21
+ const aliasedExports = new Map();
22
22
  const scripts = new Set();
23
23
  const importedInternalSymbols = new Map();
24
24
  const jsxImport = getJSXImplicitImportBase(sourceFile);
@@ -47,10 +47,10 @@ export const getImportsAndExports = (sourceFile, options) => {
47
47
  importedInternalSymbols.set(symbol, filePath);
48
48
  };
49
49
  const addImport = (options) => {
50
- const { specifier, symbol, identifier = '__anonymous', isReExport = false } = options;
50
+ const { specifier, symbol, identifier = '__anonymous', isReExport = false, pos } = options;
51
51
  if (isBuiltin(specifier))
52
52
  return;
53
- const module = sourceFile.resolvedModules?.get(specifier, undefined);
53
+ const module = getResolvedModule(specifier);
54
54
  if (module?.resolvedModule) {
55
55
  const filePath = module.resolvedModule.resolvedFileName;
56
56
  if (filePath) {
@@ -74,7 +74,13 @@ export const getImportsAndExports = (sourceFile, options) => {
74
74
  }
75
75
  }
76
76
  else {
77
- unresolvedImports.add(specifier);
77
+ if (typeof pos === 'number') {
78
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);
79
+ unresolvedImports.add({ specifier, pos, line: line + 1, col: character + 1 });
80
+ }
81
+ else {
82
+ unresolvedImports.add({ specifier });
83
+ }
78
84
  }
79
85
  };
80
86
  const maybeAddNamespaceAccessAsImport = ({ namespace, member }) => {
@@ -87,7 +93,7 @@ export const getImportsAndExports = (sourceFile, options) => {
87
93
  }
88
94
  }
89
95
  };
90
- const addExport = ({ node, identifier, type, pos, members = [] }) => {
96
+ const addExport = ({ node, identifier, type, pos, posDecl, members = [] }) => {
91
97
  if (options.skipExports)
92
98
  return;
93
99
  const jsDocTags = getJSDocTags(node);
@@ -95,10 +101,10 @@ export const getImportsAndExports = (sourceFile, options) => {
95
101
  const item = exports.get(identifier);
96
102
  const crew = [...item.members, ...members];
97
103
  const tags = new Set([...item.jsDocTags, ...jsDocTags]);
98
- exports.set(identifier, { ...item, node, type, pos, members: crew, jsDocTags: tags });
104
+ exports.set(identifier, { ...item, members: crew, jsDocTags: tags });
99
105
  }
100
106
  else {
101
- exports.set(identifier, { node, type, pos, members, jsDocTags });
107
+ exports.set(identifier, { node, type, members, jsDocTags, pos, posDecl: posDecl ?? pos });
102
108
  }
103
109
  if (!jsDocTags.has('@alias')) {
104
110
  if (ts.isExportAssignment(node))
@@ -109,9 +115,17 @@ export const getImportsAndExports = (sourceFile, options) => {
109
115
  };
110
116
  const maybeAddAliasedExport = (node, alias) => {
111
117
  const identifier = node?.getText();
112
- if (identifier && sourceFile.symbol?.exports?.has(identifier)) {
113
- aliasedExports[identifier] = aliasedExports[identifier] ?? [identifier];
114
- aliasedExports[identifier].push(alias);
118
+ if (node && identifier) {
119
+ const exprt = sourceFile.symbol?.exports?.get(identifier);
120
+ if (exprt && exprt.valueDeclaration) {
121
+ if (!aliasedExports.has(identifier)) {
122
+ const pos = getLineAndCharacterOfPosition(exprt.valueDeclaration, exprt.valueDeclaration.pos);
123
+ aliasedExports.set(identifier, [{ symbol: identifier, ...pos }]);
124
+ }
125
+ const i = aliasedExports.get(identifier);
126
+ const pos = getLineAndCharacterOfPosition(node, node.pos);
127
+ i?.push({ symbol: alias, ...pos });
128
+ }
115
129
  }
116
130
  };
117
131
  const visit = (node) => {
@@ -122,11 +136,14 @@ export const getImportsAndExports = (sourceFile, options) => {
122
136
  [results].flat().forEach(addImport);
123
137
  }
124
138
  }
125
- for (const visitor of visitors.export) {
126
- if (visitor) {
127
- const results = visitor(node, options);
128
- if (results)
129
- [results].flat().forEach(addExport);
139
+ const isTopLevel = node.parent === sourceFile || node.parent?.parent === sourceFile;
140
+ if (isTopLevel) {
141
+ for (const visitor of visitors.export) {
142
+ if (visitor) {
143
+ const results = visitor(node, options);
144
+ if (results)
145
+ [results].flat().forEach(addExport);
146
+ }
130
147
  }
131
148
  }
132
149
  for (const visitor of visitors.script) {
@@ -153,7 +170,7 @@ export const getImportsAndExports = (sourceFile, options) => {
153
170
  },
154
171
  exports: {
155
172
  exported: exports,
156
- duplicate: Object.values(aliasedExports),
173
+ duplicate: [...aliasedExports.values()],
157
174
  },
158
175
  scripts,
159
176
  };
@@ -1,2 +1,2 @@
1
1
  import ts from 'typescript';
2
- export declare function createCustomModuleResolver(customSys: typeof ts.sys, compilerOptions: ts.CompilerOptions, virtualFileExtensions: string[]): (moduleNames: string[], containingFile: string) => Array<ts.ResolvedModule | undefined>;
2
+ export declare function createCustomModuleResolver(customSys: typeof ts.sys, compilerOptions: ts.CompilerOptions, virtualFileExtensions: string[]): (moduleNames: string[], containingFile: string) => Array<ts.ResolvedModuleFull | undefined>;
@@ -1,29 +1,55 @@
1
1
  import { existsSync } from 'node:fs';
2
+ import { isBuiltin } from 'node:module';
2
3
  import ts from 'typescript';
3
4
  import { sanitizeSpecifier } from '../util/modules.js';
4
- import { dirname, extname, isInternal, join } from '../util/path.js';
5
+ import { dirname, extname, isAbsolute, isInternal, join } from '../util/path.js';
6
+ import { isDeclarationFileExtension } from './ast-helpers.js';
5
7
  import { ensureRealFilePath, isVirtualFilePath } from './utils.js';
8
+ const resolutionCache = new Map();
9
+ const fileExists = (name, containingFile) => {
10
+ const resolvedFileName = isAbsolute(name) ? name : join(dirname(containingFile), name);
11
+ if (existsSync(resolvedFileName)) {
12
+ return {
13
+ resolvedFileName,
14
+ extension: extname(name),
15
+ isExternalLibraryImport: false,
16
+ resolvedUsingTsExtension: false,
17
+ };
18
+ }
19
+ };
6
20
  export function createCustomModuleResolver(customSys, compilerOptions, virtualFileExtensions) {
7
21
  function resolveModuleNames(moduleNames, containingFile) {
8
- return moduleNames.map(moduleName => resolveModuleName(moduleName, containingFile));
22
+ return moduleNames.map(moduleName => {
23
+ const key = moduleName.startsWith('.')
24
+ ? join(dirname(containingFile), moduleName)
25
+ : `${containingFile}:${moduleName}`;
26
+ if (resolutionCache.has(key))
27
+ return resolutionCache.get(key);
28
+ const resolvedModule = resolveModuleName(moduleName, containingFile);
29
+ resolutionCache.set(key, resolvedModule);
30
+ return resolvedModule;
31
+ });
9
32
  }
10
33
  function resolveModuleName(name, containingFile) {
11
34
  const sanitizedSpecifier = sanitizeSpecifier(name);
35
+ if (isBuiltin(sanitizedSpecifier))
36
+ return undefined;
12
37
  const tsResolvedModule = ts.resolveModuleName(sanitizedSpecifier, containingFile, compilerOptions, ts.sys).resolvedModule;
13
38
  if (!tsResolvedModule) {
14
39
  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
- }
40
+ if (extension && !virtualFileExtensions.includes(extension)) {
41
+ const module = fileExists(sanitizedSpecifier, containingFile);
42
+ if (module)
43
+ return module;
25
44
  }
26
45
  }
46
+ if (tsResolvedModule &&
47
+ isDeclarationFileExtension(tsResolvedModule?.extension) &&
48
+ isInternal(tsResolvedModule.resolvedFileName)) {
49
+ const module = fileExists(sanitizedSpecifier, containingFile);
50
+ if (module)
51
+ return module;
52
+ }
27
53
  if (virtualFileExtensions.length === 0)
28
54
  return tsResolvedModule;
29
55
  if (tsResolvedModule && !isVirtualFilePath(tsResolvedModule.resolvedFileName, virtualFileExtensions)) {
@@ -5,8 +5,21 @@ export default visit(() => true, node => {
5
5
  if (ts.isExportDeclaration(node)) {
6
6
  if (node.exportClause && ts.isNamedExports(node.exportClause)) {
7
7
  const type = node.isTypeOnly ? SymbolType.TYPE : SymbolType.UNKNOWN;
8
+ const sourceFile = node.getSourceFile();
9
+ const declarations = sourceFile.getNamedDeclarations?.();
8
10
  return node.exportClause.elements.map(element => {
9
- return { node: element, identifier: element.name.getText(), type, pos: element.name.pos };
11
+ const identifier = String(element.name.escapedText);
12
+ const declaration = declarations?.get(identifier)?.find((d) => d !== element);
13
+ const pos = element.name.pos;
14
+ const name = ts.getNameOfDeclaration(declaration);
15
+ const posDecl = name?.pos ?? declaration?.pos ?? pos;
16
+ return {
17
+ node: element,
18
+ identifier,
19
+ type,
20
+ pos,
21
+ posDecl,
22
+ };
10
23
  });
11
24
  }
12
25
  }
@@ -1,7 +1,7 @@
1
1
  import ts from 'typescript';
2
2
  import { SymbolType } from '../../../types/issues.js';
3
3
  import { compact } from '../../../util/array.js';
4
- import { isPrivateMember, stripQuotes } from '../../ast-helpers.js';
4
+ import { isGetOrSetAccessorDeclaration, isPrivateMember, stripQuotes } from '../../ast-helpers.js';
5
5
  import { exportVisitor as visit } from '../index.js';
6
6
  export default visit(() => true, node => {
7
7
  const modifierKinds = node.modifiers?.map(modifier => modifier.kind) ?? [];
@@ -47,7 +47,10 @@ export default visit(() => true, node => {
47
47
  const identifier = modifierKinds.includes(ts.SyntaxKind.DefaultKeyword) ? 'default' : node.name.getText();
48
48
  const pos = (node.name ?? node).getStart();
49
49
  const members = node.members
50
- .filter((member) => (ts.isPropertyDeclaration(member) || ts.isMethodDeclaration(member)) && !isPrivateMember(member))
50
+ .filter((member) => (ts.isPropertyDeclaration(member) ||
51
+ ts.isMethodDeclaration(member) ||
52
+ isGetOrSetAccessorDeclaration(member)) &&
53
+ !isPrivateMember(member))
51
54
  .map(member => ({
52
55
  node: member,
53
56
  identifier: member.name.getText(),
@@ -1,30 +1,38 @@
1
1
  import ts from 'typescript';
2
2
  import { SymbolType } from '../../../types/issues.js';
3
- import { isModuleExportsAccessExpression, stripQuotes } from '../../ast-helpers.js';
3
+ import { stripQuotes } from '../../ast-helpers.js';
4
4
  import { isJS } from '../helpers.js';
5
5
  import { exportVisitor as visit } from '../index.js';
6
+ const isModuleExportsAccess = (node) => ts.isIdentifier(node.expression) && node.expression.escapedText === 'module' && node.name.escapedText === 'exports';
6
7
  export default visit(isJS, node => {
7
- if (isModuleExportsAccessExpression(node)) {
8
- const parent = node.parent;
9
- if (ts.isPropertyAccessExpression(parent)) {
10
- const identifier = parent.name.getText();
11
- const pos = parent.name.getStart();
12
- return { node, identifier, type: SymbolType.UNKNOWN, pos };
13
- }
14
- else if (ts.isElementAccessExpression(parent)) {
15
- const identifier = stripQuotes(parent.argumentExpression.getText());
16
- const pos = parent.argumentExpression.getStart();
17
- return { node, identifier, type: SymbolType.UNKNOWN, pos };
18
- }
19
- else if (ts.isBinaryExpression(parent)) {
20
- const expr = parent.right;
21
- if (ts.isObjectLiteralExpression(expr) && expr.properties.every(ts.isShorthandPropertyAssignment)) {
22
- return expr.properties.map(node => {
23
- return { node, identifier: node.getText(), type: SymbolType.UNKNOWN, pos: node.pos };
24
- });
8
+ if (ts.isExpressionStatement(node)) {
9
+ if (ts.isBinaryExpression(node.expression)) {
10
+ if (ts.isPropertyAccessExpression(node.expression.left)) {
11
+ if (ts.isPropertyAccessExpression(node.expression.left.expression) &&
12
+ isModuleExportsAccess(node.expression.left.expression)) {
13
+ const identifier = node.expression.left.name.getText();
14
+ const pos = node.expression.left.name.pos;
15
+ return { node, identifier, type: SymbolType.UNKNOWN, pos };
16
+ }
17
+ else if (isModuleExportsAccess(node.expression.left)) {
18
+ const expr = node.expression.right;
19
+ if (ts.isObjectLiteralExpression(expr) && expr.properties.every(ts.isShorthandPropertyAssignment)) {
20
+ return expr.properties.map(node => {
21
+ return { node, identifier: node.getText(), type: SymbolType.UNKNOWN, pos: node.pos };
22
+ });
23
+ }
24
+ else {
25
+ return { node, identifier: 'default', type: SymbolType.UNKNOWN, pos: expr.pos };
26
+ }
27
+ }
25
28
  }
26
- else {
27
- return { node, identifier: 'default', type: SymbolType.UNKNOWN, pos: node.getStart() };
29
+ else if (ts.isElementAccessExpression(node.expression.left) &&
30
+ ts.isPropertyAccessExpression(node.expression.left.expression) &&
31
+ ts.isIdentifier(node.expression.left.expression.name) &&
32
+ isModuleExportsAccess(node.expression.left.expression)) {
33
+ const identifier = stripQuotes(node.expression.left.argumentExpression.getText());
34
+ const pos = node.expression.left.argumentExpression.pos;
35
+ return { node, identifier, type: SymbolType.UNKNOWN, pos };
28
36
  }
29
37
  }
30
38
  }
@@ -5,7 +5,7 @@ export default visit(() => true, node => {
5
5
  if (isImportCall(node)) {
6
6
  if (node.arguments[0] && ts.isStringLiteralLike(node.arguments[0])) {
7
7
  const specifier = node.arguments[0].text;
8
- return { specifier, identifier: 'default' };
8
+ return { specifier, identifier: 'default', pos: node.arguments[0].pos };
9
9
  }
10
10
  }
11
11
  });
@@ -12,17 +12,17 @@ export default visit(() => true, (node, options) => {
12
12
  return;
13
13
  const imports = [];
14
14
  if (isDefaultImport(node)) {
15
- imports.push({ specifier, identifier: 'default' });
15
+ imports.push({ specifier, identifier: 'default', pos: node.moduleSpecifier.pos });
16
16
  }
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: '*' });
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 => {
24
24
  const identifier = (element.propertyName ?? element.name).getText();
25
- imports.push({ symbol: element.symbol, specifier, identifier });
25
+ imports.push({ symbol: element.symbol, specifier, identifier, pos: element.pos });
26
26
  });
27
27
  }
28
28
  }
@@ -6,6 +6,6 @@ export default visit(isNotJS, node => {
6
6
  ts.isExternalModuleReference(node.moduleReference) &&
7
7
  ts.isStringLiteralLike(node.moduleReference.expression)) {
8
8
  const specifier = node.moduleReference.expression.text;
9
- return { specifier, identifier: 'default' };
9
+ return { specifier, identifier: 'default', pos: node.moduleReference.expression.pos };
10
10
  }
11
11
  });
@@ -1,11 +1,43 @@
1
1
  import ts from 'typescript';
2
- import { isValidImportTypeNode } from '../../ast-helpers.js';
3
2
  import { importVisitor as visit } from '../index.js';
3
+ const extractImportSpecifiers = (node) => {
4
+ const importSpecifiers = [];
5
+ function visit(node) {
6
+ if (ts.isJSDocTypeExpression(node)) {
7
+ const typeNode = node.type;
8
+ if (ts.isTypeReferenceNode(typeNode) && typeNode.typeArguments) {
9
+ typeNode.typeArguments.forEach(arg => {
10
+ if (ts.isImportTypeNode(arg)) {
11
+ const importClause = arg.argument;
12
+ if (ts.isLiteralTypeNode(importClause) && ts.isStringLiteral(importClause.literal)) {
13
+ importSpecifiers.push(importClause.literal.text);
14
+ }
15
+ }
16
+ });
17
+ }
18
+ }
19
+ if (ts.isJSDocTypeTag(node)) {
20
+ const typeNode = node.typeExpression?.type;
21
+ if (ts.isImportTypeNode(typeNode)) {
22
+ const importClause = typeNode.argument;
23
+ if (ts.isLiteralTypeNode(importClause) && ts.isStringLiteral(importClause.literal)) {
24
+ importSpecifiers.push(importClause.literal.text);
25
+ }
26
+ }
27
+ }
28
+ ts.forEachChild(node, visit);
29
+ }
30
+ visit(node);
31
+ return importSpecifiers;
32
+ };
4
33
  export default visit(() => true, node => {
5
- if ('jsDoc' in node) {
6
- const type = ts.getJSDocType(node);
7
- if (type && isValidImportTypeNode(type)) {
8
- return { specifier: type.argument.literal.text };
34
+ if ('jsDoc' in node && node.jsDoc) {
35
+ const jsDoc = node.jsDoc;
36
+ if (jsDoc.length > 0 && jsDoc[0].parent.parent === node.parent) {
37
+ return jsDoc
38
+ .flatMap(jsDoc => (jsDoc.tags ?? []).flatMap(extractImportSpecifiers))
39
+ .map(specifier => ({ specifier }));
9
40
  }
10
41
  }
42
+ return [];
11
43
  });
@@ -6,7 +6,7 @@ export default visit(() => true, node => {
6
6
  if (node.arguments[0] && ts.isStringLiteralLike(node.arguments[0])) {
7
7
  const specifier = node.arguments[0].text;
8
8
  if (specifier)
9
- return { specifier };
9
+ return { specifier, pos: node.arguments[0].pos };
10
10
  }
11
11
  }
12
12
  });
@@ -4,16 +4,21 @@ export default visit(() => true, node => {
4
4
  if (ts.isExportDeclaration(node)) {
5
5
  if (node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) {
6
6
  if (!node.exportClause) {
7
- return { identifier: '*', specifier: node.moduleSpecifier.text, isReExport: true };
7
+ return { identifier: '*', specifier: node.moduleSpecifier.text, isReExport: true, pos: node.pos };
8
8
  }
9
9
  else if (node.exportClause.kind === ts.SyntaxKind.NamespaceExport) {
10
- return { identifier: '*', specifier: node.moduleSpecifier.text, isReExport: true };
10
+ return {
11
+ identifier: '*',
12
+ specifier: node.moduleSpecifier.text,
13
+ isReExport: true,
14
+ pos: node.exportClause.name.pos,
15
+ };
11
16
  }
12
17
  else {
13
18
  const specifier = node.moduleSpecifier;
14
19
  return node.exportClause.elements.map(element => {
15
20
  const identifier = (element.propertyName ?? element.name).getText();
16
- return { identifier, specifier: specifier.text, isReExport: true };
21
+ return { identifier, specifier: specifier.text, isReExport: true, pos: element.pos };
17
22
  });
18
23
  }
19
24
  }
@@ -13,30 +13,30 @@ export default visit(() => true, node => {
13
13
  });
14
14
  if (propertyAccessExpression) {
15
15
  const identifier = String(propertyAccessExpression.name.escapedText);
16
- return { identifier, specifier };
16
+ return { identifier, specifier, pos: propertyAccessExpression.name.pos };
17
17
  }
18
18
  else {
19
19
  const variableDeclaration = node.parent;
20
20
  if (ts.isVariableDeclaration(variableDeclaration) &&
21
21
  ts.isVariableDeclarationList(variableDeclaration.parent)) {
22
22
  if (ts.isIdentifier(variableDeclaration.name)) {
23
- return { identifier: 'default', specifier };
23
+ return { identifier: 'default', specifier, pos: node.arguments[0].pos };
24
24
  }
25
25
  else {
26
26
  const bindings = findDescendants(variableDeclaration, ts.isBindingElement);
27
27
  if (bindings.length > 0) {
28
28
  return bindings.map(element => {
29
29
  const identifier = (element.propertyName ?? element.name).getText();
30
- return { identifier, specifier };
30
+ return { identifier, specifier, pos: element.pos };
31
31
  });
32
32
  }
33
33
  else {
34
- return { identifier: 'default', specifier };
34
+ return { identifier: 'default', specifier, pos: node.arguments[0].pos };
35
35
  }
36
36
  }
37
37
  }
38
38
  else {
39
- return { identifier: 'default', specifier };
39
+ return { identifier: 'default', specifier, pos: node.arguments[0].pos };
40
40
  }
41
41
  }
42
42
  }
@@ -1,2 +1,4 @@
1
- export declare const compact: <T>(collection: (T | undefined)[]) => T[];
1
+ type Collection<T> = Array<T> | Set<T>;
2
+ export declare const compact: <T>(collection: Collection<T | undefined>) => T[];
2
3
  export declare const arrayify: (value?: string[] | string) => string[];
4
+ export {};
@@ -1,15 +1,16 @@
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 --ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)\n -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\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 --debug-file-filter Filter for files in debug output (regex as string)\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$ knip --debug --debug-file-filter '(specific|particular)-module'\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;
5
- 'debug-file-filter': string | undefined;
6
5
  dependencies: boolean | undefined;
6
+ directory: string | undefined;
7
7
  exclude: string[] | undefined;
8
8
  exports: boolean | undefined;
9
9
  help: boolean | undefined;
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;
@@ -1,4 +1,4 @@
1
- import { parseArgs } from 'node:util';
1
+ import { parseArgs } from './parse-args.js';
2
2
  export const helpText = `✂️ Find unused files, dependencies and exports in your JavaScript and TypeScript projects
3
3
 
4
4
  Usage: knip [options]
@@ -8,14 +8,15 @@ Options:
8
8
  -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)
9
9
  --production Analyze only production source files (e.g. no tests, devDependencies, exported types)
10
10
  --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
11
- --ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)
12
11
  -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)
12
+ --directory [dir] Run process from a different directory (default: cwd)
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)
@@ -25,7 +26,6 @@ Options:
25
26
  --no-exit-code Always exit with code zero (0)
26
27
  --max-issues Maximum number of issues before non-zero exit code (default: 0)
27
28
  -d, --debug Show debug output
28
- --debug-file-filter Filter for files in debug output (regex as string)
29
29
  --performance Measure count and running time of expensive functions and display stats table
30
30
  -h, --help Print this help text
31
31
  -V, --version Print version
@@ -39,7 +39,6 @@ $ knip --production
39
39
  $ knip --workspace packages/client --include files,dependencies
40
40
  $ knip -c ./config/knip.json --reporter compact
41
41
  $ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
42
- $ knip --debug --debug-file-filter '(specific|particular)-module'
43
42
 
44
43
  More documentation and bug reports: https://github.com/webpro/knip`;
45
44
  let parsedArgs;
@@ -48,14 +47,15 @@ try {
48
47
  options: {
49
48
  config: { type: 'string', short: 'c' },
50
49
  debug: { type: 'boolean', short: 'd' },
51
- 'debug-file-filter': { type: 'string' },
52
50
  dependencies: { type: 'boolean' },
51
+ directory: { type: 'string' },
53
52
  exclude: { type: 'string', multiple: true },
54
53
  exports: { type: 'boolean' },
55
54
  help: { type: 'boolean', short: 'h' },
56
55
  'ignore-internal': { type: 'boolean' },
57
56
  include: { type: 'string', multiple: true },
58
57
  'include-entry-exports': { type: 'boolean' },
58
+ 'isolate-workspaces': { type: 'boolean' },
59
59
  'max-issues': { type: 'string' },
60
60
  'no-config-hints': { type: 'boolean' },
61
61
  'no-exit-code': { type: 'boolean' },