knip 4.6.0 → 5.0.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/constants.js CHANGED
@@ -94,9 +94,9 @@ export const ISSUE_TYPE_TITLE = {
94
94
  binaries: 'Unlisted binaries',
95
95
  unresolved: 'Unresolved imports',
96
96
  exports: 'Unused exports',
97
- nsExports: 'Unused exports in namespaces',
97
+ nsExports: 'Exports in used namespace',
98
98
  types: 'Unused exported types',
99
- nsTypes: 'Unused exported types in namespaces',
99
+ nsTypes: 'Exported types in used namespace',
100
100
  enumMembers: 'Unused exported enum members',
101
101
  classMembers: 'Unused exported class members',
102
102
  duplicates: 'Duplicate exports',
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ import { fromBinary, isBinary } from './util/protocols.js';
18
18
  import { _resolveSpecifier } from './util/require.js';
19
19
  import { shouldIgnore } from './util/tag.js';
20
20
  import { loadTSConfig } from './util/tsconfig-loader.js';
21
+ import { getType, getHasStrictlyNsReferences } from './util/type.js';
21
22
  import { WorkspaceWorker } from './WorkspaceWorker.js';
22
23
  export const main = async (unresolvedConfiguration) => {
23
24
  const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports, isIsolateWorkspaces, tags, isFix, fixTypes, } = unresolvedConfiguration;
@@ -457,17 +458,18 @@ export const main = async (unresolvedConfiguration) => {
457
458
  continue;
458
459
  }
459
460
  }
460
- const hasNsImport = Boolean(importsForExport?.hasStar);
461
+ const [hasStrictlyNsReferences, namespace] = getHasStrictlyNsReferences(importsForExport);
461
462
  const isType = ['enum', 'type', 'interface'].includes(exportedItem.type);
462
- if (hasNsImport && ((!report.nsTypes && isType) || (!report.nsExports && !isType)))
463
+ if (hasStrictlyNsReferences && ((!report.nsTypes && isType) || (!report.nsExports && !isType)))
463
464
  continue;
