knip 6.3.1 → 6.4.1
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/LICENSE +15 -0
- package/dist/ConfigurationChief.d.ts +6 -0
- package/dist/ProjectPrincipal.d.ts +2 -2
- package/dist/ProjectPrincipal.js +32 -13
- package/dist/WorkspaceWorker.d.ts +1 -1
- package/dist/WorkspaceWorker.js +19 -2
- package/dist/compilers/index.d.ts +10 -0
- package/dist/compilers/scss.js +22 -16
- package/dist/graph/analyze.js +2 -0
- package/dist/graph/build.d.ts +2 -2
- package/dist/graph/build.js +5 -5
- package/dist/plugins/bun/index.js +2 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/panda-css/index.d.ts +3 -0
- package/dist/plugins/panda-css/index.js +18 -0
- package/dist/plugins/panda-css/types.d.ts +3 -0
- package/dist/plugins/panda-css/types.js +1 -0
- package/dist/plugins/tailwind/index.js +2 -2
- package/dist/plugins/webpack/index.js +21 -1
- package/dist/reporters/util/configuration-hints.js +5 -0
- package/dist/run.js +5 -0
- package/dist/schema/configuration.d.ts +15 -0
- package/dist/schema/plugins.d.ts +5 -0
- package/dist/schema/plugins.js +1 -0
- package/dist/types/PluginNames.d.ts +2 -2
- package/dist/types/PluginNames.js +1 -0
- package/dist/types/issues.d.ts +1 -1
- package/dist/types/module-graph.d.ts +1 -0
- package/dist/typescript/comments.d.ts +4 -0
- package/dist/typescript/comments.js +64 -0
- package/dist/typescript/get-imports-and-exports.js +23 -46
- package/dist/typescript/resolve-module-names.d.ts +1 -0
- package/dist/typescript/resolve-module-names.js +22 -0
- package/dist/typescript/visitors/calls.js +74 -1
- package/dist/typescript/visitors/walk.d.ts +4 -0
- package/dist/util/create-options.d.ts +10 -0
- package/dist/util/file-entry-cache.js +10 -3
- package/dist/util/glob-cache.d.ts +12 -0
- package/dist/util/glob-cache.js +124 -0
- package/dist/util/glob.js +12 -1
- package/dist/util/module-graph.js +7 -0
- package/dist/util/pattern-extensions.d.ts +1 -0
- package/dist/util/pattern-extensions.js +32 -0
- package/dist/util/watch.js +4 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/schema.json +4 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Comment } from 'oxc-parser';
|
|
2
|
+
type CommentImportAdder = (specifier: string, identifier: string | undefined, alias: string | undefined, namespace: string | undefined, pos: number, modifiers: number) => void;
|
|
3
|
+
export declare const extractImportsFromComments: (comments: readonly Comment[], firstStmtStart: number, addImport: CommentImportAdder) => void;
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { IMPORT_FLAGS } from "../constants.js";
|
|
2
|
+
const jsDocImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)(?:\.(\w+))?/g;
|
|
3
|
+
const jsDocImportTagRe = /@import\s+(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
4
|
+
const jsxImportSourceRe = /@jsxImportSource\s+(\S+)/;
|
|
5
|
+
const referenceTypesRe = /\s*<reference\s+types\s*=\s*"([^"]+)"[^/]*\/>/;
|
|
6
|
+
const envPragmaRe = /@(vitest|jest)-environment\s+([@\w./-]+)/g;
|
|
7
|
+
const resolveEnvironmentPragma = (tool, value) => {
|
|
8
|
+
if (value === 'node')
|
|
9
|
+
return undefined;
|
|
10
|
+
if (value.startsWith('.') || value.startsWith('/'))
|
|
11
|
+
return value;
|
|
12
|
+
if (tool === 'jest') {
|
|
13
|
+
if (value === 'jsdom')
|
|
14
|
+
return 'jest-environment-jsdom';
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (value === 'edge-runtime')
|
|
18
|
+
return '@edge-runtime/vm';
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
export const extractImportsFromComments = (comments, firstStmtStart, addImport) => {
|
|
22
|
+
for (const comment of comments) {
|
|
23
|
+
const text = comment.value;
|
|
24
|
+
let results;
|
|
25
|
+
if (comment.type === 'Block') {
|
|
26
|
+
jsDocImportRe.lastIndex = 0;
|
|
27
|
+
while ((results = jsDocImportRe.exec(text)) !== null) {
|
|
28
|
+
const before = text.slice(0, results.index);
|
|
29
|
+
const lastOpen = before.lastIndexOf('{');
|
|
30
|
+
if (lastOpen === -1 || before.indexOf('}', lastOpen) !== -1)
|
|
31
|
+
continue;
|
|
32
|
+
const specifier = results[1];
|
|
33
|
+
const member = results[2];
|
|
34
|
+
addImport(specifier, member, undefined, undefined, comment.start + results.index, IMPORT_FLAGS.TYPE_ONLY);
|
|
35
|
+
}
|
|
36
|
+
jsDocImportTagRe.lastIndex = 0;
|
|
37
|
+
while ((results = jsDocImportTagRe.exec(text)) !== null) {
|
|
38
|
+
const specifier = results[1];
|
|
39
|
+
addImport(specifier, undefined, undefined, undefined, comment.start + results.index, IMPORT_FLAGS.TYPE_ONLY);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const jsxMatch = text.match(jsxImportSourceRe);
|
|
43
|
+
if (jsxMatch) {
|
|
44
|
+
addImport(jsxMatch[1], undefined, undefined, undefined, comment.start, IMPORT_FLAGS.TYPE_ONLY);
|
|
45
|
+
}
|
|
46
|
+
if (comment.end <= firstStmtStart) {
|
|
47
|
+
envPragmaRe.lastIndex = 0;
|
|
48
|
+
while ((results = envPragmaRe.exec(text)) !== null) {
|
|
49
|
+
const id = resolveEnvironmentPragma(results[1], results[2]);
|
|
50
|
+
if (!id)
|
|
51
|
+
continue;
|
|
52
|
+
const isLocal = id.startsWith('.') || id.startsWith('/');
|
|
53
|
+
const modifiers = isLocal ? IMPORT_FLAGS.ENTRY : IMPORT_FLAGS.NONE;
|
|
54
|
+
addImport(id, undefined, undefined, undefined, comment.start + results.index, modifiers);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (comment.type === 'Line') {
|
|
58
|
+
const refMatch = comment.value.match(referenceTypesRe);
|
|
59
|
+
if (refMatch) {
|
|
60
|
+
addImport(refMatch[1], undefined, undefined, undefined, comment.start, IMPORT_FLAGS.TYPE_ONLY);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
@@ -5,14 +5,10 @@ import { getPackageNameFromFilePath, isStartsLikePackageName, sanitizeSpecifier
|
|
|
5
5
|
import { timerify } from "../util/Performance.js";
|
|
6
6
|
import { dirname, isInNodeModules, resolve } from "../util/path.js";
|
|
7
7
|
import { shouldIgnore } from "../util/tag.js";
|
|
8
|
-
import {
|
|
8
|
+
import { extractImportsFromComments } from "./comments.js";
|
|
9
|
+
import { buildLineStarts, getLineAndCol, parseFile, shouldCountRefs, } from "./visitors/helpers.js";
|
|
9
10
|
import { buildJSDocTagLookup } from "./visitors/jsdoc.js";
|
|
10
11
|
import { walkAST } from "./visitors/walk.js";
|
|
11
|
-
const jsDocImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)(?:\.(\w+))?/g;
|
|
12
|
-
const jsDocImportTagRe = /@import\s+(?:\{[^}]*\}|\*\s+as\s+\w+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
13
|
-
const jsxImportSourceRe = /@jsxImportSource\s+(\S+)/;
|
|
14
|
-
const referenceTypesRe = /\s*<reference\s+types\s*=\s*"([^"]+)"[^/]*\/>/;
|
|
15
|
-
const envRe = /@(?:vitest|jest)-environment\s+(\S+)/g;
|
|
16
12
|
const getImportsAndExports = (filePath, sourceText, resolveModule, options, ignoreExportsUsedInFile, skipExportsForFile, visitor, pluginCtx, cachedParseResult) => {
|
|
17
13
|
const skipExports = skipExportsForFile || !options.isReportExports;
|
|
18
14
|
const internal = new Map();
|
|
@@ -166,10 +162,19 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
|
|
|
166
162
|
const lineStarts = buildLineStarts(sourceText);
|
|
167
163
|
const getJSDocTags = buildJSDocTagLookup(result.comments, sourceText);
|
|
168
164
|
let hasNodeModuleImport = false;
|
|
165
|
+
let hasWorkerThreadsImport = false;
|
|
166
|
+
let hasChildProcessImport = false;
|
|
167
|
+
let hasPathJoinImport = false;
|
|
168
|
+
let hasPathResolveImport = false;
|
|
169
169
|
for (const _imports of result.module.staticImports) {
|
|
170
170
|
const specifier = _imports.moduleRequest.value;
|
|
171
171
|
if (specifier === 'node:module' || specifier === 'module')
|
|
172
172
|
hasNodeModuleImport = true;
|
|
173
|
+
else if (specifier === 'node:worker_threads' || specifier === 'worker_threads')
|
|
174
|
+
hasWorkerThreadsImport = true;
|
|
175
|
+
else if (specifier === 'node:child_process' || specifier === 'child_process')
|
|
176
|
+
hasChildProcessImport = true;
|
|
177
|
+
const isPathImport = specifier === 'node:path' || specifier === 'path';
|
|
173
178
|
const pos = _imports.moduleRequest.start;
|
|
174
179
|
const jsdocTags = getJSDocTags(_imports.start);
|
|
175
180
|
if (_imports.entries.length === 0) {
|
|
@@ -199,6 +204,12 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
|
|
|
199
204
|
const importedName = entry.importName.name;
|
|
200
205
|
const localName = entry.localName.value;
|
|
201
206
|
const alias = localName !== importedName ? localName : undefined;
|
|
207
|
+
if (isPathImport && !alias) {
|
|
208
|
+
if (importedName === 'join')
|
|
209
|
+
hasPathJoinImport = true;
|
|
210
|
+
else if (importedName === 'resolve')
|
|
211
|
+
hasPathResolveImport = true;
|
|
212
|
+
}
|
|
202
213
|
addImport(specifier, importedName, alias, undefined, entry.localName.start, modifiers, pos, jsdocTags, resolved);
|
|
203
214
|
if (internalPath)
|
|
204
215
|
localImportMap.set(localName, { importedName, filePath: internalPath, isNamespace: false });
|
|
@@ -263,52 +274,18 @@ const getImportsAndExports = (filePath, sourceText, resolveModule, options, igno
|
|
|
263
274
|
localRefs: ignoreExportsUsedInFile ? new Set() : undefined,
|
|
264
275
|
destructuredExports,
|
|
265
276
|
hasNodeModuleImport,
|
|
277
|
+
hasWorkerThreadsImport,
|
|
278
|
+
hasChildProcessImport,
|
|
279
|
+
hasPathJoinImport,
|
|
280
|
+
hasPathResolveImport,
|
|
266
281
|
resolveModule,
|
|
267
282
|
programFiles,
|
|
268
283
|
entryFiles,
|
|
269
284
|
visitor,
|
|
270
285
|
getJSDocTags,
|
|
271
286
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
let results;
|
|
275
|
-
if (comment.type === 'Block') {
|
|
276
|
-
jsDocImportRe.lastIndex = 0;
|
|
277
|
-
while ((results = jsDocImportRe.exec(text)) !== null) {
|
|
278
|
-
const before = text.slice(0, results.index);
|
|
279
|
-
const lastOpen = before.lastIndexOf('{');
|
|
280
|
-
if (lastOpen === -1 || before.indexOf('}', lastOpen) !== -1)
|
|
281
|
-
continue;
|
|
282
|
-
const specifier = results[1];
|
|
283
|
-
const member = results[2];
|
|
284
|
-
addImport(specifier, member, undefined, undefined, comment.start + results.index, IMPORT_FLAGS.TYPE_ONLY);
|
|
285
|
-
}
|
|
286
|
-
jsDocImportTagRe.lastIndex = 0;
|
|
287
|
-
while ((results = jsDocImportTagRe.exec(text)) !== null) {
|
|
288
|
-
const specifier = results[1];
|
|
289
|
-
addImport(specifier, undefined, undefined, undefined, comment.start + results.index, IMPORT_FLAGS.TYPE_ONLY);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const jsxMatch = text.match(jsxImportSourceRe);
|
|
293
|
-
if (jsxMatch) {
|
|
294
|
-
addImport(jsxMatch[1], undefined, undefined, undefined, comment.start, IMPORT_FLAGS.TYPE_ONLY);
|
|
295
|
-
}
|
|
296
|
-
envRe.lastIndex = 0;
|
|
297
|
-
while ((results = envRe.exec(text)) !== null) {
|
|
298
|
-
const id = stripQuotes(results[1]);
|
|
299
|
-
if (!id)
|
|
300
|
-
continue;
|
|
301
|
-
const isLocal = id.startsWith('.') || id.startsWith('/');
|
|
302
|
-
const modifiers = isLocal ? IMPORT_FLAGS.ENTRY : IMPORT_FLAGS.NONE;
|
|
303
|
-
addImport(id, undefined, undefined, undefined, comment.start + results.index, modifiers);
|
|
304
|
-
}
|
|
305
|
-
if (comment.type === 'Line') {
|
|
306
|
-
const refMatch = comment.value.match(referenceTypesRe);
|
|
307
|
-
if (refMatch) {
|
|
308
|
-
addImport(refMatch[1], undefined, undefined, undefined, comment.start, IMPORT_FLAGS.TYPE_ONLY);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
287
|
+
const firstStmtStart = result.program.body[0]?.start ?? Number.POSITIVE_INFINITY;
|
|
288
|
+
extractImportsFromComments(result.comments, firstStmtStart, addImport);
|
|
312
289
|
for (const [id, item] of exports) {
|
|
313
290
|
item.referencedIn = referencedInExport.get(id);
|
|
314
291
|
if (localRefs && shouldCountRefs(ignoreExportsUsedInFile, item.type) && (localRefs.has(id) || item.isReExport)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ToSourceFilePath } from '../util/to-source-path.ts';
|
|
2
2
|
import type { ResolveModule } from './visitors/helpers.ts';
|
|
3
|
+
export declare function clearModuleResolutionCaches(): void;
|
|
3
4
|
export declare function createCustomModuleResolver(compilerOptions: {
|
|
4
5
|
paths?: Record<string, string[]>;
|
|
5
6
|
rootDirs?: string[];
|
|
@@ -5,6 +5,11 @@ import { sanitizeSpecifier } from "../util/modules.js";
|
|
|
5
5
|
import { timerify } from "../util/Performance.js";
|
|
6
6
|
import { dirname, extname, isAbsolute, isInNodeModules, join } from "../util/path.js";
|
|
7
7
|
import { _createSyncModuleResolver, _resolveModuleSync } from "../util/resolve.js";
|
|
8
|
+
const moduleResolutionCaches = [];
|
|
9
|
+
export function clearModuleResolutionCaches() {
|
|
10
|
+
for (const cache of moduleResolutionCaches)
|
|
11
|
+
cache.clear();
|
|
12
|
+
}
|
|
8
13
|
function compilePathMappings(paths) {
|
|
9
14
|
if (!paths)
|
|
10
15
|
return undefined;
|
|
@@ -40,7 +45,24 @@ export function createCustomModuleResolver(compilerOptions, customCompilerExtens
|
|
|
40
45
|
isExternalLibraryImport: mapped === resolvedFileName && isInNodeModules(resolvedFileName),
|
|
41
46
|
};
|
|
42
47
|
}
|
|
48
|
+
const cache = new Map();
|
|
49
|
+
moduleResolutionCaches.push(cache);
|
|
43
50
|
function resolveModuleName(name, containingFile) {
|
|
51
|
+
const dir = dirname(containingFile);
|
|
52
|
+
let byName = cache.get(dir);
|
|
53
|
+
if (byName) {
|
|
54
|
+
if (byName.has(name))
|
|
55
|
+
return byName.get(name);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
byName = new Map();
|
|
59
|
+
cache.set(dir, byName);
|
|
60
|
+
}
|
|
61
|
+
const result = resolveModuleNameUncached(name, containingFile);
|
|
62
|
+
byName.set(name, result);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function resolveModuleNameUncached(name, containingFile) {
|
|
44
66
|
const specifier = sanitizeSpecifier(name);
|
|
45
67
|
if (isBuiltin(specifier))
|
|
46
68
|
return undefined;
|
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
import { IMPORT_FLAGS, OPAQUE } from "../../constants.js";
|
|
2
2
|
import { addValue } from "../../util/module-graph.js";
|
|
3
3
|
import { getStringValue, isStringLiteral } from "./helpers.js";
|
|
4
|
+
function extractInlineDirnamePath(node, s) {
|
|
5
|
+
if (node?.type !== 'CallExpression')
|
|
6
|
+
return undefined;
|
|
7
|
+
const callee = node.callee;
|
|
8
|
+
let isPathHelper = false;
|
|
9
|
+
if (callee?.type === 'MemberExpression' &&
|
|
10
|
+
!callee.computed &&
|
|
11
|
+
callee.object?.type === 'Identifier' &&
|
|
12
|
+
callee.object.name === 'path' &&
|
|
13
|
+
callee.property?.type === 'Identifier' &&
|
|
14
|
+
(callee.property.name === 'join' || callee.property.name === 'resolve')) {
|
|
15
|
+
isPathHelper = true;
|
|
16
|
+
}
|
|
17
|
+
else if (callee?.type === 'Identifier') {
|
|
18
|
+
if (callee.name === 'join' && s.hasPathJoinImport)
|
|
19
|
+
isPathHelper = true;
|
|
20
|
+
else if (callee.name === 'resolve' && s.hasPathResolveImport)
|
|
21
|
+
isPathHelper = true;
|
|
22
|
+
}
|
|
23
|
+
if (!isPathHelper)
|
|
24
|
+
return undefined;
|
|
25
|
+
const args = node.arguments;
|
|
26
|
+
if (!args || args.length < 2)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (args[0]?.type !== 'Identifier' || args[0].name !== '__dirname')
|
|
29
|
+
return undefined;
|
|
30
|
+
const parts = [];
|
|
31
|
+
for (let i = 1; i < args.length; i++) {
|
|
32
|
+
if (!isStringLiteral(args[i]))
|
|
33
|
+
return undefined;
|
|
34
|
+
const value = getStringValue(args[i]);
|
|
35
|
+
if (value == null)
|
|
36
|
+
return undefined;
|
|
37
|
+
parts.push(value);
|
|
38
|
+
}
|
|
39
|
+
if (parts.length === 0)
|
|
40
|
+
return undefined;
|
|
41
|
+
const joined = parts.join('/').replace(/\/+/g, '/');
|
|
42
|
+
return joined.startsWith('.') || joined.startsWith('/') ? joined : `./${joined}`;
|
|
43
|
+
}
|
|
44
|
+
const CHILD_PROCESS_ENTRY_METHODS = new Set(['fork', 'spawn', 'execFile']);
|
|
4
45
|
export function handleCallExpression(node, s) {
|
|
5
46
|
if (node.callee.type === 'Identifier' &&
|
|
6
47
|
node.callee.name === 'require' &&
|
|
@@ -53,6 +94,25 @@ export function handleCallExpression(node, s) {
|
|
|
53
94
|
return;
|
|
54
95
|
}
|
|
55
96
|
}
|
|
97
|
+
if (s.hasChildProcessImport && node.arguments.length >= 1) {
|
|
98
|
+
let isChildProcessEntry = false;
|
|
99
|
+
if (node.callee.type === 'Identifier' && CHILD_PROCESS_ENTRY_METHODS.has(node.callee.name)) {
|
|
100
|
+
isChildProcessEntry = true;
|
|
101
|
+
}
|
|
102
|
+
else if (node.callee.type === 'MemberExpression' &&
|
|
103
|
+
!node.callee.computed &&
|
|
104
|
+
node.callee.property.type === 'Identifier' &&
|
|
105
|
+
CHILD_PROCESS_ENTRY_METHODS.has(node.callee.property.name)) {
|
|
106
|
+
isChildProcessEntry = true;
|
|
107
|
+
}
|
|
108
|
+
if (isChildProcessEntry) {
|
|
109
|
+
const specifier = extractInlineDirnamePath(node.arguments[0], s);
|
|
110
|
+
if (specifier) {
|
|
111
|
+
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
56
116
|
if (node.callee.type === 'MemberExpression' &&
|
|
57
117
|
!node.callee.computed &&
|
|
58
118
|
node.callee.object.type === 'Identifier' &&
|
|
@@ -70,12 +130,15 @@ export function handleCallExpression(node, s) {
|
|
|
70
130
|
if (internalImport) {
|
|
71
131
|
if (_import.isNamespace)
|
|
72
132
|
addValue(internalImport.import, OPAQUE, s.filePath);
|
|
73
|
-
else
|
|
133
|
+
else {
|
|
74
134
|
internalImport.refs.add(arg.name);
|
|
135
|
+
(internalImport.enumerated ??= new Set()).add(arg.name);
|
|
136
|
+
}
|
|
75
137
|
}
|
|
76
138
|
}
|
|
77
139
|
}
|
|
78
140
|
}
|
|
141
|
+
return;
|
|
79
142
|
}
|
|
80
143
|
const markRefIfNs = (name) => {
|
|
81
144
|
const _import = s.localImportMap.get(name);
|
|
@@ -116,5 +179,15 @@ export function handleNewExpression(node, s) {
|
|
|
116
179
|
const specifier = getStringValue(node.arguments[0]);
|
|
117
180
|
if (specifier)
|
|
118
181
|
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.OPTIONAL);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (s.hasWorkerThreadsImport &&
|
|
185
|
+
node.callee.type === 'Identifier' &&
|
|
186
|
+
node.callee.name === 'Worker' &&
|
|
187
|
+
node.arguments.length >= 1) {
|
|
188
|
+
const specifier = extractInlineDirnamePath(node.arguments[0], s);
|
|
189
|
+
if (specifier) {
|
|
190
|
+
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY);
|
|
191
|
+
}
|
|
119
192
|
}
|
|
120
193
|
}
|
|
@@ -33,6 +33,10 @@ interface WalkContext {
|
|
|
33
33
|
localRefs: Set<string> | undefined;
|
|
34
34
|
destructuredExports: Set<string>;
|
|
35
35
|
hasNodeModuleImport: boolean;
|
|
36
|
+
hasWorkerThreadsImport: boolean;
|
|
37
|
+
hasChildProcessImport: boolean;
|
|
38
|
+
hasPathJoinImport: boolean;
|
|
39
|
+
hasPathResolveImport: boolean;
|
|
36
40
|
resolveModule: ResolveModule;
|
|
37
41
|
programFiles: Set<string>;
|
|
38
42
|
entryFiles: Set<string>;
|
|
@@ -407,6 +407,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
407
407
|
entry?: string | string[] | undefined;
|
|
408
408
|
project?: string | string[] | undefined;
|
|
409
409
|
} | undefined;
|
|
410
|
+
'panda-css'?: string | boolean | string[] | {
|
|
411
|
+
config?: string | string[] | undefined;
|
|
412
|
+
entry?: string | string[] | undefined;
|
|
413
|
+
project?: string | string[] | undefined;
|
|
414
|
+
} | undefined;
|
|
410
415
|
parcel?: string | boolean | string[] | {
|
|
411
416
|
config?: string | string[] | undefined;
|
|
412
417
|
entry?: string | string[] | undefined;
|
|
@@ -1123,6 +1128,11 @@ export declare const createOptions: (options: CreateOptions) => Promise<{
|
|
|
1123
1128
|
entry?: string | string[] | undefined;
|
|
1124
1129
|
project?: string | string[] | undefined;
|
|
1125
1130
|
} | undefined;
|
|
1131
|
+
'panda-css'?: string | boolean | string[] | {
|
|
1132
|
+
config?: string | string[] | undefined;
|
|
1133
|
+
entry?: string | string[] | undefined;
|
|
1134
|
+
project?: string | string[] | undefined;
|
|
1135
|
+
} | undefined;
|
|
1126
1136
|
parcel?: string | boolean | string[] | {
|
|
1127
1137
|
config?: string | string[] | undefined;
|
|
1128
1138
|
entry?: string | string[] | undefined;
|
|
@@ -85,14 +85,21 @@ export class FileEntryCache {
|
|
|
85
85
|
return meta;
|
|
86
86
|
}
|
|
87
87
|
reconcile() {
|
|
88
|
-
this.removeNotFoundFiles();
|
|
89
88
|
for (const [entryName, cacheEntry] of this.normalizedEntries) {
|
|
90
89
|
try {
|
|
91
|
-
const
|
|
90
|
+
const stat = fs.statSync(entryName);
|
|
91
|
+
const meta = Object.assign(cacheEntry.meta ?? {}, {
|
|
92
|
+
size: stat.size,
|
|
93
|
+
mtime: stat.mtime.getTime(),
|
|
94
|
+
});
|
|
92
95
|
this.cache.set(entryName, meta);
|
|
93
96
|
}
|
|
94
97
|
catch (error) {
|
|
95
|
-
if (error.code
|
|
98
|
+
if (error.code === 'ENOENT') {
|
|
99
|
+
this.normalizedEntries.delete(entryName);
|
|
100
|
+
this.cache.delete(entryName);
|
|
101
|
+
}
|
|
102
|
+
else
|
|
96
103
|
throw error;
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const initGlobCache: (cacheLocation: string) => void;
|
|
2
|
+
export declare const isGlobCacheEnabled: () => boolean;
|
|
3
|
+
export declare const computeGlobCacheKey: (input: {
|
|
4
|
+
patterns: string[];
|
|
5
|
+
cwd: string;
|
|
6
|
+
dir: string;
|
|
7
|
+
gitignore: boolean;
|
|
8
|
+
}) => string;
|
|
9
|
+
export declare const getCachedGlob: (key: string) => string[] | undefined;
|
|
10
|
+
export declare const setCachedGlob: (key: string, paths: string[], baseDir: string) => void;
|
|
11
|
+
export declare const clearGlobCache: () => void;
|
|
12
|
+
export declare const flushGlobCache: () => void;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { deserialize, serialize } from 'node:v8';
|
|
5
|
+
import { version } from "../version.js";
|
|
6
|
+
import { debugLog } from "./debug.js";
|
|
7
|
+
import { isDirectory, isFile } from "./fs.js";
|
|
8
|
+
import { dirname } from "./path.js";
|
|
9
|
+
const CACHE_FILENAME = `glob-${version}.cache`;
|
|
10
|
+
let cacheFilePath;
|
|
11
|
+
let cache;
|
|
12
|
+
let isDirty = false;
|
|
13
|
+
export const initGlobCache = (cacheLocation) => {
|
|
14
|
+
cacheFilePath = path.resolve(cacheLocation, CACHE_FILENAME);
|
|
15
|
+
if (isFile(cacheFilePath)) {
|
|
16
|
+
try {
|
|
17
|
+
cache = deserialize(fs.readFileSync(cacheFilePath));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
debugLog('*', `Error reading glob cache from ${cacheFilePath}`);
|
|
21
|
+
cache = new Map();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
cache = new Map();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export const isGlobCacheEnabled = () => cache !== undefined;
|
|
29
|
+
export const computeGlobCacheKey = (input) => {
|
|
30
|
+
const h = createHash('sha1');
|
|
31
|
+
h.update(input.cwd);
|
|
32
|
+
h.update('\0');
|
|
33
|
+
h.update(input.dir);
|
|
34
|
+
h.update('\0');
|
|
35
|
+
h.update(input.gitignore ? '1' : '0');
|
|
36
|
+
h.update('\0');
|
|
37
|
+
for (const p of input.patterns) {
|
|
38
|
+
h.update(p);
|
|
39
|
+
h.update('\0');
|
|
40
|
+
}
|
|
41
|
+
return h.digest('base64url');
|
|
42
|
+
};
|
|
43
|
+
const validateEntry = (entry) => {
|
|
44
|
+
for (const dir in entry.dirMtimes) {
|
|
45
|
+
try {
|
|
46
|
+
const stat = fs.statSync(dir);
|
|
47
|
+
if (stat.mtimeMs !== entry.dirMtimes[dir])
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
56
|
+
export const getCachedGlob = (key) => {
|
|
57
|
+
if (!cache)
|
|
58
|
+
return undefined;
|
|
59
|
+
const entry = cache.get(key);
|
|
60
|
+
if (!entry)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (!validateEntry(entry)) {
|
|
63
|
+
cache.delete(key);
|
|
64
|
+
isDirty = true;
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return entry.paths;
|
|
68
|
+
};
|
|
69
|
+
const captureDirMtimes = (paths, baseDir) => {
|
|
70
|
+
const dirs = new Set();
|
|
71
|
+
dirs.add(baseDir);
|
|
72
|
+
for (const p of paths) {
|
|
73
|
+
let d = dirname(p);
|
|
74
|
+
while (d.length >= baseDir.length) {
|
|
75
|
+
if (dirs.has(d))
|
|
76
|
+
break;
|
|
77
|
+
dirs.add(d);
|
|
78
|
+
const parent = dirname(d);
|
|
79
|
+
if (parent === d)
|
|
80
|
+
break;
|
|
81
|
+
d = parent;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const result = {};
|
|
85
|
+
for (const d of dirs) {
|
|
86
|
+
try {
|
|
87
|
+
const stat = fs.statSync(d);
|
|
88
|
+
if (stat.isDirectory())
|
|
89
|
+
result[d] = stat.mtimeMs;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
};
|
|
96
|
+
export const setCachedGlob = (key, paths, baseDir) => {
|
|
97
|
+
if (!cache)
|
|
98
|
+
return;
|
|
99
|
+
cache.set(key, {
|
|
100
|
+
paths,
|
|
101
|
+
dirMtimes: captureDirMtimes(paths, baseDir),
|
|
102
|
+
});
|
|
103
|
+
isDirty = true;
|
|
104
|
+
};
|
|
105
|
+
export const clearGlobCache = () => {
|
|
106
|
+
if (cache) {
|
|
107
|
+
cache.clear();
|
|
108
|
+
isDirty = true;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
export const flushGlobCache = () => {
|
|
112
|
+
if (!cache || !cacheFilePath || !isDirty)
|
|
113
|
+
return;
|
|
114
|
+
try {
|
|
115
|
+
const dir = dirname(cacheFilePath);
|
|
116
|
+
if (!isDirectory(dir))
|
|
117
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
118
|
+
fs.writeFileSync(cacheFilePath, serialize(cache));
|
|
119
|
+
isDirty = false;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
debugLog('*', `Error writing glob cache to ${cacheFilePath}`);
|
|
123
|
+
}
|
|
124
|
+
};
|
package/dist/util/glob.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fg from 'fast-glob';
|
|
2
2
|
import { compact } from "./array.js";
|
|
3
|
+
import { computeGlobCacheKey, getCachedGlob, isGlobCacheEnabled, setCachedGlob } from "./glob-cache.js";
|
|
3
4
|
import { glob } from "./glob-core.js";
|
|
4
5
|
import { timerify } from "./Performance.js";
|
|
5
6
|
import { isAbsolute, join, relative } from "./path.js";
|
|
@@ -24,7 +25,14 @@ const defaultGlob = async ({ cwd, dir = cwd, patterns, gitignore = true, label }
|
|
|
24
25
|
const globPatterns = prependDirToPatterns(cwd, dir, patterns);
|
|
25
26
|
if (globPatterns[0].startsWith('!'))
|
|
26
27
|
return [];
|
|
27
|
-
|
|
28
|
+
const cacheEnabled = isGlobCacheEnabled();
|
|
29
|
+
const cacheKey = cacheEnabled ? computeGlobCacheKey({ patterns: globPatterns, cwd, dir, gitignore }) : '';
|
|
30
|
+
if (cacheEnabled) {
|
|
31
|
+
const cached = getCachedGlob(cacheKey);
|
|
32
|
+
if (cached)
|
|
33
|
+
return cached;
|
|
34
|
+
}
|
|
35
|
+
const paths = await glob(globPatterns, {
|
|
28
36
|
cwd,
|
|
29
37
|
dir,
|
|
30
38
|
gitignore,
|
|
@@ -32,6 +40,9 @@ const defaultGlob = async ({ cwd, dir = cwd, patterns, gitignore = true, label }
|
|
|
32
40
|
dot: true,
|
|
33
41
|
label,
|
|
34
42
|
});
|
|
43
|
+
if (cacheEnabled && paths.length > 0)
|
|
44
|
+
setCachedGlob(cacheKey, paths, dir);
|
|
45
|
+
return paths;
|
|
35
46
|
};
|
|
36
47
|
const syncGlob = ({ cwd, patterns }) => fg.sync(patterns, { cwd, followSymbolicLinks: false });
|
|
37
48
|
const dirGlob = async ({ cwd, patterns, gitignore = true }) => glob(patterns, {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const updateImportMaps = (fromImportMaps, toImportMaps) => {
|
|
2
2
|
for (const id of fromImportMaps.refs)
|
|
3
3
|
toImportMaps.refs.add(id);
|
|
4
|
+
if (fromImportMaps.enumerated) {
|
|
5
|
+
if (!toImportMaps.enumerated)
|
|
6
|
+
toImportMaps.enumerated = new Set();
|
|
7
|
+
for (const id of fromImportMaps.enumerated)
|
|
8
|
+
toImportMaps.enumerated.add(id);
|
|
9
|
+
}
|
|
4
10
|
for (const [id, v] of fromImportMaps.import)
|
|
5
11
|
addValues(toImportMaps.import, id, v);
|
|
6
12
|
for (const [id, v] of fromImportMaps.importAs)
|
|
@@ -46,6 +52,7 @@ export const createFileNode = () => ({
|
|
|
46
52
|
});
|
|
47
53
|
export const createImports = () => ({
|
|
48
54
|
refs: new Set(),
|
|
55
|
+
enumerated: undefined,
|
|
49
56
|
import: new Map(),
|
|
50
57
|
importAs: new Map(),
|
|
51
58
|
importNs: new Map(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const extractPatternExtensions: (pattern: string) => string[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const TRAILING_BRACE_RE = /\.\{([^{}]+)\}$/;
|
|
2
|
+
const TRAILING_PAREN_RE = /\.[@+*?]?\(([^()]+)\)$/;
|
|
3
|
+
const TRAILING_LITERAL_RE = /\.([a-zA-Z0-9]+)$/;
|
|
4
|
+
const SIMPLE_EXT_RE = /^[a-zA-Z0-9]+$/;
|
|
5
|
+
const collectExtensions = (inner, delim) => {
|
|
6
|
+
const parts = inner.split(delim);
|
|
7
|
+
const exts = [];
|
|
8
|
+
for (let i = 0; i < parts.length; i++) {
|
|
9
|
+
const t = parts[i].trim();
|
|
10
|
+
if (SIMPLE_EXT_RE.test(t))
|
|
11
|
+
exts.push(`.${t}`);
|
|
12
|
+
}
|
|
13
|
+
return exts;
|
|
14
|
+
};
|
|
15
|
+
export const extractPatternExtensions = (pattern) => {
|
|
16
|
+
const end = pattern.endsWith('!') ? pattern.length - 1 : pattern.length;
|
|
17
|
+
const slashIdx = pattern.lastIndexOf('/', end - 1);
|
|
18
|
+
const segment = pattern.slice(slashIdx + 1, end);
|
|
19
|
+
if (segment.length === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const last = segment[segment.length - 1];
|
|
22
|
+
if (last === '}') {
|
|
23
|
+
const m = TRAILING_BRACE_RE.exec(segment);
|
|
24
|
+
return m ? collectExtensions(m[1], ',') : [];
|
|
25
|
+
}
|
|
26
|
+
if (last === ')') {
|
|
27
|
+
const m = TRAILING_PAREN_RE.exec(segment);
|
|
28
|
+
return m ? collectExtensions(m[1], '|') : [];
|
|
29
|
+
}
|
|
30
|
+
const m = TRAILING_LITERAL_RE.exec(segment);
|
|
31
|
+
return m ? [`.${m[1]}`] : [];
|
|
32
|
+
};
|
package/dist/util/watch.js
CHANGED
|
@@ -4,6 +4,8 @@ import { debugLog } from "./debug.js";
|
|
|
4
4
|
import { isFile } from "./fs.js";
|
|
5
5
|
import { updateImportMap } from "./module-graph.js";
|
|
6
6
|
import { toAbsolute, toPosix, toRelative } from "./path.js";
|
|
7
|
+
import { clearModuleResolutionCaches } from "../typescript/resolve-module-names.js";
|
|
8
|
+
import { clearGlobCache } from "./glob-cache.js";
|
|
7
9
|
import { clearResolverCache } from "./resolve.js";
|
|
8
10
|
const createUpdate = (options) => {
|
|
9
11
|
const duration = performance.now() - options.startTime;
|
|
@@ -56,6 +58,8 @@ export const getSessionHandler = async (options, { analyzedFiles, analyzeSourceF
|
|
|
56
58
|
if (added.size === 0 && deleted.size === 0 && modified.size === 0)
|
|
57
59
|
return;
|
|
58
60
|
clearResolverCache();
|
|
61
|
+
clearModuleResolutionCaches();
|
|
62
|
+
clearGlobCache();
|
|
59
63
|
invalidateCache(graph);
|
|
60
64
|
unreferencedFiles.clear();
|
|
61
65
|
const cachedUnusedFiles = collector.purge();
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "6.
|
|
1
|
+
export declare const version = "6.4.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '6.
|
|
1
|
+
export const version = '6.4.1';
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -632,6 +632,10 @@
|
|
|
632
632
|
"title": "oxlint plugin configuration (https://knip.dev/reference/plugins/oxlint)",
|
|
633
633
|
"$ref": "#/definitions/plugin"
|
|
634
634
|
},
|
|
635
|
+
"panda-css": {
|
|
636
|
+
"title": "panda-css plugin configuration (https://knip.dev/reference/plugins/panda-css)",
|
|
637
|
+
"$ref": "#/definitions/plugin"
|
|
638
|
+
},
|
|
635
639
|
"payload": {
|
|
636
640
|
"title": "payload plugin configuration (https://knip.dev/reference/plugins/payload)",
|
|
637
641
|
"$ref": "#/definitions/plugin"
|