@reliverse/dler 2.0.6 → 2.0.8

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 (46) hide show
  1. package/package.json +16 -15
  2. package/src/cli.ts +0 -8
  3. package/src/cmds/build/cmd.ts +0 -568
  4. package/src/cmds/clean/cmd.ts +0 -166
  5. package/src/cmds/clean/impl.ts +0 -900
  6. package/src/cmds/clean/presets.ts +0 -158
  7. package/src/cmds/clean/types.ts +0 -71
  8. package/src/cmds/init/cmd.ts +0 -68
  9. package/src/cmds/init/impl/config.ts +0 -105
  10. package/src/cmds/init/impl/generators.ts +0 -220
  11. package/src/cmds/init/impl/prompts.ts +0 -137
  12. package/src/cmds/init/impl/types.ts +0 -25
  13. package/src/cmds/init/impl/utils.ts +0 -17
  14. package/src/cmds/init/impl/validators.ts +0 -55
  15. package/src/cmds/integrate/cmd.ts +0 -82
  16. package/src/cmds/integrate/impl.ts +0 -204
  17. package/src/cmds/integrate/integrations/base.ts +0 -69
  18. package/src/cmds/integrate/integrations/nextjs.ts +0 -227
  19. package/src/cmds/integrate/integrations/registry.ts +0 -45
  20. package/src/cmds/integrate/integrations/ultracite.ts +0 -53
  21. package/src/cmds/integrate/types.ts +0 -48
  22. package/src/cmds/integrate/utils/biome.ts +0 -173
  23. package/src/cmds/integrate/utils/context.ts +0 -148
  24. package/src/cmds/integrate/utils/temp.ts +0 -47
  25. package/src/cmds/perf/analysis/bundle.ts +0 -311
  26. package/src/cmds/perf/analysis/filesystem.ts +0 -324
  27. package/src/cmds/perf/analysis/monorepo.ts +0 -439
  28. package/src/cmds/perf/benchmarks/command.ts +0 -230
  29. package/src/cmds/perf/benchmarks/memory.ts +0 -249
  30. package/src/cmds/perf/benchmarks/runner.ts +0 -220
  31. package/src/cmds/perf/cmd.ts +0 -285
  32. package/src/cmds/perf/impl.ts +0 -411
  33. package/src/cmds/perf/reporters/console.ts +0 -331
  34. package/src/cmds/perf/reporters/html.ts +0 -984
  35. package/src/cmds/perf/reporters/json.ts +0 -42
  36. package/src/cmds/perf/types.ts +0 -220
  37. package/src/cmds/perf/utils/cache.ts +0 -234
  38. package/src/cmds/perf/utils/formatter.ts +0 -190
  39. package/src/cmds/perf/utils/stats.ts +0 -153
  40. package/src/cmds/publish/cmd.ts +0 -213
  41. package/src/cmds/shell/cmd.ts +0 -61
  42. package/src/cmds/tsc/cache.ts +0 -237
  43. package/src/cmds/tsc/cmd.ts +0 -139
  44. package/src/cmds/tsc/impl.ts +0 -855
  45. package/src/cmds/tsc/types.ts +0 -66
  46. package/tsconfig.json +0 -9
