knip 6.3.0 → 6.4.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.
Files changed (53) hide show
  1. package/LICENSE +15 -0
  2. package/dist/ConfigurationChief.d.ts +6 -0
  3. package/dist/DependencyDeputy.js +6 -12
  4. package/dist/ProjectPrincipal.d.ts +2 -2
  5. package/dist/ProjectPrincipal.js +32 -13
  6. package/dist/WorkspaceWorker.d.ts +1 -1
  7. package/dist/WorkspaceWorker.js +19 -2
  8. package/dist/compilers/index.d.ts +10 -0
  9. package/dist/compilers/scss.js +22 -16
  10. package/dist/graph/analyze.js +2 -0
  11. package/dist/graph/build.d.ts +2 -2
  12. package/dist/graph/build.js +5 -5
  13. package/dist/plugins/index.d.ts +1 -0
  14. package/dist/plugins/index.js +2 -0
  15. package/dist/plugins/panda-css/index.d.ts +3 -0
  16. package/dist/plugins/panda-css/index.js +18 -0
  17. package/dist/plugins/panda-css/types.d.ts +3 -0
  18. package/dist/plugins/panda-css/types.js +1 -0
  19. package/dist/plugins/react-router/index.js +1 -1
  20. package/dist/plugins/tailwind/index.js +2 -2
  21. package/dist/plugins/webpack/index.js +21 -1
  22. package/dist/reporters/util/configuration-hints.js +5 -0
  23. package/dist/run.js +5 -0
  24. package/dist/schema/configuration.d.ts +15 -0
  25. package/dist/schema/plugins.d.ts +5 -0
  26. package/dist/schema/plugins.js +1 -0
  27. package/dist/types/PluginNames.d.ts +2 -2
  28. package/dist/types/PluginNames.js +1 -0
  29. package/dist/types/issues.d.ts +1 -1
  30. package/dist/types/module-graph.d.ts +1 -0
  31. package/dist/typescript/comments.d.ts +4 -0
  32. package/dist/typescript/comments.js +64 -0
  33. package/dist/typescript/get-imports-and-exports.js +23 -46
  34. package/dist/typescript/resolve-module-names.d.ts +1 -0
  35. package/dist/typescript/resolve-module-names.js +22 -0
  36. package/dist/typescript/visitors/calls.js +75 -2
  37. package/dist/typescript/visitors/imports.js +12 -8
  38. package/dist/typescript/visitors/members.js +4 -3
  39. package/dist/typescript/visitors/walk.d.ts +6 -2
  40. package/dist/typescript/visitors/walk.js +5 -5
  41. package/dist/util/create-options.d.ts +10 -0
  42. package/dist/util/file-entry-cache.js +10 -3
  43. package/dist/util/glob-cache.d.ts +12 -0
  44. package/dist/util/glob-cache.js +124 -0
  45. package/dist/util/glob.js +12 -1
  46. package/dist/util/module-graph.js +7 -0
  47. package/dist/util/pattern-extensions.d.ts +1 -0
  48. package/dist/util/pattern-extensions.js +32 -0
  49. package/dist/util/watch.js +4 -0
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +1 -1
  52. package/package.json +2 -2
  53. package/schema.json +4 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License (ISC)
2
+
3
+ Copyright 2022-2025 Lars Kappert
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose
6
+ with or without fee is hereby granted, provided that the above copyright notice
7
+ and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
13
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
14
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
15
+ THIS SOFTWARE.
@@ -422,6 +422,11 @@ export declare class ConfigurationChief {
422
422
  entry?: string | string[] | undefined;
423
423
  project?: string | string[] | undefined;
424
424
  } | undefined;
