knip 5.51.1 → 5.52.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.
@@ -307,7 +307,7 @@ export class ConfigurationChief {
307
307
  getNegatedWorkspacePatterns(name) {
308
308
  const descendentWorkspaces = this.getDescendentWorkspaces(name);
309
309
  const matchName = new RegExp(`^${name}/`);
310
- const ignoredWorkspaces = this.getIgnoredWorkspacesFor(name);
310
+ const ignoredWorkspaces = this.getIgnoredWorkspacesFor(name).map(p => p.replace(/\/\*$/, '/**'));
311
311
  return [...ignoredWorkspaces, ...descendentWorkspaces]
312
312
  .map(workspaceName => workspaceName.replace(matchName, ''))
313
313
  .map(workspaceName => `!${workspaceName}`);
@@ -236,7 +236,7 @@ export class WorkspaceWorker {
236
236
  addInput(toInput(id));
237
237
  }
238
238
  else if ((!plugin.resolveEntryPaths && !plugin.resolveFromAST) ||
239
- (configFilePaths.length === 0 &&
239
+ (configFilePaths.filter(path => basename(path) !== 'package.json').length === 0 &&
240
240
  (!this.configFilesMap.get(wsName)?.get(pluginName) ||
241
241
  this.configFilesMap.get(wsName)?.get(pluginName)?.size === 0))) {
242
242
  if (plugin.entry)
@@ -66,7 +66,7 @@ export const resolve = (_binary, args, options) => {
66
66
  return resolveDlx(argsForDlx, options);
67
67
  }
68
68
  const { manifestScriptNames, fromArgs } = options;
69
- if (parsed.filter)
69
+ if (parsed.filter && !parsed.recursive)
70
70
  return [];
71
71
  if (manifestScriptNames.has(command) || commands.includes(command))
72
72
  return [];
@@ -1,20 +1,20 @@
1
- import EasyTable from 'easy-table';
2
1
  import { relative } from '../util/path.js';
2
+ import { Table } from '../util/table.js';
3
3
  import { getTitle } from './util.js';
4
4
  const printHeader = (size, title) => console.log(`<details>\n${title ? `<summary>${title} (${size})</summary>\n` : ''}\n\`\`\``);
5
5
  const printFooter = () => console.log('```\n\n</details>\n');
6
6
  const logIssueRecord = (issues) => {
7
- const table = new EasyTable();
7
+ const table = new Table();
8
8
  for (const issue of issues) {
9
9
  table.cell('symbol', issue.symbols ? issue.symbols.map(s => s.symbol).join(', ') : issue.symbol);
10
- issue.parentSymbol && table.cell('parentSymbol', issue.parentSymbol);
11
- issue.symbolType && table.cell('symbolType', issue.symbolType);
10
+ table.cell('parentSymbol', issue.parentSymbol && issue.parentSymbol);
11
+ table.cell('symbolType', issue.symbolType && issue.symbolType);
12
12
  const pos = issue.line === undefined ? '' : `:${issue.line}${issue.col === undefined ? '' : `:${issue.col}`}`;
13
13
  const cell = issue.type === 'files' ? '' : `${relative(issue.filePath)}${pos}`;
14
14
  table.cell('filePath', cell);
15
15
  table.newRow();
16
16
  }
17
- console.log(table.sort(['filePath', 'parentSymbol', 'symbol']).print().trim());
17
+ console.log(table.sort('filePath').toString());
18
18
  };
19
19
  export default ({ report, issues }) => {
20
20
  const reportMultipleGroups = Object.values(report).filter(Boolean).length > 1;
@@ -1,17 +1,17 @@
1
- import EasyTable from 'easy-table';
2
1
  import picocolors from 'picocolors';
3
2
  import { ROOT_WORKSPACE_NAME } from '../constants.js';
4
3
  import { SymbolType } from '../types/issues.js';
5
4
  import { relative, toRelative } from '../util/path.js';
6
5
  import { truncate } from '../util/string.js';
6
+ import { Table } from '../util/table.js';
7
7
  import { getTitle, identity, logTitle, logTitleDimmed } from './util.js';
8
8
  const dim = picocolors.gray;
9
9
  const bright = picocolors.whiteBright;
10
10
  const TRUNCATE_WIDTH = 40;
11
11
  const truncateStart = (text, width) => (text.length > width ? `...${text.slice(-(width - 3))}` : text);
12
12
  const sortByPos = (a, b) => {
13
- const [f, r, c] = a.filePath.split(':');
14
- const [f2, r2, c2] = b.filePath.split(':');
13
+ const [f, r, c] = a.filePath.value.split(':');
14
+ const [f2, r2, c2] = b.filePath.value.split(':');
15
15
  return f === f2 ? (Number(r) === Number(r2) ? Number(c) - Number(c2) : Number(r) - Number(r2)) : f.localeCompare(f2);
16
16
  };
17
17
  const hl = (issue) => {
@@ -26,20 +26,20 @@ const hl = (issue) => {
26
26
  return issue.symbol;
27
27
  };
28
28
  const logIssueRecord = (issues) => {
29
- const table = new EasyTable();
29
+ const table = new Table({ truncateStart: ['filePath'], noTruncate: ['symbolType'] });
30
30
  for (const issue of issues) {
31
+ table.newRow();
31
32
  const print = issue.isFixed || issue.severity === 'warn' ? dim : identity;
32
33
  const symbols = issue.symbols;
33
34
  table.cell('symbol', print(symbols ? truncate(symbols.map(s => s.symbol).join(', '), TRUNCATE_WIDTH) : hl(issue)));
34
- issue.parentSymbol && table.cell('parentSymbol', print(issue.parentSymbol));
35
- issue.symbolType && issue.symbolType !== SymbolType.UNKNOWN && table.cell('symbolType', print(issue.symbolType));
35
+ table.cell('parentSymbol', issue.parentSymbol && print(issue.parentSymbol));
36
+ table.cell('symbolType', issue.symbolType && issue.symbolType !== SymbolType.UNKNOWN && print(issue.symbolType));
36
37
  const pos = issue.line === undefined ? '' : `:${issue.line}${issue.col === undefined ? '' : `:${issue.col}`}`;
37
38
  const cell = issue.type === 'files' ? '' : `${relative(issue.filePath)}${pos}`;
38
39
  table.cell('filePath', print(cell));
39
- issue.isFixed && table.cell('fixed', print('(removed)'));
40
- table.newRow();
40
+ table.cell('fixed', issue.isFixed && print('(removed)'));
41
41
  }
42
- console.log(table.sort(sortByPos).print().trim());
42
+ console.log(table.sort(sortByPos).toString());
43
43
  };
44
44
  export default ({ report, issues, tagHints, configurationHints, isDisableConfigHints, isTreatConfigHintsAsErrors, isShowProgress, }) => {
45
45
  const reportMultipleGroups = Object.values(report).filter(Boolean).length > 1;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- export declare const knipConfigurationSchema: z.ZodObject<{
2
+ export declare const knipConfigurationSchema: z.ZodObject<z.objectUtil.extendShape<z.objectUtil.extendShape<z.objectUtil.extendShape<{
3
3
  $schema: z.ZodOptional<z.ZodString>;
4
4
  rules: z.ZodOptional<z.ZodRecord<z.ZodUnion<[z.ZodLiteral<"files">, z.ZodLiteral<"dependencies">, z.ZodLiteral<"devDependencies">, z.ZodLiteral<"optionalPeerDependencies">, z.ZodLiteral<"unlisted">, z.ZodLiteral<"binaries">, z.ZodLiteral<"unresolved">, z.ZodLiteral<"exports">, z.ZodLiteral<"types">, z.ZodLiteral<"nsExports">, z.ZodLiteral<"nsTypes">, z.ZodLiteral<"duplicates">, z.ZodLiteral<"enumMembers">, z.ZodLiteral<"classMembers">]>, z.ZodEnum<["error", "warn", "off"]>>>;
5
5
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
@@ -18,11 +18,11 @@ export declare const knipConfigurationSchema: z.ZodObject<{
18
18
  asyncCompilers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodFunction<z.ZodTuple<[z.ZodString, z.ZodString], z.ZodUnknown>, z.ZodPromise<z.ZodString>>>>;
19
19
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
20
20
  treatConfigHintsAsErrors: z.ZodOptional<z.ZodBoolean>;
21
- } & {
21
+ }, {
22
22
  include: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"files">, z.ZodLiteral<"dependencies">, z.ZodLiteral<"devDependencies">, z.ZodLiteral<"optionalPeerDependencies">, z.ZodLiteral<"unlisted">, z.ZodLiteral<"binaries">, z.ZodLiteral<"unresolved">, z.ZodLiteral<"exports">, z.ZodLiteral<"types">, z.ZodLiteral<"nsExports">, z.ZodLiteral<"nsTypes">, z.ZodLiteral<"duplicates">, z.ZodLiteral<"enumMembers">, z.ZodLiteral<"classMembers">]>, "many">>;
23
23
  exclude: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"files">, z.ZodLiteral<"dependencies">, z.ZodLiteral<"devDependencies">, z.ZodLiteral<"optionalPeerDependencies">, z.ZodLiteral<"unlisted">, z.ZodLiteral<"binaries">, z.ZodLiteral<"unresolved">, z.ZodLiteral<"exports">, z.ZodLiteral<"types">, z.ZodLiteral<"nsExports">, z.ZodLiteral<"nsTypes">, z.ZodLiteral<"duplicates">, z.ZodLiteral<"enumMembers">, z.ZodLiteral<"classMembers">]>, "many">>;
24
- } & {
25
- workspaces: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
24
+ }>, {
25
+ workspaces: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<z.objectUtil.extendShape<{
26
26
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
27
27
  project: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
28
28
  paths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
@@ -32,7 +32,7 @@ export declare const knipConfigurationSchema: z.ZodObject<{
32
32
  ignoreMembers: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodType<RegExp, z.ZodTypeDef, RegExp>]>, "many">>;
33
33
  ignoreUnresolved: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodType<RegExp, z.ZodTypeDef, RegExp>]>, "many">>;
34
34
  includeEntryExports: z.ZodOptional<z.ZodBoolean>;
35
- } & {
35
+ }, {
36
36
  angular: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
37
37
  config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
38
38
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
@@ -1333,7 +1333,7 @@ export declare const knipConfigurationSchema: z.ZodObject<{
1333
1333
  entry?: string | string[] | undefined;
1334
1334
  project?: string | string[] | undefined;
1335
1335
  }>]>>;
1336
- }, "strip", z.ZodTypeAny, {
1336
+ }>, "strip", z.ZodTypeAny, {
1337
1337
  node?: string | boolean | string[] | {
1338
1338
  config?: string | string[] | undefined;
1339
1339
  entry?: string | string[] | undefined;
@@ -2354,7 +2354,7 @@ export declare const knipConfigurationSchema: z.ZodObject<{
2354
2354
  ignoreUnresolved?: (string | RegExp)[] | undefined;
2355
2355
  includeEntryExports?: boolean | undefined;
2356
2356
  }>>>;
2357
- } & {
2357
+ }>, {
2358
2358
  angular: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>, z.ZodObject<{
2359
2359
  config: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
2360
2360
  entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
@@ -3655,7 +3655,7 @@ export declare const knipConfigurationSchema: z.ZodObject<{
3655
3655
  entry?: string | string[] | undefined;
3656
3656
  project?: string | string[] | undefined;
3657
3657
  }>]>>;
3658
- }, "strict", z.ZodTypeAny, {
3658
+ }>, "strict", z.ZodTypeAny, {
3659
3659
  exclude?: ("dependencies" | "exports" | "files" | "devDependencies" | "optionalPeerDependencies" | "unlisted" | "binaries" | "unresolved" | "types" | "nsExports" | "nsTypes" | "duplicates" | "enumMembers" | "classMembers")[] | undefined;
3660
3660
  tags?: string[] | undefined;
3661
3661
  include?: ("dependencies" | "exports" | "files" | "devDependencies" | "optionalPeerDependencies" | "unlisted" | "binaries" | "unresolved" | "types" | "nsExports" | "nsTypes" | "duplicates" | "enumMembers" | "classMembers")[] | undefined;
@@ -1,11 +1,11 @@
1
1
  import { PerformanceObserver, performance } from 'node:perf_hooks';
2
2
  import { constants } from 'node:perf_hooks';
3
3
  import { memoryUsage } from 'node:process';
4
- import EasyTable from 'easy-table';
5
4
  import prettyMilliseconds from 'pretty-ms';
6
5
  import parsedArgValues from './cli-arguments.js';
7
6
  import { debugLog } from './debug.js';
8
7
  import { getStats } from './math.js';
8
+ import { Table } from './table.js';
9
9
  const { performance: isEnabled = false } = parsedArgValues;
10
10
  export const timerify = (fn, name = fn.name) => {
11
11
  if (!isEnabled)
@@ -69,18 +69,19 @@ class Performance {
69
69
  }
70
70
  getTable() {
71
71
  const entriesByName = this.getEntriesByName();
72
- const table = new EasyTable();
72
+ const table = new Table({ header: true });
73
+ const twoFixed = (value) => (typeof value === 'number' ? value.toFixed(2) : value);
73
74
  for (const [name, values] of Object.entries(entriesByName)) {
74
75
  const stats = getStats(values);
75
- table.cell('Name', name);
76
- table.cell('size', values.length, EasyTable.number(0));
77
- table.cell('min', stats.min, EasyTable.number(2));
78
- table.cell('max', stats.max, EasyTable.number(2));
79
- table.cell('median', stats.median, EasyTable.number(2));
80
- table.cell('sum', stats.sum, EasyTable.number(2));
81
76
  table.newRow();
77
+ table.cell('Name', name);
78
+ table.cell('size', values.length);
79
+ table.cell('min', stats.min, twoFixed);
80
+ table.cell('max', stats.max, twoFixed);
81
+ table.cell('median', stats.median, twoFixed);
82
+ table.cell('sum', stats.sum, twoFixed);
82
83
  }
83
- table.sort(['sum|des']);
84
+ table.sort('sum|desc');
84
85
  return table.toString().trim();
85
86
  }
86
87
  getCurrentDurationInMs(startTime) {
@@ -1 +1,3 @@
1
1
  export declare const truncate: (text: string, width: number) => string;
2
+ export declare const truncateStart: (text: string, width: number) => string;
3
+ export declare const pad: (value: string, width: number, fillString?: string, align?: "left" | "center" | "right") => string;
@@ -1 +1,7 @@
1
1
  export const truncate = (text, width) => text.length > width ? `${text.slice(0, width - 3)}...` : text;
2
+ export const truncateStart = (text, width) => text.length > width ? `...${text.slice(-(width - 3))}` : text;
3
+ export const pad = (value, width, fillString, align) => align === 'right'
4
+ ? value.padStart(width, fillString)
5
+ : align === 'center'
6
+ ? value.padStart((value.length + width) / 2, fillString).padEnd(width, fillString)
7
+ : value.padEnd(width, fillString);
@@ -0,0 +1,20 @@
1
+ type Value = string | number | undefined | false | null;
2
+ export declare class Table {
3
+ private columns;
4
+ private rows;
5
+ private header;
6
+ private maxWidth;
7
+ private truncateStart;
8
+ private noTruncate;
9
+ constructor(options?: {
10
+ maxWidth?: number;
11
+ header?: boolean;
12
+ truncateStart?: string[];
13
+ noTruncate?: string[];
14
+ });
15
+ cell(column: string, value: Value, formatter?: (value: Value) => string): this;
16
+ newRow(): this;
17
+ sort(compareFn: ((a: any, b: any) => number) | string): this;
18
+ toString(): string;
19
+ }
20
+ export {};
@@ -0,0 +1,100 @@
1
+ import { pad, truncate, truncateStart } from './string.js';
2
+ const DEFAULT_MAX_WIDTH = process.stdout.columns || 120;
3
+ const MIN_TRUNCATED_WIDTH = 4;
4
+ const COLUMN_SEPARATOR = ' ';
5
+ export class Table {
6
+ columns = [];
7
+ rows = [];
8
+ header;
9
+ maxWidth;
10
+ truncateStart = [];
11
+ noTruncate = [];
12
+ constructor(options) {
13
+ this.header = options?.header ?? false;
14
+ this.maxWidth = options?.maxWidth || DEFAULT_MAX_WIDTH;
15
+ this.truncateStart = options?.truncateStart || [];
16
+ this.noTruncate = options?.noTruncate || [];
17
+ }
18
+ cell(column, value, formatter) {
19
+ if (!this.columns.includes(column))
20
+ this.columns.push(column);
21
+ const row = this.rows[this.rows.length - 1];
22
+ row[column] = {
23
+ value,
24
+ formatted: formatter ? formatter(value) : undefined,
25
+ align: typeof value === 'number' ? 'right' : 'left',
26
+ };
27
+ return this;
28
+ }
29
+ newRow() {
30
+ this.rows.push({});
31
+ return this;
32
+ }
33
+ sort(compareFn) {
34
+ if (typeof compareFn === 'function') {
35
+ this.rows.sort(compareFn);
36
+ return this;
37
+ }
38
+ this.rows.sort((a, b) => {
39
+ const [col, order] = compareFn.split('|');
40
+ const vA = a[col].value;
41
+ const vB = b[col].value;
42
+ if (typeof vA === 'string' && typeof vB === 'string')
43
+ return (order === 'desc' ? -1 : 1) * vA.localeCompare(vB);
44
+ if (typeof vA === 'number' && typeof vB === 'number')
45
+ return order === 'desc' ? vB - vA : vA - vB;
46
+ return !vA ? 1 : !vB ? -1 : 0;
47
+ });
48
+ return this;
49
+ }
50
+ toString() {
51
+ const columns = this.columns.filter(col => this.rows.some(row => typeof row[col].value === 'string' || typeof row[col].value === 'number'));
52
+ if (this.header) {
53
+ const headerRow = {};
54
+ const linesRow = {};
55
+ for (const col of columns) {
56
+ headerRow[col] = { value: col, align: this.rows[0][col].align === 'right' ? 'center' : 'left' };
57
+ linesRow[col] = { value: '', fill: '-' };
58
+ }
59
+ this.rows.unshift(linesRow);
60
+ this.rows.unshift(headerRow);
61
+ }
62
+ const columnWidths = columns.reduce((acc, col) => {
63
+ acc[col] = Math.max(...this.rows.map(row => String(row[col]?.formatted || row[col]?.value || '').length));
64
+ return acc;
65
+ }, {});
66
+ const separatorWidth = (columns.length - 1) * COLUMN_SEPARATOR.length;
67
+ const totalWidth = Object.values(columnWidths).reduce((sum, width) => sum + width, 0) + separatorWidth;
68
+ if (totalWidth > this.maxWidth) {
69
+ const reservedWidth = columns
70
+ .filter(col => this.noTruncate.includes(col))
71
+ .reduce((sum, col) => sum + columnWidths[col], 0);
72
+ const truncatableColumns = columns.filter(col => !this.noTruncate.includes(col));
73
+ const minWidth = truncatableColumns.length * 4;
74
+ const availableWidth = this.maxWidth - separatorWidth - reservedWidth - minWidth;
75
+ const truncatableWidth = truncatableColumns.reduce((sum, col) => sum + columnWidths[col], 0) - minWidth;
76
+ const reduction = availableWidth / truncatableWidth;
77
+ let roundingDiff = availableWidth;
78
+ for (const col of truncatableColumns) {
79
+ const reducedWidth = MIN_TRUNCATED_WIDTH + Math.floor((columnWidths[col] - MIN_TRUNCATED_WIDTH) * reduction);
80
+ columnWidths[col] = reducedWidth;
81
+ roundingDiff -= reducedWidth - MIN_TRUNCATED_WIDTH;
82
+ }
83
+ if (roundingDiff > 0) {
84
+ columnWidths[truncatableColumns.length > 0 ? truncatableColumns[0] : columns[0]] += roundingDiff;
85
+ }
86
+ }
87
+ return this.rows
88
+ .map(row => columns
89
+ .map((col, index) => {
90
+ const cell = row[col];
91
+ const width = columnWidths[col];
92
+ const fill = cell.fill || ' ';
93
+ const padded = pad(String(cell.formatted || cell.value || ''), width, fill, cell.align);
94
+ const truncated = this.truncateStart.includes(col) ? truncateStart(padded, width) : truncate(padded, width);
95
+ return index === 0 ? truncated : COLUMN_SEPARATOR + truncated;
96
+ })
97
+ .join(''))
98
+ .join('\n');
99
+ }
100
+ }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.51.1";
1
+ export declare const version = "5.52.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.51.1';
1
+ export const version = '5.52.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "5.51.1",
3
+ "version": "5.52.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://knip.dev",
6
6
  "repository": {
@@ -61,7 +61,6 @@
61
61
  ],
62
62
  "dependencies": {
63
63
  "@nodelib/fs.walk": "^1.2.3",
64
- "easy-table": "1.2.0",
65
64
  "enhanced-resolve": "^5.18.1",
66
65
  "fast-glob": "^3.3.3",
67
66
  "jiti": "^2.4.2",