@savvy-web/lint-staged 0.8.0 → 1.0.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.
package/index.js CHANGED
@@ -1,60 +1,7 @@
1
- import typescript from "typescript";
2
- import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
1
  import sort_package_json from "sort-package-json";
4
- import { dirname, isAbsolute, join, normalize, relative, resolve } from "node:path";
5
- import parser from "@typescript-eslint/parser";
6
- import { ESLint } from "eslint";
7
- import eslint_plugin_tsdoc from "eslint-plugin-tsdoc";
8
- import { parse } from "yaml";
9
- import { Command as Command_Command, Yaml, PnpmWorkspace, Filter } from "./878.js";
10
- class Biome {
11
- static glob = "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}";
12
- static defaultExcludes = [
13
- "package.json",
14
- "package-lock.json",
15
- "__fixtures__",
16
- "__test__/fixtures"
17
- ];
18
- static handler = Biome.create();
19
- static findBiome() {
20
- const result = Command_Command.findTool("biome");
21
- return result.command;
22
- }
23
- static isAvailable() {
24
- return Command_Command.findTool("biome").available;
25
- }
26
- static findConfig() {
27
- for (const name of [
28
- "biome.jsonc",
29
- "biome.json"
30
- ]){
31
- const libPath = `lib/configs/${name}`;
32
- if (existsSync(libPath)) return libPath;
33
- if (existsSync(name)) return name;
34
- }
35
- }
36
- static create(options = {}) {
37
- const excludes = options.exclude ?? [
38
- ...Biome.defaultExcludes
39
- ];
40
- const config = options.config ?? Biome.findConfig();
41
- return (filenames)=>{
42
- const filtered = Filter.exclude(filenames, excludes);
43
- if (0 === filtered.length) return [];
44
- const biomeCmd = Command_Command.requireTool("biome", "Biome is not available. Install it globally (recommended) or add @biomejs/biome as a dev dependency.");
45
- const files = Filter.shellEscape(filtered);
46
- const flags = options.flags ?? [];
47
- const configFlag = config ? `--config-path=${config}` : "";
48
- const cmd = [
49
- `${biomeCmd} check --write --no-errors-on-unmatched`,
50
- configFlag,
51
- ...flags,
52
- files
53
- ].filter(Boolean).join(" ");
54
- return cmd;
55
- };
56
- }
57
- }
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { Filter, Command as Command_Command, isWorkspacePackagePath, Biome, PnpmWorkspace, Yaml, getWorkspaceRoot } from "./878.js";
58
5
  class Markdown {
59
6
  static glob = "**/*.{md,mdx}";
60
7
  static defaultExcludes = [];
@@ -67,6 +14,7 @@ class Markdown {
67
14
  return Command_Command.findTool("markdownlint-cli2").available;
68
15
  }
69
16
  static findConfig() {
17
+ const root = getWorkspaceRoot() ?? process.cwd();
70
18
  const filenames = [
71
19
  ".markdownlint-cli2.jsonc",
72
20
  ".markdownlint-cli2.json",
@@ -77,9 +25,10 @@ class Markdown {
77
25
  ".markdownlint.yaml"
78
26
  ];
79
27
  for (const name of filenames){
80
- const libPath = `lib/configs/${name}`;
28
+ const libPath = join(root, "lib/configs", name);
81
29
  if (existsSync(libPath)) return libPath;
82
- if (existsSync(name)) return name;
30
+ const rootPath = join(root, name);
31
+ if (existsSync(rootPath)) return rootPath;
83
32
  }
84
33
  }
85
34
  static create(options = {}) {
@@ -112,12 +61,18 @@ class PackageJson {
112
61
  "__fixtures__"
113
62
  ];
114
63
  static handler = PackageJson.create();
64
+ static filterToWorkspaceRoots(filenames, excludes) {
65
+ const excluded = Filter.exclude(filenames, [
66
+ ...excludes
67
+ ]);
68
+ return excluded.filter((f)=>isWorkspacePackagePath(f));
69
+ }
115
70
  static fmtCommand(options = {}) {
116
71
  const excludes = options.exclude ?? [
117
72
  ...PackageJson.defaultExcludes
118
73
  ];
119
74
  return (filenames)=>{
120
- const filtered = Filter.exclude(filenames, excludes);
75
+ const filtered = PackageJson.filterToWorkspaceRoots(filenames, excludes);
121
76
  if (0 === filtered.length) return [];
122
77
  const cmd = Command_Command.findSavvyLint();
123
78
  return `${cmd} fmt package-json ${Filter.shellEscape(filtered)}`;
@@ -130,7 +85,7 @@ class PackageJson {
130
85
  const skipSort = options.skipSort ?? false;
131
86
  const skipFormat = options.skipFormat ?? false;
132
87
  return (filenames)=>{
133
- const filtered = Filter.exclude(filenames, excludes);
88
+ const filtered = PackageJson.filterToWorkspaceRoots(filenames, excludes);
134
89
  if (0 === filtered.length) return [];
135
90
  if (!skipSort) for (const filepath of filtered){
136
91
  const content = readFileSync(filepath, "utf-8");
@@ -163,524 +118,9 @@ class ShellScripts {
163
118
  };
164
119
  }
165
120
  }
166
- class TsDocLinter {
167
- eslint;
168
- constructor(options = {}){
169
- const ignorePatterns = options.ignorePatterns ?? [];
170
- const config = [
171
- {
172
- ignores: [
173
- "**/node_modules/**",
174
- "**/dist/**",
175
- "**/coverage/**",
176
- ...ignorePatterns
177
- ]
178
- },
179
- {
180
- files: [
181
- "**/*.ts",
182
- "**/*.tsx",
183
- "**/*.mts",
184
- "**/*.cts"
185
- ],
186
- languageOptions: {
187
- parser: parser
188
- },
189
- plugins: {
190
- tsdoc: eslint_plugin_tsdoc
191
- },
192
- rules: {
193
- "tsdoc/syntax": "error"
194
- }
195
- }
196
- ];
197
- this.eslint = new ESLint({
198
- overrideConfigFile: true,
199
- overrideConfig: config
200
- });
201
- }
202
- async lintFiles(filePaths) {
203
- if (0 === filePaths.length) return [];
204
- const results = await this.eslint.lintFiles(filePaths);
205
- return results.map((result)=>({
206
- filePath: result.filePath,
207
- errorCount: result.errorCount,
208
- warningCount: result.warningCount,
209
- messages: result.messages.map((msg)=>({
210
- line: msg.line,
211
- column: msg.column,
212
- severity: msg.severity,
213
- message: msg.message,
214
- ruleId: msg.ruleId
215
- }))
216
- }));
217
- }
218
- async lintFilesAndThrow(filePaths) {
219
- const results = await this.lintFiles(filePaths);
220
- const errors = [];
221
- for (const result of results)if (result.errorCount > 0) {
222
- for (const msg of result.messages)if (2 === msg.severity) errors.push(`${result.filePath}:${msg.line}:${msg.column} - ${msg.message}`);
223
- }
224
- if (errors.length > 0) throw new Error(`TSDoc validation failed:\n${errors.join("\n")}`);
225
- }
226
- static formatResults(results) {
227
- const lines = [];
228
- for (const result of results)if (0 !== result.errorCount || 0 !== result.warningCount) {
229
- lines.push(`\n${result.filePath}`);
230
- for (const msg of result.messages){
231
- const severity = 2 === msg.severity ? "error" : "warning";
232
- const rule = msg.ruleId ? ` (${msg.ruleId})` : "";
233
- lines.push(` ${msg.line}:${msg.column} ${severity} ${msg.message}${rule}`);
234
- }
235
- }
236
- const totalErrors = results.reduce((sum, r)=>sum + r.errorCount, 0);
237
- const totalWarnings = results.reduce((sum, r)=>sum + r.warningCount, 0);
238
- if (totalErrors > 0 || totalWarnings > 0) lines.push(`\n✖ ${totalErrors} error(s), ${totalWarnings} warning(s)`);
239
- return lines.join("\n");
240
- }
241
- static hasErrors(results) {
242
- return results.some((r)=>r.errorCount > 0);
243
- }
244
- }
245
- const TS_EXTENSIONS = [
246
- ".ts",
247
- ".tsx",
248
- ".mts",
249
- ".cts"
250
- ];
251
- class EntryExtractor {
252
- extract(packageJson) {
253
- const entries = {};
254
- const unresolved = [];
255
- const { exports } = packageJson;
256
- if (!exports) {
257
- const mainEntry = packageJson.module ?? packageJson.main;
258
- if (mainEntry && this.isTypeScriptFile(mainEntry)) entries["."] = mainEntry;
259
- else if (mainEntry) unresolved.push(".");
260
- return {
261
- entries,
262
- unresolved
263
- };
264
- }
265
- if ("string" == typeof exports) {
266
- if (this.isTypeScriptFile(exports)) entries["."] = exports;
267
- else unresolved.push(".");
268
- return {
269
- entries,
270
- unresolved
271
- };
272
- }
273
- this.extractFromObject(exports, entries, unresolved, ".");
274
- return {
275
- entries,
276
- unresolved
277
- };
278
- }
279
- extractFromObject(obj, entries, unresolved, currentPath) {
280
- for (const [key, value] of Object.entries(obj)){
281
- const exportPath = key.startsWith(".") ? key : currentPath;
282
- if ("string" == typeof value) {
283
- if (this.isTypeScriptFile(value)) entries[exportPath] = value;
284
- else if (key.startsWith(".")) unresolved.push(exportPath);
285
- } else if (value && "object" == typeof value && !Array.isArray(value)) {
286
- const nested = value;
287
- const tsPath = this.findTypeScriptCondition(nested);
288
- if (tsPath) entries[exportPath] = tsPath;
289
- else if (key.startsWith(".")) this.extractFromObject(nested, entries, unresolved, exportPath);
290
- else {
291
- const sourcePath = this.findSourceCondition(nested);
292
- if (sourcePath && this.isTypeScriptFile(sourcePath)) entries[exportPath] = sourcePath;
293
- }
294
- }
295
- }
296
- }
297
- findTypeScriptCondition(conditions) {
298
- const priorityKeys = [
299
- "source",
300
- "typescript",
301
- "development",
302
- "default"
303
- ];
304
- for (const key of priorityKeys){
305
- const value = conditions[key];
306
- if ("string" == typeof value && this.isTypeScriptFile(value)) return value;
307
- if (value && "object" == typeof value) {
308
- const nested = this.findTypeScriptCondition(value);
309
- if (nested) return nested;
310
- }
311
- }
312
- return null;
313
- }
314
- findSourceCondition(conditions) {
315
- const priorityKeys = [
316
- "source",
317
- "import",
318
- "require",
319
- "default"
320
- ];
321
- for (const key of priorityKeys){
322
- const value = conditions[key];
323
- if ("string" == typeof value) return value;
324
- if (value && "object" == typeof value) {
325
- const nested = this.findSourceCondition(value);
326
- if (nested) return nested;
327
- }
328
- }
329
- return null;
330
- }
331
- isTypeScriptFile(filePath) {
332
- return TS_EXTENSIONS.some((ext)=>filePath.endsWith(ext));
333
- }
334
- }
335
- class ImportGraph {
336
- options;
337
- program = null;
338
- compilerOptions = null;
339
- moduleResolutionCache = null;
340
- constructor(options){
341
- this.options = options;
342
- }
343
- traceFromEntries(entryPaths) {
344
- const errors = [];
345
- const visited = new Set();
346
- const entries = [];
347
- const initResult = this.initializeProgram();
348
- if (!initResult.success) return {
349
- files: [],
350
- entries: [],
351
- errors: [
352
- initResult.error
353
- ]
354
- };
355
- for (const entryPath of entryPaths){
356
- const absolutePath = this.resolveEntryPath(entryPath);
357
- if (!existsSync(absolutePath)) {
358
- errors.push({
359
- type: "entry_not_found",
360
- message: `Entry file not found: ${entryPath}`,
361
- path: absolutePath
362
- });
363
- continue;
364
- }
365
- entries.push(absolutePath);
366
- this.traceImports(absolutePath, visited, errors);
367
- }
368
- const files = Array.from(visited).filter((file)=>this.isSourceFile(file));
369
- return {
370
- files: files.sort(),
371
- entries,
372
- errors
373
- };
374
- }
375
- traceFromPackageExports(packageJsonPath) {
376
- const absolutePath = this.resolveEntryPath(packageJsonPath);
377
- let packageJson;
378
- try {
379
- if (!existsSync(absolutePath)) return {
380
- files: [],
381
- entries: [],
382
- errors: [
383
- {
384
- type: "package_json_not_found",
385
- message: `Failed to read package.json: File not found at ${absolutePath}`,
386
- path: absolutePath
387
- }
388
- ]
389
- };
390
- const content = readFileSync(absolutePath, "utf-8");
391
- packageJson = JSON.parse(content);
392
- } catch (error) {
393
- const message = error instanceof Error ? error.message : String(error);
394
- return {
395
- files: [],
396
- entries: [],
397
- errors: [
398
- {
399
- type: "package_json_parse_error",
400
- message: `Failed to parse package.json: ${message}`,
401
- path: absolutePath
402
- }
403
- ]
404
- };
405
- }
406
- const extractor = new EntryExtractor();
407
- const { entries } = extractor.extract(packageJson);
408
- const packageDir = dirname(absolutePath);
409
- const entryPaths = Object.values(entries).map((p)=>resolve(packageDir, p));
410
- return this.traceFromEntries(entryPaths);
411
- }
412
- initializeProgram() {
413
- if (this.program) return {
414
- success: true
415
- };
416
- const configPath = this.findTsConfig();
417
- if (!configPath) {
418
- this.compilerOptions = {
419
- moduleResolution: typescript.ModuleResolutionKind.NodeNext,
420
- module: typescript.ModuleKind.NodeNext,
421
- target: typescript.ScriptTarget.ESNext,
422
- strict: true
423
- };
424
- this.moduleResolutionCache = typescript.createModuleResolutionCache(this.options.rootDir, (fileName)=>fileName.toLowerCase(), this.compilerOptions);
425
- const host = typescript.createCompilerHost(this.compilerOptions, true);
426
- host.getCurrentDirectory = ()=>this.options.rootDir;
427
- this.program = typescript.createProgram([], this.compilerOptions, host);
428
- return {
429
- success: true
430
- };
431
- }
432
- const configFile = typescript.readConfigFile(configPath, (path)=>readFileSync(path, "utf-8"));
433
- if (configFile.error) {
434
- const message = typescript.flattenDiagnosticMessageText(configFile.error.messageText, "\n");
435
- return {
436
- success: false,
437
- error: {
438
- type: "tsconfig_read_error",
439
- message: `Failed to read tsconfig.json: ${message}`,
440
- path: configPath
441
- }
442
- };
443
- }
444
- const parsed = typescript.parseJsonConfigFileContent(configFile.config, typescript.sys, dirname(configPath));
445
- if (parsed.errors.length > 0) {
446
- const messages = parsed.errors.map((e)=>typescript.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
447
- return {
448
- success: false,
449
- error: {
450
- type: "tsconfig_parse_error",
451
- message: `Failed to parse tsconfig.json: ${messages}`,
452
- path: configPath
453
- }
454
- };
455
- }
456
- this.compilerOptions = parsed.options;
457
- this.moduleResolutionCache = typescript.createModuleResolutionCache(this.options.rootDir, (fileName)=>fileName.toLowerCase(), this.compilerOptions);
458
- const host = typescript.createCompilerHost(this.compilerOptions, true);
459
- host.getCurrentDirectory = ()=>this.options.rootDir;
460
- this.program = typescript.createProgram([], this.compilerOptions, host);
461
- return {
462
- success: true
463
- };
464
- }
465
- findTsConfig() {
466
- if (this.options.tsconfigPath) {
467
- const customPath = isAbsolute(this.options.tsconfigPath) ? this.options.tsconfigPath : resolve(this.options.rootDir, this.options.tsconfigPath);
468
- if (existsSync(customPath)) return customPath;
469
- return null;
470
- }
471
- const configPath = typescript.findConfigFile(this.options.rootDir, (path)=>existsSync(path));
472
- return configPath ?? null;
473
- }
474
- resolveEntryPath(entryPath) {
475
- if (isAbsolute(entryPath)) return normalize(entryPath);
476
- return normalize(resolve(this.options.rootDir, entryPath));
477
- }
478
- traceImports(filePath, visited, errors) {
479
- const normalizedPath = normalize(filePath);
480
- if (visited.has(normalizedPath)) return;
481
- if (this.isExternalModule(normalizedPath)) return;
482
- visited.add(normalizedPath);
483
- let content;
484
- try {
485
- content = readFileSync(normalizedPath, "utf-8");
486
- } catch {
487
- errors.push({
488
- type: "file_read_error",
489
- message: `Failed to read file: ${normalizedPath}`,
490
- path: normalizedPath
491
- });
492
- return;
493
- }
494
- const sourceFile = typescript.createSourceFile(normalizedPath, content, typescript.ScriptTarget.Latest, true);
495
- const imports = this.extractImports(sourceFile);
496
- for (const importPath of imports){
497
- const resolved = this.resolveImport(importPath, normalizedPath);
498
- if (resolved) this.traceImports(resolved, visited, errors);
499
- }
500
- }
501
- extractImports(sourceFile) {
502
- const imports = [];
503
- const visit = (node)=>{
504
- if (typescript.isImportDeclaration(node)) {
505
- const specifier = node.moduleSpecifier;
506
- if (typescript.isStringLiteral(specifier)) imports.push(specifier.text);
507
- } else if (typescript.isExportDeclaration(node)) {
508
- const specifier = node.moduleSpecifier;
509
- if (specifier && typescript.isStringLiteral(specifier)) imports.push(specifier.text);
510
- } else if (typescript.isCallExpression(node)) {
511
- const expression = node.expression;
512
- if (expression.kind === typescript.SyntaxKind.ImportKeyword && node.arguments.length > 0) {
513
- const arg = node.arguments[0];
514
- if (arg && typescript.isStringLiteral(arg)) imports.push(arg.text);
515
- }
516
- }
517
- typescript.forEachChild(node, visit);
518
- };
519
- visit(sourceFile);
520
- return imports;
521
- }
522
- resolveImport(specifier, fromFile) {
523
- if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
524
- if (!this.compilerOptions?.paths || !Object.keys(this.compilerOptions.paths).length) return null;
525
- }
526
- if (!this.compilerOptions || !this.moduleResolutionCache) return null;
527
- const resolved = typescript.resolveModuleName(specifier, fromFile, this.compilerOptions, typescript.sys, this.moduleResolutionCache);
528
- if (resolved.resolvedModule) {
529
- const resolvedPath = resolved.resolvedModule.resolvedFileName;
530
- if (resolved.resolvedModule.isExternalLibraryImport) return null;
531
- if (resolvedPath.endsWith(".d.ts")) {
532
- const sourcePath = resolvedPath.replace(/\.d\.ts$/, ".ts");
533
- if (existsSync(sourcePath)) return sourcePath;
534
- return null;
535
- }
536
- return resolvedPath;
537
- }
538
- return null;
539
- }
540
- isExternalModule(filePath) {
541
- return filePath.includes("/node_modules/") || filePath.includes("\\node_modules\\");
542
- }
543
- isSourceFile(filePath) {
544
- if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx") && !filePath.endsWith(".mts") && !filePath.endsWith(".cts")) return false;
545
- if (filePath.endsWith(".d.ts") || filePath.endsWith(".d.mts") || filePath.endsWith(".d.cts")) return false;
546
- if (filePath.includes(".test.") || filePath.includes(".spec.")) return false;
547
- if (filePath.includes("/__test__/") || filePath.includes("\\__test__\\")) return false;
548
- if (filePath.includes("/__tests__/") || filePath.includes("\\__tests__\\")) return false;
549
- const excludePatterns = this.options.excludePatterns ?? [];
550
- for (const pattern of excludePatterns)if (filePath.includes(pattern)) return false;
551
- return true;
552
- }
553
- static fromEntries(entryPaths, options) {
554
- const graph = new ImportGraph(options);
555
- return graph.traceFromEntries(entryPaths);
556
- }
557
- static fromPackageExports(packageJsonPath, options) {
558
- const graph = new ImportGraph(options);
559
- return graph.traceFromPackageExports(packageJsonPath);
560
- }
561
- }
562
- function expandWorkspaceGlob(rootDir, pattern) {
563
- const base = pattern.replace(/\/\*+$/, "");
564
- const baseDir = resolve(rootDir, base);
565
- if (!existsSync(baseDir)) return [];
566
- const results = [];
567
- for (const entry of readdirSync(baseDir, {
568
- withFileTypes: true
569
- }))if (entry.isDirectory()) {
570
- const candidate = join(baseDir, entry.name);
571
- if (existsSync(join(candidate, "package.json"))) results.push(candidate);
572
- }
573
- return results;
574
- }
575
- function detectWorkspacePackages(rootDir) {
576
- const pnpmWorkspacePath = join(rootDir, "pnpm-workspace.yaml");
577
- if (existsSync(pnpmWorkspacePath)) try {
578
- const content = readFileSync(pnpmWorkspacePath, "utf-8");
579
- const parsed = parse(content);
580
- if (Array.isArray(parsed?.packages)) return parsed.packages.flatMap((pattern)=>expandWorkspaceGlob(rootDir, pattern));
581
- } catch {}
582
- const rootPkgPath = join(rootDir, "package.json");
583
- if (existsSync(rootPkgPath)) try {
584
- const pkg = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
585
- const patterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages;
586
- if (Array.isArray(patterns)) return patterns.flatMap((pattern)=>expandWorkspaceGlob(rootDir, pattern));
587
- } catch {}
588
- return [];
589
- }
590
- class TsDocResolver {
591
- options;
592
- constructor(options){
593
- this.options = options;
594
- }
595
- resolve() {
596
- const { rootDir } = this.options;
597
- const workspaces = [];
598
- const repoTsdocPath = join(rootDir, "tsdoc.json");
599
- const repoTsdocConfig = existsSync(repoTsdocPath) ? repoTsdocPath : void 0;
600
- const workspacePaths = detectWorkspacePackages(rootDir);
601
- const isMonorepo = workspacePaths.length > 1;
602
- if (0 === workspacePaths.length) {
603
- const result = this.resolveWorkspace(rootDir, repoTsdocConfig);
604
- if (result) workspaces.push(result);
605
- } else for (const workspacePath of workspacePaths){
606
- const result = this.resolveWorkspace(workspacePath, repoTsdocConfig);
607
- if (result) workspaces.push(result);
608
- }
609
- const result = {
610
- workspaces,
611
- isMonorepo
612
- };
613
- if (void 0 !== repoTsdocConfig) result.repoTsdocConfig = repoTsdocConfig;
614
- return result;
615
- }
616
- resolveWorkspace(workspacePath, repoTsdocConfig) {
617
- const packageJsonPath = join(workspacePath, "package.json");
618
- if (!existsSync(packageJsonPath)) return null;
619
- let packageJson;
620
- try {
621
- const content = readFileSync(packageJsonPath, "utf-8");
622
- packageJson = JSON.parse(content);
623
- } catch {
624
- return null;
625
- }
626
- const workspaceTsdocPath = join(workspacePath, "tsdoc.json");
627
- const workspaceTsdocConfig = existsSync(workspaceTsdocPath) ? workspaceTsdocPath : void 0;
628
- const tsdocConfigPath = workspaceTsdocConfig ?? repoTsdocConfig;
629
- if (!tsdocConfigPath) return null;
630
- if (!packageJson.exports) return null;
631
- const name = packageJson.name ?? relative(this.options.rootDir, workspacePath);
632
- const errors = [];
633
- const graphOptions = {
634
- rootDir: workspacePath
635
- };
636
- if (void 0 !== this.options.excludePatterns) graphOptions.excludePatterns = this.options.excludePatterns;
637
- const graph = new ImportGraph(graphOptions);
638
- const result = graph.traceFromPackageExports(packageJsonPath);
639
- for (const error of result.errors)errors.push(error.message);
640
- return {
641
- name,
642
- path: workspacePath,
643
- tsdocConfigPath,
644
- files: result.files,
645
- errors
646
- };
647
- }
648
- filterStagedFiles(stagedFiles) {
649
- const result = this.resolve();
650
- const output = [];
651
- for (const workspace of result.workspaces){
652
- const workspaceFiles = new Set(workspace.files);
653
- const matchedFiles = stagedFiles.filter((f)=>workspaceFiles.has(f));
654
- if (matchedFiles.length > 0) output.push({
655
- files: matchedFiles,
656
- tsdocConfigPath: workspace.tsdocConfigPath
657
- });
658
- }
659
- return output;
660
- }
661
- needsLinting(filePath) {
662
- const result = this.resolve();
663
- for (const workspace of result.workspaces)if (workspace.files.includes(filePath)) return true;
664
- return false;
665
- }
666
- getTsDocConfig(filePath) {
667
- const result = this.resolve();
668
- for (const workspace of result.workspaces)if (workspace.files.includes(filePath)) return workspace.tsdocConfigPath;
669
- }
670
- findWorkspace(filePath) {
671
- const result = this.resolve();
672
- for (const workspace of result.workspaces)if (filePath.startsWith(workspace.path)) return workspace;
673
- }
674
- }
675
121
  class TypeScript {
676
122
  static glob = "*.{ts,cts,mts,tsx}";
677
123
  static defaultExcludes = [];
678
- static defaultTsdocExcludes = [
679
- ".test.",
680
- ".spec.",
681
- "__test__",
682
- "__tests__"
683
- ];
684
124
  static cachedCompilerResult = null;
685
125
  static detectCompiler(_cwd) {
686
126
  if (null !== TypeScript.cachedCompilerResult) return TypeScript.cachedCompilerResult.compiler;
@@ -713,57 +153,23 @@ class TypeScript {
713
153
  TypeScript.cachedCompilerResult = null;
714
154
  }
715
155
  static handler = TypeScript.create();
716
- static isTsdocAvailable(cwd = process.cwd()) {
717
- let dir = resolve(cwd);
718
- while(true){
719
- if (existsSync(join(dir, "tsdoc.json"))) return true;
720
- const parent = dirname(dir);
721
- if (parent === dir) break;
722
- dir = parent;
723
- }
724
- return false;
725
- }
726
156
  static create(options = {}) {
727
157
  const excludes = options.exclude ?? [
728
158
  ...TypeScript.defaultExcludes
729
159
  ];
730
- const tsdocExcludes = options.excludeTsdoc ?? [
731
- ...TypeScript.defaultTsdocExcludes
732
- ];
733
- const skipTsdoc = options.skipTsdoc ?? false;
734
160
  const skipTypecheck = options.skipTypecheck ?? false;
735
- const rootDir = options.rootDir ?? Command_Command.findRoot();
736
161
  let typecheckCommand;
737
162
  const getTypecheckCommand = ()=>{
738
163
  if (void 0 === typecheckCommand) typecheckCommand = options.typecheckCommand ?? TypeScript.getDefaultTypecheckCommand();
739
164
  return typecheckCommand;
740
165
  };
741
- return async (filenames)=>{
166
+ return (filenames)=>{
742
167
  const filtered = Filter.exclude(filenames, excludes);
743
168
  if (0 === filtered.length) return [];
744
- const commands = [];
745
- if (!skipTsdoc) {
746
- const resolver = new TsDocResolver({
747
- rootDir,
748
- excludePatterns: [
749
- ...tsdocExcludes
750
- ]
751
- });
752
- const absoluteFiles = filtered.map((f)=>isAbsolute(f) ? f : join(rootDir, f));
753
- const tsdocGroups = resolver.filterStagedFiles(absoluteFiles);
754
- for (const group of tsdocGroups)if (group.files.length > 0) {
755
- const linter = new TsDocLinter({
756
- ignorePatterns: tsdocExcludes.map((p)=>`**/*${p}*`)
757
- });
758
- const results = await linter.lintFiles(group.files);
759
- if (TsDocLinter.hasErrors(results)) {
760
- const output = TsDocLinter.formatResults(results);
761
- throw new Error(`TSDoc validation failed:\n${output}`);
762
- }
763
- }
764
- }
765
- if (!skipTypecheck && filtered.length > 0) commands.push(getTypecheckCommand());
766
- return commands;
169
+ if (!skipTypecheck) return [
170
+ getTypecheckCommand()
171
+ ];
172
+ return [];
767
173
  };
768
174
  }
769
175
  }
@@ -888,6 +294,6 @@ class Handler {
888
294
  throw new Error("Handler.create() must be implemented by subclass");
889
295
  }
890
296
  }
891
- export { Command, Filter, PnpmWorkspace, Yaml, checkCommand, fmtCommand, initCommand, rootCommand, runCli } from "./878.js";
297
+ export { Biome, Command, Filter, PnpmWorkspace, Yaml, checkCommand, fmtCommand, getWorkspacePackagePaths, getWorkspacePackages, getWorkspaceRoot, initCommand, isWorkspacePackagePath, resetWorkspaceCache, rootCommand, runCli } from "./878.js";
892
298
  export { ConfigDiscovery, ConfigDiscoveryLive } from "@savvy-web/silk-effects";
893
- export { Biome, EntryExtractor, Handler, ImportGraph, Markdown, PackageJson, Preset, ShellScripts, TsDocLinter, TsDocResolver, TypeScript, createConfig };
299
+ export { Handler, Markdown, PackageJson, Preset, ShellScripts, TypeScript, createConfig };