knip 5.29.1 → 5.30.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.
@@ -43,7 +43,8 @@ export declare class WorkspaceWorker {
43
43
  private determineEnabledPlugins;
44
44
  private getConfigForPlugin;
45
45
  getEntryFilePatterns(): string[];
46
- getProjectFilePatterns(testFilePatterns: string[]): string[];
46
+ getProjectFilePatterns(projectFilePatterns: string[]): string[];
47
+ getPluginEntryFilePatterns(patterns: string[]): string[];
47
48
  getPluginProjectFilePatterns(): string[];
48
49
  getPluginConfigPatterns(): string[];
49
50
  getProductionEntryFilePatterns(negatedTestFilePatterns: string[]): string[];
@@ -1,7 +1,7 @@
1
1
  import { CacheConsultant } from './CacheConsultant.js';
2
2
  import { plugins } from './plugins.js';
3
3
  import { debugLogArray, debugLogObject } from './util/debug.js';
4
- import { _pureGlob, hasNoProductionSuffix, hasProductionSuffix, negate, prependDirToPattern } from './util/glob.js';
4
+ import { _glob, hasNoProductionSuffix, hasProductionSuffix, negate, prependDirToPattern } from './util/glob.js';
5
5
  import { get, getKeysByValue } from './util/object.js';
6
6
  import { basename, dirname, join, toPosix } from './util/path.js';
7
7
  import { getFinalEntryPaths, loadConfigForPlugin } from './util/plugin.js';
@@ -74,7 +74,7 @@ export class WorkspaceWorker {
74
74
  const excludeProductionNegations = entry.filter(pattern => !(pattern.startsWith('!') && pattern.endsWith('!')));
75
75
  return [excludeProductionNegations, this.negatedWorkspacePatterns].flat();
76
76
  }
77
- getProjectFilePatterns(testFilePatterns) {
77
+ getProjectFilePatterns(projectFilePatterns) {
78
78
  const { project } = this.config;
79
79
  if (project.length === 0)
80
80
  return [];
@@ -85,10 +85,13 @@ export class WorkspaceWorker {
85
85
  excludeProductionNegations,
86
86
  negatedPluginConfigPatterns,
87
87
  negatedPluginProjectFilePatterns,
88
- testFilePatterns,
88
+ projectFilePatterns,
89
89
  this.negatedWorkspacePatterns,
90
90
  ].flat();
91
91
  }
92
+ getPluginEntryFilePatterns(patterns) {
93
+ return [patterns, this.negatedWorkspacePatterns].flat();
94
+ }
92
95
  getPluginProjectFilePatterns() {
93
96
  const patterns = [];
94
97
  for (const [pluginName, plugin] of Object.entries(plugins)) {
@@ -175,7 +178,7 @@ export class WorkspaceWorker {
175
178
  if (!pluginConfig)
176
179
  continue;
177
180
  const patterns = this.getConfigurationFilePatterns(pluginName);
178
- const allConfigFilePaths = await _pureGlob({ patterns, cwd, gitignore: false });
181
+ const allConfigFilePaths = await _glob({ patterns, cwd: baseOptions.rootCwd, dir: cwd, gitignore: false });
179
182
  const { packageJsonPath } = plugin;
180
183
  const configFilePaths = allConfigFilePaths.filter(filePath => basename(filePath) !== 'package.json' ||
181
184
  (typeof packageJsonPath === 'function'
package/dist/index.js CHANGED
@@ -11,8 +11,8 @@ import { getCompilerExtensions, getIncludedCompilers } from './compilers/index.j
11
11
  import { getFilteredScripts } from './manifest/helpers.js';
12
12
  import { debugLog, debugLogArray, debugLogObject } from './util/debug.js';
13
13
  import { getOrCreateFileNode, updateImportMap } from './util/dependency-graph.js';
14
+ import { getGitIgnoredHandler } from './util/glob-core.js';
14
15
  import { _glob, negate } from './util/glob.js';
15
- import { getGitIgnoredHandler } from './util/globby.js';
16
16
  import { getReferencedDependencyHandler } from './util/handle-dependency.js';
17
17
  import { getHasStrictlyNsReferences, getType } from './util/has-strictly-ns-references.js';
18
18
  import { getIsIdentifierReferencedHandler } from './util/is-identifier-referenced.js';
@@ -111,7 +111,7 @@ export const main = async (unresolvedConfiguration) => {
111
111
  principal.addEntryPaths(definitionPaths);
112
112
  debugLogArray(name, 'Definition paths', definitionPaths);
113
113
  const ignore = worker.getIgnorePatterns();
114
- const sharedGlobOptions = { cwd, workingDir: dir, gitignore };
114
+ const sharedGlobOptions = { cwd, dir, gitignore };
115
115
  collector.addIgnorePatterns(ignore.map(pattern => join(cwd, pattern)));
116
116
  const options = { manifestScriptNames, cwd: dir, dependencies };
117
117
  const dependenciesFromManifest = _getDependenciesFromScripts(manifestScripts, options);
@@ -159,7 +159,7 @@ export const main = async (unresolvedConfiguration) => {
159
159
  principal.addProjectPath(projectPath);
160
160
  }
161
161
  {
162
- const patterns = [...entryFilePatterns, ...productionEntryFilePatterns];
162
+ const patterns = worker.getPluginEntryFilePatterns([...entryFilePatterns, ...productionEntryFilePatterns]);
163
163
  const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
164
164
  debugLogArray(name, 'Plugin entry paths', pluginWorkspaceEntryPaths);
165
165
  principal.addEntryPaths(pluginWorkspaceEntryPaths, { skipExportsAnalysis: true });
@@ -5,6 +5,5 @@ declare const _default: {
5
5
  isEnabled: IsPluginEnabled;
6
6
  entry: string[];
7
7
  production: string[];
8
- project: string[];
9
8
  };
10
9
  export default _default;
@@ -7,14 +7,12 @@ const entry = ['svelte.config.js', ...viteConfig];
7
7
  const production = [
8
8
  'src/routes/**/+{page,server,page.server,error,layout,layout.server}{,@*}.{js,ts,svelte}',
9
9
  'src/hooks.{server,client}.{js,ts}',
10
- 'src/params/*{js,ts}',
10
+ 'src/params/*.{js,ts}',
11
11
  ];
12
- const project = ['src/**/*.{js,ts,svelte}'];
13
12
  export default {
14
13
  title,
15
14
  enablers,
16
15
  isEnabled,
17
16
  entry,
18
17
  production,
19
- project,
20
18
  };
@@ -2,7 +2,7 @@ import { hasDependency } from '#p/util/plugin.js';
2
2
  const title = 'WebdriverIO';
3
3
  const enablers = ['@wdio/cli'];
4
4
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
5
- const config = ['wdio.conf.js'];
5
+ const config = ['wdio.conf.{js,ts}'];
6
6
  const resolveConfig = async (config) => {
7
7
  const cfg = config?.config;
8
8
  if (!cfg)
@@ -8,8 +8,8 @@ export default visit(() => true, (node, { isFixExports, isFixTypes }) => {
8
8
  const sourceFile = node.getSourceFile();
9
9
  const declarations = sourceFile.getNamedDeclarations?.();
10
10
  return node.exportClause.elements.map(element => {
11
- const identifier = String(element.name.escapedText);
12
- const propName = element.propertyName?.escapedText;
11
+ const identifier = String(element.name.text);
12
+ const propName = element.propertyName?.text;
13
13
  const symbol = declarations?.get(propName ?? identifier)?.[0]?.symbol;
14
14
  const pos = element.name.pos;
15
15
  const fix = isFixExports || isFixTypes ? [element.getStart(), element.getEnd()] : undefined;
@@ -10,7 +10,7 @@ export default visit(() => true, node => {
10
10
  if (node.exportClause.kind === ts.SyntaxKind.NamespaceExport) {
11
11
  return {
12
12
  identifier: IMPORT_STAR,
13
- namespace: String(node.exportClause.name.escapedText),
13
+ namespace: String(node.exportClause.name.text),
14
14
  specifier: node.moduleSpecifier.text,
15
15
  isReExport: true,
16
16
  pos: node.exportClause.name.pos,
@@ -20,8 +20,8 @@ export default visit(() => true, node => {
20
20
  return node.exportClause.elements.map(element => {
21
21
  if (element.propertyName && element.name) {
22
22
  return {
23
- identifier: String(element.propertyName.escapedText),
24
- alias: String(element.name.escapedText),
23
+ identifier: String(element.propertyName.text),
24
+ alias: String(element.name.text),
25
25
  specifier: specifier.text,
26
26
  isReExport: true,
27
27
  pos: element.pos,
@@ -9,6 +9,19 @@ type GlobOptions = {
9
9
  readonly dir: string;
10
10
  } & FastGlobOptionsWithoutCwd;
11
11
  type FastGlobOptionsWithoutCwd = Pick<FastGlobOptions, 'onlyDirectories' | 'ignore' | 'absolute' | 'dot'>;
12
+ export declare const convertGitignoreToPicomatchIgnorePatterns: (pattern: string) => {
13
+ negated: boolean;
14
+ patterns: string[];
15
+ };
16
+ export declare const parseAndConvertGitignorePatterns: (patterns: string, ancestor?: string) => {
17
+ negated: boolean;
18
+ patterns: string[];
19
+ }[];
20
+ export declare const findAndParseGitignores: (cwd: string) => Promise<{
21
+ gitignoreFiles: string[];
22
+ ignores: Set<string>;
23
+ unignores: string[];
24
+ }>;
12
25
  export declare function globby(patterns: string | string[], options: GlobOptions): Promise<string[]>;
13
26
  export declare function getGitIgnoredHandler(options: Options): Promise<(path: string) => boolean>;
14
27
  export {};
@@ -0,0 +1,192 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { promisify } from 'node:util';
3
+ import { walk as _walk } from '@nodelib/fs.walk';
4
+ import fg, {} from 'fast-glob';
5
+ import picomatch from 'picomatch';
6
+ import { GLOBAL_IGNORE_PATTERNS, ROOT_WORKSPACE_NAME } from '../constants.js';
7
+ import { timerify } from './Performance.js';
8
+ import { debugLogObject } from './debug.js';
9
+ import { isFile } from './fs.js';
10
+ import { dirname, join, relative, toPosix } from './path.js';
11
+ const walk = promisify(_walk);
12
+ const _picomatch = timerify(picomatch);
13
+ const cachedIgnores = new Map();
14
+ export const convertGitignoreToPicomatchIgnorePatterns = (pattern) => {
15
+ const negated = pattern[0] === '!';
16
+ if (negated)
17
+ pattern = pattern.slice(1);
18
+ let extPattern;
19
+ if (pattern.endsWith('/'))
20
+ pattern = pattern.slice(0, -1);
21
+ if (pattern.startsWith('*/**/'))
22
+ pattern = pattern.slice(5);
23
+ if (pattern.startsWith('/'))
24
+ pattern = pattern.slice(1);
25
+ else if (!pattern.startsWith('**/'))
26
+ pattern = `**/${pattern}`;
27
+ if (pattern.endsWith('/*'))
28
+ extPattern = pattern;
29
+ else
30
+ extPattern = `${pattern}/**`;
31
+ return { negated, patterns: [pattern, extPattern] };
32
+ };
33
+ export const parseAndConvertGitignorePatterns = (patterns, ancestor) => {
34
+ const matchFrom = ancestor ? new RegExp(`^(!?/?)(${ancestor})`) : undefined;
35
+ return patterns
36
+ .split(/\r?\n/)
37
+ .filter(line => line.trim() && !line.startsWith('#'))
38
+ .flatMap(line => {
39
+ const pattern = line.replace(/(?<!\\)#.*/, '').trim();
40
+ if (ancestor && matchFrom) {
41
+ if (pattern.match(matchFrom))
42
+ return [pattern.replace(matchFrom, '$1')];
43
+ if (pattern.startsWith('/**/'))
44
+ return [pattern.slice(1)];
45
+ if (pattern.startsWith('!/**/'))
46
+ return [`!${pattern.slice(2)}`];
47
+ if (pattern.startsWith('/') || pattern.startsWith('!/'))
48
+ return [];
49
+ }
50
+ return [pattern];
51
+ })
52
+ .map(pattern => convertGitignoreToPicomatchIgnorePatterns(pattern));
53
+ };
54
+ const findAncestorGitignoreFiles = (cwd) => {
55
+ const gitignorePaths = [];
56
+ let dir = dirname(cwd);
57
+ let prev;
58
+ while (dir) {
59
+ const filePath = join(dir, '.gitignore');
60
+ if (isFile(filePath))
61
+ gitignorePaths.push(filePath);
62
+ dir = dirname((prev = dir));
63
+ if (prev === dir || dir === '.')
64
+ break;
65
+ }
66
+ return gitignorePaths;
67
+ };
68
+ export const findAndParseGitignores = async (cwd) => {
69
+ const init = ['.git', ...GLOBAL_IGNORE_PATTERNS];
70
+ const ignores = new Set(init);
71
+ const unignores = [];
72
+ const gitignoreFiles = [];
73
+ const pmOptions = { ignore: unignores };
74
+ const matchers = new Set(init.map(pattern => _picomatch(pattern, pmOptions)));
75
+ const matcher = (str) => {
76
+ for (const isMatch of matchers) {
77
+ const state = isMatch(str);
78
+ if (state)
79
+ return state;
80
+ }
81
+ return false;
82
+ };
83
+ const addFile = (filePath) => {
84
+ gitignoreFiles.push(relative(cwd, filePath));
85
+ const dir = dirname(toPosix(filePath));
86
+ const base = relative(cwd, dir);
87
+ const ancestor = base.startsWith('..') ? `${relative(dir, cwd)}/` : undefined;
88
+ const dirIgnores = new Set(base === '' ? init : []);
89
+ const dirUnignores = new Set();
90
+ const patterns = readFileSync(filePath, 'utf8');
91
+ for (const rule of parseAndConvertGitignorePatterns(patterns, ancestor)) {
92
+ const [pattern1, pattern2] = rule.patterns;
93
+ if (rule.negated) {
94
+ if (base === '' || base.startsWith('..')) {
95
+ if (!unignores.includes(pattern2)) {
96
+ unignores.push(...rule.patterns);
97
+ dirUnignores.add(pattern1);
98
+ dirUnignores.add(pattern2);
99
+ }
100
+ }
101
+ else {
102
+ if (!unignores.includes(pattern2.startsWith('**/') ? pattern2 : `**/${pattern2}`)) {
103
+ const unignore = join(base, pattern1);
104
+ const extraUnignore = join(base, pattern2);
105
+ unignores.push(unignore, extraUnignore);
106
+ dirUnignores.add(unignore);
107
+ dirUnignores.add(extraUnignore);
108
+ }
109
+ }
110
+ }
111
+ else {
112
+ if (base === '' || base.startsWith('..')) {
113
+ ignores.add(pattern1);
114
+ ignores.add(pattern2);
115
+ dirIgnores.add(pattern1);
116
+ dirIgnores.add(pattern2);
117
+ }
118
+ else {
119
+ const ignore = join(base, pattern1);
120
+ const extraIgnore = join(base, pattern2);
121
+ ignores.add(ignore);
122
+ ignores.add(extraIgnore);
123
+ dirIgnores.add(ignore);
124
+ dirIgnores.add(extraIgnore);
125
+ }
126
+ }
127
+ }
128
+ const cacheDir = ancestor ? cwd : dir;
129
+ const cacheForDir = cachedIgnores.get(cwd);
130
+ if (ancestor && cacheForDir) {
131
+ for (const pattern of dirIgnores)
132
+ cacheForDir?.ignores.add(pattern);
133
+ cacheForDir.unignores = Array.from(new Set([...cacheForDir.unignores, ...dirUnignores]));
134
+ }
135
+ else {
136
+ cachedIgnores.set(cacheDir, { ignores: dirIgnores, unignores: Array.from(dirUnignores) });
137
+ }
138
+ for (const pattern of dirIgnores)
139
+ matchers.add(_picomatch(pattern, pmOptions));
140
+ };
141
+ findAncestorGitignoreFiles(cwd).forEach(addFile);
142
+ if (isFile('.git/info/exclude'))
143
+ addFile('.git/info/exclude');
144
+ const entryFilter = (entry) => {
145
+ if (entry.dirent.isFile() && entry.name === '.gitignore') {
146
+ addFile(entry.path);
147
+ return true;
148
+ }
149
+ return false;
150
+ };
151
+ const deepFilter = (entry) => !matcher(relative(cwd, entry.path));
152
+ await walk(cwd, {
153
+ entryFilter: timerify(entryFilter),
154
+ deepFilter: timerify(deepFilter),
155
+ });
156
+ debugLogObject('*', 'Parsed gitignore files', { gitignoreFiles, ignores, unignores });
157
+ return { gitignoreFiles, ignores, unignores };
158
+ };
159
+ const _parseFindGitignores = timerify(findAndParseGitignores);
160
+ export async function globby(patterns, options) {
161
+ if (Array.isArray(patterns) && patterns.length === 0)
162
+ return [];
163
+ const ignore = options.gitignore && Array.isArray(options.ignore) ? [...options.ignore] : [];
164
+ if (options.gitignore) {
165
+ let dir = options.dir;
166
+ let prev;
167
+ while (dir) {
168
+ const cacheForDir = cachedIgnores.get(dir);
169
+ if (cacheForDir) {
170
+ ignore.push(...cacheForDir.ignores);
171
+ }
172
+ dir = dirname((prev = dir));
173
+ if (prev === dir || dir === '.')
174
+ break;
175
+ }
176
+ }
177
+ else {
178
+ ignore.push(...GLOBAL_IGNORE_PATTERNS);
179
+ }
180
+ const fgOptions = Object.assign(options, { ignore });
181
+ debugLogObject(relative(options.cwd, options.dir) || ROOT_WORKSPACE_NAME, 'Glob options', { patterns, ...fgOptions });
182
+ return fg.glob(patterns, fgOptions);
183
+ }
184
+ export async function getGitIgnoredHandler(options) {
185
+ cachedIgnores.clear();
186
+ if (options.gitignore === false)
187
+ return () => false;
188
+ const gitignore = await _parseFindGitignores(options.cwd);
189
+ const matcher = _picomatch(Array.from(gitignore.ignores), { ignore: gitignore.unignores });
190
+ const isGitIgnored = (filePath) => matcher(relative(options.cwd, filePath));
191
+ return timerify(isGitIgnored);
192
+ }
@@ -1,17 +1,14 @@
1
- export declare const prependDirToPattern: (workingDir: string, pattern: string) => string;
2
- export declare const negate: (pattern: string) => string;
3
- export declare const hasProductionSuffix: (pattern: string) => boolean;
4
- export declare const hasNoProductionSuffix: (pattern: string) => boolean;
5
- interface BaseGlobOptions {
1
+ interface GlobOptions {
6
2
  cwd: string;
3
+ dir?: string;
7
4
  patterns: string[];
8
5
  gitignore?: boolean;
9
6
  }
10
- interface GlobOptions extends BaseGlobOptions {
11
- workingDir?: string;
12
- }
13
- export declare const _glob: ({ cwd, workingDir, patterns, gitignore }: GlobOptions) => Promise<string[]>;
14
- export declare const _pureGlob: ({ cwd, patterns, gitignore }: BaseGlobOptions) => Promise<string[]>;
15
- export declare const _firstGlob: ({ cwd, patterns }: BaseGlobOptions) => Promise<string | Buffer | undefined>;
16
- export declare const _dirGlob: ({ cwd, patterns, gitignore }: BaseGlobOptions) => Promise<string[]>;
7
+ export declare const prependDirToPattern: (dir: string, pattern: string) => string;
8
+ export declare const negate: (pattern: string) => string;
9
+ export declare const hasProductionSuffix: (pattern: string) => boolean;
10
+ export declare const hasNoProductionSuffix: (pattern: string) => boolean;
11
+ export declare const _glob: ({ cwd, dir, patterns, gitignore }: GlobOptions) => Promise<string[]>;
12
+ export declare const _firstGlob: ({ cwd, patterns }: GlobOptions) => Promise<string | Buffer | undefined>;
13
+ export declare const _dirGlob: ({ cwd, patterns, gitignore }: GlobOptions) => Promise<string[]>;
17
14
  export {};
package/dist/util/glob.js CHANGED
@@ -2,44 +2,37 @@ import fg from 'fast-glob';
2
2
  import { GLOBAL_IGNORE_PATTERNS } from '../constants.js';
3
3
  import { timerify } from './Performance.js';
4
4
  import { compact } from './array.js';
5
- import { globby } from './globby.js';
5
+ import { globby } from './glob-core.js';
6
6
  import { join, relative } from './path.js';
7
- export const prependDirToPattern = (workingDir, pattern) => {
7
+ const prependDirToPatterns = (cwd, dir, patterns) => {
8
+ const relativePath = relative(cwd, dir);
9
+ const prepend = (pattern) => prependDirToPattern(relativePath, pattern);
10
+ return compact([patterns].flat().map(prepend).map(removeProductionSuffix)).sort(negatedLast);
11
+ };
12
+ const removeProductionSuffix = (pattern) => pattern.replace(/!$/, '');
13
+ const negatedLast = (pattern) => (pattern.startsWith('!') ? 1 : -1);
14
+ export const prependDirToPattern = (dir, pattern) => {
8
15
  if (pattern.startsWith('!'))
9
- return `!${join(workingDir, pattern.slice(1))}`;
10
- return join(workingDir, pattern);
16
+ return `!${join(dir, pattern.slice(1))}`;
17
+ return join(dir, pattern);
11
18
  };
12
19
  export const negate = (pattern) => pattern.replace(/^!?/, '!');
13
20
  export const hasProductionSuffix = (pattern) => pattern.endsWith('!');
14
21
  export const hasNoProductionSuffix = (pattern) => !pattern.endsWith('!');
15
- const removeProductionSuffix = (pattern) => pattern.replace(/!$/, '');
16
- const negatedLast = (pattern) => (pattern.startsWith('!') ? 1 : -1);
17
- const glob = async ({ cwd, workingDir = cwd, patterns, gitignore = true }) => {
22
+ const glob = async ({ cwd, dir = cwd, patterns, gitignore = true }) => {
18
23
  if (patterns.length === 0)
19
24
  return [];
20
- const relativePath = relative(cwd, workingDir);
21
- const prepend = (pattern) => prependDirToPattern(relativePath, pattern);
22
- const globPatterns = compact([patterns].flat().map(prepend).map(removeProductionSuffix)).sort(negatedLast);
25
+ const globPatterns = prependDirToPatterns(cwd, dir, patterns);
23
26
  if (globPatterns[0].startsWith('!'))
24
27
  return [];
25
28
  return globby(globPatterns, {
26
29
  cwd,
27
- dir: workingDir,
30
+ dir,
28
31
  gitignore,
29
32
  absolute: true,
30
33
  dot: true,
31
34
  });
32
35
  };
33
- const pureGlob = async ({ cwd, patterns, gitignore = true }) => {
34
- if (patterns.length === 0)
35
- return [];
36
- return globby(patterns, {
37
- cwd,
38
- dir: cwd,
39
- gitignore,
40
- absolute: true,
41
- });
42
- };
43
36
  const firstGlob = async ({ cwd, patterns }) => {
44
37
  const stream = fg.globStream(patterns.map(removeProductionSuffix), { cwd, ignore: GLOBAL_IGNORE_PATTERNS });
45
38
  for await (const entry of stream) {
@@ -53,6 +46,5 @@ const dirGlob = async ({ cwd, patterns, gitignore = true }) => globby(patterns,
53
46
  gitignore,
54
47
  });
55
48
  export const _glob = timerify(glob);
56
- export const _pureGlob = timerify(pureGlob);
57
49
  export const _firstGlob = timerify(firstGlob);
58
50
  export const _dirGlob = timerify(dirGlob);
@@ -7,7 +7,7 @@ export declare const getDefinitelyTypedFor: (packageName: string) => string;
7
7
  export declare const getPackageFromDefinitelyTyped: (typedDependency: string) => string;
8
8
  export declare const getEntryPathsFromManifest: (manifest: PackageJson, sharedGlobOptions: {
9
9
  cwd: string;
10
- workingDir: string;
10
+ dir: string;
11
11
  gitignore: boolean;
12
12
  ignore: string[];
13
13
  }) => Promise<string[]>;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "5.29.1";
1
+ export declare const version = "5.30.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.29.1';
1
+ export const version = '5.30.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "5.29.1",
3
+ "version": "5.30.0",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://knip.dev",
6
6
  "repository": {
@@ -1,139 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { promisify } from 'node:util';
3
- import { walk as _walk } from '@nodelib/fs.walk';
4
- import fg, {} from 'fast-glob';
5
- import picomatch from 'picomatch';
6
- import { GLOBAL_IGNORE_PATTERNS, ROOT_WORKSPACE_NAME } from '../constants.js';
7
- import { timerify } from './Performance.js';
8
- import { debugLogObject } from './debug.js';
9
- import { isFile } from './fs.js';
10
- import { dirname, join, relative, toPosix, toRelative } from './path.js';
11
- const walk = promisify(_walk);
12
- const _picomatch = timerify(picomatch);
13
- const cachedIgnores = new Map();
14
- function convertGitignoreToPicomatch(pattern) {
15
- const negated = pattern[0] === '!';
16
- if (negated) {
17
- pattern = pattern.slice(1);
18
- }
19
- let extPattern;
20
- if (pattern.startsWith('*/**/'))
21
- pattern = pattern.slice(5);
22
- if (pattern.startsWith('/'))
23
- pattern = pattern.slice(1);
24
- else if (!pattern.startsWith('**/'))
25
- pattern = `**/${pattern}`;
26
- if (pattern.endsWith('/*'))
27
- extPattern = pattern;
28
- else if (pattern.endsWith('/'))
29
- extPattern = `${pattern}**`;
30
- else
31
- extPattern = `${pattern}/**`;
32
- return { negated, patterns: [pattern, extPattern] };
33
- }
34
- function parseGitignoreFile(filePath) {
35
- const file = readFileSync(filePath, 'utf8');
36
- return file
37
- .split(/\r?\n/)
38
- .filter(line => line.trim() && !line.startsWith('#'))
39
- .map(pattern => convertGitignoreToPicomatch(pattern.replace(/(?<!\\)#.*/, '').trim()));
40
- }
41
- async function parseFindGitignores(options) {
42
- const ignores = ['.git', ...GLOBAL_IGNORE_PATTERNS];
43
- const unignores = [];
44
- const gitignoreFiles = [];
45
- const pmOptions = { ignore: unignores };
46
- const matchers = ignores.map(ignore => _picomatch(ignore, pmOptions));
47
- const matcher = (str) => {
48
- for (const isMatch of matchers) {
49
- const state = isMatch(str);
50
- if (state)
51
- return state;
52
- }
53
- return false;
54
- };
55
- const addFile = (filePath) => {
56
- gitignoreFiles.push(toRelative(filePath));
57
- const dir = dirname(toPosix(filePath));
58
- const base = relative(options.cwd, dir);
59
- const dirIgnores = base === '' ? ['.git', ...GLOBAL_IGNORE_PATTERNS] : [];
60
- const dirUnignores = [];
61
- for (const rule of parseGitignoreFile(filePath)) {
62
- const [p, ext] = rule.patterns;
63
- if (rule.negated) {
64
- if (base === '') {
65
- if (!unignores.includes(ext))
66
- dirUnignores.push(...rule.patterns);
67
- }
68
- else {
69
- if (!unignores.includes(ext.startsWith('**/') ? ext : `**/${ext}`)) {
70
- dirUnignores.push(join(base, p), join(base, ext));
71
- }
72
- }
73
- }
74
- else {
75
- if (base === '') {
76
- if (!ignores.includes(ext))
77
- dirIgnores.push(...rule.patterns);
78
- }
79
- else {
80
- if (!ignores.includes(ext.startsWith('**/') ? ext : `**/${ext}`)) {
81
- dirIgnores.push(join(base, p), join(base, ext));
82
- }
83
- }
84
- }
85
- }
86
- ignores.push(...dirIgnores);
87
- unignores.push(...dirUnignores);
88
- cachedIgnores.set(dir, { ignores: dirIgnores, unignores: dirUnignores });
89
- matchers.push(...dirIgnores.map(ignore => _picomatch(ignore, pmOptions)));
90
- };
91
- if (isFile('.git/info/exclude'))
92
- addFile('.git/info/exclude');
93
- const entryFilter = (entry) => {
94
- if (entry.dirent.isFile() && entry.name === '.gitignore') {
95
- addFile(entry.path);
96
- return true;
97
- }
98
- return false;
99
- };
100
- const deepFilter = (entry) => !matcher(relative(options.cwd, entry.path));
101
- await walk(options.cwd, {
102
- entryFilter: timerify(entryFilter),
103
- deepFilter: timerify(deepFilter),
104
- });
105
- debugLogObject('*', 'Parsed gitignore files', { gitignoreFiles, ignores, unignores });
106
- return { ignores, unignores };
107
- }
108
- const _parseFindGitignores = timerify(parseFindGitignores);
109
- export async function globby(patterns, options) {
110
- if (Array.isArray(patterns) && patterns.length === 0)
111
- return [];
112
- const ignore = options.gitignore && Array.isArray(options.ignore) ? [...options.ignore] : [];
113
- if (options.gitignore) {
114
- let dir = options.dir;
115
- while (dir !== options.cwd) {
116
- const i = cachedIgnores.get(dir);
117
- if (i) {
118
- ignore.push(...i.ignores);
119
- ignore.push(...i.unignores.map(e => `!${e}`));
120
- }
121
- dir = dirname(dir);
122
- }
123
- const i = cachedIgnores.get(options.cwd);
124
- if (i)
125
- ignore.push(...i.ignores);
126
- }
127
- const { dir, ...fastGlobOptions } = { ...options, ignore };
128
- debugLogObject(relative(options.cwd, dir) || ROOT_WORKSPACE_NAME, 'Glob options', { patterns, ...options });
129
- return fg.glob(patterns, fastGlobOptions);
130
- }
131
- export async function getGitIgnoredHandler(options) {
132
- cachedIgnores.clear();
133
- if (options.gitignore === false)
134
- return () => false;
135
- const gitignore = await _parseFindGitignores(options);
136
- const matcher = _picomatch(gitignore.ignores, { ignore: gitignore.unignores });
137
- const isGitIgnored = (filePath) => matcher(relative(options.cwd, filePath));
138
- return timerify(isGitIgnored);
139
- }