464
465
  if (!isExportedItemReferenced(exportedItem)) {
465
- const type = isType ? (hasNsImport ? 'nsTypes' : 'types') : hasNsImport ? 'nsExports' : 'exports';
466
+ const type = getType(hasStrictlyNsReferences, isType);
466
467
  collector.addIssue({
467
468
  type,
468
469
  filePath,
469
470
  symbol: identifier,
470
471
  symbolType: exportedItem.type,
472
+ parentSymbol: namespace,
471
473
  pos: exportedItem.pos,
472
474
  line: exportedItem.line,
473
475
  col: exportedItem.col,
@@ -2,7 +2,6 @@ import { OwnershipEngine } from '@snyk/github-codeowners/dist/lib/ownership/inde
2
2
  import { isFile } from '../util/fs.js';
3
3
  import { relative, resolve } from '../util/path.js';
4
4
  import { convert } from './util.js';
5
- const mergeTypes = (type) => type === 'exports' || type === 'nsExports' ? 'exports' : type === 'types' || type === 'nsTypes' ? 'types' : type;
6
5
  export default async ({ report, issues, options }) => {
7
6
  let opts = {};
8
7
  try {
@@ -26,21 +25,22 @@ export default async ({ report, issues, options }) => {
26
25
  ...(report.unlisted && { unlisted: [] }),
27
26
  ...(report.binaries && { binaries: [] }),
28
27
  ...(report.unresolved && { unresolved: [] }),
29
- ...((report.exports || report.nsExports) && { exports: [] }),
30
- ...((report.types || report.nsTypes) && { types: [] }),
28
+ ...(report.exports && { exports: [] }),
29
+ ...(report.nsExports && { nsExports: [] }),
30
+ ...(report.types && { types: [] }),
31
+ ...(report.nsTypes && { nsTypes: [] }),
31
32
  ...(report.enumMembers && { enumMembers: {} }),
32
33
  ...(report.classMembers && { classMembers: {} }),
33
34
  ...(report.duplicates && { duplicates: [] }),
34
35
  };
35
36
  return row;
36
37
  };
37
- for (const [reportType, isReportType] of Object.entries(report)) {
38
+ for (const [type, isReportType] of Object.entries(report)) {
38
39
  if (isReportType) {
39
- if (reportType === 'files') {
40
+ if (type === 'files') {
40
41
  }
41
42
  else {
42
- const type = mergeTypes(reportType);
43
- flatten(issues[reportType]).forEach(issue => {
43
+ flatten(issues[type]).forEach(issue => {
44
44
  const { filePath, symbol, symbols, parentSymbol } = issue;
45
45
  json[filePath] = json[filePath] ?? initRow(filePath);
46
46
  if (type === 'duplicates') {
@@ -54,7 +54,7 @@ export default async ({ report, issues, options }) => {
54
54
  }
55
55
  }
56
56
  else {
57
- if (type === 'exports' || type === 'types' || type === 'unresolved') {
57
+ if (['exports', 'nsExports', 'types', 'nsTypes', 'unresolved'].includes(type)) {
58
58
  json[filePath][type]?.push(convert(issue));
59
59
  }
60
60
  else {
@@ -44,7 +44,7 @@ export type Issues = {
44
44
  classMembers: IssueRecords;
45
45
  };
46
46
  export type IssueType = keyof Issues;
47
- export type SymbolIssueType = Exclude<IssueType, 'files'>;
47
+ type SymbolIssueType = Exclude<IssueType, 'files'>;
48
48
  export type Report = {
49
49
  [key in keyof Issues]: boolean;
50
50
  };
@@ -71,3 +71,4 @@ export type ConfigurationHint = {
71
71
  identifier: string | RegExp;
72
72
  workspaceName?: string;
73
73
  };
74
+ export {};
@@ -225,20 +225,55 @@ const getImportsAndExports = (sourceFile, getResolvedModule, typeChecker, option
225
225
  const result = visitor(node, options);
226
226
  result && (Array.isArray(result) ? result.forEach(addScript) : addScript(result));
227
227
  }
228
- if (ts.isIdentifier(node) && isAccessExpression(node.parent)) {
229
- const symbol = sourceFile.locals?.get(String(node.escapedText));
230
- if (symbol) {
231
- if (importedInternalSymbols.has(symbol)) {
232
- let members = [];
233
- let current = node.parent;
234
- while (current) {
235
- const ms = getMemberStringLiterals(typeChecker, current);
236
- if (!ms)
237
- break;
238
- members = members.concat(ms.flatMap(id => (members.length === 0 ? id : members.map(ns => `${ns}.${id}`))));
239
- current = current.parent;
228
+ if (ts.isIdentifier(node)) {
229
+ if (isAccessExpression(node.parent)) {
230
+ const symbol = sourceFile.locals?.get(String(node.escapedText));
231
+ if (symbol) {
232
+ if (importedInternalSymbols.has(symbol)) {
233
+ let members = [];
234
+ let current = node.parent;
235
+ while (current) {
236
+ const ms = getMemberStringLiterals(typeChecker, current);
237
+ if (!ms)
238
+ break;
239
+ members = members.concat(ms.flatMap(id => (members.length === 0 ? id : members.map(ns => `${ns}.${id}`))));
240
+ current = current.parent;
241
+ }
242
+ maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
243
+ }
244
+ }
245
+ }
246
+ else if (ts.isShorthandPropertyAssignment(node.parent) ||
247
+ (ts.isCallExpression(node.parent) && node.parent.arguments.includes(node)) ||
248
+ ts.isSpreadAssignment(node.parent) ||
249
+ ts.isExportAssignment(node.parent)) {
250
+ const symbol = sourceFile.locals?.get(String(node.escapedText));
251
+ if (symbol) {
252
+ const importedSymbolFilePath = importedInternalSymbols.get(symbol);
253
+ if (importedSymbolFilePath) {
254
+ internalImports[importedSymbolFilePath].identifiers.add(String(node.escapedText));
255
+ }
256
+ }
257
+ }
258
+ else if (ts.isVariableDeclaration(node.parent)) {
259
+ if (ts.isVariableDeclarationList(node.parent.parent) && ts.isObjectBindingPattern(node.parent.name)) {
260
+ const symbol = sourceFile.locals?.get(String(node.escapedText));
261
+ if (symbol) {
262
+ const importedSymbolFilePath = importedInternalSymbols.get(symbol);
263
+ if (importedSymbolFilePath) {
264
+ const members = node.parent.name.elements.flatMap(decl => decl.name.getText());
265
+ maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
266
+ }
267
+ }
268
+ }
269
+ else if (node.parent.initializer === node) {
270
+ const symbol = sourceFile.locals?.get(String(node.escapedText));
271
+ if (symbol) {
272
+ const importedSymbolFilePath = importedInternalSymbols.get(symbol);
273
+ if (importedSymbolFilePath) {
274
+ internalImports[importedSymbolFilePath].identifiers.add(String(node.escapedText));
275
+ }
240
276
  }
241
- maybeAddAccessExpressionAsNsImport(String(node.escapedText), members);
242
277
  }
243
278
  }
244
279
  }
@@ -12,5 +12,6 @@ type Options = {
12
12
  dependencies?: boolean;
13
13
  exports?: boolean;
14
14
  };
15
+ export declare const defaultExcludedIssueTypes: string[];
15
16
  export declare const getIncludedIssueTypes: (cliArgs: CLIArguments, { include, exclude, isProduction }?: Options) => Report;
16
17
  export {};
@@ -1,6 +1,6 @@
1
1
  import { ISSUE_TYPES } from '../constants.js';
2
2
  import { ConfigurationError } from './errors.js';
3
- const defaultExcludedIssueTypes = ['classMembers'];
3
+ export const defaultExcludedIssueTypes = ['classMembers', 'nsExports', 'nsTypes'];
4
4
  const defaultIssueTypes = ISSUE_TYPES.filter(type => !defaultExcludedIssueTypes.includes(type));
5
5
  const normalize = (values) => values.map(value => value.split(',')).flat();
6
6
  export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
@@ -0,0 +1,3 @@
1
+ import type { SerializableImports } from '../types/imports.js';
2
+ export declare const getHasStrictlyNsReferences: (importsForExport: SerializableImports) => [boolean, string?];
3
+ export declare const getType: (hasOnlyNsReference: boolean, isType: boolean) => "exports" | "nsExports" | "types" | "nsTypes";
@@ -0,0 +1,16 @@
1
+ export const getHasStrictlyNsReferences = (importsForExport) => {
2
+ if (!importsForExport || !importsForExport.hasStar || importsForExport.importedNs.size === 0)
3
+ return [false];
4
+ let namespace;
5
+ for (const ns of importsForExport.importedNs) {
6
+ const hasNs = importsForExport.identifiers.has(ns);
7
+ if (!hasNs)
8
+ return [false, ns];
9
+ for (const id of importsForExport.identifiers)
10
+ if (id.startsWith(ns + '.'))
11
+ return [false, ns];
12
+ namespace = ns;
13
+ }
14
+ return [true, namespace];
15
+ };
16
+ export const getType = (hasOnlyNsReference, isType) => hasOnlyNsReference ? (isType ? 'nsTypes' : 'nsExports') : isType ? 'types' : 'exports';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "4.6.0",
3
+ "version": "5.0.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": {