425
+ 'panda-css'?: string | boolean | string[] | {
426
+ config?: string | string[] | undefined;
427
+ entry?: string | string[] | undefined;
428
+ project?: string | string[] | undefined;
429
+ } | undefined;
425
430
  parcel?: string | boolean | string[] | {
426
431
  config?: string | string[] | undefined;
427
432
  entry?: string | string[] | undefined;
@@ -865,6 +870,7 @@ export declare class ConfigurationChief {
865
870
  "openapi-ts"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
866
871
  oxfmt?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
867
872
  oxlint?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
873
+ "panda-css"?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
868
874
  parcel?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
869
875
  payload?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
870
876
  playwright?: (boolean | import("./types/config.ts").EnsuredPluginConfiguration) | undefined;
@@ -187,12 +187,12 @@ export class DependencyDeputy {
187
187
  const referencedDependencies = this.referencedDependencies.get(workspace);
188
188
  const hasTypesIncluded = this.getHasTypesIncluded(workspace);
189
189
  const peeker = new PackagePeeker(manifestStr);
190
- const peerDepCount = {};
191
- const isReferencedDependency = (dependency, isPeerDep) => {
190
+ const isReferencedDependency = (dependency, visited = new Set()) => {
192
191
  if (referencedDependencies?.has(dependency))
193
192
  return true;
194
- if (isPeerDep && peerDepCount[dependency])
193
+ if (visited.has(dependency))
195
194
  return false;
195
+ visited.add(dependency);
196
196
  const [scope, typedDependency] = dependency.split('/');
197
197
  if (scope === DT_SCOPE) {
198
198
  const typedPackageName = getPackageFromDefinitelyTyped(typedDependency);
@@ -205,21 +205,15 @@ export class DependencyDeputy {
205
205
  ...this.getHostDependenciesFor(workspace, typedPackageName),
206
206
  ];
207
207
  if (hostDependencies.length)
208
- return !!hostDependencies.find(host => isReferencedDependency(host.name, true));
208
+ return !!hostDependencies.find(host => isReferencedDependency(host.name, visited));
209
209
  if (!referencedDependencies?.has(dependency))
210
210
  return false;
211
211
  return referencedDependencies.has(typedPackageName);
212
212
  }
213
213
  const hostDependencies = this.getHostDependenciesFor(workspace, dependency);
214
- for (const { name } of hostDependencies) {
215
- if (!peerDepCount[name])
216
- peerDepCount[name] = 1;
217
- else
218
- peerDepCount[name]++;
219
- }
220
- return hostDependencies.some(hostDependency => (isPeerDep === false || !hostDependency.isPeerOptional) && isReferencedDependency(hostDependency.name, true));
214
+ return hostDependencies.some(hostDependency => isReferencedDependency(hostDependency.name, visited));
221
215
  };
222
- const isNotReferencedDependency = (dependency) => !isReferencedDependency(dependency, false);
216
+ const isNotReferencedDependency = (dependency) => !isReferencedDependency(dependency);
223
217
  for (const symbol of this.getProductionDependencies(workspace).filter(isNotReferencedDependency)) {
224
218
  const position = peeker.getLocation('dependencies', symbol);
225
219
  dependencyIssues.push({ type: 'dependencies', workspace, filePath, symbol, fixes: [], ...position });
@@ -43,11 +43,11 @@ export declare class ProjectPrincipal {
43
43
  addProjectPath(filePath: string): void;
44
44
  removeProjectPath(filePath: string): void;
45
45
  runAsyncCompilers(): Promise<void>;
46
- walkAndAnalyze(analyzeFile: (filePath: string, parseResult: ParseResult | undefined, sourceText: string) => Iterable<string> | undefined): void;
46
+ walkAndAnalyze(analyzeFile: (filePath: string, parseResult: ParseResult | undefined, sourceText: string, cachedFile?: FileNode) => Iterable<string> | undefined): void;
47
47
  getUsedResolvedFiles(): string[];
48
48
  private resolveSpecifier;
49
49
  getUnreferencedFiles(): string[];
50
- analyzeSourceFile(filePath: string, options: GetImportsAndExportsOptions, ignoreExportsUsedInFile: IgnoreExportsUsedInFile, parseResult?: ParseResult, sourceText?: string): FileNode;
50
+ analyzeSourceFile(filePath: string, options: GetImportsAndExportsOptions, ignoreExportsUsedInFile: IgnoreExportsUsedInFile, parseResult?: ParseResult, sourceText?: string, cachedFile?: FileNode): FileNode;
51
51
  invalidateFile(filePath: string): void;
52
52
  reconcileCache(graph: ModuleGraph): void;
53
53
  }
@@ -134,22 +134,46 @@ export class ProjectPrincipal {
134
134
  const visited = new Set([...this.entryPaths, ...this.programPaths]);
135
135
  let lastEntrySize = this.entryPaths.size;
136
136
  let lastProgramSize = this.programPaths.size;
137
+ const rescanFrontier = () => {
138
+ if (this.entryPaths.size > lastEntrySize || this.programPaths.size > lastProgramSize) {
139
+ for (const p of this.entryPaths)
140
+ visited.add(p);
141
+ for (const p of this.programPaths)
142
+ visited.add(p);
143
+ lastEntrySize = this.entryPaths.size;
144
+ lastProgramSize = this.programPaths.size;
145
+ }
146
+ };
137
147
  for (const filePath of visited) {
148
+ const isProjectPath = this.projectPaths.has(filePath);
149
+ let cachedFile;
150
+ if (isProjectPath) {
151
+ const fd = this.cache.getFileDescriptor(filePath);
152
+ if (!fd.changed && fd.meta?.data)
153
+ cachedFile = fd.meta.data;
154
+ }
155
+ if (cachedFile) {
156
+ const internalPaths = analyzeFile(filePath, undefined, '', cachedFile);
157
+ if (internalPaths)
158
+ for (const p of internalPaths)
159
+ visited.add(p);
160
+ rescanFrontier();
161
+ continue;
162
+ }
138
163
  const sourceText = this.fileManager.readFile(filePath);
139
164
  if (!sourceText) {
140
- if (this.projectPaths.has(filePath))
165
+ if (isProjectPath)
141
166
  analyzeFile(filePath, undefined, '');
142
167
  continue;
143
168
  }
144
169
  try {
145
170
  const result = parseFile(filePath, sourceText);
146
171
  this.fileManager.sourceTextCache.delete(filePath);
147
- if (this.projectPaths.has(filePath)) {
172
+ if (isProjectPath) {
148
173
  const internalPaths = analyzeFile(filePath, result, sourceText);
149
- if (internalPaths) {
174
+ if (internalPaths)
150
175
  for (const p of internalPaths)
151
176
  visited.add(p);
152
- }
153
177
  }
154
178
  else {
155
179
  for (const specifier of extractSpecifiers(result, sourceText, filePath)) {
@@ -158,14 +182,7 @@ export class ProjectPrincipal {
158
182
  visited.add(resolved);
159
183
  }
160
184
  }
161
- if (this.entryPaths.size > lastEntrySize || this.programPaths.size > lastProgramSize) {
162
- for (const p of this.entryPaths)
163
- visited.add(p);
164
- for (const p of this.programPaths)
165
- visited.add(p);
166
- lastEntrySize = this.entryPaths.size;
167
- lastProgramSize = this.programPaths.size;
168
- }
185
+ rescanFrontier();
169
186
  }
170
187
  catch {
171
188
  }
@@ -199,7 +216,9 @@ export class ProjectPrincipal {
199
216
  getUnreferencedFiles() {
200
217
  return Array.from(this.projectPaths).filter(filePath => !this.resolvedFiles.has(filePath));
201
218
  }
202
- analyzeSourceFile(filePath, options, ignoreExportsUsedInFile, parseResult, sourceText) {
219
+ analyzeSourceFile(filePath, options, ignoreExportsUsedInFile, parseResult, sourceText, cachedFile) {
220
+ if (cachedFile)
221
+ return cachedFile;
203
222
  const fd = this.cache.getFileDescriptor(filePath);
204
223
  if (!fd.changed && fd.meta?.data)
205
224
  return fd.meta.data;
@@ -63,7 +63,7 @@ export declare class WorkspaceWorker {
63
63
  registerVisitors(options: RegisterVisitorsOptions): void;
64
64
  runPlugins(): Promise<Input[]>;
65
65
  private filterTransitiveDependencies;
66
- getConfigurationHints(type: 'entry' | 'project', patterns: string[], filePaths: string[], includedPaths: Set<string>): ConfigurationHint[];
66
+ getConfigurationHints(type: 'entry' | 'project', patterns: string[], filePaths: string[], includedPaths: Set<string>, compilerExtensions?: Set<string>): ConfigurationHint[];
67
67
  onDispose(): void;
68
68
  }
69
69
  export {};
@@ -2,7 +2,7 @@ import picomatch from 'picomatch';
2
2
  import { _getInputsFromScripts } from "./binaries/index.js";
3
3
  import { CacheConsultant } from "./CacheConsultant.js";
4
4
  import { isDefaultPattern } from "./ConfigurationChief.js";
5
- import { ROOT_WORKSPACE_NAME } from "./constants.js";
5
+ import { DEFAULT_EXTENSIONS, ROOT_WORKSPACE_NAME } from "./constants.js";
6
6
  import { getFilteredScripts } from "./manifest/helpers.js";
7
7
  import { PluginEntries, Plugins } from "./plugins.js";
8
8
  import { collectStringLiterals, isExternalReExportsOnly } from "./typescript/ast-helpers.js";
@@ -15,6 +15,7 @@ import { getPackageNameFromSpecifier } from "./util/modules.js";
15
15
  import { getKeysByValue } from "./util/object.js";
16
16
  import { timerify } from "./util/Performance.js";
17
17
  import { basename, dirname, isInternal, join } from "./util/path.js";
18
+ import { extractPatternExtensions } from "./util/pattern-extensions.js";
18
19
  import { loadConfigForPlugin } from "./util/plugin.js";
19
20
  import { ELLIPSIS } from "./util/string.js";
20
21
  const nullConfig = { config: null, entry: null, project: null };
@@ -403,7 +404,7 @@ export class WorkspaceWorker {
403
404
  }
404
405
  }
405
406
  }
406
- getConfigurationHints(type, patterns, filePaths, includedPaths) {
407
+ getConfigurationHints(type, patterns, filePaths, includedPaths, compilerExtensions) {
407
408
  const hints = [];
408
409
  const entries = this.config[type].filter(pattern => !pattern.startsWith('!'));
409
410
  const workspaceName = this.name;
@@ -429,6 +430,22 @@ export class WorkspaceWorker {
429
430
  }
430
431
  }
431
432
  }
433
+ if (type === 'project' && compilerExtensions) {
434
+ const seen = new Set();
435
+ for (const pattern of userDefinedPatterns) {
436
+ for (const ext of extractPatternExtensions(pattern)) {
437
+ if (seen.has(ext) || DEFAULT_EXTENSIONS.has(ext))
438
+ continue;
439
+ seen.add(ext);
440
+ if (compilerExtensions.has(ext)) {
441
+ hints.push({ type: 'project-extension-redundant', identifier: ext, workspaceName });
442
+ }
443
+ else {
444
+ hints.push({ type: 'project-extension-unregistered', identifier: ext, workspaceName });
445
+ }
446
+ }
447
+ }
448
+ }
432
449
  return hints;
433
450
  }
434
451
  onDispose() {
@@ -370,6 +370,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
370
370
  entry?: string | string[] | undefined;
371
371
  project?: string | string[] | undefined;
372
372
  } | undefined;
373
+ 'panda-css'?: string | boolean | string[] | {
374
+ config?: string | string[] | undefined;
375
+ entry?: string | string[] | undefined;
376
+ project?: string | string[] | undefined;
377
+ } | undefined;
373
378
  parcel?: string | boolean | string[] | {
374
379
  config?: string | string[] | undefined;
375
380
  entry?: string | string[] | undefined;
@@ -1086,6 +1091,11 @@ export declare const partitionCompilers: (rawLocalConfig: RawConfiguration) => {
1086
1091
  entry?: string | string[] | undefined;
1087
1092
  project?: string | string[] | undefined;
1088
1093
  } | undefined;
1094
+ 'panda-css'?: string | boolean | string[] | {
1095
+ config?: string | string[] | undefined;
1096
+ entry?: string | string[] | undefined;
1097
+ project?: string | string[] | undefined;
1098
+ } | undefined;
1089
1099
  parcel?: string | boolean | string[] | {
1090
1100
  config?: string | string[] | undefined;
1091
1101
  entry?: string | string[] | undefined;
@@ -1,20 +1,26 @@
1
- import { existsSync } from 'node:fs';
2
- import { basename, dirname, join } from "../util/path.js";
1
+ import { basename, dirname } from "../util/path.js";
3
2
  const condition = (hasDependency) => hasDependency('sass') || hasDependency('sass-embedded') || hasDependency('node-sass');
4
3
  const importMatcher = /@(?:use|import|forward)\s+['"](pkg:)?([^'"]+)['"]/g;
5
- const resolvePartial = (specifier, containingFile) => {
6
- const rel = specifier.startsWith('.') ? specifier : `./${specifier}`;
7
- const name = basename(rel);
8
- if (name.startsWith('_'))
9
- return rel;
10
- const dir = dirname(rel);
11
- const partial = name.endsWith('.scss') ? `_${name}` : `_${name}.scss`;
12
- if (existsSync(join(dirname(containingFile), dir, partial)))
13
- return `${dir}/_${name}`;
14
- return rel;
4
+ const isAlias = (s) => (s.charCodeAt(0) === 64 && s.charCodeAt(1) === 47) || s.charCodeAt(0) === 126 || s.charCodeAt(0) === 35;
5
+ const candidates = (specifier) => {
6
+ const spec = specifier.startsWith('.') || isAlias(specifier) ? specifier : `./${specifier}`;
7
+ const name = basename(spec);
8
+ const dir = dirname(spec);
9
+ const base = name.endsWith('.scss') || name.endsWith('.sass') ? name : `${name}.scss`;
10
+ const plain = `${dir}/${base}`;
11
+ return name.startsWith('_') ? [plain] : [plain, `${dir}/_${base}`];
12
+ };
13
+ const compiler = text => {
14
+ const out = [];
15
+ let i = 0;
16
+ for (const match of text.matchAll(importMatcher)) {
17
+ const spec = match[2];
18
+ if (!spec || spec.startsWith('sass:'))
19
+ continue;
20
+ const specs = match[1] ? [spec] : candidates(spec);
21
+ for (const s of specs)
22
+ out.push(`import _$${i++} from '${s}';`);
23
+ }
24
+ return out.join('\n');
15
25
  };
16
- const compiler = (text, filePath) => [...text.matchAll(importMatcher)]
17
- .filter(match => match[2] && !match[2].startsWith('sass:'))
18
- .map((match, i) => `import _$${i} from '${match[1] ? match[2] : resolvePartial(match[2], filePath)}';`)
19
- .join('\n');
20
26
  export default { condition, compiler };
@@ -81,6 +81,8 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
81
81
  exportedItem.members.length > 0 &&
82
82
  exportedItem.type !== 'enum';
83
83
  if ((isEnumMembers || isNsMembers) && exportedItem.members.length > 0) {
84
+ if (importsForExport.enumerated?.has(identifier))
85
+ continue;
84
86
  if (!options.includedIssueTypes.nsTypes && importsForExport.refs.has(identifier))
85
87
  continue;
86
88
  if (isEnumMembers && hasStrictlyEnumReferences(importsForExport, identifier))
@@ -4,7 +4,7 @@ import type { ConsoleStreamer } from '../ConsoleStreamer.ts';
4
4
  import type { DependencyDeputy } from '../DependencyDeputy.ts';
5
5
  import type { IssueCollector } from '../IssueCollector.ts';
6
6
  import type { ProjectPrincipal } from '../ProjectPrincipal.ts';
7
- import type { ModuleGraph } from '../types/module-graph.ts';
7
+ import type { FileNode, ModuleGraph } from '../types/module-graph.ts';
8
8
  import type { MainOptions } from '../util/create-options.ts';
9
9
  interface BuildOptions {
10
10
  chief: ConfigurationChief;
@@ -22,7 +22,7 @@ export declare function build({ chief, collector, counselor, deputy, principal,
22
22
  entryPaths: Set<string>;
23
23
  analyzedFiles: Set<string>;
24
24
  unreferencedFiles: Set<string>;
25
- analyzeSourceFile: (filePath: string, pp: ProjectPrincipal, parseResult?: import("oxc-parser").ParseResult, sourceText?: string) => void;
25
+ analyzeSourceFile: (filePath: string, pp: ProjectPrincipal, parseResult?: import("oxc-parser").ParseResult, sourceText?: string, cachedFile?: FileNode) => void;
26
26
  enabledPluginsStore: Map<string, string[]>;
27
27
  }>;
28
28
  export {};
@@ -250,7 +250,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
250
250
  ]);
251
251
  const projectPaths = await _glob({ ...sharedGlobOptions, patterns, label: 'project paths' });
252
252
  if (!options.isProduction) {
253
- const hints = worker.getConfigurationHints('project', config.project, projectPaths, principal.projectPaths);
253
+ const hints = worker.getConfigurationHints('project', config.project, projectPaths, principal.projectPaths, new Set(extensions));
254
254
  for (const hint of hints)
255
255
  collector.addConfigurationHint(hint);
256
256
  }
@@ -273,13 +273,13 @@ export async function build({ chief, collector, counselor, deputy, principal, is
273
273
  skipTypeOnly: options.isStrict,
274
274
  tags: options.tags,
275
275
  };
276
- const analyzeSourceFile = (filePath, pp, parseResult, sourceText) => {
276
+ const analyzeSourceFile = (filePath, pp, parseResult, sourceText, cachedFile) => {
277
277
  if (!options.isWatch && !options.isSession && analyzedFiles.has(filePath))
278
278
  return;
279
279
  analyzedFiles.add(filePath);
280
280
  const workspace = chief.findWorkspaceByFilePath(filePath);
281
281
  if (workspace) {
282
- const file = pp.analyzeSourceFile(filePath, analyzeOpts, chief.config.ignoreExportsUsedInFile, parseResult, sourceText);
282
+ const file = pp.analyzeSourceFile(filePath, analyzeOpts, chief.config.ignoreExportsUsedInFile, parseResult, sourceText, cachedFile);
283
283
  const unresolvedImports = new Set();
284
284
  for (const unresolvedImport of file.imports.unresolved) {
285
285
  const { specifier } = unresolvedImport;
@@ -370,8 +370,8 @@ export async function build({ chief, collector, counselor, deputy, principal, is
370
370
  await principal.runAsyncCompilers();
371
371
  }
372
372
  streamer.cast('Analyzing source files');
373
- principal.walkAndAnalyze((filePath, parseResult, sourceText) => {
374
- analyzeSourceFile(filePath, principal, parseResult, sourceText);
373
+ principal.walkAndAnalyze((filePath, parseResult, sourceText, cachedFile) => {
374
+ analyzeSourceFile(filePath, principal, parseResult, sourceText, cachedFile);
375
375
  const node = graph.get(filePath);
376
376
  if (!node)
377
377
  return;
@@ -77,6 +77,7 @@ export declare const Plugins: {
77
77
  'openapi-ts': import("../types/config.ts").Plugin;
78
78
  oxfmt: import("../types/config.ts").Plugin;
79
79
  oxlint: import("../types/config.ts").Plugin;
80
+ 'panda-css': import("../types/config.ts").Plugin;
80
81
  parcel: import("../types/config.ts").Plugin;
81
82
  payload: import("../types/config.ts").Plugin;
82
83
  playwright: import("../types/config.ts").Plugin;
@@ -71,6 +71,7 @@ import { default as oclif } from "./oclif/index.js";
71
71
  import { default as openapiTs } from "./openapi-ts/index.js";
72
72
  import { default as oxfmt } from "./oxfmt/index.js";
73
73
  import { default as oxlint } from "./oxlint/index.js";
74
+ import { default as pandaCss } from "./panda-css/index.js";
74
75
  import { default as parcel } from "./parcel/index.js";
75
76
  import { default as payload } from "./payload/index.js";
76
77
  import { default as playwright } from "./playwright/index.js";
@@ -215,6 +216,7 @@ export const Plugins = {
215
216
  'openapi-ts': openapiTs,
216
217
  oxfmt,
217
218
  oxlint,
219
+ 'panda-css': pandaCss,
218
220
  parcel,
219
221
  payload,
220
222
  playwright,
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../../types/config.ts';
2
+ declare const plugin: Plugin;
3
+ export default plugin;
@@ -0,0 +1,18 @@
1
+ import { toDeferResolve, toDependency } from "../../util/input.js";
2
+ import { hasDependency } from "../../util/plugin.js";
3
+ const title = 'Panda CSS';
4
+ const enablers = ['@pandacss/dev'];
5
+ const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
+ const config = ['panda.config.{ts,js,mjs,cjs,mts,cts}'];
7
+ const resolveConfig = config => {
8
+ const presets = (config.presets ?? []).filter((preset) => typeof preset === 'string');
9
+ return [...presets.map(id => toDeferResolve(id)), toDependency('postcss')];
10
+ };
11
+ const plugin = {
12
+ title,
13
+ enablers,
14
+ isEnabled,
15
+ config,
16
+ resolveConfig,
17
+ };
18
+ export default plugin;
@@ -0,0 +1,3 @@
1
+ export type PandaCSSConfig = {
2
+ presets?: (string | Record<string, unknown>)[];
3
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -26,7 +26,7 @@ const resolveConfig = async (localConfig, options) => {
26
26
  routeConfig = await load(routesPathJs);
27
27
  }
28
28
  const mapRoute = (route) => {
29
- return [join(appDir, route.file), ...(route.children ? route.children.flatMap(mapRoute) : [])];
29
+ return [toAbsolute(route.file, appDir), ...(route.children ? route.children.flatMap(mapRoute) : [])];
30
30
  };
31
31
  const routes = routeConfig
32
32
  .flatMap(mapRoute)
@@ -1,11 +1,11 @@
1
1
  import { hasDependency } from "../../util/plugin.js";
2
2
  import compiler from "./compiler.js";
3
3
  const title = 'Tailwind';
4
- const enablers = ['tailwindcss'];
4
+ const enablers = ['tailwindcss', '@tailwindcss/vite', '@tailwindcss/postcss', '@tailwindcss/cli'];
5
5
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
6
6
  const entry = ['tailwind.config.{js,cjs,mjs,ts}'];
7
7
  const registerCompilers = ({ registerCompiler, hasDependency }) => {
8
- if (hasDependency('tailwindcss'))
8
+ if (enablers.some(enabler => hasDependency(enabler)))
9
9
  registerCompiler({ extension: '.css', compiler });
10
10
  };
11
11
  const plugin = {
@@ -13,6 +13,11 @@ const hasBabelOptions = (use) => Boolean(use) &&
13
13
  typeof use.loader === 'string' &&
14
14
  use.loader === 'babel-loader' &&
15
15
  typeof use.options === 'object';
16
+ const hasLoaderOptions = (use) => Boolean(use) &&
17
+ typeof use !== 'string' &&
18
+ 'loader' in use &&
19
+ typeof use.loader === 'string' &&
20
+ typeof use.options === 'object';
16
21
  const info = {
17
22
  compiler: '',
18
23
  issuer: '',
@@ -47,13 +52,28 @@ const resolveRuleSetDependencies = (rule) => {
47
52
  return resolveUseItem(item);
48
53
  });
49
54
  };
55
+ const isSwcLoader = (loader) => loader === 'builtin:swc-loader' || loader.endsWith('/swc-loader') || loader === 'swc-loader';
56
+ const resolveSwcPluginDependencies = (use) => {
57
+ if (!hasLoaderOptions(use) || !isSwcLoader(use.loader))
58
+ return [];
59
+ const plugins = use.options.jsc?.experimental?.plugins;
60
+ if (!Array.isArray(plugins))
61
+ return [];
62
+ return plugins.flatMap(plugin => {
63
+ if (typeof plugin === 'string')
64
+ return [plugin];
65
+ if (Array.isArray(plugin) && typeof plugin[0] === 'string')
66
+ return [plugin[0]];
67
+ return [];
68
+ });
69
+ };
50
70
  const resolveUseItem = (use) => {
51
71
  if (!use)
52
72
  return [];
53
73
  if (typeof use === 'string')
54
74
  return [use];
55
75
  if ('loader' in use && typeof use.loader === 'string')
56
- return [use.loader];
76
+ return [use.loader, ...resolveSwcPluginDependencies(use)];
57
77
  return [];
58
78
  };
59
79
  export const findWebpackDependenciesFromConfig = async (config, options) => {
@@ -39,6 +39,8 @@ const addWorkspace = (options) => options.configFilePath
39
39
  ? `Add ${bright('entry')} and/or refine ${bright('project')} files in ${bright(`workspaces["${options.workspaceName}"]`)} (${options.size} unused files)`
40
40
  : `Create ${bright('knip.json')} configuration file with ${bright(`workspaces["${options.workspaceName}"]`)} object (${options.size} unused files)`;
41
41
  const packageEntry = () => 'Package entry file not found';
42
+ const extensionUnregistered = () => `Extension in ${bright('project')} not registered as a compiler — see https://knip.dev/features/compilers#tracking-non-source-files`;
43
+ const extensionRedundant = () => `Extension already registered as a compiler — remove from ${bright('project')} pattern`;
42
44
  const hintPrinters = new Map([
43
45
  ['ignore', { print: unused }],
44
46
  ['ignoreFiles', { print: unused }],
@@ -48,6 +50,8 @@ const hintPrinters = new Map([
48
50
  ['ignoreWorkspaces', { print: unused }],
49
51
  ['entry-empty', { print: empty }],
50
52
  ['project-empty', { print: empty }],
53
+ ['project-extension-unregistered', { print: extensionUnregistered }],
54
+ ['project-extension-redundant', { print: extensionRedundant }],
51
55
  ['entry-redundant', { print: remove }],
52
56
  ['project-redundant', { print: remove }],
53
57
  ['top-level-unconfigured', { print: add }],
@@ -66,6 +70,7 @@ const hintTypesOrder = [
66
70
  ['ignoreBinaries'],
67
71
  ['ignoreUnresolved'],
68
72
  ['entry-empty', 'project-empty', 'entry-redundant', 'project-redundant'],
73
+ ['project-extension-unregistered', 'project-extension-redundant'],
69
74
  ['package-entry'],
70
75
  ];
71
76
  export const finalizeConfigurationHints = (results, options) => {
package/dist/run.js CHANGED
@@ -9,12 +9,15 @@ import { IssueCollector } from "./IssueCollector.js";
9
9
  import { ProjectPrincipal } from "./ProjectPrincipal.js";
10
10
  import watchReporter from "./reporters/watch.js";
11
11
  import { debugLogObject } from "./util/debug.js";
12
+ import { flushGlobCache, initGlobCache } from "./util/glob-cache.js";
12
13
  import { getGitIgnoredHandler } from "./util/glob-core.js";
13
14
  import { getModuleSourcePathHandler } from "./util/to-source-path.js";
14
15
  import { getSessionHandler } from "./util/watch.js";
15
16
  export const run = async (options) => {
16
17
  debugLogObject('*', 'Unresolved configuration', options);
17
18
  debugLogObject('*', 'Included issue types', options.includedIssueTypes);
19
+ if (options.isCache)
20
+ initGlobCache(options.cacheLocation);
18
21
  const chief = new ConfigurationChief(options);
19
22
  const deputy = new DependencyDeputy(options);
20
23
  const streamer = new ConsoleStreamer(options);
@@ -79,6 +82,8 @@ export const run = async (options) => {
79
82
  const { issues, counters, tagHints, configurationHints } = collector.getIssues();
80
83
  if (!options.isWatch)
81
84
  streamer.clear();
85
+ if (options.isCache)
86
+ flushGlobCache();
82
87
  return {
83
88
  results: {
84
89
  issues,
@@ -367,6 +367,11 @@ export declare const workspaceConfigurationSchema: z.ZodMiniObject<{
367
367
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
368
368
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
369
369
  }, z.core.$strip>]>>;
370
+ 'panda-css': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
371
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
372
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
373
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
374
+ }, z.core.$strip>]>>;
370
375
  parcel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
371
376
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
372
377
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -1094,6 +1099,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
1094
1099
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1095
1100
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1096
1101
  }, z.core.$strip>]>>;
1102
+ 'panda-css': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1103
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1104
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1105
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1106
+ }, z.core.$strip>]>>;
1097
1107
  parcel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1098
1108
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1099
1109
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -1810,6 +1820,11 @@ export declare const knipConfigurationSchema: z.ZodMiniObject<{
1810
1820
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1811
1821
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1812
1822
  }, z.core.$strip>]>>;
1823
+ 'panda-css': z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1824
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1825
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1826
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1827
+ }, z.core.$strip>]>>;
1813
1828
  parcel: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
1814
1829
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
1815
1830
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -371,6 +371,11 @@ export declare const pluginsSchema: z.ZodMiniObject<{
371
371
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
372
372
  project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
373
373
  }, z.core.$strip>]>;
374
+ 'panda-css': z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
375
+ config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
376
+ entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
377
+ project: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
378
+ }, z.core.$strip>]>;
374
379
  parcel: z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>, z.ZodMiniObject<{
375
380
  config: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
376
381
  entry: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniString<string>>]>>;
@@ -83,6 +83,7 @@ export const pluginsSchema = z.object({
83
83
  'openapi-ts': pluginSchema,
84
84
  oxfmt: pluginSchema,
85
85
  oxlint: pluginSchema,
86
+ 'panda-css': pluginSchema,
86
87
  parcel: pluginSchema,
87
88
  payload: pluginSchema,
88
89
  playwright: pluginSchema,