knip 1.12.0 → 1.12.2

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/cli.js CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import './util/register.js';
3
3
  import path from 'node:path';
4
+ import prettyMilliseconds from 'pretty-ms';
4
5
  import reporters from './reporters/index.js';
5
6
  import parsedArgs, { helpText } from './util/cli-arguments.js';
6
7
  import { ConfigurationError } from './util/errors.js';
7
8
  import { _load } from './util/loader.js';
8
- import { measure } from './util/performance.js';
9
+ import { Performance } from './util/performance.js';
9
10
  import { version } from './version.js';
10
11
  import { main } from './index.js';
11
- const { values: { debug: isDebug = false, help: isHelp, 'include-entry-exports': isIncludeEntryExports = false, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, version: isVersion, }, } = parsedArgs;
12
+ const { debug: isDebug = false, help: isHelp, 'include-entry-exports': isIncludeEntryExports = false, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, performance: isObservePerf = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgs.values;
12
13
  if (isHelp) {
13
14
  console.log(helpText);
14
15
  process.exit(0);
@@ -22,6 +23,7 @@ const isShowProgress = !isDebug && isNoProgress === false && process.stdout.isTT
22
23
  const printReport = reporter in reporters ? reporters[reporter] : await _load(path.join(cwd, reporter));
23
24
  const run = async () => {
24
25
  try {
26
+ const perfObserver = new Performance(isObservePerf);
25
27
  const { report, issues, counters } = await main({
26
28
  cwd,
27
29
  tsConfigFile: tsConfig,
@@ -35,7 +37,12 @@ const run = async () => {
35
37
  const totalErrorCount = Object.keys(report)
36
38
  .filter(reportGroup => report[reportGroup])
37
39
  .reduce((errorCount, reportGroup) => errorCount + counters[reportGroup], 0);
38
- await measure.print();
40
+ if (isObservePerf) {
41
+ await perfObserver.finalize();
42
+ console.log('\n' + perfObserver.getTable());
43
+ console.log('\nTotal running time:', prettyMilliseconds(perfObserver.getTotalTime()));
44
+ perfObserver.reset();
45
+ }
39
46
  if (!noExitCode && totalErrorCount > Number(maxIssues)) {
40
47
  process.exit(totalErrorCount);
41
48
  }
@@ -8,12 +8,12 @@ import { arrayify } from './util/array.js';
8
8
  import parsedArgs from './util/cli-arguments.js';
9
9
  import { ConfigurationError } from './util/errors.js';
10
10
  import { findFile, loadJSON } from './util/fs.js';
11
- import { ensurePosixPath } from './util/glob.js';
12
11
  import { _load } from './util/loader.js';
12
+ import { relativePosix } from './util/path.js';
13
13
  import { toCamelCase } from './util/plugin.js';
14
14
  import { resolveIncludedIssueTypes } from './util/resolve-included-issue-types.js';
15
15
  import { byPathDepth } from './util/workspace.js';
16
- const { values: { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, }, } = parsedArgs;
16
+ const { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, } = parsedArgs.values;
17
17
  const defaultWorkspaceConfig = DEFAULT_WORKSPACE_CONFIG;
18
18
  const defaultConfig = {
19
19
  include: [],
@@ -135,9 +135,7 @@ export default class ConfigurationChief {
135
135
  ignore: this.config.ignoreWorkspaces,
136
136
  absolute: false,
137
137
  });
138
- this.manifestWorkspaces = Array.from(workspaces.values())
139
- .map(dir => path.relative(this.cwd, dir))
140
- .map(ensurePosixPath);
138
+ this.manifestWorkspaces = Array.from(workspaces.values()).map(dir => relativePosix(this.cwd, dir));
141
139
  return this.manifestWorkspaces;
142
140
  }
143
141
  return [];
package/dist/index.js CHANGED
@@ -9,7 +9,8 @@ import { compact } from './util/array.js';
9
9
  import { debugLogObject, debugLogFiles } from './util/debug.js';
10
10
  import { _findImportModuleSpecifiers } from './util/find-import-specifiers.js';
11
11
  import { findFile, loadJSON } from './util/fs.js';
12
- import { _glob, ensurePosixPath } from './util/glob.js';
12
+ import { _glob } from './util/glob.js';
13
+ import { toPosixPath } from './util/path.js';
13
14
  import { _findDuplicateExportedNames } from './util/project.js';
14
15
  import { loadTSConfig } from './util/tsconfig-loader.js';
15
16
  import { byPathDepth } from './util/workspace.js';
@@ -223,7 +224,7 @@ export const main = async (unresolvedConfiguration) => {
223
224
  const filePath = sourceFile.getFilePath();
224
225
  if (report.dependencies || report.unlisted) {
225
226
  const filePath = sourceFile.getFilePath();
226
- const workspaceDir = workspaceDirs.find(workspaceDir => filePath.startsWith(ensurePosixPath(workspaceDir)));
227
+ const workspaceDir = workspaceDirs.find(workspaceDir => filePath.startsWith(toPosixPath(workspaceDir)));
227
228
  const workspace = workspaces.find(workspace => workspace.dir === workspaceDir);
228
229
  if (workspace) {
229
230
  const [, externalModuleSpecifiers] = moduleSpecifierCache.get(sourceFile) ??
@@ -1,9 +1,8 @@
1
- import path from 'node:path';
2
1
  import { ISSUE_TYPES } from './constants.js';
3
2
  import { initReport, initIssues, initCounters } from './issues/initializers.js';
4
3
  import { getTitle } from './reporters/util.js';
5
4
  import { getLine, LineRewriter } from './util/log.js';
6
- import { relative } from './util/path.js';
5
+ import { relativePosix } from './util/path.js';
7
6
  export default class IssueCollector {
8
7
  report;
9
8
  issues;
@@ -40,8 +39,7 @@ export default class IssueCollector {
40
39
  });
41
40
  }
42
41
  addIssue(issue) {
43
- issue.filePath = path.relative(this.cwd, issue.filePath);
44
- const key = relative(issue.filePath);
42
+ const key = relativePosix(this.cwd, issue.filePath);
45
43
  this.issues[issue.type][key] = this.issues[issue.type][key] ?? {};
46
44
  if (!this.issues[issue.type][key][issue.symbol]) {
47
45
  this.issues[issue.type][key][issue.symbol] = issue;
@@ -68,7 +66,7 @@ export default class IssueCollector {
68
66
  }
69
67
  if (issue && processed < total) {
70
68
  messages.push('');
71
- messages.push(`Processing: ${relative(issue.filePath)}`);
69
+ messages.push(`Processing: ${relativePosix(issue.filePath)}`);
72
70
  }
73
71
  this.lineRewriter.update(messages);
74
72
  }
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { ts } from 'ts-morph';
3
3
  import { debugLogSourceFiles } from './util/debug.js';
4
- import { ensurePosixPath } from './util/glob.js';
4
+ import { toPosixPath } from './util/path.js';
5
5
  import { _createProject, partitionSourceFiles, _resolveSourceFileDependencies, _removeExternalSourceFiles, } from './util/project.js';
6
6
  const baseCompilerOptions = {
7
7
  allowJs: true,
@@ -36,7 +36,7 @@ export default class ProjectPrincipal {
36
36
  this.projectPaths.add(filePath);
37
37
  }
38
38
  removeProjectPath(filePath) {
39
- this.projectPaths.delete(ensurePosixPath(filePath));
39
+ this.projectPaths.delete(toPosixPath(filePath));
40
40
  }
41
41
  addTypeScriptPaths(workspaceDir, compilerOptions) {
42
42
  if (!compilerOptions || !compilerOptions.paths)
@@ -1,12 +1,12 @@
1
1
  import path from 'node:path';
2
2
  import { OwnershipEngine } from '@snyk/github-codeowners/dist/lib/ownership/index.js';
3
3
  import chalk from 'chalk';
4
- import { relative } from '../util/path.js';
4
+ import { relativePosix } from '../util/path.js';
5
5
  import { getTitle, logTitle, logIssueLine } from './util.js';
6
6
  const logIssueSet = (issues) => {
7
7
  issues
8
8
  .sort((a, b) => (a.owner < b.owner ? -1 : 1))
9
- .forEach(issue => console.log(chalk.cyan(issue.owner), issue.symbol.startsWith('/') ? relative(issue.symbol) : issue.symbol));
9
+ .forEach(issue => console.log(chalk.cyan(issue.owner), issue.symbol.startsWith('/') ? relativePosix(issue.symbol) : issue.symbol));
10
10
  };
11
11
  const logIssueRecord = (issues) => {
12
12
  const sortedByFilePath = issues.sort((a, b) => (a.owner < b.owner ? -1 : 1));
@@ -26,7 +26,7 @@ export default ({ report, issues, options }) => {
26
26
  const [dependenciesOwner = '[no-owner]'] = codeownersEngine.calcFileOwnership('package.json');
27
27
  const fallbackOwner = dependenciesOwner;
28
28
  let totalIssues = 0;
29
- const calcFileOwnership = (filePath) => codeownersEngine.calcFileOwnership(relative(filePath))[0] ?? fallbackOwner;
29
+ const calcFileOwnership = (filePath) => codeownersEngine.calcFileOwnership(relativePosix(filePath))[0] ?? fallbackOwner;
30
30
  const addOwner = (issue) => ({ ...issue, owner: calcFileOwnership(issue.filePath) });
31
31
  for (const [reportType, isReportType] of Object.entries(report)) {
32
32
  if (isReportType) {
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { OwnershipEngine } from '@snyk/github-codeowners/dist/lib/ownership/index.js';
3
3
  import { isFile } from '../util/fs.js';
4
- import { relative } from '../util/path.js';
4
+ import { relativePosix } from '../util/path.js';
5
5
  const mergeTypes = (type) => type === 'exports' || type === 'nsExports' ? 'exports' : type === 'types' || type === 'nsTypes' ? 'types' : type;
6
6
  export default async ({ report, issues, options }) => {
7
7
  let opts = {};
@@ -16,7 +16,7 @@ export default async ({ report, issues, options }) => {
16
16
  const codeownersEngine = isFile(codeownersFilePath) && OwnershipEngine.FromCodeownersFile(codeownersFilePath);
17
17
  const flatten = (issues) => Object.values(issues).map(Object.values).flat();
18
18
  const initRow = (filePath) => {
19
- const file = relative(filePath);
19
+ const file = relativePosix(filePath);
20
20
  const row = {
21
21
  file,
22
22
  ...(codeownersEngine && { owners: codeownersEngine.calcFileOwnership(file) }),
@@ -1,5 +1,5 @@
1
1
  import EasyTable from 'easy-table';
2
- import { relative } from '../util/path.js';
2
+ import { relativePosix } from '../util/path.js';
3
3
  import { getTitle, logTitle, logIssueSet } from './util.js';
4
4
  const TRUNCATE_WIDTH = 40;
5
5
  const truncate = (text) => (text.length > TRUNCATE_WIDTH ? text.slice(0, TRUNCATE_WIDTH - 3) + '...' : text);
@@ -9,7 +9,7 @@ const logIssueRecord = (issues) => {
9
9
  table.cell('symbol', issue.symbols ? truncate(issue.symbols.join(', ')) : issue.symbol);
10
10
  issue.parentSymbol && table.cell('parentSymbol', issue.parentSymbol);
11
11
  issue.symbolType && table.cell('symbolType', issue.symbolType);
12
- table.cell('filePath', relative(issue.filePath));
12
+ table.cell('filePath', relativePosix(issue.filePath));
13
13
  table.newRow();
14
14
  });
15
15
  console.log(table.sort(['filePath', 'parentSymbol', 'symbol']).print().trim());
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { ISSUE_TYPE_TITLE } from '../constants.js';
3
- import { relative } from '../util/path.js';
3
+ import { relativePosix } from '../util/path.js';
4
4
  export const getTitle = (reportType) => {
5
5
  return ISSUE_TYPE_TITLE[reportType];
6
6
  };
@@ -8,8 +8,8 @@ export const logTitle = (title, count) => console.log(`${chalk.bold.yellow.under
8
8
  export const logIssueLine = ({ owner, filePath, symbols, parentSymbol }) => {
9
9
  const symbol = symbols ? `: ${symbols.join(', ')}` : '';
10
10
  const parent = parentSymbol ? ` (${parentSymbol})` : '';
11
- console.log(`${owner ? `${chalk.cyan(owner)} ` : ''}${relative(filePath)}${symbol}${parent}`);
11
+ console.log(`${owner ? `${chalk.cyan(owner)} ` : ''}${relativePosix(filePath)}${symbol}${parent}`);
12
12
  };
13
13
  export const logIssueSet = (issues) => {
14
- issues.sort().forEach(value => console.log(value.startsWith('/') ? relative(value) : value));
14
+ issues.sort().forEach(value => console.log(value.startsWith('/') ? relativePosix(value) : value));
15
15
  };
@@ -4,25 +4,24 @@ import * as FallbackResolver from './resolvers/fallback.js';
4
4
  import * as KnownResolvers from './resolvers/index.js';
5
5
  const spawningBinaries = ['cross-env', 'dotenv'];
6
6
  export const getBinariesFromScript = (script, { cwd, manifest, knownGlobalsOnly = false }) => {
7
- const findByArgs = (args) => (args.length > 0 ? findBinaries(parse(args.join(' ')).commands) : []);
8
- const findBinaries = (items) => items.flatMap(item => {
9
- switch (item.type) {
7
+ if (!script)
8
+ return [];
9
+ const fromArgs = (args) => getBinariesFromScript(args.join(' '), { cwd, manifest });
10
+ const getBinariesFromNodes = (nodes) => nodes.flatMap(node => {
11
+ switch (node.type) {
10
12
  case 'Command': {
11
- const binary = item.name?.text;
13
+ const binary = node.name?.text;
12
14
  if (!binary || binary === '.' || binary === 'source')
13
15
  return [];
14
16
  if (binary.startsWith('-') || binary.startsWith('"') || binary.startsWith('..'))
15
17
  return [];
16
18
  if (['bun', 'deno'].includes(binary))
17
19
  return [];
18
- const args = item.suffix?.map(arg => arg.text) ?? [];
20
+ const args = node.suffix?.map(arg => arg.text) ?? [];
19
21
  if (['!', 'test'].includes(binary))
20
- return findByArgs(args);
22
+ return fromArgs(args);
21
23
  if (binary in KnownResolvers) {
22
- return KnownResolvers[binary].resolve(binary, args, cwd, manifest, (args) => {
23
- const [binary, ...rest] = args;
24
- return FallbackResolver.resolve(binary, rest, cwd);
25
- });
24
+ return KnownResolvers[binary].resolve(binary, args, { cwd, manifest, fromArgs });
26
25
  }
27
26
  if (knownGlobalsOnly)
28
27
  return [];
@@ -31,24 +30,24 @@ export const getBinariesFromScript = (script, { cwd, manifest, knownGlobalsOnly
31
30
  const [spawnedBinary] = parsedArgs._;
32
31
  if (spawnedBinary) {
33
32
  const restArgs = args.slice(args.indexOf(spawnedBinary));
34
- return [binary, ...findByArgs(restArgs)];
33
+ return [binary, ...fromArgs(restArgs)];
35
34
  }
36
35
  else {
37
36
  return [];
38
37
  }
39
38
  }
40
- return FallbackResolver.resolve(binary, args, cwd);
39
+ return FallbackResolver.resolve(binary, args, { cwd, manifest, fromArgs });
41
40
  }
42
41
  case 'LogicalExpression':
43
- return findBinaries([item.left, item.right]);
42
+ return getBinariesFromNodes([node.left, node.right]);
44
43
  case 'If':
45
- return findBinaries([...item.clause.commands, ...item.then.commands]);
44
+ return getBinariesFromNodes([...node.clause.commands, ...node.then.commands]);
46
45
  case 'For':
47
- return findBinaries(item.do.commands);
46
+ return getBinariesFromNodes(node.do.commands);
48
47
  default:
49
48
  return [];
50
49
  }
51
50
  });
52
51
  const parsed = parse(script);
53
- return parsed?.commands ? findBinaries(parsed.commands) : [];
52
+ return parsed?.commands ? getBinariesFromNodes(parsed.commands) : [];
54
53
  };
@@ -1,13 +1,2 @@
1
- import type { PackageJson } from 'type-fest';
2
- type Options = {
3
- cwd?: string;
4
- manifest?: PackageJson;
5
- ignore?: string[];
6
- knownGlobalsOnly?: boolean;
7
- };
8
- type GetBinariesFromScripts = (npmScripts: string | string[], options?: Options) => {
9
- entryFiles: string[];
10
- binaries: string[];
11
- };
1
+ import type { GetBinariesFromScripts } from './types.js';
12
2
  export declare const _getReferencesFromScripts: GetBinariesFromScripts;
13
- export {};
@@ -1 +1,2 @@
1
- export declare const resolve: (binary: string, args: string[], cwd: string) => string[];
1
+ import type { Resolver } from '../types.js';
2
+ export declare const resolve: Resolver;
@@ -1,28 +1,13 @@
1
- import path from 'node:path';
2
1
  import parseArgs from 'minimist';
3
- import { tryResolve } from '../../require.js';
4
- const resolveArguments = {
5
- 'ts-node': (parsed) => [parsed._[0], parsed.require].flat(),
6
- tsx: (parsed) => parsed._.filter(p => p !== 'watch'),
7
- default: (parsed) => [parsed.require].flat(),
2
+ import { tryResolveFilePaths } from './node.js';
3
+ const argResolvers = {
4
+ 'ts-node': parsed => [parsed._[0], parsed.require].flat(),
5
+ tsx: parsed => parsed._.filter(p => p !== 'watch'),
6
+ default: parsed => [parsed.require].flat(),
8
7
  };
9
- export const resolve = (binary, args, cwd) => {
8
+ export const resolve = (binary, args, { cwd }) => {
10
9
  const parsed = parseArgs(args, { string: ['r'], alias: { require: ['r', 'loader'] } });
11
- const resolver = resolveArguments[binary] ?? resolveArguments.default;
10
+ const resolver = argResolvers[binary] ?? argResolvers.default;
12
11
  const resolve = resolver(parsed);
13
- return [
14
- binary,
15
- ...resolve.flatMap(specifier => {
16
- if (specifier) {
17
- const filePath = path.join(cwd, specifier);
18
- if (filePath.startsWith(cwd)) {
19
- const resolvedFilePath = tryResolve(filePath);
20
- if (resolvedFilePath)
21
- return [resolvedFilePath];
22
- }
23
- return [specifier];
24
- }
25
- return [];
26
- }),
27
- ];
12
+ return [binary, ...tryResolveFilePaths(cwd, resolve)];
28
13
  };
@@ -1 +1,3 @@
1
- export declare const resolve: (binary: string, args: string[], cwd: string) => string[];
1
+ import type { Resolver } from '../types.js';
2
+ export declare const tryResolveFilePaths: (cwd: string, specifiers: string[]) => string[];
3
+ export declare const resolve: Resolver;
@@ -1,19 +1,20 @@
1
1
  import path from 'node:path';
2
2
  import parseArgs from 'minimist';
3
3
  import { tryResolve } from '../../require.js';
4
- export const resolve = (binary, args, cwd) => {
5
- const parsed = parseArgs(args, { string: ['r'], alias: { require: ['r', 'loader', 'experimental-loader'] } });
6
- const resolve = [parsed._[0], parsed.require].flat();
7
- return resolve.flatMap(specifier => {
8
- if (specifier) {
9
- const filePath = path.join(cwd, specifier);
10
- if (filePath.startsWith(cwd)) {
11
- const resolvedFilePath = tryResolve(filePath);
12
- if (resolvedFilePath)
13
- return [resolvedFilePath];
14
- }
15
- return [specifier];
4
+ const tryResolveFilePath = (cwd, specifier, fallback) => {
5
+ if (specifier) {
6
+ const filePath = path.join(cwd, specifier);
7
+ if (filePath.startsWith(cwd)) {
8
+ const resolvedFilePath = tryResolve(filePath);
9
+ if (resolvedFilePath)
10
+ return [resolvedFilePath];
16
11
  }
17
- return [];
18
- });
12
+ return fallback ? [fallback] : [];
13
+ }
14
+ return [];
15
+ };
16
+ export const tryResolveFilePaths = (cwd, specifiers) => specifiers.flatMap(specifier => tryResolveFilePath(cwd, specifier, specifier));
17
+ export const resolve = (binary, args, { cwd }) => {
18
+ const parsed = parseArgs(args, { string: ['r'], alias: { require: ['r', 'loader', 'experimental-loader'] } });
19
+ return [...tryResolveFilePath(cwd, parsed._[0]), ...tryResolveFilePaths(cwd, [parsed.require].flat())];
19
20
  };
@@ -1,4 +1,2 @@
1
- import type { PackageJson } from 'type-fest';
2
- type FindByArgs = (args: string[]) => string[];
3
- export declare const resolve: (binary: string, args: string[], cwd: string, manifest: PackageJson, findByArgs: FindByArgs) => string[];
4
- export {};
1
+ import type { Resolver } from '../types.js';
2
+ export declare const resolve: Resolver;
@@ -1,5 +1,5 @@
1
1
  import parseArgs from 'minimist';
2
- export const resolve = (binary, args, cwd, manifest, findByArgs) => {
2
+ export const resolve = (binary, args, { fromArgs }) => {
3
3
  const parsed = parseArgs(args, { '--': true, stopEarly: true, boolean: ['yes', 'no'], alias: { yes: 'y', no: 'n' } });
4
- return [...(parsed.yes ? [] : findByArgs(parsed._)), ...(parsed['--'] ? findByArgs(parsed['--']) : [])];
4
+ return [...(parsed.yes ? [] : fromArgs(parsed._)), ...(parsed['--'] ? fromArgs(parsed['--']) : [])];
5
5
  };
@@ -1,2 +1,2 @@
1
- import type { PackageJson } from 'type-fest';
2
- export declare const resolve: (binary: string, args: string[], cwd: string, manifest: PackageJson) => string[];
1
+ import type { Resolver } from '../types.js';
2
+ export declare const resolve: Resolver;
@@ -1,6 +1,8 @@
1
1
  import parseArgs from 'minimist';
2
2
  const commands = [
3
3
  'add',
4
+ 'dlx',
5
+ 'run',
4
6
  'i',
5
7
  'install',
6
8
  'up',
@@ -31,15 +33,13 @@ const commands = [
31
33
  't',
32
34
  'tst',
33
35
  ];
34
- export const resolve = (binary, args, cwd, manifest) => {
36
+ export const resolve = (binary, args, { manifest }) => {
35
37
  const scripts = manifest.scripts ? Object.keys(manifest.scripts) : [];
36
38
  const parsed = parseArgs(args, {});
37
39
  const [command, result] = parsed._;
38
40
  if (scripts.includes(command) || commands.includes(command))
39
41
  return [];
40
- if (command === 'run' && scripts.includes(result))
41
- return [];
42
- if (command === 'exec' || command === 'run')
42
+ if (command === 'exec')
43
43
  return [result];
44
44
  return command ? [command] : [];
45
45
  };
@@ -1,2 +1,2 @@
1
- import type { PackageJson } from 'type-fest';
2
- export declare const resolve: (binary: string, args: string[], cwd: string, manifest: PackageJson) => string[];
1
+ import type { Resolver } from '../types.js';
2
+ export declare const resolve: Resolver;
@@ -30,7 +30,7 @@ const commands = [
30
30
  'workspace',
31
31
  'workspaces',
32
32
  ];
33
- export const resolve = (binary, args, cwd, manifest) => {
33
+ export const resolve = (binary, args, { manifest, fromArgs }) => {
34
34
  const scripts = manifest.scripts ? Object.keys(manifest.scripts) : [];
35
35
  const parsed = parseArgs(args, {});
36
36
  const [command, result] = parsed._;
@@ -40,5 +40,7 @@ export const resolve = (binary, args, cwd, manifest) => {
40
40
  return [];
41
41
  if (command === 'run' || command === 'exec')
42
42
  return [result];
43
+ if (command === 'node')
44
+ return fromArgs(parsed._);
43
45
  return command ? [command] : [];
44
46
  };
@@ -0,0 +1,18 @@
1
+ import type { PackageJson } from 'type-fest';
2
+ type Options = {
3
+ cwd?: string;
4
+ manifest?: PackageJson;
5
+ ignore?: string[];
6
+ knownGlobalsOnly?: boolean;
7
+ };
8
+ export type GetBinariesFromScripts = (npmScripts: string | string[], options?: Options) => {
9
+ entryFiles: string[];
10
+ binaries: string[];
11
+ };
12
+ type FromArgs = (args: string[]) => string[];
13
+ export type Resolver = (binary: string, args: string[], options: {
14
+ cwd: string;
15
+ manifest: PackageJson;
16
+ fromArgs: FromArgs;
17
+ }) => string[];
18
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,5 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="nano-memoize" />
3
- export declare const ensurePosixPath: (value: string) => string;
4
3
  export declare const negate: (pattern: string) => string;
5
4
  export declare const hasProductionSuffix: (pattern: string) => boolean;
6
5
  export declare const hasNoProductionSuffix: (pattern: string) => boolean;
package/dist/util/glob.js CHANGED
@@ -5,8 +5,8 @@ import memoize from 'nano-memoize';
5
5
  import { ROOT_WORKSPACE_NAME } from '../constants.js';
6
6
  import { compact } from './array.js';
7
7
  import { debugLogObject } from './debug.js';
8
+ import { relativePosix } from './path.js';
8
9
  import { timerify } from './performance.js';
9
- export const ensurePosixPath = (value) => value.split(path.sep).join(path.posix.sep);
10
10
  const prependDirToPattern = (workingDir, pattern) => {
11
11
  if (pattern.startsWith('!'))
12
12
  return '!' + path.posix.join(workingDir, pattern.slice(1));
@@ -18,9 +18,7 @@ export const hasNoProductionSuffix = (pattern) => !pattern.endsWith('!');
18
18
  const removeProductionSuffix = (pattern) => pattern.replace(/!$/, '');
19
19
  const negatedLast = (pattern) => (pattern.startsWith('!') ? 1 : -1);
20
20
  const glob = async ({ cwd, workingDir = cwd, patterns, ignore = [], gitignore = true }) => {
21
- const cwdPosix = ensurePosixPath(cwd);
22
- const workingDirPosix = ensurePosixPath(workingDir);
23
- const relativePath = path.posix.relative(cwdPosix, workingDirPosix);
21
+ const relativePath = relativePosix(cwd, workingDir);
24
22
  const prepend = (pattern) => prependDirToPattern(relativePath, pattern);
25
23
  const globPatterns = compact([patterns].flat().map(prepend).map(removeProductionSuffix)).sort(negatedLast);
26
24
  const ignorePatterns = compact([
@@ -1,10 +1,10 @@
1
- import { ensurePosixPath } from './glob.js';
1
+ import { toPosixPath } from './path.js';
2
2
  export const getPackageNameFromModuleSpecifier = (moduleSpecifier) => {
3
3
  const parts = moduleSpecifier.split('/').slice(0, 2);
4
4
  return moduleSpecifier.startsWith('@') ? parts.join('/') : parts[0];
5
5
  };
6
6
  export const getPackageName = (value) => {
7
- const match = ensurePosixPath(value).match(/(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/g);
7
+ const match = toPosixPath(value).match(/(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/g);
8
8
  if (match)
9
9
  return match[match.length - 1];
10
10
  if (value.startsWith('@')) {
@@ -1 +1,2 @@
1
- export declare const relative: (to: string) => string;
1
+ export declare const toPosixPath: (value: string) => string;
2
+ export declare const relativePosix: (from: string, to?: string) => string;
package/dist/util/path.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import path from 'node:path';
2
- import { ensurePosixPath } from './glob.js';
3
2
  const cwd = process.cwd();
4
- export const relative = (to) => ensurePosixPath(path.relative(cwd, to));
3
+ export const toPosixPath = (value) => value.split(path.sep).join(path.posix.sep);
4
+ export const relativePosix = (from, to) => toPosixPath(path.relative(to ? from : cwd, to ?? from));
@@ -1,23 +1,23 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  import { PerformanceObserver, PerformanceEntry } from 'node:perf_hooks';
3
- import EasyTable from 'easy-table';
4
3
  import type { TimerifyOptions } from 'node:perf_hooks';
5
4
  type Timerify = <T extends (...params: any[]) => any>(fn: T, options?: TimerifyOptions) => T;
6
5
  export declare const timerify: Timerify;
7
- declare class Performance {
8
- enabled: boolean;
6
+ export declare class Performance {
7
+ isEnabled: boolean;
9
8
  startTime: number;
9
+ endTime: number;
10
10
  entries: PerformanceEntry[];
11
11
  instanceId?: number;
12
12
  observer?: PerformanceObserver;
13
- constructor(enabled: boolean);
14
- start(name: string): void;
15
- end(name: string): void;
16
- getEntriesByName(): Record<string, number[]>;
17
- getTable(): EasyTable;
18
- flush(): Promise<void>;
19
- print(): Promise<void>;
13
+ constructor(isEnabled: boolean);
14
+ private setMark;
15
+ private clearMark;
16
+ private flush;
17
+ private getEntriesByName;
18
+ getTable(): string;
19
+ getTotalTime(): number;
20
+ finalize(): Promise<void>;
20
21
  reset(): void;
21
22
  }
22
- export declare const measure: Performance;
23
23
  export {};
@@ -1,19 +1,18 @@
1
1
  import { performance, PerformanceObserver } from 'node:perf_hooks';
2
2
  import EasyTable from 'easy-table';
3
- import prettyMilliseconds from 'pretty-ms';
4
- import parsedArgs from './cli-arguments.js';
5
3
  import Summary from 'summary';
6
- const { values } = parsedArgs;
7
- const { performance: isEnabled = false } = values;
4
+ import parsedArgs from './cli-arguments.js';
5
+ const { performance: isEnabled = false } = parsedArgs.values;
8
6
  export const timerify = fn => (isEnabled ? performance.timerify(fn) : fn);
9
- class Performance {
10
- enabled;
7
+ export class Performance {
8
+ isEnabled;
11
9
  startTime = 0;
10
+ endTime = 0;
12
11
  entries = [];
13
12
  instanceId;
14
13
  observer;
15
- constructor(enabled) {
16
- if (enabled) {
14
+ constructor(isEnabled) {
15
+ if (isEnabled) {
17
16
  this.startTime = performance.now();
18
17
  this.instanceId = Math.floor(performance.now() * 100);
19
18
  this.observer = new PerformanceObserver(items => {
@@ -21,25 +20,26 @@ class Performance {
21
20
  this.entries.push(entry);
22
21
  });
23
22
  });
24
- this.observer.observe({ entryTypes: ['measure', 'function'] });
23
+ this.observer.observe({ entryTypes: ['function'] });
25
24
  }
26
- this.enabled = enabled;
25
+ this.isEnabled = isEnabled;
27
26
  }
28
- start(name) {
29
- if (!this.enabled)
30
- return;
27
+ setMark(name) {
31
28
  const id = `${this.instanceId}:${name}`;
32
29
  performance.mark(`${id}:start`);
33
30
  }
34
- end(name) {
35
- if (!this.enabled)
36
- return;
31
+ clearMark(name) {
37
32
  const id = `${this.instanceId}:${name}`;
38
33
  performance.mark(`${id}:end`);
39
34
  performance.measure(id, `${id}:start`, `${id}:end`);
40
35
  performance.clearMarks(`${id}:start`);
41
36
  performance.clearMarks(`${id}:end`);
42
37
  }
38
+ async flush() {
39
+ this.setMark('_flush');
40
+ await new Promise(resolve => setTimeout(resolve, 1));
41
+ this.clearMark('_flush');
42
+ }
43
43
  getEntriesByName() {
44
44
  return this.entries.reduce((entries, entry) => {
45
45
  const name = entry.name.replace(`${this.instanceId}:`, '');
@@ -62,23 +62,19 @@ class Performance {
62
62
  table.newRow();
63
63
  });
64
64
  table.sort(['sum|des']);
65
- return table;
65
+ return table.toString().trim();
66
66
  }
67
- async flush() {
68
- this.start('_flush');
69
- await new Promise(resolve => setTimeout(resolve, 1));
70
- this.end('_flush');
67
+ getTotalTime() {
68
+ return this.endTime - this.startTime;
71
69
  }
72
- async print() {
73
- if (!this.enabled)
70
+ async finalize() {
71
+ if (!this.isEnabled)
74
72
  return;
73
+ this.endTime = performance.now();
75
74
  await this.flush();
76
- console.log('\n' + this.getTable().toString().trim());
77
- console.log('\nTotal running time:', prettyMilliseconds(performance.now() - this.startTime));
78
75
  }
79
76
  reset() {
80
77
  this.entries = [];
81
78
  this.observer?.disconnect();
82
79
  }
83
80
  }
84
- export const measure = new Performance(isEnabled);
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "1.12.0";
1
+ export declare const version = "1.12.2";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.12.0';
1
+ export const version = '1.12.2';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "1.12.0",
3
+ "version": "1.12.2",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://github.com/webpro/knip",
6
6
  "repository": "github:webpro/knip",