@reliverse/dler 2.0.0 → 2.0.2

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 (135) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +3 -0
  3. package/dist/cmds/build/cmd.d.ts +2 -0
  4. package/dist/cmds/build/cmd.js +564 -0
  5. package/dist/cmds/clean/cmd.d.ts +2 -0
  6. package/dist/cmds/clean/cmd.js +146 -0
  7. package/dist/cmds/clean/impl.d.ts +2 -0
  8. package/dist/cmds/clean/impl.js +627 -0
  9. package/dist/cmds/clean/presets.d.ts +10 -0
  10. package/dist/cmds/clean/presets.js +112 -0
  11. package/dist/cmds/clean/types.d.ts +62 -0
  12. package/dist/cmds/clean/types.js +0 -0
  13. package/dist/cmds/init/cmd.d.ts +3 -0
  14. package/dist/cmds/init/cmd.js +56 -0
  15. package/dist/cmds/init/impl/config.d.ts +45 -0
  16. package/dist/cmds/init/impl/config.js +99 -0
  17. package/dist/cmds/init/impl/generators.d.ts +6 -0
  18. package/dist/cmds/init/impl/generators.js +178 -0
  19. package/dist/cmds/init/impl/prompts.d.ts +2 -0
  20. package/dist/cmds/init/impl/prompts.js +98 -0
  21. package/dist/cmds/init/impl/types.d.ts +22 -0
  22. package/dist/cmds/init/impl/types.js +0 -0
  23. package/dist/cmds/init/impl/utils.d.ts +4 -0
  24. package/dist/cmds/init/impl/utils.js +11 -0
  25. package/dist/cmds/init/impl/validators.d.ts +4 -0
  26. package/dist/cmds/init/impl/validators.js +42 -0
  27. package/dist/cmds/integrate/cmd.d.ts +3 -0
  28. package/dist/cmds/integrate/cmd.js +70 -0
  29. package/dist/cmds/integrate/impl.d.ts +7 -0
  30. package/dist/cmds/integrate/impl.js +127 -0
  31. package/dist/cmds/integrate/integrations/base.d.ts +13 -0
  32. package/dist/cmds/integrate/integrations/base.js +41 -0
  33. package/dist/cmds/integrate/integrations/nextjs.d.ts +16 -0
  34. package/dist/cmds/integrate/integrations/nextjs.js +167 -0
  35. package/dist/cmds/integrate/integrations/registry.d.ts +7 -0
  36. package/dist/cmds/integrate/integrations/registry.js +31 -0
  37. package/dist/cmds/integrate/integrations/ultracite.d.ts +11 -0
  38. package/dist/cmds/integrate/integrations/ultracite.js +40 -0
  39. package/dist/cmds/integrate/types.d.ts +39 -0
  40. package/dist/cmds/integrate/types.js +0 -0
  41. package/dist/cmds/integrate/utils/biome.d.ts +4 -0
  42. package/dist/cmds/integrate/utils/biome.js +140 -0
  43. package/dist/cmds/integrate/utils/context.d.ts +3 -0
  44. package/dist/cmds/integrate/utils/context.js +111 -0
  45. package/dist/cmds/integrate/utils/temp.d.ts +3 -0
  46. package/dist/cmds/integrate/utils/temp.js +36 -0
  47. package/dist/cmds/perf/analysis/bundle.d.ts +20 -0
  48. package/dist/cmds/perf/analysis/bundle.js +225 -0
  49. package/dist/cmds/perf/analysis/filesystem.d.ts +27 -0
  50. package/dist/cmds/perf/analysis/filesystem.js +246 -0
  51. package/dist/cmds/perf/analysis/monorepo.d.ts +29 -0
  52. package/dist/cmds/perf/analysis/monorepo.js +307 -0
  53. package/dist/cmds/perf/benchmarks/command.d.ts +21 -0
  54. package/dist/cmds/perf/benchmarks/command.js +162 -0
  55. package/dist/cmds/perf/benchmarks/memory.d.ts +41 -0
  56. package/dist/cmds/perf/benchmarks/memory.js +169 -0
  57. package/dist/cmds/perf/benchmarks/runner.d.ts +22 -0
  58. package/dist/cmds/perf/benchmarks/runner.js +157 -0
  59. package/dist/cmds/perf/cmd.d.ts +2 -0
  60. package/dist/cmds/perf/cmd.js +238 -0
  61. package/dist/cmds/perf/impl.d.ts +24 -0
  62. package/dist/cmds/perf/impl.js +304 -0
  63. package/dist/cmds/perf/reporters/console.d.ts +12 -0
  64. package/dist/cmds/perf/reporters/console.js +257 -0
  65. package/dist/cmds/perf/reporters/html.d.ts +27 -0
  66. package/dist/cmds/perf/reporters/html.js +881 -0
  67. package/dist/cmds/perf/reporters/json.d.ts +9 -0
  68. package/dist/cmds/perf/reporters/json.js +32 -0
  69. package/dist/cmds/perf/types.d.ts +184 -0
  70. package/dist/cmds/perf/types.js +0 -0
  71. package/dist/cmds/perf/utils/cache.d.ts +23 -0
  72. package/dist/cmds/perf/utils/cache.js +171 -0
  73. package/dist/cmds/perf/utils/formatter.d.ts +17 -0
  74. package/dist/cmds/perf/utils/formatter.js +134 -0
  75. package/dist/cmds/perf/utils/stats.d.ts +15 -0
  76. package/dist/cmds/perf/utils/stats.js +101 -0
  77. package/dist/cmds/publish/cmd.d.ts +3 -0
  78. package/dist/cmds/publish/cmd.js +189 -0
  79. package/dist/cmds/shell/cmd.d.ts +3 -0
  80. package/dist/cmds/shell/cmd.js +50 -0
  81. package/dist/cmds/tsc/cache.d.ts +27 -0
  82. package/dist/cmds/tsc/cache.js +160 -0
  83. package/dist/cmds/tsc/cmd.d.ts +2 -0
  84. package/dist/cmds/tsc/cmd.js +111 -0
  85. package/dist/cmds/tsc/impl.d.ts +41 -0
  86. package/dist/cmds/tsc/impl.js +572 -0
  87. package/dist/cmds/tsc/types.d.ts +57 -0
  88. package/dist/cmds/tsc/types.js +0 -0
  89. package/package.json +4 -11
  90. package/src/cli.ts +8 -0
  91. package/src/cmds/build/cmd.ts +582 -0
  92. package/src/cmds/clean/cmd.ts +166 -0
  93. package/src/cmds/clean/impl.ts +900 -0
  94. package/src/cmds/clean/presets.ts +158 -0
  95. package/src/cmds/clean/types.ts +71 -0
  96. package/src/cmds/init/cmd.ts +68 -0
  97. package/src/cmds/init/impl/config.ts +105 -0
  98. package/src/cmds/init/impl/generators.ts +220 -0
  99. package/src/cmds/init/impl/prompts.ts +137 -0
  100. package/src/cmds/init/impl/types.ts +25 -0
  101. package/src/cmds/init/impl/utils.ts +17 -0
  102. package/src/cmds/init/impl/validators.ts +55 -0
  103. package/src/cmds/integrate/cmd.ts +82 -0
  104. package/src/cmds/integrate/impl.ts +204 -0
  105. package/src/cmds/integrate/integrations/base.ts +69 -0
  106. package/src/cmds/integrate/integrations/nextjs.ts +227 -0
  107. package/src/cmds/integrate/integrations/registry.ts +45 -0
  108. package/src/cmds/integrate/integrations/ultracite.ts +53 -0
  109. package/src/cmds/integrate/types.ts +48 -0
  110. package/src/cmds/integrate/utils/biome.ts +173 -0
  111. package/src/cmds/integrate/utils/context.ts +148 -0
  112. package/src/cmds/integrate/utils/temp.ts +47 -0
  113. package/src/cmds/perf/analysis/bundle.ts +311 -0
  114. package/src/cmds/perf/analysis/filesystem.ts +324 -0
  115. package/src/cmds/perf/analysis/monorepo.ts +439 -0
  116. package/src/cmds/perf/benchmarks/command.ts +230 -0
  117. package/src/cmds/perf/benchmarks/memory.ts +249 -0
  118. package/src/cmds/perf/benchmarks/runner.ts +220 -0
  119. package/src/cmds/perf/cmd.ts +285 -0
  120. package/src/cmds/perf/impl.ts +411 -0
  121. package/src/cmds/perf/reporters/console.ts +331 -0
  122. package/src/cmds/perf/reporters/html.ts +984 -0
  123. package/src/cmds/perf/reporters/json.ts +42 -0
  124. package/src/cmds/perf/types.ts +220 -0
  125. package/src/cmds/perf/utils/cache.ts +234 -0
  126. package/src/cmds/perf/utils/formatter.ts +190 -0
  127. package/src/cmds/perf/utils/stats.ts +153 -0
  128. package/src/cmds/publish/cmd.ts +215 -0
  129. package/src/cmds/shell/cmd.ts +61 -0
  130. package/src/cmds/tsc/cache.ts +237 -0
  131. package/src/cmds/tsc/cmd.ts +139 -0
  132. package/src/cmds/tsc/impl.ts +855 -0
  133. package/src/cmds/tsc/types.ts +66 -0
  134. package/tsconfig.json +9 -0
  135. package/cli.js +0 -1316