@@ -1,855 +0,0 @@
1
- // apps/dler/src/cmds/tsc/impl.ts
2
-
3
- import { existsSync } from "node:fs";
4
- import { cpus } from "node:os";
5
- import { join, relative, resolve } from "node:path";
6
- import { writeErrorLines } from "@reliverse/dler-helpers";
7
- import { logger } from "@reliverse/dler-logger";
8
- import pMap from "@reliverse/dler-mapper";
9
- import { createIgnoreFilter, normalizePatterns } from "@reliverse/dler-matcher";
10
- import {
11
- getWorkspacePatterns,
12
- hasWorkspaces,
13
- readPackageJSON,
14
- } from "@reliverse/dler-pkg-tsc";
15
- import clipboard from "clipboardy";
16
- import { TscCache } from "./cache";
17
- import type { PackageDiscoveryResult } from "./types";
18
-
19
- const DEFAULT_CONCURRENCY = Math.max(4, cpus().length);
20
- const DISCOVERY_CONCURRENCY = 10;
21
-
22
- // ============================================================================
23
- // Types
24
- // ============================================================================
25
-
26
- export interface PackageInfo {
27
- name: string;
28
- path: string;
29
- hasTsConfig: boolean;
30
- }
31
-
32
- interface TscResult {
33
- package: PackageInfo;
34
- success: boolean;
35
- skipped: boolean;
36
- cached: boolean;
37
- totalErrors: number;
38
- totalWarnings: number;
39
- filteredErrors: number;
40
- filteredWarnings: number;
41
- output: string;
42
- filteredOutput: string;
43
- executionTime: number;
44
- }
45
-
46
- interface TscSummary {
47
- totalPackages: number;
48
- failedPackages: number;
49
- successfulPackages: number;
50
- skippedPackages: number;
51
- totalErrors: number;
52
- totalWarnings: number;
53
- hasErrors: boolean;
54
- results: TscResult[];
55
- }
56
-
57
- interface TscOptions {
58
- concurrency?: number;
59
- stopOnError?: boolean;
60
- verbose?: boolean;
61
- copyLogs?: boolean;
62
- cache?: boolean;
63
- incremental?: boolean;
64
- autoConcurrency?: boolean;
65
- skipUnchanged?: boolean;
66
- buildMode?: boolean;
67
- }
68
-
69
- interface SpawnResult {
70
- stdout: string;
71
- stderr: string;
72
- exitCode: number;
73
- }
74
-
75
- // ============================================================================
76
- // Constants
77
- // ============================================================================
78
-
79
- const TS_ERROR_REGEX = /\([0-9]+,[0-9]+\): (error|warning) TS[0-9]+:/;
80
-
81
- // ============================================================================
82
- // Package Discovery
83
- // ============================================================================
84
-
85
- const findMonorepoRoot = async (startDir?: string): Promise<string | null> => {
86
- let currentDir = resolve(startDir ?? process.cwd());
87
-
88
- while (currentDir !== "/") {
89
- const pkgPath = join(currentDir, "package.json");
90
-
91
- if (existsSync(pkgPath)) {
92
- const pkg = await readPackageJSON(currentDir);
93
-
94
- if (pkg && hasWorkspaces(pkg)) {
95
- return currentDir;
96
- }
97
- }
98
-
99
- const parentDir = resolve(currentDir, "..");
100
- if (parentDir === currentDir) break;
101
- currentDir = parentDir;
102
- }
103
-
104
- return null;
105
- };
106
-
107
- const resolvePackageInfo = async (
108
- packagePath: string,
109
- ): Promise<PackageInfo | null> => {
110
- const pkgJsonPath = join(packagePath, "package.json");
111
- const tsConfigPath = join(packagePath, "tsconfig.json");
112
-
113
- // Early skip if no package.json
114
- if (!existsSync(pkgJsonPath)) {
115
- return null;
116
- }
117
-
118
- // Early skip if no tsconfig.json (cheaper check first)
119
- if (!existsSync(tsConfigPath)) {
120
- return null;
121
- }
122
-
123
- try {
124
- const pkg = await readPackageJSON(packagePath);
125
-
126
- if (!pkg?.name) {
127
- return null;
128
- }
129
-
130
- return {
131
- name: pkg.name,
132
- path: packagePath,
133
- hasTsConfig: true, // We already checked this above
134
- };
135
- } catch {
136
- return null;
137
- }
138
- };
139
-
140
- const getWorkspacePackages = async (
141
- cwd?: string,
142
- ): Promise<PackageDiscoveryResult> => {
143
- const startTime = Date.now();
144
- const monorepoRoot = await findMonorepoRoot(cwd);
145
-
146
- if (!monorepoRoot) {
147
- throw new Error(
148
- "āŒ No monorepo found. Ensure package.json has 'workspaces' field.",
149
- );
150
- }
151
-
152
- const rootPkg = await readPackageJSON(monorepoRoot);
153
- if (!rootPkg) {
154
- throw new Error("āŒ Could not read root package.json");
155
- }
156
-
157
- const patterns = getWorkspacePatterns(rootPkg);
158
-
159
- if (!patterns.length) {
160
- throw new Error("āŒ No workspace patterns found in package.json");
161
- }
162
-
163
- // Collect all potential package paths first
164
- const allPackagePaths: string[] = [];
165
- const seenPaths = new Set<string>();
166
-
167
- for (const pattern of patterns) {
168
- // Check if pattern contains wildcards
169
- if (pattern.includes('*')) {
170
- // Pattern with wildcards - use glob
171
- const glob = new Bun.Glob(pattern);
172
- const matches = glob.scanSync({ cwd: monorepoRoot, onlyFiles: false });
173
-
174
- for (const match of matches) {
175
- const packagePath = resolve(monorepoRoot, match);
176
-
177
- if (seenPaths.has(packagePath)) continue;
178
- seenPaths.add(packagePath);
179
- allPackagePaths.push(packagePath);
180
- }
181
- } else {
182
- // Direct package path (no wildcards)
183
- const packagePath = resolve(monorepoRoot, pattern);
184
-
185
- if (seenPaths.has(packagePath)) continue;
186
- seenPaths.add(packagePath);
187
- allPackagePaths.push(packagePath);
188
- }
189
- }
190
-
191
- // Resolve package info in parallel
192
- const packageResults = await pMap(
193
- allPackagePaths,
194
- async (packagePath) => {
195
- const pkgInfo = await resolvePackageInfo(packagePath);
196
- return { packagePath, pkgInfo };
197
- },
198
- { concurrency: DISCOVERY_CONCURRENCY },
199
- );
200
-
201
- const packages = packageResults
202
- .filter((result) => result.pkgInfo !== null)
203
- .map((result) => result.pkgInfo!);
204
-
205
- const discoveryTime = Date.now() - startTime;
206
-
207
- return {
208
- packages,
209
- monorepoRoot,
210
- discoveryTime,
211
- cacheHits: 0, // Will be updated by cache layer
212
- cacheMisses: packages.length,
213
- };
214
- };
215
-
216
- // ============================================================================
217
- // Package Filtering
218
- // ============================================================================
219
-
220
- const filterPackages = (
221
- packages: PackageInfo[],
222
- ignore?: string | string[],
223
- ): PackageInfo[] => {
224
- // Always ignore @reliverse/dler-v1 package
225
- const alwaysIgnored = ["@reliverse/dler-v1"];
226
-
227
- // Combine user-provided ignore patterns with always ignored packages
228
- const combinedIgnore = ignore
229
- ? Array.isArray(ignore)
230
- ? [...alwaysIgnored, ...ignore]
231
- : [...alwaysIgnored, ignore]
232
- : alwaysIgnored;
233
-
234
- const ignoreFilter = createIgnoreFilter(combinedIgnore);
235
- return ignoreFilter(packages);
236
- };
237
-
238
- // ============================================================================
239
- // TypeScript Execution
240
- // ============================================================================
241
-
242
- const hasProjectReferences = async (packagePath: string): Promise<boolean> => {
243
- try {
244
- const tsConfigPath = join(packagePath, "tsconfig.json");
245
- if (!existsSync(tsConfigPath)) return false;
246
-
247
- const content = await Bun.file(tsConfigPath).text();
248
- const config = JSON.parse(content);
249
- return !!(
250
- config.references &&
251
- Array.isArray(config.references) &&
252
- config.references.length > 0
253
- );
254
- } catch {
255
- return false;
256
- }
257
- };
258
-
259
- const runTscCommand = async (
260
- packagePath: string,
261
- options: { incremental?: boolean; buildMode?: boolean } = {},
262
- ): Promise<SpawnResult> => {
263
- try {
264
- const { incremental = true, buildMode = false } = options;
265
-
266
- let args: string[];
267
-
268
- if (buildMode && (await hasProjectReferences(packagePath))) {
269
- // Use tsc --build for project references (faster for multi-package setups)
270
- args = ["tsc", "--build"];
271
- if (incremental) {
272
- args.push("--incremental");
273
- }
274
- } else {
275
- // Use regular tsc --noEmit for single packages
276
- args = ["tsc", "--noEmit"];
277
- if (incremental) {
278
- args.push("--incremental");
279
- // Add tsbuildinfo file path for incremental compilation
280
- const tsBuildInfoPath = join(
281
- packagePath,
282
- "node_modules/.cache/dler-tsc",
283
- `${packagePath.split(/[/\\]/).pop()}.tsbuildinfo`,
284
- );
285
- args.push("--tsBuildInfoFile", tsBuildInfoPath);
286
- }
287
- }
288
-
289
- const proc = Bun.spawn(args, {
290
- cwd: packagePath,
291
- stdout: "pipe",
292
- stderr: "pipe",
293
- });
294
-
295
- const [stdout, stderr] = await Promise.all([
296
- new Response(proc.stdout).text(),
297
- new Response(proc.stderr).text(),
298
- ]);
299
-
300
- const exitCode = await proc.exited;
301
-
302
- return { stdout, stderr, exitCode };
303
- } catch (error) {
304
- throw new Error(
305
- `Failed to spawn tsc: ${error instanceof Error ? error.message : String(error)}`,
306
- );
307
- }
308
- };
309
-
310
- // ============================================================================
311
- // Output Filtering
312
- // ============================================================================
313
-
314
- const countErrorsAndWarnings = (
315
- output: string,
316
- ): { errors: number; warnings: number } => {
317
- const lines = output.split("\n");
318
- let errors = 0;
319
- let warnings = 0;
320
-
321
- for (const line of lines) {
322
- if (TS_ERROR_REGEX.test(line)) {
323
- if (line.includes(": error TS")) {
324
- errors++;
325
- } else if (line.includes(": warning TS")) {
326
- warnings++;
327
- }
328
- }
329
- }
330
-
331
- return { errors, warnings };
332
- };
333
-
334
- const filterOutputLines = (output: string, packagePath: string, monorepoRoot: string): string => {
335
- const lines = output.split("\n");
336
- const filtered: string[] = [];
337
- const normalizedPackagePath = resolve(packagePath);
338
-
339
- for (const line of lines) {
340
- // Keep non-error lines
341
- if (!TS_ERROR_REGEX.test(line)) {
342
- filtered.push(line);
343
- continue;
344
- }
345
-
346
- // Extract file path from error line and convert to full path
347
- const match = line.match(/^(.+?)\(/);
348
-
349
- if (match && match[1]) {
350
- const relativePath = match[1];
351
- const fullPath = resolve(packagePath, relativePath);
352
- const normalizedFilePath = resolve(fullPath);
353
-
354
- // Check if error is from another package
355
- const isCrossPackageError = line.includes("../") || line.includes("..\\");
356
-
357
- if (isCrossPackageError) {
358
- // Only include if file is within current package
359
- if (normalizedFilePath.startsWith(normalizedPackagePath)) {
360
- // Convert relative path to full path from monorepo root
361
- const relativeToMonorepo = relative(monorepoRoot, normalizedFilePath);
362
- const updatedLine = line.replace(relativePath, relativeToMonorepo);
363
- filtered.push(updatedLine);
364
- }
365
- } else {
366
- // For same-package errors, also convert to full path from monorepo root
367
- const relativeToMonorepo = relative(monorepoRoot, normalizedFilePath);
368
- const updatedLine = line.replace(relativePath, relativeToMonorepo);
369
- filtered.push(updatedLine);
370
- }
371
- } else {
372
- filtered.push(line);
373
- }
374
- }
375
-
376
- return filtered.join("\n");
377
- };
378
-
379
- // ============================================================================
380
- // Package Processing
381
- // ============================================================================
382
-
383
- const runTscOnPackage = async (
384
- pkg: PackageInfo,
385
- monorepoRoot: string,
386
- options: {
387
- verbose?: boolean;
388
- cache?: TscCache;
389
- incremental?: boolean;
390
- buildMode?: boolean;
391
- } = {},
392
- ): Promise<TscResult> => {
393
- const {
394
- verbose = false,
395
- cache,
396
- incremental = true,
397
- buildMode = false,
398
- } = options;
399
- const startTime = Date.now();
400
-
401
- if (!pkg.hasTsConfig) {
402
- if (verbose) {
403
- logger.info(`ā­ļø Skipping ${pkg.name} (no tsconfig.json)`);
404
- }
405
- return {
406
- package: pkg,
407
- success: true,
408
- skipped: true,
409
- cached: false,
410
- totalErrors: 0,
411
- totalWarnings: 0,
412
- filteredErrors: 0,
413
- filteredWarnings: 0,
414
- output: "",
415
- filteredOutput: "",
416
- executionTime: Date.now() - startTime,
417
- };
418
- }
419
-
420
- // Check cache first
421
- if (cache) {
422
- const shouldSkip = await cache.shouldSkipPackage(pkg);
423
- if (shouldSkip) {
424
- if (verbose) {
425
- logger.info(`⚔ Skipping ${pkg.name} (no changes since last check)`);
426
- }
427
- const cachedResult = await cache.getCachedResult(pkg);
428
- return {
429
- package: pkg,
430
- success: !cachedResult?.hasErrors,
431
- skipped: false,
432
- cached: true,
433
- totalErrors: cachedResult?.errorCount ?? 0,
434
- totalWarnings: cachedResult?.warningCount ?? 0,
435
- filteredErrors: cachedResult?.errorCount ?? 0,
436
- filteredWarnings: cachedResult?.warningCount ?? 0,
437
- output: cachedResult?.output ?? "Cached result",
438
- filteredOutput: cachedResult?.filteredOutput ?? "Cached result",
439
- executionTime: Date.now() - startTime,
440
- };
441
- }
442
- }
443
-
444
- if (verbose) {
445
- logger.info(`šŸ” Checking ${pkg.name}...`);
446
- }
447
-
448
- try {
449
- const result = await runTscCommand(pkg.path, { incremental, buildMode });
450
- const output = result.stdout + result.stderr;
451
- const filteredOutput = filterOutputLines(output, pkg.path, monorepoRoot);
452
-
453
- const totalCounts = countErrorsAndWarnings(output);
454
- const filteredCounts = countErrorsAndWarnings(filteredOutput);
455
-
456
- if (verbose) {
457
- const status = filteredCounts.errors === 0 ? "āœ…" : "āŒ";
458
- logger.log(
459
- `${status} ${pkg.name}: ${filteredCounts.errors} errors, ${filteredCounts.warnings} warnings`,
460
- );
461
- }
462
-
463
- const tscResult: TscResult = {
464
- package: pkg,
465
- success: filteredCounts.errors === 0,
466
- skipped: false,
467
- cached: false,
468
- totalErrors: totalCounts.errors,
469
- totalWarnings: totalCounts.warnings,
470
- filteredErrors: filteredCounts.errors,
471
- filteredWarnings: filteredCounts.warnings,
472
- output,
473
- filteredOutput,
474
- executionTime: Date.now() - startTime,
475
- };
476
-
477
- // Update cache
478
- if (cache) {
479
- await cache.updatePackageCache(pkg, {
480
- success: tscResult.success,
481
- errorCount: tscResult.filteredErrors,
482
- warningCount: tscResult.filteredWarnings,
483
- output: tscResult.output,
484
- filteredOutput: tscResult.filteredOutput,
485
- });
486
- }
487
-
488
- return tscResult;
489
- } catch (error) {
490
- logger.error(
491
- `āŒ ${pkg.name}: Failed to run tsc - ${error instanceof Error ? error.message : String(error)}`,
492
- );
493
- return {
494
- package: pkg,
495
- success: false,
496
- skipped: false,
497
- cached: false,
498
- totalErrors: 1,
499
- totalWarnings: 0,
500
- filteredErrors: 1,
501
- filteredWarnings: 0,
502
- output: error instanceof Error ? error.message : String(error),
503
- filteredOutput: error instanceof Error ? error.message : String(error),
504
- executionTime: Date.now() - startTime,
505
- };
506
- }
507
- };
508
-
509
- // ============================================================================
510
- // Result Collection
511
- // ============================================================================
512
-
513
- const collectAllResults = async (
514
- packages: PackageInfo[],
515
- monorepoRoot: string,
516
- options: TscOptions = {},
517
- cache?: TscCache,
518
- ): Promise<TscSummary> => {
519
- const {
520
- concurrency = DEFAULT_CONCURRENCY,
521
- stopOnError = false,
522
- verbose = false,
523
- incremental = true,
524
- buildMode = false,
525
- } = options;
526
-
527
- // Log progress for package processing
528
- if (!verbose) {
529
- logger.info(`Processing ${packages.length} packages...`);
530
- }
531
-
532
- try {
533
- const tscResults = await pMap(
534
- packages,
535
- async (pkg, index) => {
536
- if (!verbose) {
537
- logger.info(
538
- `Processing ${pkg.name} (${index + 1}/${packages.length})...`,
539
- );
540
- }
541
- return runTscOnPackage(pkg, monorepoRoot, {
542
- verbose,
543
- cache,
544
- incremental,
545
- buildMode,
546
- });
547
- },
548
- {
549
- concurrency,
550
- stopOnError,
551
- },
552
- );
553
-
554
- const failedPackages = tscResults.filter(
555
- (r) => !r.success && !r.skipped,
556
- ).length;
557
- const successfulPackages = tscResults.filter((r) => r.success).length;
558
- const skippedPackages = tscResults.filter((r) => r.skipped).length;
559
- const totalErrors = tscResults.reduce(
560
- (sum, r) => sum + r.filteredErrors,
561
- 0,
562
- );
563
- const totalWarnings = tscResults.reduce(
564
- (sum, r) => sum + r.filteredWarnings,
565
- 0,
566
- );
567
-
568
- return {
569
- totalPackages: packages.length,
570
- failedPackages,
571
- successfulPackages,
572
- skippedPackages,
573
- totalErrors,
574
- totalWarnings,
575
- hasErrors: failedPackages > 0,
576
- results: tscResults,
577
- };
578
- } catch (error) {
579
- // Handle aggregate errors from pMap when stopOnError is false
580
- if (error instanceof AggregateError) {
581
- const tscResults: TscResult[] = error.errors.map((err, index) => {
582
- const pkg = packages[index];
583
- if (!pkg) {
584
- throw new Error(`Package at index ${index} not found`);
585
- }
586
-
587
- if (verbose) {
588
- logger.error(
589
- `āŒ ${pkg.name}: Aggregate error - ${err instanceof Error ? err.message : String(err)}`,
590
- );
591
- }
592
-
593
- return {
594
- package: pkg,
595
- success: false,
596
- skipped: false,
597
- cached: false,
598
- totalErrors: 1,
599
- totalWarnings: 0,
600
- filteredErrors: 1,
601
- filteredWarnings: 0,
602
- output: err instanceof Error ? err.message : String(err),
603
- filteredOutput: err instanceof Error ? err.message : String(err),
604
- executionTime: 0,
605
- };
606
- });
607
-
608
- const failedPackages = tscResults.filter(
609
- (r) => !r.success && !r.skipped,
610
- ).length;
611
- const successfulPackages = tscResults.filter((r) => r.success).length;
612
- const skippedPackages = tscResults.filter((r) => r.skipped).length;
613
- const totalErrors = tscResults.reduce(
614
- (sum, r) => sum + r.filteredErrors,
615
- 0,
616
- );
617
- const totalWarnings = tscResults.reduce(
618
- (sum, r) => sum + r.filteredWarnings,
619
- 0,
620
- );
621
-
622
- return {
623
- totalPackages: packages.length,
624
- failedPackages,
625
- successfulPackages,
626
- skippedPackages,
627
- totalErrors,
628
- totalWarnings,
629
- hasErrors: failedPackages > 0,
630
- results: tscResults,
631
- };
632
- }
633
-
634
- // Re-throw other errors
635
- throw error;
636
- }
637
- };
638
-
639
- // ============================================================================
640
- // Clipboard Functionality
641
- // ============================================================================
642
-
643
- const collectFailedPackageLogs = (summary: TscSummary): string => {
644
- const failed = summary.results.filter((r) => !r.success && !r.skipped);
645
-
646
- if (failed.length === 0) {
647
- return "";
648
- }
649
-
650
- const logs: string[] = [];
651
- logs.push(
652
- "I received the following TypeScript errors (please analyse the related code for each and correct them):",
653
- );
654
- logs.push("```");
655
- logs.push("TypeScript Check (bun dler tsc)");
656
- logs.push("");
657
-
658
- for (const result of failed) {
659
- logs.push(`šŸ“¦ ${result.package.name}`);
660
- logs.push(
661
- ` Errors: ${result.filteredErrors}, Warnings: ${result.filteredWarnings}`,
662
- );
663
- logs.push(" " + "─".repeat(30));
664
-
665
- if (result.filteredOutput.trim()) {
666
- const lines = result.filteredOutput
667
- .trim()
668
- .split("\n")
669
- .map((line) => ` ${line}`);
670
- logs.push(...lines);
671
- }
672
-
673
- logs.push("```");
674
- logs.push("");
675
- logs.push("");
676
- }
677
-
678
- return logs.join("\n");
679
- };
680
-
681
- const copyLogsToClipboard = async (summary: TscSummary): Promise<void> => {
682
- try {
683
- const logs = collectFailedPackageLogs(summary);
684
-
685
- if (!logs) {
686
- logger.info("ā„¹ļø No failed packages to copy to clipboard");
687
- return;
688
- }
689
-
690
- await clipboard.write(logs);
691
- logger.success("šŸ“‹ Failed package logs copied to clipboard!");
692
- } catch (error) {
693
- logger.error("āŒ Failed to copy logs to clipboard:");
694
- if (error instanceof Error) {
695
- logger.error(error.message);
696
- } else {
697
- logger.error(String(error));
698
- }
699
- }
700
- };
701
-
702
- // ============================================================================
703
- // Output Formatting
704
- // ============================================================================
705
-
706
- const formatOutput = (summary: TscSummary, verbose: boolean): void => {
707
- const { totalPackages, failedPackages, successfulPackages, skippedPackages } =
708
- summary;
709
-
710
- // Summary header
711
- logger.log("━".repeat(60));
712
- logger.log(`šŸ“Š TypeScript Check Summary:`);
713
- logger.log(` Total packages: ${totalPackages}`);
714
- logger.log(` āœ… Passed: ${successfulPackages}`);
715
- logger.log(` āŒ Failed: ${failedPackages}`);
716
- logger.log(` ā­ļø Skipped: ${skippedPackages}`);
717
- logger.log(` šŸ› Total errors: ${summary.totalErrors}`);
718
- logger.log(` āš ļø Total warnings: ${summary.totalWarnings}`);
719
- logger.log("━".repeat(60));
720
-
721
- // Failed packages
722
- const failed = summary.results.filter((r) => !r.success && !r.skipped);
723
-
724
- if (failed.length > 0) {
725
- logger.error("\nāŒ Failed Packages:\n");
726
-
727
- for (const result of failed) {
728
- logger.error(`šŸ“¦ ${result.package.name}`);
729
- logger.error(
730
- ` Errors: ${result.filteredErrors}, Warnings: ${result.filteredWarnings}`,
731
- );
732
-
733
- if (result.filteredOutput.trim()) {
734
- logger.error(" ─".repeat(30));
735
- const lines = result.filteredOutput
736
- .trim()
737
- .split("\n")
738
- .map((line) => ` ${line}`);
739
- writeErrorLines(lines);
740
- logger.error("");
741
- }
742
- }
743
- }
744
-
745
- if (verbose) {
746
- // Successful packages
747
- const successful = summary.results.filter((r) => r.success && !r.skipped);
748
-
749
- if (successful.length > 0) {
750
- logger.success("\nāœ… Successful Packages:\n");
751
- for (const result of successful) {
752
- logger.success(` • ${result.package.name}`);
753
- }
754
- }
755
-
756
- // Skipped packages
757
- const skipped = summary.results.filter((r) => r.skipped);
758
-
759
- if (skipped.length > 0) {
760
- logger.info("\nā­ļø Skipped Packages (no tsconfig.json):\n");
761
- for (const result of skipped) {
762
- logger.info(` • ${result.package.name}`);
763
- }
764
- }
765
-
766
- logger.log("");
767
- }
768
- };
769
-
770
- // ============================================================================
771
- // Main Entry Point
772
- // ============================================================================
773
-
774
- export const runTscOnAllPackages = async (
775
- ignore?: string | string[],
776
- cwd?: string,
777
- options: TscOptions = {},
778
- ): Promise<TscSummary> => {
779
- const {
780
- verbose = false,
781
- copyLogs = false,
782
- cache: enableCache = true,
783
- autoConcurrency = false,
784
- } = options;
785
-
786
- return (async () => {
787
- // Initialize cache
788
- const cache = enableCache ? new TscCache() : undefined;
789
- if (cache) {
790
- await cache.initialize();
791
- }
792
-
793
- // Discover packages with timing
794
- const discoveryResult = await getWorkspacePackages(cwd);
795
- const { packages: allPackages, discoveryTime } = discoveryResult;
796
-
797
- if (verbose) {
798
- logger.info(
799
- ` Found ${allPackages.length} packages (${discoveryTime}ms)`,
800
- );
801
- logger.info(" Packages found:");
802
- for (const pkg of allPackages) {
803
- const configStatus = pkg.hasTsConfig ? "āœ…" : "ā­ļø";
804
- logger.info(` ${configStatus} ${pkg.name} (${pkg.path})`);
805
- }
806
- logger.info("");
807
- }
808
-
809
- // Apply filters
810
- const packages = filterPackages(allPackages, ignore);
811
- const ignoredCount = allPackages.length - packages.length;
812
-
813
- if (ignoredCount > 0) {
814
- // Always ignore @reliverse/dler-v1 package
815
- const alwaysIgnored = ["@reliverse/dler-v1"];
816
- const combinedIgnore = ignore
817
- ? Array.isArray(ignore)
818
- ? [...alwaysIgnored, ...ignore]
819
- : [...alwaysIgnored, ignore]
820
- : alwaysIgnored;
821
-
822
- const patterns = normalizePatterns(combinedIgnore);
823
- logger.info(
824
- ` Ignoring ${ignoredCount} packages matching: ${patterns.join(", ")}`,
825
- );
826
- }
827
-
828
- // Auto-detect concurrency if requested
829
- let concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
830
- if (autoConcurrency) {
831
- concurrency = Math.max(4, cpus().length * 2);
832
- }
833
-
834
- const { stopOnError = false } = options;
835
- logger.info(
836
- ` Checking ${packages.length} packages (concurrency: ${concurrency}, stopOnError: ${stopOnError})...\n`,
837
- );
838
-
839
- if (verbose) {
840
- logger.info("šŸš€ Starting TypeScript checks...\n");
841
- }
842
-
843
- const summary = await collectAllResults(packages, discoveryResult.monorepoRoot, options, cache);
844
-
845
- // Display results
846
- formatOutput(summary, verbose);
847
-
848
- // Copy logs to clipboard if requested and there are errors
849
- if (copyLogs && summary.hasErrors) {
850
- await copyLogsToClipboard(summary);
851
- }
852
-
853
- return summary;
854
- })();
855
- };