knip 5.51.0 → 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)
@@ -30,6 +30,7 @@ const commands = [
30
30
  'patch-commit',
31
31
  'patch-remove',
32
32
  'patch',
33
+ 'prepare',
33
34
  'prune',
34
35
  'publish',
35
36
  'rb',
@@ -57,20 +58,19 @@ const commands = [
57
58
  export const resolve = (_binary, args, options) => {
58
59
  const parsed = parseArgs(args, {
59
60
  boolean: ['recursive', 'silent', 'shell-mode'],
60
- alias: { recursive: 'r', silent: 's', 'shell-mode': 'c' },
61
+ alias: { recursive: 'r', silent: 's', 'shell-mode': 'c', filter: 'F' },
61
62
  });
62
- const [command, binary] = parsed._;
63
+ const [command] = parsed._;
63
64
  if (command === 'dlx') {
64
65
  const argsForDlx = args.filter(arg => arg !== 'dlx');
65
66
  return resolveDlx(argsForDlx, options);
66
67
  }
67
68
  const { manifestScriptNames, fromArgs } = options;
69
+ if (parsed.filter && !parsed.recursive)
70
+ return [];
68
71
  if (manifestScriptNames.has(command) || commands.includes(command))
69
72
  return [];
70
- if (command === 'exec') {
71
- if (parsed._.length > 2)
72
- return [toBinary(binary), ...fromArgs(parsed._.slice(1))];
73
- return [toBinary(binary)];
74
- }
73
+ if (command === 'exec')
74
+ return fromArgs(parsed._.slice(1));
75
75
  return command ? [toBinary(command)] : [];
76
76
  };
@@ -10,12 +10,13 @@ import { getOrCreateFileNode, updateImportMap } from '../util/module-graph.js';
10
10
  import { getEntryPathsFromManifest } from '../util/package-json.js';
11
11
  import { dirname, isAbsolute, join, relative } from '../util/path.js';
12
12
  import {} from '../util/tag.js';
13
- import { augmentWorkspace, getToSourcePathHandler } from '../util/to-source-path.js';
13
+ import { augmentWorkspace, getToSourcePathHandler, getToSourcePathsHandler } from '../util/to-source-path.js';
14
14
  import { loadTSConfig } from '../util/tsconfig-loader.js';
15
15
  export async function build({ cacheLocation, chief, collector, cwd, deputy, factory, gitignore, isCache, isFixExports, isFixTypes, isGitIgnored, isIsolateWorkspaces, isProduction, isSkipLibs, isStrict, isWatch, report, streamer, tags, tsConfigFile, workspaces, }) {
16
16
  const configFilesMap = new Map();
17
17
  const enabledPluginsStore = new Map();
18
18
  const toSourceFilePath = getToSourcePathHandler(chief);
19
+ const toSourceFilePaths = getToSourcePathsHandler(chief);
19
20
  const getReferencedInternalFilePath = getReferencedInputsHandler(collector, deputy, chief, isGitIgnored);
20
21
  const isReportClassMembers = report.classMembers;
21
22
  for (const workspace of workspaces) {
@@ -71,9 +72,9 @@ export async function build({ cacheLocation, chief, collector, cwd, deputy, fact
71
72
  const ignore = worker.getIgnorePatterns();
72
73
  const sharedGlobOptions = { cwd, dir, gitignore };
73
74
  collector.addIgnorePatterns(ignore.map(pattern => join(cwd, pattern)));
74
- const entryPathsFromManifest = await getEntryPathsFromManifest(manifest, { cwd: dir, ignore });
75
- for (const filePath of entryPathsFromManifest) {
76
- inputs.add(toProductionEntry(toSourceFilePath(filePath, extensionGlobStr) ?? filePath));
75
+ const entryPathsFromManifest = getEntryPathsFromManifest(manifest);
76
+ for (const filePath of await toSourceFilePaths(entryPathsFromManifest, dir, extensionGlobStr)) {
77
+ inputs.add(toProductionEntry(filePath));
77
78
  }
78
79
  const principal = factory.createPrincipal({
79
80
  cwd: dir,
@@ -1,4 +1,5 @@
1
1
  import type { IsPluginEnabled, Resolve } from '../../types/config.js';
2
+ export declare const config: string[];
2
3
  declare const _default: {
3
4
  title: string;
4
5
  enablers: string[];
@@ -3,7 +3,7 @@ import { hasDependency } from '../../util/plugin.js';
3
3
  const title = 'Astro';
4
4
  const enablers = ['astro'];
5
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
- const config = ['astro.config.{js,cjs,mjs,ts}'];
6
+ export const config = ['astro.config.{js,cjs,mjs,ts,mts}'];
7
7
  const entry = ['src/content/config.ts', 'src/content.config.ts'];
8
8
  const production = [
9
9
  'src/pages/**/*.{astro,mdx,js,ts}',
@@ -5,8 +5,8 @@ const enablers = ['prettier'];
5
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
6
  const config = [
7
7
  '.prettierrc',
8
- '.prettierrc.{json,js,cjs,mjs,yml,yaml,toml,json5}',
9
- 'prettier.config.{js,cjs,mjs}',
8
+ '.prettierrc.{json,js,cjs,mjs,ts,cts,mts,yml,yaml,toml,json5}',
9
+ 'prettier.config.{js,cjs,mjs,ts,cts,mts}',
10
10
  'package.{json,yaml}',
11
11
  ];
12
12
  const resolveConfig = config => {
@@ -1,10 +1,10 @@
1
1
  import { toProductionEntry } from '../../util/input.js';
2
2
  import { hasDependency } from '../../util/plugin.js';
3
+ import { config } from '../astro/index.js';
3
4
  import { getComponentPathsFromSourceFile } from './resolveFromAST.js';
4
5
  const title = 'Starlight';
5
6
  const enablers = ['@astrojs/starlight'];
6
7
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
- const config = ['astro.config.{js,cjs,mjs,ts}'];
8
8
  const resolveFromAST = (sourceFile) => {
9
9
  const componentPaths = getComponentPathsFromSourceFile(sourceFile);
10
10
  return Array.from(componentPaths).map(id => toProductionEntry(id));
@@ -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) {
@@ -11,6 +11,10 @@ export declare const negate: (pattern: string) => string;
11
11
  export declare const hasProductionSuffix: (pattern: string) => boolean;
12
12
  export declare const hasNoProductionSuffix: (pattern: string) => boolean;
13
13
  export declare const _glob: ({ cwd, dir, patterns, gitignore, label }: GlobOptions) => Promise<string[]>;
14
+ export declare const _syncGlob: ({ cwd, patterns }: {
15
+ cwd?: string;
16
+ patterns: string | string[];
17
+ }) => string[];
14
18
  export declare const _firstGlob: ({ cwd, patterns }: GlobOptions) => Promise<string | Buffer<ArrayBufferLike> | undefined>;
15
19
  export declare const _dirGlob: ({ cwd, patterns, gitignore }: GlobOptions) => Promise<string[]>;
16
20
  export {};
package/dist/util/glob.js CHANGED
@@ -34,6 +34,7 @@ const defaultGlob = async ({ cwd, dir = cwd, patterns, gitignore = true, label }
34
34
  label,
35
35
  });
36
36
  };
37
+ const syncGlob = ({ cwd, patterns }) => fg.sync(patterns, { cwd });
37
38
  const firstGlob = async ({ cwd, patterns }) => {
38
39
  const stream = fg.globStream(patterns.map(removeProductionSuffix), { cwd, ignore: GLOBAL_IGNORE_PATTERNS });
39
40
  for await (const entry of stream) {
@@ -47,5 +48,6 @@ const dirGlob = async ({ cwd, patterns, gitignore = true }) => glob(patterns, {
47
48
  gitignore,
48
49
  });
49
50
  export const _glob = timerify(defaultGlob);
51
+ export const _syncGlob = timerify(syncGlob);
50
52
  export const _firstGlob = timerify(firstGlob);
51
53
  export const _dirGlob = timerify(dirGlob);
@@ -7,8 +7,5 @@ interface ExtendedPackageJson extends PackageJson {
7
7
  }
8
8
  export declare const load: (filePath: string) => Promise<ExtendedPackageJson>;
9
9
  export declare const save: (filePath: string, content: ExtendedPackageJson) => Promise<void>;
10
- export declare const getEntryPathsFromManifest: (manifest: PackageJson, options: {
11
- cwd: string;
12
- ignore: string[];
13
- }) => Promise<string[]>;
10
+ export declare const getEntryPathsFromManifest: (manifest: PackageJson) => Set<string>;
14
11
  export {};
@@ -1,5 +1,4 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
- import { _glob } from './glob.js';
3
2
  const INDENT = Symbol.for('indent');
4
3
  const NEWLINE = Symbol.for('newline');
5
4
  const DEFAULT_NEWLINE = '\n';
@@ -46,7 +45,7 @@ export const save = async (filePath, content) => {
46
45
  const fileContent = `${JSON.stringify(content, null, space)}\n`.replace(/\n/g, EOL);
47
46
  await writeFile(filePath, fileContent);
48
47
  };
49
- export const getEntryPathsFromManifest = (manifest, options) => {
48
+ export const getEntryPathsFromManifest = (manifest) => {
50
49
  const { main, module, browser, bin, exports, types, typings } = manifest;
51
50
  const entryPaths = new Set();
52
51
  if (typeof main === 'string')
@@ -77,5 +76,5 @@ export const getEntryPathsFromManifest = (manifest, options) => {
77
76
  entryPaths.add(types);
78
77
  if (typeof typings === 'string')
79
78
  entryPaths.add(typings);
80
- return _glob({ patterns: Array.from(entryPaths), ...options, gitignore: false, label: 'package.json entry paths' });
79
+ return entryPaths;
81
80
  };
@@ -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
+ }
@@ -1,5 +1,6 @@
1
1
  import type { CompilerOptions } from 'typescript';
2
2
  import type { ConfigurationChief, Workspace } from '../ConfigurationChief.js';
3
3
  export declare const augmentWorkspace: (workspace: Workspace, dir: string, compilerOptions: CompilerOptions) => void;
4
- export declare const getToSourcePathHandler: (chief: ConfigurationChief) => (filePath: string, extensions?: string) => string | undefined;
4
+ export declare const getToSourcePathHandler: (chief: ConfigurationChief) => (filePath: string) => string | undefined;
5
+ export declare const getToSourcePathsHandler: (chief: ConfigurationChief) => (specifiers: Set<string>, cwd: string, extensions?: string) => Promise<string[]>;
5
6
  export type ToSourceFilePath = ReturnType<typeof getToSourcePathHandler>;
@@ -1,8 +1,8 @@
1
- import fastGlob from 'fast-glob';
2
1
  import { DEFAULT_EXTENSIONS } from '../constants.js';
3
- import { debugLog } from './debug.js';
2
+ import { debugLog, debugLogArray } from './debug.js';
4
3
  import { isDirectory } from './fs.js';
5
- import { isInternal, join, toRelative } from './path.js';
4
+ import { _glob, _syncGlob } from './glob.js';
5
+ import { isAbsolute, isInternal, join, toRelative } from './path.js';
6
6
  const defaultExtensions = `.{${DEFAULT_EXTENSIONS.map(ext => ext.slice(1)).join(',')}}`;
7
7
  const hasTSExt = /(?<!\.d)\.(m|c)?tsx?$/;
8
8
  const hasDTSExt = /.d\.(m|c)?ts$/;
@@ -14,7 +14,7 @@ export const augmentWorkspace = (workspace, dir, compilerOptions) => {
14
14
  };
15
15
  export const getToSourcePathHandler = (chief) => {
16
16
  const toSourceMapCache = new Map();
17
- return (filePath, extensions = defaultExtensions) => {
17
+ return (filePath) => {
18
18
  if (!isInternal(filePath) || hasTSExt.test(filePath))
19
19
  return;
20
20
  if (toSourceMapCache.has(filePath))
@@ -23,8 +23,8 @@ export const getToSourcePathHandler = (chief) => {
23
23
  if (workspace?.srcDir && workspace.outDir) {
24
24
  if ((!filePath.startsWith(workspace.srcDir) && filePath.startsWith(workspace.outDir)) ||
25
25
  (workspace.srcDir === workspace.outDir && hasDTSExt.test(filePath))) {
26
- const pattern = filePath.replace(workspace.outDir, workspace.srcDir).replace(matchExt, extensions);
27
- const [srcFilePath] = fastGlob.sync(pattern);
26
+ const pattern = filePath.replace(workspace.outDir, workspace.srcDir).replace(matchExt, defaultExtensions);
27
+ const srcFilePath = _syncGlob({ patterns: pattern })[0];
28
28
  toSourceMapCache.set(filePath, srcFilePath);
29
29
  if (srcFilePath && srcFilePath !== filePath) {
30
30
  debugLog('*', `Source mapping ${toRelative(filePath)} → ${toRelative(srcFilePath)}`);
@@ -34,3 +34,22 @@ export const getToSourcePathHandler = (chief) => {
34
34
  }
35
35
  };
36
36
  };
37
+ export const getToSourcePathsHandler = (chief) => {
38
+ return async (specifiers, cwd, extensions = defaultExtensions) => {
39
+ const patterns = new Set();
40
+ for (const specifier of specifiers) {
41
+ const absSpecifier = isAbsolute(specifier) ? specifier : join(cwd, specifier);
42
+ const ws = chief.findWorkspaceByFilePath(absSpecifier);
43
+ if (ws?.srcDir && ws.outDir && !absSpecifier.startsWith(ws.srcDir) && absSpecifier.startsWith(ws.outDir)) {
44
+ const pattern = absSpecifier.replace(ws.outDir, ws.srcDir).replace(matchExt, extensions);
45
+ patterns.add(pattern);
46
+ }
47
+ else {
48
+ patterns.add(absSpecifier);
49
+ }
50
+ }
51
+ const filePaths = await _glob({ patterns: Array.from(patterns), cwd });
52
+ debugLogArray(toRelative(cwd), 'Source mapping (package.json)', filePaths);
53
+ return filePaths;
54
+ };
55
+ };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.51.0";
1
+ export declare const version = "5.52.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.51.0';
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.0",
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",