@@ -0,0 +1,153 @@
1
+ // apps/dler/src/cmds/perf/utils/stats.ts
2
+
3
+ import type { Statistics } from "../types";
4
+
5
+ export const calculateStatistics = (values: number[]): Statistics => {
6
+ if (values.length === 0) {
7
+ return {
8
+ min: 0,
9
+ max: 0,
10
+ mean: 0,
11
+ median: 0,
12
+ p95: 0,
13
+ p99: 0,
14
+ variance: 0,
15
+ standardDeviation: 0,
16
+ coefficientOfVariation: 0,
17
+ };
18
+ }
19
+
20
+ const sorted = [...values].sort((a, b) => a - b);
21
+ const n = values.length;
22
+
23
+ const min = sorted[0]!;
24
+ const max = sorted[n - 1]!;
25
+ const mean = values.reduce((sum, val) => sum + val, 0) / n;
26
+
27
+ const median =
28
+ n % 2 === 0
29
+ ? (sorted[n / 2 - 1]! + sorted[n / 2]!) / 2
30
+ : sorted[Math.floor(n / 2)]!;
31
+
32
+ const p95 = percentile(sorted, 0.95);
33
+ const p99 = percentile(sorted, 0.99);
34
+
35
+ const variance =
36
+ values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / n;
37
+ const standardDeviation = Math.sqrt(variance);
38
+ const coefficientOfVariation = mean === 0 ? 0 : standardDeviation / mean;
39
+
40
+ return {
41
+ min,
42
+ max,
43
+ mean,
44
+ median,
45
+ p95,
46
+ p99,
47
+ variance,
48
+ standardDeviation,
49
+ coefficientOfVariation,
50
+ };
51
+ };
52
+
53
+ export const percentile = (sorted: number[], p: number): number => {
54
+ if (sorted.length === 0) return 0;
55
+ if (sorted.length === 1) return sorted[0]!;
56
+
57
+ const index = p * (sorted.length - 1);
58
+ const lower = Math.floor(index);
59
+ const upper = Math.ceil(index);
60
+
61
+ if (lower === upper) {
62
+ return sorted[lower]!;
63
+ }
64
+
65
+ const weight = index - lower;
66
+ return sorted[lower]! * (1 - weight) + sorted[upper]! * weight;
67
+ };
68
+
69
+ export const calculateMemoryGrowth = (
70
+ initial: number,
71
+ final: number,
72
+ ): number => {
73
+ return final - initial;
74
+ };
75
+
76
+ export const calculateMemoryAverage = (measurements: number[]): number => {
77
+ if (measurements.length === 0) return 0;
78
+ return measurements.reduce((sum, val) => sum + val, 0) / measurements.length;
79
+ };
80
+
81
+ export const findPeakMemory = (measurements: number[]): number => {
82
+ return measurements.length === 0 ? 0 : Math.max(...measurements);
83
+ };
84
+
85
+ export const calculateImprovement = (
86
+ baseline: number,
87
+ current: number,
88
+ ): number => {
89
+ if (baseline === 0) return 0;
90
+ return ((baseline - current) / baseline) * 100;
91
+ };
92
+
93
+ export const calculateRegression = (
94
+ baseline: number,
95
+ current: number,
96
+ ): number => {
97
+ if (baseline === 0) return 0;
98
+ return ((current - baseline) / baseline) * 100;
99
+ };
100
+
101
+ export const isSignificantChange = (
102
+ baseline: number,
103
+ current: number,
104
+ threshold = 5,
105
+ ): boolean => {
106
+ const change = Math.abs(calculateImprovement(baseline, current));
107
+ return change >= threshold;
108
+ };
109
+
110
+ export const calculateConfidenceInterval = (
111
+ values: number[],
112
+ confidence = 0.95,
113
+ ): { lower: number; upper: number } => {
114
+ if (values.length < 2) {
115
+ return { lower: values[0] ?? 0, upper: values[0] ?? 0 };
116
+ }
117
+
118
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
119
+ const variance =
120
+ values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) /
121
+ (values.length - 1);
122
+ const standardError = Math.sqrt(variance / values.length);
123
+
124
+ // Using t-distribution approximation for small samples
125
+ const tValue = confidence === 0.95 ? 1.96 : 2.576; // 95% or 99%
126
+ const margin = tValue * standardError;
127
+
128
+ return {
129
+ lower: mean - margin,
130
+ upper: mean + margin,
131
+ };
132
+ };
133
+
134
+ export const detectOutliers = (values: number[], threshold = 2): number[] => {
135
+ if (values.length < 3) return [];
136
+
137
+ const stats = calculateStatistics(values);
138
+ const outliers: number[] = [];
139
+
140
+ for (const value of values) {
141
+ const zScore = Math.abs((value - stats.mean) / stats.standardDeviation);
142
+ if (zScore > threshold) {
143
+ outliers.push(value);
144
+ }
145
+ }
146
+
147
+ return outliers;
148
+ };
149
+
150
+ export const removeOutliers = (values: number[], threshold = 2): number[] => {
151
+ const outliers = detectOutliers(values, threshold);
152
+ return values.filter((val) => !outliers.includes(val));
153
+ };
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import type { BumpType } from "@reliverse/dler-bump";
4
+ import {
5
+ defineCmd,
6
+ defineCmdArgs,
7
+ defineCmdCfg,
8
+ } from "@reliverse/dler-launcher";
9
+ import { logger } from "@reliverse/dler-logger";
10
+ import {
11
+ type PackageKind,
12
+ type PublishOptions,
13
+ publishAllPackages,
14
+ type RegistryType,
15
+ } from "@reliverse/dler-publish";
16
+
17
+ const publishCmd = async (args: any): Promise<void> => {
18
+ try {
19
+ // Check if running in Bun
20
+ if (typeof process.versions.bun === "undefined") {
21
+ logger.error("❌ This command requires Bun runtime. Sorry.");
22
+ process.exit(1);
23
+ }
24
+
25
+ const options: PublishOptions = {
26
+ dryRun: args.dryRun,
27
+ tag: args.tag,
28
+ access: args.access as "public" | "restricted",
29
+ otp: args.otp,
30
+ authType: args.authType as "web" | "legacy",
31
+ verbose: args.verbose,
32
+ bump: args.bump as BumpType,
33
+ concurrency: args.concurrency,
34
+ registry: args.registry as RegistryType,
35
+ kind: args.kind as PackageKind,
36
+ bumpDisable: args.bumpDisable,
37
+ };
38
+
39
+ const results = await publishAllPackages(args.cwd, args.ignore, options);
40
+
41
+ // Log warnings (non-fatal)
42
+ if (results.warningCount > 0) {
43
+ for (const result of results.results) {
44
+ if (result.warning) {
45
+ logger.warn(` ⚠️ ${result.packageName}: ${result.warning}`);
46
+ }
47
+ }
48
+ }
49
+
50
+ if (results.hasErrors) {
51
+ logger.error(
52
+ `\n❌ Publishing failed: ${results.errorCount} error(s), ${results.successCount} success(es)`,
53
+ );
54
+
55
+ // Log individual errors
56
+ for (const result of results.results) {
57
+ if (!result.success) {
58
+ logger.error(` ❌ ${result.packageName}: ${result.error}`);
59
+ }
60
+ }
61
+
62
+ process.exit(1);
63
+ }
64
+
65
+ logger.success(
66
+ `\n✅ All packages published successfully! (${results.successCount} packages)`,
67
+ );
68
+
69
+ if (args.verbose) {
70
+ for (const result of results.results) {
71
+ if (result.success && !result.warning) {
72
+ logger.log(` ✅ ${result.packageName}@${result.version}`);
73
+ }
74
+ }
75
+ }
76
+ } catch (error) {
77
+ logger.error("\n❌ Publish failed:");
78
+
79
+ if (error instanceof Error) {
80
+ logger.error(error.message);
81
+ } else {
82
+ logger.error(String(error));
83
+ }
84
+
85
+ process.exit(1);
86
+ }
87
+ };
88
+
89
+ const publishCmdArgs = defineCmdArgs({
90
+ ignore: {
91
+ type: "string",
92
+ description: "Package(s) to ignore (supports wildcards like @reliverse/*)",
93
+ },
94
+ cwd: {
95
+ type: "string",
96
+ description: "Working directory (monorepo root)",
97
+ },
98
+ bump: {
99
+ type: "string",
100
+ description:
101
+ "Version bump type: major, minor, patch, premajor, preminor, prepatch, prerelease",
102
+ },
103
+ tag: {
104
+ type: "string",
105
+ description: "npm dist-tag (default: latest)",
106
+ },
107
+ access: {
108
+ type: "string",
109
+ description: "Access level: public or restricted (default: public)",
110
+ },
111
+ dryRun: {
112
+ type: "boolean",
113
+ description:
114
+ "Simulate publishing without actually publishing (default: false)",
115
+ },
116
+ otp: {
117
+ type: "string",
118
+ description: "One-time password for 2FA authentication",
119
+ },
120
+ authType: {
121
+ type: "string",
122
+ description: "Authentication method: web or legacy (default: web)",
123
+ },
124
+ concurrency: {
125
+ type: "number",
126
+ description: "Number of packages to publish concurrently (default: 3)",
127
+ },
128
+ verbose: {
129
+ type: "boolean",
130
+ description: "Verbose mode (default: false)",
131
+ },
132
+ registry: {
133
+ type: "string",
134
+ description:
135
+ "Registry to publish to: npm, jsr, vercel, npm-jsr, or none (default: npm)",
136
+ },
137
+ kind: {
138
+ type: "string",
139
+ description:
140
+ "Package kind: library, browser-app, native-app, or cli (default: library)",
141
+ },
142
+ bumpDisable: {
143
+ type: "boolean",
144
+ description:
145
+ "Disable version bumping for all published packages, overwrites config (default: false)",
146
+ },
147
+ });
148
+
149
+ const publishCmdCfg = defineCmdCfg({
150
+ name: "publish",
151
+ description:
152
+ "Publish workspace packages to npm registry using Bun's native publish command. Automatically handles version bumping, package.json modification, and dist folder validation. Supports dler.ts configuration for per-package settings.",
153
+ examples: [
154
+ "dler publish",
155
+ 'dler publish --ignore "@reliverse/*"',
156
+ 'dler publish --ignore "@reliverse/dler-colors" --ignore "@reliverse/dler-v1"',
157
+ 'dler publish --ignore "@reliverse/dler-colors @reliverse/dler-v1"',
158
+ "dler publish --cwd /path/to/monorepo",
159
+ "dler publish --cwd /path/to/monorepo --ignore @reliverse/*",
160
+ "dler publish --bump patch",
161
+ "dler publish --bump minor --tag next",
162
+ "dler publish --bump major --access public",
163
+ "dler publish --dry-run",
164
+ "dler publish --dry-run --verbose",
165
+ "dler publish --tag alpha",
166
+ "dler publish --access restricted",
167
+ "dler publish --otp 123456",
168
+ "dler publish --auth-type legacy",
169
+ "dler publish --concurrency 3",
170
+ "dler publish --verbose",
171
+ "dler publish --bump patch --tag next --dry-run --verbose",
172
+ "dler publish --ignore @reliverse/* --bump minor --concurrency 2",
173
+ "dler publish --registry npm",
174
+ "dler publish --registry jsr",
175
+ "dler publish --registry vercel",
176
+ "dler publish --registry npm-jsr",
177
+ "dler publish --registry none",
178
+ "dler publish --kind library",
179
+ "dler publish --kind browser-app",
180
+ "dler publish --kind native-app",
181
+ "dler publish --kind cli",
182
+ "dler publish --kind library --registry npm",
183
+ "dler publish --kind browser-app --registry vercel",
184
+ "dler publish --kind cli --registry jsr",
185
+ "dler publish --bumpDisable",
186
+ "dler publish --bumpDisable --dry-run",
187
+ "dler publish --bumpDisable --tag next",
188
+ "",
189
+ "# Configuration Examples:",
190
+ "# Create dler.ts in your monorepo root:",
191
+ "# export default {",
192
+ "# publish: {",
193
+ "# global: { access: 'public', tag: 'latest', registry: 'npm', kind: 'library' },",
194
+ "# packages: { ",
195
+ "# 'my-library': { tag: 'next', bump: 'minor', registry: 'jsr', kind: 'library' },",
196
+ "# 'my-web-app': { registry: 'vercel', kind: 'browser-app' },",
197
+ "# 'my-native-app': { registry: 'none', kind: 'native-app' },",
198
+ "# 'my-cli-tool': { registry: 'npm', kind: 'cli' },",
199
+ "# 'my-library': { bumpDisable: true, tag: 'next' }",
200
+ "# },",
201
+ "# patterns: [{ pattern: '*example*', config: { dryRun: true, registry: 'vercel', kind: 'browser-app' } }]",
202
+ "# }",
203
+ "# }",
204
+ "",
205
+ "# Note: Make sure to run 'dler build --prepareForPublish' first to:",
206
+ "# - Generate dist folders and declaration files",
207
+ "# - Transform package.json exports field for built files",
208
+ "# - Add bin field for CLI packages",
209
+ "# - Set private: false and publishConfig",
210
+ "# The publish command will then handle version bumping and registry publishing",
211
+ "# CLI flags override dler.ts configuration settings",
212
+ ],
213
+ });
214
+
215
+ export default defineCmd(publishCmd, publishCmdArgs, publishCmdCfg);
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import {
4
+ defineCmd,
5
+ defineCmdArgs,
6
+ defineCmdCfg,
7
+ } from "@reliverse/dler-launcher";
8
+ import { logger } from "@reliverse/dler-logger";
9
+ import { $ } from "bun";
10
+
11
+ const shellCmd = async (args: { x: string }): Promise<void> => {
12
+ try {
13
+ // Execute the command using Bun Shell
14
+ const commandParts = args.x.split(/\s+/);
15
+ const [command, ...commandArgs] = commandParts;
16
+
17
+ // Use template literal with arguments interpolation
18
+ await $`${command} ${commandArgs.join(" ")}`;
19
+ } catch (error) {
20
+ logger.error("\n❌ Command failed:");
21
+
22
+ if (error instanceof Error) {
23
+ // Check if it's a ShellError with exit code
24
+ if ("exitCode" in error) {
25
+ logger.error(`Exit code: ${(error as any).exitCode}`);
26
+ if ((error as any).stdout) {
27
+ logger.error(`STDOUT: ${(error as any).stdout.toString()}`);
28
+ }
29
+ if ((error as any).stderr) {
30
+ logger.error(`STDERR: ${(error as any).stderr.toString()}`);
31
+ }
32
+ } else {
33
+ logger.error(error.message);
34
+ }
35
+ } else {
36
+ logger.error(String(error));
37
+ }
38
+
39
+ process.exit(1);
40
+ }
41
+ };
42
+
43
+ const shellCmdArgs = defineCmdArgs({
44
+ x: {
45
+ type: "string",
46
+ required: true,
47
+ description: "Shell command to execute",
48
+ },
49
+ });
50
+
51
+ const shellCmdCfg = defineCmdCfg({
52
+ name: "shell",
53
+ description: "Execute shell commands using Bun Shell API",
54
+ examples: [
55
+ 'dler shell --x "echo Hello World"',
56
+ 'dler shell --x "ls -la"',
57
+ 'dler shell --x "cat package.json | grep name"',
58
+ ],
59
+ });
60
+
61
+ export default defineCmd(shellCmd, shellCmdArgs, shellCmdCfg);
@@ -0,0 +1,237 @@
1
+ // apps/dler/src/cmds/tsc/cache.ts
2
+
3
+ import { existsSync, statSync } from "node:fs";
4
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import type { PackageInfo } from "./impl";
7
+ import type {
8
+ CacheMetadata,
9
+ PackageCacheEntry,
10
+ SourceFileInfo,
11
+ TscCacheOptions,
12
+ } from "./types";
13
+
14
+ const CACHE_VERSION = "1.0.0";
15
+ const DEFAULT_CACHE_DIR = "node_modules/.cache/dler-tsc";
16
+ const DEFAULT_MAX_AGE = 24 * 60 * 60 * 1000; // 24 hours
17
+
18
+ export class TscCache {
19
+ private options: TscCacheOptions;
20
+ private metadata: CacheMetadata | null = null;
21
+ private metadataPath: string;
22
+
23
+ constructor(options: Partial<TscCacheOptions> = {}) {
24
+ this.options = {
25
+ enabled: options.enabled ?? true,
26
+ cacheDir: options.cacheDir ?? DEFAULT_CACHE_DIR,
27
+ maxAge: options.maxAge ?? DEFAULT_MAX_AGE,
28
+ };
29
+ this.metadataPath = join(this.options.cacheDir, "metadata.json");
30
+ }
31
+
32
+ async initialize(): Promise<void> {
33
+ if (!this.options.enabled) return;
34
+
35
+ try {
36
+ await mkdir(this.options.cacheDir, { recursive: true });
37
+ await this.loadMetadata();
38
+ } catch (error) {
39
+ // Cache initialization failed, disable caching
40
+ this.options.enabled = false;
41
+ }
42
+ }
43
+
44
+ private async loadMetadata(): Promise<void> {
45
+ if (!existsSync(this.metadataPath)) {
46
+ this.metadata = {
47
+ version: CACHE_VERSION,
48
+ lastUpdated: Date.now(),
49
+ packages: {},
50
+ };
51
+ return;
52
+ }
53
+
54
+ try {
55
+ const content = await readFile(this.metadataPath, "utf-8");
56
+ this.metadata = JSON.parse(content) as CacheMetadata;
57
+
58
+ // Check if cache is too old
59
+ if (Date.now() - this.metadata.lastUpdated > this.options.maxAge) {
60
+ this.metadata = {
61
+ version: CACHE_VERSION,
62
+ lastUpdated: Date.now(),
63
+ packages: {},
64
+ };
65
+ }
66
+ } catch {
67
+ this.metadata = {
68
+ version: CACHE_VERSION,
69
+ lastUpdated: Date.now(),
70
+ packages: {},
71
+ };
72
+ }
73
+ }
74
+
75
+ private async saveMetadata(): Promise<void> {
76
+ if (!this.options.enabled || !this.metadata) return;
77
+
78
+ try {
79
+ this.metadata.lastUpdated = Date.now();
80
+ await writeFile(
81
+ this.metadataPath,
82
+ JSON.stringify(this.metadata, null, 2),
83
+ "utf-8",
84
+ );
85
+ } catch {
86
+ // Ignore save errors
87
+ }
88
+ }
89
+
90
+ private async getSourceFiles(packagePath: string): Promise<SourceFileInfo[]> {
91
+ const sourceFiles: SourceFileInfo[] = [];
92
+ const tsConfigPath = join(packagePath, "tsconfig.json");
93
+
94
+ if (!existsSync(tsConfigPath)) {
95
+ return sourceFiles;
96
+ }
97
+
98
+ try {
99
+ // Find all TypeScript files in the package
100
+ const glob = new Bun.Glob("**/*.{ts,tsx}");
101
+ const matches = glob.scanSync({
102
+ cwd: packagePath,
103
+ onlyFiles: true,
104
+ });
105
+
106
+ for (const match of matches) {
107
+ const filePath = join(packagePath, match);
108
+ if (existsSync(filePath)) {
109
+ const stats = statSync(filePath);
110
+ sourceFiles.push({
111
+ path: match,
112
+ mtime: stats.mtime.getTime(),
113
+ size: stats.size,
114
+ });
115
+ }
116
+ }
117
+ } catch {
118
+ // Ignore glob errors
119
+ }
120
+
121
+ return sourceFiles;
122
+ }
123
+
124
+ private hasSourceFilesChanged(
125
+ cached: SourceFileInfo[],
126
+ current: SourceFileInfo[],
127
+ ): boolean {
128
+ if (cached.length !== current.length) return true;
129
+
130
+ const currentMap = new Map(current.map((file) => [file.path, file]));
131
+
132
+ for (const cachedFile of cached) {
133
+ const currentFile = currentMap.get(cachedFile.path);
134
+ if (
135
+ !currentFile ||
136
+ currentFile.mtime !== cachedFile.mtime ||
137
+ currentFile.size !== cachedFile.size
138
+ ) {
139
+ return true;
140
+ }
141
+ }
142
+
143
+ return false;
144
+ }
145
+
146
+ async shouldSkipPackage(pkg: PackageInfo): Promise<boolean> {
147
+ if (!this.options.enabled || !this.metadata) return false;
148
+
149
+ const cacheEntry = this.metadata.packages[pkg.name];
150
+ if (!cacheEntry || !cacheEntry.lastSuccess) return false;
151
+
152
+ // Check if package was successfully checked recently
153
+ const timeSinceLastSuccess = Date.now() - cacheEntry.lastSuccess;
154
+ if (timeSinceLastSuccess > this.options.maxAge) return false;
155
+
156
+ // Check if source files have changed
157
+ const currentSourceFiles = await this.getSourceFiles(pkg.path);
158
+ if (
159
+ this.hasSourceFilesChanged(cacheEntry.sourceFiles, currentSourceFiles)
160
+ ) {
161
+ return false;
162
+ }
163
+
164
+ return true;
165
+ }
166
+
167
+ async getCachedResult(pkg: PackageInfo): Promise<PackageCacheEntry | null> {
168
+ if (!this.options.enabled || !this.metadata) return null;
169
+
170
+ const cacheEntry = this.metadata.packages[pkg.name];
171
+ if (!cacheEntry) return null;
172
+
173
+ // Check if source files have changed
174
+ const currentSourceFiles = await this.getSourceFiles(pkg.path);
175
+ if (
176
+ this.hasSourceFilesChanged(cacheEntry.sourceFiles, currentSourceFiles)
177
+ ) {
178
+ return null;
179
+ }
180
+
181
+ return cacheEntry;
182
+ }
183
+
184
+ async updatePackageCache(
185
+ pkg: PackageInfo,
186
+ result: {
187
+ success: boolean;
188
+ errorCount: number;
189
+ warningCount: number;
190
+ output?: string;
191
+ filteredOutput?: string;
192
+ },
193
+ ): Promise<void> {
194
+ if (!this.options.enabled || !this.metadata) return;
195
+
196
+ const sourceFiles = await this.getSourceFiles(pkg.path);
197
+ const now = Date.now();
198
+
199
+ this.metadata.packages[pkg.name] = {
200
+ lastCheck: now,
201
+ lastSuccess: result.success
202
+ ? now
203
+ : (this.metadata.packages[pkg.name]?.lastSuccess ?? null),
204
+ sourceFiles,
205
+ hasErrors: !result.success,
206
+ errorCount: result.errorCount,
207
+ warningCount: result.warningCount,
208
+ output: result.output,
209
+ filteredOutput: result.filteredOutput,
210
+ };
211
+
212
+ await this.saveMetadata();
213
+ }
214
+
215
+ async clearCache(): Promise<void> {
216
+ if (!this.options.enabled) return;
217
+
218
+ this.metadata = {
219
+ version: CACHE_VERSION,
220
+ lastUpdated: Date.now(),
221
+ packages: {},
222
+ };
223
+
224
+ await this.saveMetadata();
225
+ }
226
+
227
+ getCacheStats(): { totalPackages: number; successfulPackages: number } {
228
+ if (!this.metadata) return { totalPackages: 0, successfulPackages: 0 };
229
+
230
+ const totalPackages = Object.keys(this.metadata.packages).length;
231
+ const successfulPackages = Object.values(this.metadata.packages).filter(
232
+ (entry) => entry.lastSuccess !== null,
233
+ ).length;
234
+
235
+ return { totalPackages, successfulPackages };
236
+ }
237
+ }