trickle-cli 0.1.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/dist/api-client.d.ts +208 -0
- package/dist/api-client.js +237 -0
- package/dist/commands/annotate.d.ts +6 -0
- package/dist/commands/annotate.js +433 -0
- package/dist/commands/audit.d.ts +7 -0
- package/dist/commands/audit.js +82 -0
- package/dist/commands/auto.d.ts +8 -0
- package/dist/commands/auto.js +268 -0
- package/dist/commands/capture.d.ts +14 -0
- package/dist/commands/capture.js +271 -0
- package/dist/commands/check.d.ts +6 -0
- package/dist/commands/check.js +408 -0
- package/dist/commands/codegen.d.ts +21 -0
- package/dist/commands/codegen.js +129 -0
- package/dist/commands/coverage.d.ts +13 -0
- package/dist/commands/coverage.js +126 -0
- package/dist/commands/dashboard.d.ts +1 -0
- package/dist/commands/dashboard.js +83 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.js +319 -0
- package/dist/commands/diff.d.ts +7 -0
- package/dist/commands/diff.js +79 -0
- package/dist/commands/docs.d.ts +13 -0
- package/dist/commands/docs.js +383 -0
- package/dist/commands/errors.d.ts +7 -0
- package/dist/commands/errors.js +180 -0
- package/dist/commands/export.d.ts +18 -0
- package/dist/commands/export.js +238 -0
- package/dist/commands/functions.d.ts +6 -0
- package/dist/commands/functions.js +71 -0
- package/dist/commands/infer.d.ts +14 -0
- package/dist/commands/infer.js +275 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.js +395 -0
- package/dist/commands/mock.d.ts +5 -0
- package/dist/commands/mock.js +232 -0
- package/dist/commands/openapi.d.ts +8 -0
- package/dist/commands/openapi.js +82 -0
- package/dist/commands/overview.d.ts +11 -0
- package/dist/commands/overview.js +266 -0
- package/dist/commands/pack.d.ts +11 -0
- package/dist/commands/pack.js +133 -0
- package/dist/commands/proxy.d.ts +13 -0
- package/dist/commands/proxy.js +312 -0
- package/dist/commands/replay.d.ts +14 -0
- package/dist/commands/replay.js +289 -0
- package/dist/commands/run.d.ts +17 -0
- package/dist/commands/run.js +997 -0
- package/dist/commands/sample.d.ts +13 -0
- package/dist/commands/sample.js +260 -0
- package/dist/commands/search.d.ts +5 -0
- package/dist/commands/search.js +80 -0
- package/dist/commands/stubs.d.ts +6 -0
- package/dist/commands/stubs.js +187 -0
- package/dist/commands/tail.d.ts +4 -0
- package/dist/commands/tail.js +76 -0
- package/dist/commands/test-gen.d.ts +13 -0
- package/dist/commands/test-gen.js +237 -0
- package/dist/commands/trace.d.ts +14 -0
- package/dist/commands/trace.js +417 -0
- package/dist/commands/types.d.ts +7 -0
- package/dist/commands/types.js +128 -0
- package/dist/commands/unpack.d.ts +11 -0
- package/dist/commands/unpack.js +166 -0
- package/dist/commands/validate.d.ts +13 -0
- package/dist/commands/validate.js +310 -0
- package/dist/commands/watch.d.ts +9 -0
- package/dist/commands/watch.js +267 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +66 -0
- package/dist/formatters/diff-formatter.d.ts +5 -0
- package/dist/formatters/diff-formatter.js +43 -0
- package/dist/formatters/type-formatter.d.ts +22 -0
- package/dist/formatters/type-formatter.js +135 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +419 -0
- package/dist/local-codegen.d.ts +22 -0
- package/dist/local-codegen.js +762 -0
- package/dist/ui/badges.d.ts +16 -0
- package/dist/ui/badges.js +71 -0
- package/dist/ui/helpers.d.ts +13 -0
- package/dist/ui/helpers.js +85 -0
- package/package.json +23 -0
- package/src/api-client.ts +407 -0
- package/src/commands/annotate.ts +450 -0
- package/src/commands/audit.ts +103 -0
- package/src/commands/auto.ts +268 -0
- package/src/commands/capture.ts +257 -0
- package/src/commands/check.ts +437 -0
- package/src/commands/codegen.ts +128 -0
- package/src/commands/coverage.ts +170 -0
- package/src/commands/dashboard.ts +46 -0
- package/src/commands/dev.ts +323 -0
- package/src/commands/diff.ts +99 -0
- package/src/commands/docs.ts +392 -0
- package/src/commands/errors.ts +205 -0
- package/src/commands/export.ts +287 -0
- package/src/commands/functions.ts +81 -0
- package/src/commands/infer.ts +260 -0
- package/src/commands/init.ts +419 -0
- package/src/commands/mock.ts +220 -0
- package/src/commands/openapi.ts +53 -0
- package/src/commands/overview.ts +310 -0
- package/src/commands/pack.ts +139 -0
- package/src/commands/proxy.ts +314 -0
- package/src/commands/replay.ts +356 -0
- package/src/commands/run.ts +1190 -0
- package/src/commands/sample.ts +259 -0
- package/src/commands/search.ts +107 -0
- package/src/commands/stubs.ts +211 -0
- package/src/commands/tail.ts +94 -0
- package/src/commands/test-gen.ts +236 -0
- package/src/commands/trace.ts +440 -0
- package/src/commands/types.ts +161 -0
- package/src/commands/unpack.ts +179 -0
- package/src/commands/validate.ts +368 -0
- package/src/commands/watch.ts +277 -0
- package/src/config.ts +38 -0
- package/src/formatters/diff-formatter.ts +51 -0
- package/src/formatters/type-formatter.ts +161 -0
- package/src/index.ts +454 -0
- package/src/local-codegen.ts +859 -0
- package/src/ui/badges.ts +66 -0
- package/src/ui/helpers.ts +80 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.watchCommand = watchCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const api_client_1 = require("../api-client");
|
|
44
|
+
const config_1 = require("../config");
|
|
45
|
+
/**
|
|
46
|
+
* Detect which codegen formats are relevant based on package.json dependencies.
|
|
47
|
+
*/
|
|
48
|
+
function detectFormats(projectDir) {
|
|
49
|
+
const pkgPath = path.join(projectDir, "package.json");
|
|
50
|
+
if (!fs.existsSync(pkgPath)) {
|
|
51
|
+
return [
|
|
52
|
+
{ format: "", fileName: "types.d.ts", label: "TypeScript types" },
|
|
53
|
+
{ format: "guards", fileName: "guards.ts", label: "Type guards" },
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
let pkg;
|
|
57
|
+
try {
|
|
58
|
+
pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [
|
|
62
|
+
{ format: "", fileName: "types.d.ts", label: "TypeScript types" },
|
|
63
|
+
{ format: "guards", fileName: "guards.ts", label: "Type guards" },
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
const deps = {
|
|
67
|
+
...(pkg.dependencies || {}),
|
|
68
|
+
...(pkg.devDependencies || {}),
|
|
69
|
+
};
|
|
70
|
+
const formats = [];
|
|
71
|
+
formats.push({ format: "", fileName: "types.d.ts", label: "TypeScript types" });
|
|
72
|
+
if (deps["axios"]) {
|
|
73
|
+
formats.push({ format: "axios", fileName: "axios-client.ts", label: "Axios client" });
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
formats.push({ format: "client", fileName: "api-client.ts", label: "Fetch API client" });
|
|
77
|
+
}
|
|
78
|
+
if (deps["@tanstack/react-query"] || deps["react-query"]) {
|
|
79
|
+
formats.push({ format: "react-query", fileName: "hooks.ts", label: "React Query hooks" });
|
|
80
|
+
}
|
|
81
|
+
if (deps["swr"]) {
|
|
82
|
+
formats.push({ format: "swr", fileName: "swr-hooks.ts", label: "SWR hooks" });
|
|
83
|
+
}
|
|
84
|
+
if (deps["zod"]) {
|
|
85
|
+
formats.push({ format: "zod", fileName: "schemas.ts", label: "Zod schemas" });
|
|
86
|
+
}
|
|
87
|
+
if (deps["@trpc/server"] || deps["@trpc/client"]) {
|
|
88
|
+
formats.push({ format: "trpc", fileName: "trpc-router.ts", label: "tRPC router" });
|
|
89
|
+
}
|
|
90
|
+
if (deps["class-validator"] || deps["@nestjs/common"]) {
|
|
91
|
+
formats.push({ format: "class-validator", fileName: "dtos.ts", label: "class-validator DTOs" });
|
|
92
|
+
}
|
|
93
|
+
if (deps["express"] || deps["@types/express"]) {
|
|
94
|
+
formats.push({ format: "handlers", fileName: "handlers.d.ts", label: "Express handler types" });
|
|
95
|
+
}
|
|
96
|
+
if (deps["msw"]) {
|
|
97
|
+
formats.push({ format: "msw", fileName: "msw-handlers.ts", label: "MSW mock handlers" });
|
|
98
|
+
}
|
|
99
|
+
formats.push({ format: "guards", fileName: "guards.ts", label: "Type guards" });
|
|
100
|
+
return formats;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build a fingerprint from the functions list to detect changes.
|
|
104
|
+
* Uses function names + type hashes + last_seen timestamps.
|
|
105
|
+
*/
|
|
106
|
+
function buildFingerprint(functions) {
|
|
107
|
+
const parts = functions
|
|
108
|
+
.map((f) => `${f.function_name}:${f.last_seen_at}`)
|
|
109
|
+
.sort();
|
|
110
|
+
return parts.join("|");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Generate all relevant type files to the output directory.
|
|
114
|
+
*/
|
|
115
|
+
async function regenerate(formats, outDir, env) {
|
|
116
|
+
if (!fs.existsSync(outDir)) {
|
|
117
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
118
|
+
}
|
|
119
|
+
const files = [];
|
|
120
|
+
let generated = 0;
|
|
121
|
+
for (const f of formats) {
|
|
122
|
+
try {
|
|
123
|
+
const result = await (0, api_client_1.fetchCodegen)({
|
|
124
|
+
env,
|
|
125
|
+
format: f.format || undefined,
|
|
126
|
+
});
|
|
127
|
+
const content = result.types;
|
|
128
|
+
if (!content || content.includes("No functions found") || content.includes("No API routes found")) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const filePath = path.join(outDir, f.fileName);
|
|
132
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
133
|
+
generated++;
|
|
134
|
+
files.push(f.fileName);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Skip failed formats silently
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { generated, files };
|
|
141
|
+
}
|
|
142
|
+
function timestamp() {
|
|
143
|
+
const now = new Date();
|
|
144
|
+
return now.toLocaleTimeString("en-US", { hour12: false });
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* `trickle watch` — Watch for new type observations and auto-regenerate type files.
|
|
148
|
+
*/
|
|
149
|
+
async function watchCommand(opts) {
|
|
150
|
+
const backendUrl = (0, config_1.getBackendUrl)();
|
|
151
|
+
const projectDir = process.cwd();
|
|
152
|
+
const outDir = path.resolve(opts.dir || ".trickle");
|
|
153
|
+
const intervalMs = parseInterval(opts.interval || "3s");
|
|
154
|
+
// Check backend connectivity
|
|
155
|
+
try {
|
|
156
|
+
const res = await fetch(`${backendUrl}/api/health`, { signal: AbortSignal.timeout(3000) });
|
|
157
|
+
if (!res.ok)
|
|
158
|
+
throw new Error("not ok");
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
console.error(chalk_1.default.red(`\n Cannot reach trickle backend at ${chalk_1.default.bold(backendUrl)}\n`));
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
// Detect formats from project deps
|
|
165
|
+
const formats = detectFormats(projectDir);
|
|
166
|
+
console.log("");
|
|
167
|
+
console.log(chalk_1.default.bold(" trickle watch"));
|
|
168
|
+
console.log(chalk_1.default.gray(" " + "─".repeat(50)));
|
|
169
|
+
console.log(chalk_1.default.gray(` Backend: ${backendUrl}`));
|
|
170
|
+
console.log(chalk_1.default.gray(` Output: ${outDir}`));
|
|
171
|
+
console.log(chalk_1.default.gray(` Interval: ${opts.interval || "3s"}`));
|
|
172
|
+
if (opts.env) {
|
|
173
|
+
console.log(chalk_1.default.gray(` Env: ${opts.env}`));
|
|
174
|
+
}
|
|
175
|
+
console.log(chalk_1.default.gray(` Formats: ${formats.map((f) => f.fileName).join(", ")}`));
|
|
176
|
+
console.log(chalk_1.default.gray(" " + "─".repeat(50)));
|
|
177
|
+
console.log("");
|
|
178
|
+
// Initial generation
|
|
179
|
+
console.log(chalk_1.default.gray(` [${timestamp()}]`) + " Performing initial type generation...");
|
|
180
|
+
let lastFingerprint = "";
|
|
181
|
+
try {
|
|
182
|
+
const { functions } = await (0, api_client_1.listFunctions)({ env: opts.env, limit: 1000 });
|
|
183
|
+
if (functions.length > 0) {
|
|
184
|
+
lastFingerprint = buildFingerprint(functions);
|
|
185
|
+
const { generated, files } = await regenerate(formats, outDir, opts.env);
|
|
186
|
+
if (generated > 0) {
|
|
187
|
+
console.log(chalk_1.default.green(` [${timestamp()}]`) +
|
|
188
|
+
` Generated ${generated} files: ${chalk_1.default.white(files.join(", "))}`);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(chalk_1.default.gray(` [${timestamp()}]`) + " No types to generate yet.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
console.log(chalk_1.default.gray(` [${timestamp()}]`) + " No observed functions yet. Waiting...");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
console.log(chalk_1.default.yellow(` [${timestamp()}]`) + " Could not fetch initial types. Will retry...");
|
|
200
|
+
}
|
|
201
|
+
console.log("");
|
|
202
|
+
console.log(chalk_1.default.gray(" Watching for type changes... (Ctrl+C to stop)"));
|
|
203
|
+
console.log("");
|
|
204
|
+
// Poll loop
|
|
205
|
+
const poll = async () => {
|
|
206
|
+
try {
|
|
207
|
+
const { functions } = await (0, api_client_1.listFunctions)({ env: opts.env, limit: 1000 });
|
|
208
|
+
const fingerprint = buildFingerprint(functions);
|
|
209
|
+
if (fingerprint !== lastFingerprint && fingerprint !== "") {
|
|
210
|
+
// Types changed — find what's new
|
|
211
|
+
const newFunctions = functions.filter((f) => {
|
|
212
|
+
// A function is "new" if it wasn't in the last fingerprint
|
|
213
|
+
return !lastFingerprint.includes(`${f.function_name}:`);
|
|
214
|
+
});
|
|
215
|
+
const updatedFunctions = functions.filter((f) => {
|
|
216
|
+
// A function is "updated" if its timestamp changed
|
|
217
|
+
const oldEntry = `${f.function_name}:${f.last_seen_at}`;
|
|
218
|
+
return lastFingerprint.includes(`${f.function_name}:`) && !lastFingerprint.includes(oldEntry);
|
|
219
|
+
});
|
|
220
|
+
lastFingerprint = fingerprint;
|
|
221
|
+
// Show what changed
|
|
222
|
+
for (const f of newFunctions) {
|
|
223
|
+
console.log(chalk_1.default.cyan(` [${timestamp()}]`) +
|
|
224
|
+
chalk_1.default.gray(" New: ") +
|
|
225
|
+
chalk_1.default.white(f.function_name));
|
|
226
|
+
}
|
|
227
|
+
for (const f of updatedFunctions) {
|
|
228
|
+
console.log(chalk_1.default.blue(` [${timestamp()}]`) +
|
|
229
|
+
chalk_1.default.gray(" Updated: ") +
|
|
230
|
+
chalk_1.default.white(f.function_name));
|
|
231
|
+
}
|
|
232
|
+
// Regenerate
|
|
233
|
+
const { generated, files } = await regenerate(formats, outDir, opts.env);
|
|
234
|
+
if (generated > 0) {
|
|
235
|
+
console.log(chalk_1.default.green(` [${timestamp()}]`) +
|
|
236
|
+
` Regenerated ${generated} files: ${chalk_1.default.white(files.join(", "))}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// Silently skip poll failures
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
// Set up interval
|
|
245
|
+
const timer = setInterval(poll, intervalMs);
|
|
246
|
+
// Handle graceful shutdown
|
|
247
|
+
const cleanup = () => {
|
|
248
|
+
clearInterval(timer);
|
|
249
|
+
console.log(chalk_1.default.gray(`\n [${timestamp()}]`) + " Watch stopped.\n");
|
|
250
|
+
process.exit(0);
|
|
251
|
+
};
|
|
252
|
+
process.on("SIGINT", cleanup);
|
|
253
|
+
process.on("SIGTERM", cleanup);
|
|
254
|
+
}
|
|
255
|
+
function parseInterval(input) {
|
|
256
|
+
const match = input.match(/^(\d+)(s|ms|m)?$/);
|
|
257
|
+
if (!match)
|
|
258
|
+
return 3000;
|
|
259
|
+
const value = parseInt(match[1], 10);
|
|
260
|
+
const unit = match[2] || "s";
|
|
261
|
+
switch (unit) {
|
|
262
|
+
case "ms": return value;
|
|
263
|
+
case "s": return value * 1000;
|
|
264
|
+
case "m": return value * 60 * 1000;
|
|
265
|
+
default: return value * 1000;
|
|
266
|
+
}
|
|
267
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getBackendUrl(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getBackendUrl = getBackendUrl;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const DEFAULT_BACKEND_URL = "http://localhost:4888";
|
|
41
|
+
function loadConfigFile() {
|
|
42
|
+
const configPath = path.join(os.homedir(), ".trickle", "config.json");
|
|
43
|
+
try {
|
|
44
|
+
if (fs.existsSync(configPath)) {
|
|
45
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
46
|
+
return JSON.parse(raw);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Ignore invalid config file
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function getBackendUrl() {
|
|
55
|
+
// 1. Environment variable takes priority
|
|
56
|
+
if (process.env.TRICKLE_BACKEND_URL) {
|
|
57
|
+
return process.env.TRICKLE_BACKEND_URL.replace(/\/+$/, "");
|
|
58
|
+
}
|
|
59
|
+
// 2. Config file
|
|
60
|
+
const config = loadConfigFile();
|
|
61
|
+
if (config?.backendUrl) {
|
|
62
|
+
return config.backendUrl.replace(/\/+$/, "");
|
|
63
|
+
}
|
|
64
|
+
// 3. Default
|
|
65
|
+
return DEFAULT_BACKEND_URL;
|
|
66
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatDiffs = formatDiffs;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const type_formatter_1 = require("./type-formatter");
|
|
9
|
+
/**
|
|
10
|
+
* Format an array of TypeDiff entries as colorized diff output.
|
|
11
|
+
*/
|
|
12
|
+
function formatDiffs(diffs) {
|
|
13
|
+
if (diffs.length === 0) {
|
|
14
|
+
return chalk_1.default.gray(" No differences found.");
|
|
15
|
+
}
|
|
16
|
+
const lines = [];
|
|
17
|
+
for (const diff of diffs) {
|
|
18
|
+
const pathStr = chalk_1.default.gray(diff.path);
|
|
19
|
+
switch (diff.kind) {
|
|
20
|
+
case "added":
|
|
21
|
+
lines.push(chalk_1.default.green(" + added ") +
|
|
22
|
+
pathStr +
|
|
23
|
+
chalk_1.default.gray(": ") +
|
|
24
|
+
(0, type_formatter_1.formatType)(diff.type, 0));
|
|
25
|
+
break;
|
|
26
|
+
case "removed":
|
|
27
|
+
lines.push(chalk_1.default.red(" - removed ") +
|
|
28
|
+
pathStr +
|
|
29
|
+
chalk_1.default.gray(": ") +
|
|
30
|
+
(0, type_formatter_1.formatType)(diff.type, 0));
|
|
31
|
+
break;
|
|
32
|
+
case "changed":
|
|
33
|
+
lines.push(chalk_1.default.yellow(" ~ changed ") +
|
|
34
|
+
pathStr +
|
|
35
|
+
chalk_1.default.gray(": ") +
|
|
36
|
+
(0, type_formatter_1.formatType)(diff.from, 0) +
|
|
37
|
+
chalk_1.default.gray(" -> ") +
|
|
38
|
+
(0, type_formatter_1.formatType)(diff.to, 0));
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface TypeNode {
|
|
2
|
+
kind: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
element?: TypeNode;
|
|
5
|
+
properties?: Record<string, TypeNode>;
|
|
6
|
+
members?: TypeNode[];
|
|
7
|
+
params?: TypeNode[];
|
|
8
|
+
returnType?: TypeNode;
|
|
9
|
+
resolved?: TypeNode;
|
|
10
|
+
key?: TypeNode;
|
|
11
|
+
value?: TypeNode;
|
|
12
|
+
elements?: TypeNode[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Format a TypeNode as colorized pseudo-TypeScript.
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatType(node: TypeNode | unknown, indent?: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format a type node as a compact single-line string (no colors).
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatTypePlain(node: TypeNode | unknown): string;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatType = formatType;
|
|
7
|
+
exports.formatTypePlain = formatTypePlain;
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const INDENT_SIZE = 2;
|
|
10
|
+
function primitiveColor(name) {
|
|
11
|
+
switch (name) {
|
|
12
|
+
case "string":
|
|
13
|
+
return chalk_1.default.green(name);
|
|
14
|
+
case "number":
|
|
15
|
+
case "bigint":
|
|
16
|
+
return chalk_1.default.yellow(name);
|
|
17
|
+
case "boolean":
|
|
18
|
+
return chalk_1.default.blue(name);
|
|
19
|
+
case "null":
|
|
20
|
+
case "undefined":
|
|
21
|
+
return chalk_1.default.gray(name);
|
|
22
|
+
case "symbol":
|
|
23
|
+
return chalk_1.default.magenta(name);
|
|
24
|
+
default:
|
|
25
|
+
return chalk_1.default.white(name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format a TypeNode as colorized pseudo-TypeScript.
|
|
30
|
+
*/
|
|
31
|
+
function formatType(node, indent = 0) {
|
|
32
|
+
if (!node || typeof node !== "object") {
|
|
33
|
+
return chalk_1.default.gray("unknown");
|
|
34
|
+
}
|
|
35
|
+
const n = node;
|
|
36
|
+
const pad = " ".repeat(indent);
|
|
37
|
+
const innerPad = " ".repeat(indent + INDENT_SIZE);
|
|
38
|
+
switch (n.kind) {
|
|
39
|
+
case "primitive":
|
|
40
|
+
return primitiveColor(n.name || "unknown");
|
|
41
|
+
case "array":
|
|
42
|
+
if (n.element) {
|
|
43
|
+
const inner = formatType(n.element, indent);
|
|
44
|
+
// Wrap complex types in parens for array notation
|
|
45
|
+
if (n.element.kind === "union") {
|
|
46
|
+
return `(${inner})[]`;
|
|
47
|
+
}
|
|
48
|
+
return `${inner}[]`;
|
|
49
|
+
}
|
|
50
|
+
return chalk_1.default.gray("unknown[]");
|
|
51
|
+
case "object": {
|
|
52
|
+
if (!n.properties)
|
|
53
|
+
return chalk_1.default.gray("{}");
|
|
54
|
+
const keys = Object.keys(n.properties);
|
|
55
|
+
if (keys.length === 0)
|
|
56
|
+
return chalk_1.default.gray("{}");
|
|
57
|
+
// Inline for small objects (2 or fewer properties)
|
|
58
|
+
if (keys.length <= 2) {
|
|
59
|
+
const props = keys.map((key) => `${chalk_1.default.white(key)}: ${formatType(n.properties[key], 0)}`);
|
|
60
|
+
return `{ ${props.join(", ")} }`;
|
|
61
|
+
}
|
|
62
|
+
// Multi-line for larger objects
|
|
63
|
+
const lines = keys.map((key) => `${innerPad}${chalk_1.default.white(key)}: ${formatType(n.properties[key], indent + INDENT_SIZE)}`);
|
|
64
|
+
return `{\n${lines.join(",\n")}\n${pad}}`;
|
|
65
|
+
}
|
|
66
|
+
case "union": {
|
|
67
|
+
if (!n.members || n.members.length === 0)
|
|
68
|
+
return chalk_1.default.gray("never");
|
|
69
|
+
return n.members.map((m) => formatType(m, indent)).join(chalk_1.default.gray(" | "));
|
|
70
|
+
}
|
|
71
|
+
case "function": {
|
|
72
|
+
const params = (n.params || [])
|
|
73
|
+
.map((p, i) => `${chalk_1.default.white(`arg${i}`)}: ${formatType(p, indent)}`)
|
|
74
|
+
.join(", ");
|
|
75
|
+
const ret = n.returnType ? formatType(n.returnType, indent) : chalk_1.default.gray("void");
|
|
76
|
+
return `(${params}) => ${ret}`;
|
|
77
|
+
}
|
|
78
|
+
case "promise": {
|
|
79
|
+
const resolved = n.resolved ? formatType(n.resolved, indent) : chalk_1.default.gray("unknown");
|
|
80
|
+
return `${chalk_1.default.cyan("Promise")}<${resolved}>`;
|
|
81
|
+
}
|
|
82
|
+
case "map": {
|
|
83
|
+
const key = n.key ? formatType(n.key, indent) : chalk_1.default.gray("unknown");
|
|
84
|
+
const value = n.value ? formatType(n.value, indent) : chalk_1.default.gray("unknown");
|
|
85
|
+
return `${chalk_1.default.cyan("Map")}<${key}, ${value}>`;
|
|
86
|
+
}
|
|
87
|
+
case "set": {
|
|
88
|
+
const element = n.element ? formatType(n.element, indent) : chalk_1.default.gray("unknown");
|
|
89
|
+
return `${chalk_1.default.cyan("Set")}<${element}>`;
|
|
90
|
+
}
|
|
91
|
+
case "tuple": {
|
|
92
|
+
if (!n.elements || n.elements.length === 0)
|
|
93
|
+
return "[]";
|
|
94
|
+
const elems = n.elements.map((e) => formatType(e, indent)).join(", ");
|
|
95
|
+
return `[${elems}]`;
|
|
96
|
+
}
|
|
97
|
+
case "unknown":
|
|
98
|
+
return chalk_1.default.gray("unknown");
|
|
99
|
+
default:
|
|
100
|
+
return chalk_1.default.gray("unknown");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format a type node as a compact single-line string (no colors).
|
|
105
|
+
*/
|
|
106
|
+
function formatTypePlain(node) {
|
|
107
|
+
if (!node || typeof node !== "object")
|
|
108
|
+
return "unknown";
|
|
109
|
+
const n = node;
|
|
110
|
+
switch (n.kind) {
|
|
111
|
+
case "primitive":
|
|
112
|
+
return n.name || "unknown";
|
|
113
|
+
case "array":
|
|
114
|
+
return n.element ? `${formatTypePlain(n.element)}[]` : "unknown[]";
|
|
115
|
+
case "object": {
|
|
116
|
+
if (!n.properties)
|
|
117
|
+
return "{}";
|
|
118
|
+
const keys = Object.keys(n.properties);
|
|
119
|
+
if (keys.length === 0)
|
|
120
|
+
return "{}";
|
|
121
|
+
const props = keys.map((k) => `${k}: ${formatTypePlain(n.properties[k])}`);
|
|
122
|
+
return `{ ${props.join(", ")} }`;
|
|
123
|
+
}
|
|
124
|
+
case "union":
|
|
125
|
+
return (n.members || []).map(formatTypePlain).join(" | ");
|
|
126
|
+
case "function": {
|
|
127
|
+
const params = (n.params || []).map((p, i) => `arg${i}: ${formatTypePlain(p)}`).join(", ");
|
|
128
|
+
return `(${params}) => ${n.returnType ? formatTypePlain(n.returnType) : "void"}`;
|
|
129
|
+
}
|
|
130
|
+
case "promise":
|
|
131
|
+
return `Promise<${n.resolved ? formatTypePlain(n.resolved) : "unknown"}>`;
|
|
132
|
+
default:
|
|
133
|
+
return "unknown";
|
|
134
|
+
}
|
|
135
|
+
}
|
package/dist/index.d.ts
ADDED