knip 5.77.4 → 5.78.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.
@@ -1,8 +1,16 @@
1
1
  import picomatch from 'picomatch';
2
+ import { partition } from './util/array.js';
2
3
  import { initCounters, initIssues } from './util/issue-initializers.js';
3
- import { timerify } from './util/Performance.js';
4
4
  import { join, relative } from './util/path.js';
5
- const isMatch = timerify(picomatch.isMatch, 'isMatch');
5
+ const createMatcher = (patterns) => {
6
+ const [negated, positive] = partition(patterns, p => p[0] === '!');
7
+ if (positive.length === 0) {
8
+ if (negated.length === 0)
9
+ return () => false;
10
+ return picomatch(negated, { dot: true });
11
+ }
12
+ return picomatch(positive, { dot: true, ignore: negated.map(p => p.slice(1)) });
13
+ };
6
14
  export class IssueCollector {
7
15
  cwd;
8
16
  rules;
@@ -27,14 +35,12 @@ export class IssueCollector {
27
35
  addIgnorePatterns(patterns) {
28
36
  for (const pattern of patterns)
29
37
  this.ignorePatterns.add(pattern);
30
- const p = [...this.ignorePatterns];
31
- this.isMatch = (filePath) => isMatch(filePath, p, { dot: true });
38
+ this.isMatch = createMatcher(this.ignorePatterns);
32
39
  }
33
40
  addIgnoreFilesPatterns(patterns) {
34
41
  for (const pattern of patterns)
35
42
  this.ignoreFilesPatterns.add(pattern);
36
- const p = [...this.ignoreFilesPatterns];
37
- this.isFileMatch = (filePath) => isMatch(filePath, p, { dot: true });
43
+ this.isFileMatch = createMatcher(this.ignoreFilesPatterns);
38
44
  }
39
45
  setIgnoreIssues(ignoreIssues) {
40
46
  if (!ignoreIssues)
@@ -49,7 +55,7 @@ export class IssueCollector {
49
55
  }
50
56
  }
51
57
  for (const [issueType, patterns] of issueTypePatterns) {
52
- this.issueMatchers.set(issueType, (filePath) => isMatch(filePath, patterns, { dot: true }));
58
+ this.issueMatchers.set(issueType, picomatch(patterns, { dot: true }));
53
59
  }
54
60
  }
55
61
  shouldIgnoreIssue(filePath, issueType) {
@@ -1,11 +1,3 @@
1
1
  import type { Issues } from './types/issues.js';
2
2
  import type { MainOptions } from './util/create-options.js';
3
- export declare class IssueFixer {
4
- options: MainOptions;
5
- constructor(options: MainOptions);
6
- fixIssues(issues: Issues): Promise<Set<string>>;
7
- private removeUnusedFiles;
8
- private removeUnusedExports;
9
- private removeUnusedDependencies;
10
- private removeUnusedCatalogEntries;
11
- }
3
+ export declare const fix: (issues: Issues, options: MainOptions) => Promise<void>;
@@ -1,9 +1,24 @@
1
1
  import { readFile, rm, writeFile } from 'node:fs/promises';
2
+ import { formatly } from 'formatly';
2
3
  import { DEFAULT_CATALOG } from './util/catalog.js';
4
+ import { debugLogArray, debugLogObject } from './util/debug.js';
3
5
  import { load, save } from './util/package-json.js';
4
6
  import { extname, join } from './util/path.js';
5
7
  import { removeExport } from './util/remove-export.js';
6
- export class IssueFixer {
8
+ export const fix = async (issues, options) => {
9
+ const fixer = new IssueFixer(options);
10
+ const touchedFiles = await fixer.fixIssues(issues);
11
+ if (options.isFormat) {
12
+ const report = await formatly(Array.from(touchedFiles));
13
+ if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
14
+ debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
15
+ }
16
+ else {
17
+ debugLogObject('*', 'Formatting files failed', report);
18
+ }
19
+ }
20
+ };
21
+ class IssueFixer {
7
22
  options;
8
23
  constructor(options) {
9
24
  this.options = options;
@@ -53,6 +53,7 @@ export declare class WorkspaceWorker {
53
53
  getEntryFilePatterns(): string[];
54
54
  getProjectFilePatterns(projectFilePatterns: string[]): string[];
55
55
  getPluginProjectFilePatterns(patterns?: string[]): string[];
56
+ private getPluginConfig;
56
57
  getPluginConfigPatterns(): string[];
57
58
  getPluginEntryFilePatterns(patterns: string[]): string[];
58
59
  getProductionEntryFilePatterns(negatedTestFilePatterns: string[]): string[];
@@ -103,13 +103,15 @@ export class WorkspaceWorker {
103
103
  }
104
104
  return [patterns, this.negatedWorkspacePatterns].flat();
105
105
  }
106
+ getPluginConfig(plugin) {
107
+ return typeof plugin.config === 'function' ? plugin.config({ cwd: this.dir }) : plugin.config;
108
+ }
106
109
  getPluginConfigPatterns() {
107
110
  const patterns = [];
108
111
  for (const [pluginName, plugin] of PluginEntries) {
109
112
  const pluginConfig = this.getConfigForPlugin(pluginName);
110
113
  if (this.enabledPluginsMap[pluginName] && pluginConfig) {
111
- const { config } = pluginConfig;
112
- patterns.push(...(config ?? plugin.config ?? []));
114
+ patterns.push(...(pluginConfig.config ?? this.getPluginConfig(plugin) ?? []));
113
115
  }
114
116
  }
115
117
  return patterns;
@@ -149,7 +151,7 @@ export class WorkspaceWorker {
149
151
  getConfigurationFilePatterns(pluginName) {
150
152
  const plugin = Plugins[pluginName];
151
153
  const pluginConfig = this.getConfigForPlugin(pluginName);
152
- return pluginConfig.config ?? plugin.config ?? [];
154
+ return pluginConfig.config ?? this.getPluginConfig(plugin) ?? [];
153
155
  }
154
156
  async runPlugins() {
155
157
  const wsName = this.name;
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
- import { main } from './index.js';
1
+ import { fix } from './IssueFixer.js';
2
+ import { run } from './run.js';
2
3
  import parseArgs, { helpText } from './util/cli-arguments.js';
3
4
  import { createOptions } from './util/create-options.js';
4
5
  import { getKnownErrors, hasErrorCause, isConfigurationError, isKnownError } from './util/errors.js';
@@ -19,7 +20,7 @@ catch (error) {
19
20
  }
20
21
  throw error;
21
22
  }
22
- const run = async () => {
23
+ const main = async () => {
23
24
  try {
24
25
  if (args.help) {
25
26
  console.log(helpText);
@@ -30,7 +31,8 @@ const run = async () => {
30
31
  process.exit(0);
31
32
  }
32
33
  const options = await createOptions({ args });
33
- const { issues, counters, tagHints, configurationHints, includedWorkspaceDirs, enabledPlugins } = await main(options);
34
+ const { results } = await run(options);
35
+ const { issues, counters, tagHints, configurationHints, includedWorkspaceDirs, enabledPlugins } = results;
34
36
  if (options.isWatch || options.isTrace)
35
37
  return;
36
38
  const initialData = {
@@ -52,6 +54,8 @@ const run = async () => {
52
54
  preprocessorOptions: args['preprocessor-options'] ?? '',
53
55
  };
54
56
  const finalData = await runPreprocessors(args.preprocessor ?? [], initialData);
57
+ if (options.isFix)
58
+ await fix(finalData.issues, options);
55
59
  await runReporters(args.reporter ?? ['symbols'], finalData);
56
60
  const totalErrorCount = Object.keys(finalData.report)
57
61
  .filter(reportGroup => finalData.report[reportGroup] && options.rules[reportGroup] === 'error')
@@ -94,4 +98,4 @@ const run = async () => {
94
98
  }
95
99
  process.exit(0);
96
100
  };
97
- await run();
101
+ await main();
@@ -1,6 +1,6 @@
1
1
  import type { HasDependency } from './types.js';
2
2
  declare const _default: {
3
3
  condition: (hasDependency: HasDependency) => boolean;
4
- compiler: (text: string) => string;
4
+ compiler: (text: string, path: string) => string;
5
5
  };
6
6
  export default _default;
@@ -1,8 +1,13 @@
1
- import { fencedCodeBlockMatcher, importMatcher } from './compilers.js';
1
+ import { frontmatterMatcher, scriptBodies } from './compilers.js';
2
2
  const condition = (hasDependency) => hasDependency('astro');
3
- const taggedTemplateMatcher = /\w+(?:\.\w+)*`[\s\S]*?`/g;
4
- const compiler = (text) => {
5
- const cleanedText = text.replace(fencedCodeBlockMatcher, '').replace(taggedTemplateMatcher, '""');
6
- return [...cleanedText.matchAll(importMatcher)].join('\n');
3
+ const compiler = (text, path) => {
4
+ const scripts = [];
5
+ const frontmatter = text.match(frontmatterMatcher);
6
+ if (frontmatter?.[1])
7
+ scripts.push(frontmatter[1]);
8
+ const scriptContent = scriptBodies(text, path);
9
+ if (scriptContent)
10
+ scripts.push(scriptContent);
11
+ return scripts.join('\n');
7
12
  };
8
13
  export default { condition, compiler };
@@ -3,4 +3,5 @@ export declare const fencedCodeBlockMatcher: RegExp;
3
3
  export declare const importMatcher: RegExp;
4
4
  export declare const importsWithinScripts: SyncCompilerFn;
5
5
  export declare const scriptBodies: SyncCompilerFn;
6
+ export declare const frontmatterMatcher: RegExp;
6
7
  export declare const importsWithinFrontmatter: (text: string, keys?: string[]) => string;
@@ -21,9 +21,9 @@ export const scriptBodies = (text) => {
21
21
  }
22
22
  return scripts.join(';\n');
23
23
  };
24
- const frontmatterMatcher = /---[\s\S]*?---/;
24
+ export const frontmatterMatcher = /^---\r?\n([\s\S]*?)\r?\n---/;
25
25
  export const importsWithinFrontmatter = (text, keys = []) => {
26
- const frontmatter = text.match(frontmatterMatcher)?.[0];
26
+ const frontmatter = text.match(frontmatterMatcher)?.[1];
27
27
  if (!frontmatter)
28
28
  return '';
29
29
  const imports = keys.flatMap(key => {
@@ -3,7 +3,6 @@ import type { ConfigurationChief } from '../ConfigurationChief.js';
3
3
  import type { ConsoleStreamer } from '../ConsoleStreamer.js';
4
4
  import type { DependencyDeputy } from '../DependencyDeputy.js';
5
5
  import type { IssueCollector } from '../IssueCollector.js';
6
- import type { IssueFixer } from '../IssueFixer.js';
7
6
  import type { PrincipalFactory } from '../PrincipalFactory.js';
8
7
  import type { ModuleGraph } from '../types/module-graph.js';
9
8
  import type { MainOptions } from '../util/create-options.js';
@@ -15,7 +14,6 @@ interface AnalyzeOptions {
15
14
  deputy: DependencyDeputy;
16
15
  entryPaths: Set<string>;
17
16
  factory: PrincipalFactory;
18
- fixer: IssueFixer;
19
17
  graph: ModuleGraph;
20
18
  streamer: ConsoleStreamer;
21
19
  unreferencedFiles: Set<string>;
@@ -39,8 +39,8 @@ export async function build({ chief, collector, counselor, deputy, factory, isGi
39
39
  });
40
40
  counselor.addWorkspace(manifest);
41
41
  }
42
- collector.addIgnorePatterns(chief.config.ignore.map(p => join(options.cwd, p)));
43
- collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(p => join(options.cwd, p)));
42
+ collector.addIgnorePatterns(chief.config.ignore.map(p => prependDirToPattern(options.cwd, p)));
43
+ collector.addIgnoreFilesPatterns(chief.config.ignoreFiles.map(p => prependDirToPattern(options.cwd, p)));
44
44
  for (const workspace of workspaces) {
45
45
  const { name, dir, ancestors, pkgName, manifestPath: filePath } = workspace;
46
46
  streamer.cast('Analyzing workspace', name);
@@ -81,8 +81,8 @@ export async function build({ chief, collector, counselor, deputy, factory, isGi
81
81
  inputs.add(toProductionEntry(id, { containingFilePath: tsConfigFilePath }));
82
82
  }
83
83
  const sharedGlobOptions = { cwd: options.cwd, dir, gitignore: options.gitignore };
84
- collector.addIgnorePatterns(config.ignore.map(p => join(options.cwd, prependDirToPattern(name, p))));
85
- collector.addIgnoreFilesPatterns(config.ignoreFiles.map(p => join(options.cwd, prependDirToPattern(name, p))));
84
+ collector.addIgnorePatterns(config.ignore.map(p => prependDirToPattern(options.cwd, prependDirToPattern(name, p))));
85
+ collector.addIgnoreFilesPatterns(config.ignoreFiles.map(p => prependDirToPattern(options.cwd, prependDirToPattern(name, p))));
86
86
  const entrySpecifiersFromManifest = getEntrySpecifiersFromManifest(manifest);
87
87
  const label = 'entry paths from package.json';
88
88
  for (const filePath of await toSourceFilePaths(entrySpecifiersFromManifest, dir, extensionGlobStr, label)) {
package/dist/index.js CHANGED
@@ -1,2 +1,8 @@
1
+ import { fix } from './IssueFixer.js';
1
2
  import { run } from './run.js';
2
- export const main = async (options) => (await run(options)).results;
3
+ export const main = async (options) => {
4
+ const { results } = await run(options);
5
+ if (options.isFix)
6
+ await fix(results.issues, options);
7
+ return results;
8
+ };
@@ -16,6 +16,11 @@ const config = [
16
16
  '.graphqlrc.{json,yml,yaml,toml,js,ts}',
17
17
  'graphql.config.{json,yml,yaml,toml,js,cjs,ts}',
18
18
  ];
19
+ const getPluginPackageName = (name) => {
20
+ if (name.startsWith('@') || name.includes('codegen-'))
21
+ return name;
22
+ return `@graphql-codegen/${name}`;
23
+ };
19
24
  const resolveConfig = config => {
20
25
  const codegenConfigs = isGraphqlProjectsConfigTypes(config)
21
26
  ? Object.values(config.projects).flatMap(project => project.extensions?.codegen ?? [])
@@ -35,7 +40,7 @@ const resolveConfig = config => {
35
40
  const flatPlugins = generateSet
36
41
  .filter((config) => !isConfigurationOutput(config))
37
42
  .flatMap(item => Object.keys(item))
38
- .map(plugin => plugin.includes('codegen-') ? plugin : `@graphql-codegen/${plugin}`);
43
+ .map(plugin => getPluginPackageName(plugin));
39
44
  const nestedPlugins = configurationOutput
40
45
  .flatMap(configOutput => (configOutput.plugins ? configOutput.plugins : []))
41
46
  .flatMap(plugin => {
@@ -48,7 +53,7 @@ const resolveConfig = config => {
48
53
  return [];
49
54
  if (isInternal(plugin))
50
55
  return [toEntry(plugin)];
51
- return [plugin.includes('codegen-') ? plugin : `@graphql-codegen/${plugin}`].map(id => toDependency(id));
56
+ return [toDependency(getPluginPackageName(plugin))];
52
57
  });
53
58
  return [...presets, ...flatPlugins, ...nestedPlugins].map(id => (typeof id === 'string' ? toDependency(id) : id));
54
59
  };
@@ -6,8 +6,6 @@ import { hasDependency } from '../../util/plugin.js';
6
6
  const title = 'Lefthook';
7
7
  const enablers = ['lefthook', '@arkweid/lefthook', '@evilmartians/lefthook'];
8
8
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
9
- const gitHookPaths = getGitHookPaths();
10
- const config = ['lefthook.yml', ...gitHookPaths];
11
9
  const resolveConfig = async (localConfig, options) => {
12
10
  if (options.isProduction)
13
11
  return [];
@@ -35,7 +33,7 @@ const plugin = {
35
33
  title,
36
34
  enablers,
37
35
  isEnabled,
38
- config,
36
+ config: options => ['lefthook.yml', ...getGitHookPaths('.git/hooks', true, options.cwd)],
39
37
  resolveConfig,
40
38
  };
41
39
  export default plugin;
@@ -9,6 +9,7 @@ const resolveConfig = async (config, options) => {
9
9
  const inputs = tasks
10
10
  .map(task => task.command)
11
11
  .filter(command => command)
12
+ .map(command => (Array.isArray(command) ? command.join(' ') : command))
12
13
  .map(command => command.replace('$workspaceRoot', options.rootCwd))
13
14
  .map(command => command.replace('$projectRoot', options.cwd))
14
15
  .flatMap(command => options.getInputsFromScripts(command));
@@ -1,7 +1,7 @@
1
1
  export interface MoonConfiguration {
2
2
  tasks?: {
3
3
  [taskName: string]: {
4
- command: string;
4
+ command: string | string[];
5
5
  };
6
6
  };
7
7
  }
@@ -1,9 +1,17 @@
1
+ import { toEntry } from '../../util/input.js';
1
2
  import { hasDependency } from '../../util/plugin.js';
2
- import { entry, resolveConfig } from '../playwright/index.js';
3
+ import { entry as playwrightEntry, resolveConfig as playwrightResolveConfig } from '../playwright/index.js';
3
4
  const title = 'Playwright for components';
4
5
  const enablers = [/^@playwright\/experimental-ct-/];
5
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
- const config = ['playwright-ct.config.{js,ts}', 'playwright/index.{js,ts,jsx,tsx}'];
7
+ const config = ['playwright-ct.config.{js,ts}'];
8
+ const ctEntry = 'playwright/index.{js,ts,jsx,tsx}';
9
+ const entry = [...playwrightEntry, ctEntry];
10
+ const resolveConfig = async (localConfig, options) => {
11
+ const inputs = await playwrightResolveConfig(localConfig, options);
12
+ inputs.push(toEntry(ctEntry));
13
+ return inputs;
14
+ };
7
15
  const plugin = {
8
16
  title,
9
17
  enablers,
@@ -9,7 +9,8 @@ const isWindows = os.platform() === 'win32';
9
9
  const title = 'React Router';
10
10
  const enablers = ['@react-router/dev'];
11
11
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
12
- const config = ['react-router.config.{js,ts}', ...(vite.config ?? [])];
12
+ const viteConfig = typeof vite.config === 'function' ? [] : (vite.config ?? []);
13
+ const config = ['react-router.config.{js,ts}', ...viteConfig];
13
14
  const resolveConfig = async (localConfig, options) => {
14
15
  const { configFileDir } = options;
15
16
  const appDirectory = localConfig.appDirectory ?? 'app';
@@ -100,7 +100,7 @@ export const findWebpackDependenciesFromConfig = async (config, options) => {
100
100
  if (entries.length === 0 && opts.context)
101
101
  entries.push('./src/index');
102
102
  for (const entry of entries) {
103
- if (isInternal(entry)) {
103
+ if (isInternal(entry) || entry.startsWith('#')) {
104
104
  const dir = opts.context ? opts.context : cwd;
105
105
  const input = isProduction
106
106
  ? toDeferResolveProductionEntry(entry, { dir })
package/dist/run.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { watch } from 'node:fs';
2
- import { formatly } from 'formatly';
3
2
  import { CatalogCounselor } from './CatalogCounselor.js';
4
3
  import { ConfigurationChief } from './ConfigurationChief.js';
5
4
  import { ConsoleStreamer } from './ConsoleStreamer.js';
@@ -7,10 +6,9 @@ import { DependencyDeputy } from './DependencyDeputy.js';
7
6
  import { analyze } from './graph/analyze.js';
8
7
  import { build } from './graph/build.js';
9
8
  import { IssueCollector } from './IssueCollector.js';
10
- import { IssueFixer } from './IssueFixer.js';
11
9
  import { PrincipalFactory } from './PrincipalFactory.js';
12
10
  import watchReporter from './reporters/watch.js';
13
- import { debugLogArray, debugLogObject } from './util/debug.js';
11
+ import { debugLogObject } from './util/debug.js';
14
12
  import { getGitIgnoredHandler } from './util/glob-core.js';
15
13
  import { getSessionHandler } from './util/watch.js';
16
14
  export const run = async (options) => {
@@ -20,7 +18,6 @@ export const run = async (options) => {
20
18
  const deputy = new DependencyDeputy(options);
21
19
  const factory = new PrincipalFactory();
22
20
  const streamer = new ConsoleStreamer(options);
23
- const fixer = new IssueFixer(options);
24
21
  const collector = new IssueCollector(options);
25
22
  const counselor = new CatalogCounselor(options);
26
23
  streamer.cast('Reading workspace configuration');
@@ -48,7 +45,6 @@ export const run = async (options) => {
48
45
  deputy,
49
46
  entryPaths,
50
47
  factory,
51
- fixer,
52
48
  graph,
53
49
  streamer,
54
50
  unreferencedFiles,
@@ -79,18 +75,6 @@ export const run = async (options) => {
79
75
  watch('.', { recursive: true }, session.listener);
80
76
  }
81
77
  const { issues, counters, tagHints, configurationHints } = collector.getIssues();
82
- if (options.isFix && !options.isSession) {
83
- const touchedFiles = await fixer.fixIssues(issues);
84
- if (options.isFormat) {
85
- const report = await formatly(Array.from(touchedFiles));
86
- if (report.ran && report.result && (report.result.runner === 'virtual' || report.result.code === 0)) {
87
- debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
88
- }
89
- else {
90
- debugLogObject('*', 'Formatting files failed', report);
91
- }
92
- }
93
- }
94
78
  if (!options.isWatch)
95
79
  streamer.clear();
96
80
  return {
@@ -110,7 +110,9 @@ export interface Plugin {
110
110
  enablers?: IgnorePatterns | string;
111
111
  isEnabled?: IsPluginEnabled;
112
112
  isRootOnly?: boolean;
113
- config?: string[];
113
+ config?: string[] | ((options: {
114
+ cwd: string;
115
+ }) => string[]);
114
116
  entry?: string[];
115
117
  production?: string[];
116
118
  project?: string[];
package/dist/types.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export type { RawConfigurationOrFn as KnipConfig } from './types/config.js';
1
+ export type { RawConfigurationOrFn as KnipConfig, WorkspaceProjectConfig } from './types/config.js';
2
2
  export type { Preprocessor, Reporter, ReporterOptions } from './types/issues.js';
3
- export type { WorkspaceProjectConfig } from './types/config.js';
@@ -1,4 +1,3 @@
1
1
  import ts from 'typescript';
2
2
  import type { Export, ExportMember } from '../types/module-graph.js';
3
- export declare const isType: (item: Export | ExportMember) => boolean;
4
3
  export declare const findInternalReferences: (item: Export | ExportMember, sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker, referencedSymbolsInExport: Set<ts.Symbol>, isBindingElement?: boolean) => [number, boolean];
@@ -1,6 +1,5 @@
1
1
  import ts from 'typescript';
2
2
  import { isIdChar } from '../util/regex.js';
3
- export const isType = (item) => item.type === 'type' || item.type === 'interface' || item.type === 'enum';
4
3
  const findInFlow = (flowNode, targetSymbol) => {
5
4
  if (!flowNode?.node)
6
5
  return false;
@@ -7,7 +7,7 @@ import { timerify } from '../util/Performance.js';
7
7
  import { dirname, isInNodeModules, resolve } from '../util/path.js';
8
8
  import { shouldIgnore } from '../util/tag.js';
9
9
  import { getAccessMembers, getDestructuredNames, getJSDocTags, getLineAndCharacterOfPosition, getTypeRef, isAccessExpression, isConsiderReferencedNS, isDestructuring, isImportSpecifier, isInForIteration, isObjectEnumerationCallExpressionArgument, isReferencedInExport, } from './ast-helpers.js';
10
- import { findInternalReferences, isType } from './find-internal-references.js';
10
+ import { findInternalReferences } from './find-internal-references.js';
11
11
  import { getImportsFromPragmas } from './pragmas/index.js';
12
12
  import getDynamicImportVisitors from './visitors/dynamic-imports/index.js';
13
13
  import getExportVisitors from './visitors/exports/index.js';
@@ -426,7 +426,7 @@ const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options, i
426
426
  for (const node of pragmaImports)
427
427
  addImport(node, sourceFile);
428
428
  for (const item of exports.values()) {
429
- if (!isType(item) && item.symbol && referencedSymbolsInExport.has(item.symbol)) {
429
+ if (item.symbol && referencedSymbolsInExport.has(item.symbol)) {
430
430
  item.self = [1, true];
431
431
  }
432
432
  else {
@@ -1,5 +1,5 @@
1
1
  type Collection<T> = Array<T> | Set<T>;
2
2
  export declare const compact: <T>(collection: Collection<T | undefined>) => T[];
3
3
  export declare const arrayify: (value?: string[] | string) => string[];
4
- export declare const partition: <T>(collection: T[], predicate: (item: T) => unknown) => [T[], T[]];
4
+ export declare const partition: <T>(collection: Collection<T>, predicate: (item: T) => unknown) => [T[], T[]];
5
5
  export {};
@@ -2,7 +2,7 @@ import { IGNORED_RUNTIME_DEPENDENCIES } from '../constants.js';
2
2
  import { debugLog } from './debug.js';
3
3
  import { fromBinary, isBinary, isConfig, isDeferResolve, isDeferResolveEntry, isDependency, toDebugString, } from './input.js';
4
4
  import { getPackageNameFromSpecifier } from './modules.js';
5
- import { dirname, isAbsolute, isInternal, join } from './path.js';
5
+ import { dirname, isAbsolute, isInNodeModules, isInternal, join } from './path.js';
6
6
  import { _resolveSync } from './resolve.js';
7
7
  const getWorkspaceFor = (input, chief, workspace) => (input.dir && chief.findWorkspaceByFilePath(`${input.dir}/`)) ||
8
8
  (input.containingFilePath && chief.findWorkspaceByFilePath(input.containingFilePath)) ||
@@ -41,7 +41,11 @@ export const createInputHandler = (deputy, chief, isGitIgnored, addIssue, extern
41
41
  return;
42
42
  }
43
43
  const packageName = getPackageNameFromSpecifier(specifier);
44
- if (packageName && (isDependency(input) || isDeferResolve(input) || isConfig(input))) {
44
+ if (packageName &&
45
+ (isDependency(input) ||
46
+ isDeferResolve(input) ||
47
+ (isDeferResolveEntry(input) && isInNodeModules(specifier)) ||
48
+ isConfig(input))) {
45
49
  const isWorkspace = chief.workspacesByPkgName.has(packageName);
46
50
  const inputWorkspace = getWorkspaceFor(input, chief, workspace);
47
51
  if (inputWorkspace) {
@@ -75,7 +79,7 @@ export const createInputHandler = (deputy, chief, isGitIgnored, addIssue, extern
75
79
  return;
76
80
  }
77
81
  const baseDir = input.dir ?? dirname(containingFilePath);
78
- const filePath = isAbsolute(specifier) ? specifier : join(baseDir, specifier);
82
+ const filePath = isAbsolute(specifier) || specifier.startsWith('#') ? specifier : join(baseDir, specifier);
79
83
  const resolvedFilePath = _resolveSync(filePath, baseDir);
80
84
  if (resolvedFilePath && isInternal(resolvedFilePath)) {
81
85
  return isGitIgnored(resolvedFilePath) ? undefined : resolvedFilePath;
@@ -1 +1 @@
1
- export declare const getGitHookPaths: (defaultPath?: string, followGitConfig?: boolean) => string[];
1
+ export declare const getGitHookPaths: (defaultPath?: string, followGitConfig?: boolean, cwd?: string) => string[];
package/dist/util/git.js CHANGED
@@ -6,15 +6,19 @@ const hookFileNames = [
6
6
  'pre-{applypatch,commit,merge-commit,push,rebase,receive}',
7
7
  'post-{checkout,commit,merge,rewrite}',
8
8
  ];
9
- const getGitHooksPath = (defaultPath = '.git/hooks') => {
9
+ const getGitHooksPath = (defaultPath = '.git/hooks', cwd) => {
10
10
  try {
11
- return execSync('git config --get core.hooksPath', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim();
11
+ return execSync('git rev-parse --git-path hooks', {
12
+ encoding: 'utf8',
13
+ stdio: ['pipe', 'pipe', 'ignore'],
14
+ cwd,
15
+ }).trim();
12
16
  }
13
17
  catch (_error) {
14
18
  return defaultPath;
15
19
  }
16
20
  };
17
- export const getGitHookPaths = (defaultPath = '.git/hooks', followGitConfig = true) => {
18
- const gitHooksPath = followGitConfig ? getGitHooksPath(defaultPath) : defaultPath;
21
+ export const getGitHookPaths = (defaultPath = '.git/hooks', followGitConfig = true, cwd) => {
22
+ const gitHooksPath = followGitConfig ? getGitHooksPath(defaultPath, cwd) : defaultPath;
19
23
  return hookFileNames.map(fileName => join(gitHooksPath, fileName));
20
24
  };
package/dist/util/glob.js CHANGED
@@ -34,7 +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
+ const syncGlob = ({ cwd, patterns }) => fg.sync(patterns, { cwd, followSymbolicLinks: false });
38
38
  const firstGlob = async ({ cwd, patterns }) => {
39
39
  const stream = fg.globStream(patterns.map(removeProductionSuffix), { cwd, ignore: GLOBAL_IGNORE_PATTERNS });
40
40
  for await (const entry of stream) {
@@ -5,11 +5,11 @@ import { _glob, _syncGlob, prependDirToPattern } from './glob.js';
5
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
- const hasDTSExt = /.d\.(m|c)?ts$/;
9
8
  const matchExt = /(\.d)?\.(m|c)?(j|t)s$/;
10
9
  export const augmentWorkspace = (workspace, dir, compilerOptions) => {
11
10
  const srcDir = join(dir, 'src');
12
- workspace.srcDir = compilerOptions.rootDir ?? (isDirectory(srcDir) ? srcDir : dir);
11
+ const outDirHasSrc = compilerOptions.outDir && isDirectory(join(compilerOptions.outDir, 'src'));
12
+ workspace.srcDir = compilerOptions.rootDir ?? (outDirHasSrc ? dir : isDirectory(srcDir) ? srcDir : dir);
13
13
  workspace.outDir = compilerOptions.outDir || workspace.srcDir;
14
14
  };
15
15
  export const getModuleSourcePathHandler = (chief) => {
@@ -21,8 +21,7 @@ export const getModuleSourcePathHandler = (chief) => {
21
21
  return toSourceMapCache.get(filePath);
22
22
  const workspace = chief.findWorkspaceByFilePath(filePath);
23
23
  if (workspace?.srcDir && workspace.outDir) {
24
- if ((!filePath.startsWith(workspace.srcDir) && filePath.startsWith(workspace.outDir)) ||
25
- (workspace.srcDir === workspace.outDir && hasDTSExt.test(filePath))) {
24
+ if (filePath.startsWith(workspace.outDir) || workspace.srcDir === workspace.outDir) {
26
25
  const pattern = filePath.replace(workspace.outDir, workspace.srcDir).replace(matchExt, defaultExtensions);
27
26
  const srcFilePath = _syncGlob({ patterns: pattern })[0];
28
27
  toSourceMapCache.set(filePath, srcFilePath);
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.77.4";
1
+ export declare const version = "5.78.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.77.4';
1
+ export const version = '5.78.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "5.77.4",
3
+ "version": "5.78.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": {