balda-js 0.0.2 → 0.0.3
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/package.json +1 -6
- package/lib/cli.d.ts +0 -6
- package/lib/cli.js +0 -929
- package/lib/cli.js.map +0 -1
- package/lib/index.cjs +0 -3384
- package/lib/index.cjs.map +0 -1
- package/lib/index.d.cts +0 -1492
- package/lib/index.d.ts +0 -1492
- package/lib/index.js +0 -3327
- package/lib/index.js.map +0 -1
package/lib/cli.js
DELETED
@@ -1,929 +0,0 @@
|
|
1
|
-
var __defProp = Object.defineProperty;
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
3
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
4
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
5
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
6
|
-
if (decorator = decorators[i])
|
7
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
8
|
-
if (kind && result) __defProp(target, key, result);
|
9
|
-
return result;
|
10
|
-
};
|
11
|
-
|
12
|
-
// src/runtime/runtime.ts
|
13
|
-
var RunTime = class {
|
14
|
-
type;
|
15
|
-
constructor() {
|
16
|
-
this.type = this.getRunTime();
|
17
|
-
}
|
18
|
-
getRunTime() {
|
19
|
-
if (typeof Bun !== "undefined") {
|
20
|
-
return "bun";
|
21
|
-
} else if (typeof Deno !== "undefined") {
|
22
|
-
return "deno";
|
23
|
-
} else if (typeof process !== "undefined") {
|
24
|
-
return "node";
|
25
|
-
}
|
26
|
-
throw new Error("No environment detected");
|
27
|
-
}
|
28
|
-
};
|
29
|
-
var runtime = new RunTime();
|
30
|
-
|
31
|
-
// src/runtime/native_args.ts
|
32
|
-
var NativeArgs = class {
|
33
|
-
/**
|
34
|
-
* Gets CLI arguments, dynamically determining where they start
|
35
|
-
* Handles different execution contexts (direct execution, tsx, ts-node, etc.)
|
36
|
-
*/
|
37
|
-
getCliArgs() {
|
38
|
-
switch (runtime.type) {
|
39
|
-
case "bun":
|
40
|
-
return this.getBunArgs();
|
41
|
-
case "node":
|
42
|
-
return this.getNodeArgs();
|
43
|
-
case "deno":
|
44
|
-
return Deno.args;
|
45
|
-
default:
|
46
|
-
throw new Error("Unsupported runtime");
|
47
|
-
}
|
48
|
-
}
|
49
|
-
/**
|
50
|
-
* Gets Bun arguments, handling different execution contexts
|
51
|
-
*/
|
52
|
-
getBunArgs() {
|
53
|
-
const args2 = Bun.argv;
|
54
|
-
const scriptIndex = this.findScriptIndex(args2);
|
55
|
-
return args2.slice(scriptIndex + 1);
|
56
|
-
}
|
57
|
-
/**
|
58
|
-
* Gets Node.js arguments, handling different execution contexts
|
59
|
-
*/
|
60
|
-
getNodeArgs() {
|
61
|
-
const args2 = process.argv;
|
62
|
-
const scriptIndex = this.findScriptIndex(args2);
|
63
|
-
return args2.slice(scriptIndex + 1);
|
64
|
-
}
|
65
|
-
/**
|
66
|
-
* Finds the index of the actual script being executed
|
67
|
-
* Handles cases like: node script.js, tsx script.ts, ts-node script.ts, yarn, yarn run, npx, etc.
|
68
|
-
*/
|
69
|
-
findScriptIndex(args2) {
|
70
|
-
const scriptPatterns = [
|
71
|
-
/\.(js|ts|mjs|cjs)$/,
|
72
|
-
/^(tsx|ts-node|node|bun|yarn|npx|pnpm|npm)$/
|
73
|
-
];
|
74
|
-
for (let i = 0; i < args2.length; i++) {
|
75
|
-
const arg2 = args2[i];
|
76
|
-
if (arg2.startsWith("-")) {
|
77
|
-
continue;
|
78
|
-
}
|
79
|
-
if (arg2 === "yarn" && i + 1 < args2.length && args2[i + 1] === "run") {
|
80
|
-
return i + 1;
|
81
|
-
}
|
82
|
-
const isScript = scriptPatterns.some((pattern) => pattern.test(arg2));
|
83
|
-
if (isScript) {
|
84
|
-
return i;
|
85
|
-
}
|
86
|
-
}
|
87
|
-
for (let i = args2.length - 1; i >= 0; i--) {
|
88
|
-
const arg2 = args2[i];
|
89
|
-
if (!arg2.startsWith("-")) {
|
90
|
-
return i;
|
91
|
-
}
|
92
|
-
}
|
93
|
-
return 1;
|
94
|
-
}
|
95
|
-
};
|
96
|
-
var nativeArgs = new NativeArgs();
|
97
|
-
|
98
|
-
// src/utils.ts
|
99
|
-
var levenshteinDistance = (str1, str2) => {
|
100
|
-
const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null));
|
101
|
-
for (let i = 0; i <= str1.length; i++) {
|
102
|
-
matrix[0][i] = i;
|
103
|
-
}
|
104
|
-
for (let j = 0; j <= str2.length; j++) {
|
105
|
-
matrix[j][0] = j;
|
106
|
-
}
|
107
|
-
for (let j = 1; j <= str2.length; j++) {
|
108
|
-
for (let i = 1; i <= str1.length; i++) {
|
109
|
-
const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
110
|
-
matrix[j][i] = Math.min(
|
111
|
-
matrix[j][i - 1] + 1,
|
112
|
-
matrix[j - 1][i] + 1,
|
113
|
-
matrix[j - 1][i - 1] + indicator
|
114
|
-
);
|
115
|
-
}
|
116
|
-
}
|
117
|
-
return matrix[str2.length][str1.length];
|
118
|
-
};
|
119
|
-
|
120
|
-
// src/commands/arg_parser.ts
|
121
|
-
var parseFlag = (arg2) => {
|
122
|
-
if (!arg2 || arg2 === "-" || arg2 === "--") {
|
123
|
-
return null;
|
124
|
-
}
|
125
|
-
const equalIndex = arg2.indexOf("=");
|
126
|
-
if (equalIndex > 0) {
|
127
|
-
const name = arg2.substring(0, equalIndex);
|
128
|
-
const value = arg2.substring(equalIndex + 1);
|
129
|
-
return {
|
130
|
-
name,
|
131
|
-
value: parseFlagValue(value)
|
132
|
-
};
|
133
|
-
}
|
134
|
-
return { name: arg2, value: true };
|
135
|
-
};
|
136
|
-
var parseFlagValue = (value) => {
|
137
|
-
if (value.toLowerCase() === "true") {
|
138
|
-
return true;
|
139
|
-
}
|
140
|
-
if (value.toLowerCase() === "false") {
|
141
|
-
return false;
|
142
|
-
}
|
143
|
-
const numValue = Number(value);
|
144
|
-
if (!Number.isNaN(numValue) && Number.isFinite(numValue)) {
|
145
|
-
return numValue;
|
146
|
-
}
|
147
|
-
return value;
|
148
|
-
};
|
149
|
-
var parseCliArgsAndFlags = () => {
|
150
|
-
const cliArgs = nativeArgs.getCliArgs();
|
151
|
-
const parsedArgs = [];
|
152
|
-
const parsedFlags = {};
|
153
|
-
if (!cliArgs || !cliArgs.length) {
|
154
|
-
return { args: parsedArgs, flags: parsedFlags };
|
155
|
-
}
|
156
|
-
for (let i = 0; i < cliArgs.length; i++) {
|
157
|
-
const arg2 = cliArgs[i];
|
158
|
-
if (!arg2 || typeof arg2 !== "string") {
|
159
|
-
continue;
|
160
|
-
}
|
161
|
-
if (arg2.startsWith("-")) {
|
162
|
-
const flag2 = parseFlag(arg2);
|
163
|
-
if (flag2) {
|
164
|
-
if (flag2.value === true && i + 1 < cliArgs.length) {
|
165
|
-
const nextArg = cliArgs[i + 1];
|
166
|
-
if (nextArg && typeof nextArg === "string" && !nextArg.startsWith("-")) {
|
167
|
-
flag2.value = parseFlagValue(nextArg);
|
168
|
-
i++;
|
169
|
-
}
|
170
|
-
}
|
171
|
-
parsedFlags[flag2.name] = flag2.value;
|
172
|
-
}
|
173
|
-
continue;
|
174
|
-
}
|
175
|
-
parsedArgs.push(arg2);
|
176
|
-
}
|
177
|
-
return { args: parsedArgs, flags: parsedFlags };
|
178
|
-
};
|
179
|
-
var findSimilarCommands = (notFoundCommand, availableCommands) => {
|
180
|
-
if (!notFoundCommand || typeof notFoundCommand !== "string") {
|
181
|
-
return "";
|
182
|
-
}
|
183
|
-
if (!availableCommands || !Array.isArray(availableCommands) || availableCommands.length === 0) {
|
184
|
-
return "";
|
185
|
-
}
|
186
|
-
const searchTerm = notFoundCommand.toLowerCase().trim();
|
187
|
-
const similarCommands = availableCommands.filter((command) => {
|
188
|
-
const normalizedCommand = command.toLowerCase();
|
189
|
-
if (normalizedCommand === searchTerm) {
|
190
|
-
return true;
|
191
|
-
}
|
192
|
-
if (normalizedCommand.includes(searchTerm) || searchTerm.includes(normalizedCommand)) {
|
193
|
-
return true;
|
194
|
-
}
|
195
|
-
const distance = levenshteinDistance(normalizedCommand, searchTerm);
|
196
|
-
const maxDistance = Math.max(searchTerm.length, normalizedCommand.length) * 0.4;
|
197
|
-
return distance <= maxDistance;
|
198
|
-
});
|
199
|
-
if (similarCommands.length === 0) {
|
200
|
-
return "";
|
201
|
-
}
|
202
|
-
const topSuggestions = similarCommands.slice(0, 3);
|
203
|
-
const suggestions = topSuggestions.map((cmd) => `\x1B[36m${cmd}\x1B[0m`).join(", ");
|
204
|
-
return `\x1B[31m\u2717\x1B[0m Command \x1B[33m${notFoundCommand}\x1B[0m not found
|
205
|
-
\x1B[32m\u{1F4A1}\x1B[0m Did you mean: ${suggestions}?`;
|
206
|
-
};
|
207
|
-
var getCalledCommandName = () => {
|
208
|
-
const cliArgs = nativeArgs.getCliArgs();
|
209
|
-
return cliArgs[0] || null;
|
210
|
-
};
|
211
|
-
|
212
|
-
// src/runtime/native_exit.ts
|
213
|
-
var NativeExit = class {
|
214
|
-
exit(code) {
|
215
|
-
switch (runtime.type) {
|
216
|
-
case "bun":
|
217
|
-
case "node":
|
218
|
-
process.exit(code);
|
219
|
-
case "deno":
|
220
|
-
Deno.exit(code);
|
221
|
-
default:
|
222
|
-
throw new Error("Unsupported runtime");
|
223
|
-
}
|
224
|
-
}
|
225
|
-
};
|
226
|
-
var nativeExit = new NativeExit();
|
227
|
-
|
228
|
-
// src/commands/command_registry.ts
|
229
|
-
import { glob } from "glob";
|
230
|
-
|
231
|
-
// src/commands/base_commands/generate_plugin.ts
|
232
|
-
import { join } from "path";
|
233
|
-
|
234
|
-
// src/metadata_store.ts
|
235
|
-
var MetadataStore = class {
|
236
|
-
static metadata = /* @__PURE__ */ new WeakMap();
|
237
|
-
/**
|
238
|
-
* Set the metadata for the given target and property key
|
239
|
-
*/
|
240
|
-
static set(target, propertyKey, value) {
|
241
|
-
if (!this.metadata.has(target)) {
|
242
|
-
this.metadata.set(target, /* @__PURE__ */ new Map());
|
243
|
-
}
|
244
|
-
this.metadata.get(target).set(propertyKey, value);
|
245
|
-
}
|
246
|
-
/**
|
247
|
-
* Get the metadata for the given target and property key
|
248
|
-
*/
|
249
|
-
static get(target, propertyKey) {
|
250
|
-
return this.metadata.get(target)?.get(propertyKey);
|
251
|
-
}
|
252
|
-
/**
|
253
|
-
* Get all the metadata for the given target
|
254
|
-
*/
|
255
|
-
static getAll(target) {
|
256
|
-
return this.metadata.get(target) || /* @__PURE__ */ new Map();
|
257
|
-
}
|
258
|
-
/**
|
259
|
-
* Delete the metadata for the given target and property key
|
260
|
-
*/
|
261
|
-
static delete(target, propertyKey) {
|
262
|
-
this.metadata.get(target)?.delete(propertyKey.toString());
|
263
|
-
}
|
264
|
-
/**
|
265
|
-
* Clear all the metadata for the given target
|
266
|
-
*/
|
267
|
-
static clear(target) {
|
268
|
-
this.metadata.delete(target);
|
269
|
-
}
|
270
|
-
};
|
271
|
-
|
272
|
-
// src/decorators/command/arg.ts
|
273
|
-
var VALIDATION_ERROR_SYMBOL = "VALIDATION_ERROR";
|
274
|
-
var args = parseCliArgsAndFlags().args.slice(1);
|
275
|
-
var arg = (options) => {
|
276
|
-
return (target, propertyKey) => {
|
277
|
-
const currentCommandName = getCalledCommandName();
|
278
|
-
if (!currentCommandName || currentCommandName !== target.commandName) {
|
279
|
-
return;
|
280
|
-
}
|
281
|
-
const argName = propertyKey;
|
282
|
-
MetadataStore.set(target, propertyKey, {
|
283
|
-
type: "arg",
|
284
|
-
name: argName,
|
285
|
-
description: options.description
|
286
|
-
});
|
287
|
-
let argValue = args.length ? args.shift() : options.defaultValue;
|
288
|
-
if (options.required && !argValue) {
|
289
|
-
const errorChain = MetadataStore.get(target, VALIDATION_ERROR_SYMBOL);
|
290
|
-
MetadataStore.set(target, VALIDATION_ERROR_SYMBOL, [
|
291
|
-
...errorChain || [],
|
292
|
-
{
|
293
|
-
type: "arg",
|
294
|
-
name: argName,
|
295
|
-
message: "Required argument not provided"
|
296
|
-
}
|
297
|
-
]);
|
298
|
-
return;
|
299
|
-
}
|
300
|
-
if (options.parse && argValue) {
|
301
|
-
argValue = options.parse(argValue);
|
302
|
-
}
|
303
|
-
Object.defineProperty(target, propertyKey, {
|
304
|
-
value: argValue,
|
305
|
-
enumerable: true,
|
306
|
-
configurable: true,
|
307
|
-
writable: true
|
308
|
-
});
|
309
|
-
};
|
310
|
-
};
|
311
|
-
|
312
|
-
// src/logger/logger.ts
|
313
|
-
import pino from "pino";
|
314
|
-
var createBaseLogger = () => {
|
315
|
-
const baseOptions = {
|
316
|
-
level: "info",
|
317
|
-
formatters: {
|
318
|
-
level: (label) => {
|
319
|
-
return { level: label };
|
320
|
-
}
|
321
|
-
}
|
322
|
-
};
|
323
|
-
return pino(baseOptions);
|
324
|
-
};
|
325
|
-
var logger = createBaseLogger();
|
326
|
-
|
327
|
-
// src/commands/base_command.ts
|
328
|
-
var Command = class {
|
329
|
-
/**
|
330
|
-
* The name of the command.
|
331
|
-
*/
|
332
|
-
static commandName = this.name;
|
333
|
-
/**
|
334
|
-
* The description of the command.
|
335
|
-
*/
|
336
|
-
static description = "";
|
337
|
-
/**
|
338
|
-
* The help text of the command.
|
339
|
-
*/
|
340
|
-
static help = [];
|
341
|
-
/**
|
342
|
-
* The options of the command.
|
343
|
-
*/
|
344
|
-
static options = {
|
345
|
-
keepAlive: false
|
346
|
-
};
|
347
|
-
/**
|
348
|
-
* Static arguments in order to be validated by decorators. Will be fetched in the command instance.
|
349
|
-
*/
|
350
|
-
static args = parseCliArgsAndFlags().args.slice(1);
|
351
|
-
/**
|
352
|
-
* Static flags in order to be validated by decorators. Will be fetched in the command instance.
|
353
|
-
*/
|
354
|
-
static flags = parseCliArgsAndFlags().flags;
|
355
|
-
static logger = logger;
|
356
|
-
/**
|
357
|
-
* Main entry point for the command.
|
358
|
-
*/
|
359
|
-
static handle() {
|
360
|
-
throw new Error(
|
361
|
-
`Handle method not implemented in command class ${this.name}`
|
362
|
-
);
|
363
|
-
}
|
364
|
-
/**
|
365
|
-
* Enhanced help flag handler with rich formatting and command information
|
366
|
-
*/
|
367
|
-
static handleHelpFlag(flags) {
|
368
|
-
const helpFlags = ["-h", "--help", "-?", "--usage"];
|
369
|
-
const hasHelpFlag = Object.keys(flags).some(
|
370
|
-
(flag2) => helpFlags.includes(flag2)
|
371
|
-
);
|
372
|
-
if (!hasHelpFlag) {
|
373
|
-
return;
|
374
|
-
}
|
375
|
-
const commandName = this.commandName;
|
376
|
-
const description = this.description || "No description available";
|
377
|
-
const helpText = this.help || [];
|
378
|
-
const options = this.options;
|
379
|
-
const helpOutput = this.generateHelpOutput(
|
380
|
-
{
|
381
|
-
name: commandName,
|
382
|
-
description,
|
383
|
-
helpText,
|
384
|
-
options,
|
385
|
-
args: this.args,
|
386
|
-
flags: this.flags
|
387
|
-
},
|
388
|
-
this
|
389
|
-
);
|
390
|
-
console.log(helpOutput);
|
391
|
-
nativeExit.exit(0);
|
392
|
-
}
|
393
|
-
static generateHelpOutput = (info, commandClass) => {
|
394
|
-
const { name, description, helpText, options, args: args2, flags } = info;
|
395
|
-
const colors = {
|
396
|
-
title: "\x1B[1;36m",
|
397
|
-
// Bright cyan
|
398
|
-
subtitle: "\x1B[1;33m",
|
399
|
-
// Bright yellow
|
400
|
-
description: "\x1B[0;37m",
|
401
|
-
// White
|
402
|
-
code: "\x1B[0;32m",
|
403
|
-
// Green
|
404
|
-
flag: "\x1B[0;35m",
|
405
|
-
// Magenta
|
406
|
-
reset: "\x1B[0m",
|
407
|
-
// Reset
|
408
|
-
error: "\x1B[0;31m",
|
409
|
-
// Red
|
410
|
-
success: "\x1B[0;32m",
|
411
|
-
// Green
|
412
|
-
info: "\x1B[0;34m"
|
413
|
-
// Blue
|
414
|
-
};
|
415
|
-
const lines = [
|
416
|
-
`${colors.title}${name}${colors.reset}`,
|
417
|
-
`${colors.description}${description}${colors.reset}`,
|
418
|
-
"",
|
419
|
-
`${colors.subtitle}Usage:${colors.reset}`,
|
420
|
-
` ${colors.code}${name}${colors.reset} [options] [arguments]`,
|
421
|
-
"",
|
422
|
-
`${colors.subtitle}Options:${colors.reset}`,
|
423
|
-
` ${colors.flag}-h, --help${colors.reset} Show this help message`,
|
424
|
-
` ${colors.flag}-?, --usage${colors.reset} Show usage information`,
|
425
|
-
"",
|
426
|
-
`${colors.subtitle}Command Options:${colors.reset}`,
|
427
|
-
` ${colors.flag}keepAlive${colors.reset} ${options?.keepAlive ?? false ? colors.success + "Enabled" + colors.reset : colors.error + "Disabled" + colors.reset}`,
|
428
|
-
""
|
429
|
-
];
|
430
|
-
if (helpText) {
|
431
|
-
const helpLines = Array.isArray(helpText) ? helpText : [helpText];
|
432
|
-
lines.push(`${colors.subtitle}Help:${colors.reset}`);
|
433
|
-
helpLines.forEach((line) => {
|
434
|
-
lines.push(` ${colors.description}${line}${colors.reset}`);
|
435
|
-
});
|
436
|
-
lines.push("");
|
437
|
-
}
|
438
|
-
const allMeta = MetadataStore.getAll(commandClass);
|
439
|
-
const argsMeta = Array.from(allMeta.values()).filter(
|
440
|
-
(meta) => meta.type === "arg"
|
441
|
-
);
|
442
|
-
const flagsMeta = Array.from(allMeta.values()).filter(
|
443
|
-
(meta) => meta.type === "flag"
|
444
|
-
);
|
445
|
-
if (argsMeta.length) {
|
446
|
-
lines.push(`${colors.subtitle}Available Arguments:${colors.reset}`);
|
447
|
-
argsMeta.forEach((meta) => {
|
448
|
-
const required = meta.required ? ` ${colors.error}(required)${colors.reset}` : "";
|
449
|
-
const description2 = meta.description ? ` ${colors.description}${meta.description}${colors.reset}` : "";
|
450
|
-
lines.push(
|
451
|
-
` ${colors.code}${meta.name}${colors.reset}${required}${description2}`
|
452
|
-
);
|
453
|
-
});
|
454
|
-
lines.push("");
|
455
|
-
}
|
456
|
-
if (flagsMeta.length) {
|
457
|
-
lines.push(`${colors.subtitle}Available Flags:${colors.reset}`);
|
458
|
-
flagsMeta.forEach((meta) => {
|
459
|
-
if (meta.aliases && !Array.isArray(meta.aliases)) {
|
460
|
-
meta.aliases = [meta.aliases];
|
461
|
-
}
|
462
|
-
const aliases = meta.aliases.length ? ` ${colors.flag}(${meta.aliases.join(", ")})${colors.reset}` : "";
|
463
|
-
const required = meta.required ? ` ${colors.error}(required)${colors.reset}` : "";
|
464
|
-
const description2 = meta.description ? ` ${colors.description}${meta.description}${colors.reset}` : "";
|
465
|
-
lines.push(
|
466
|
-
` ${colors.flag}--${meta.name}${aliases}${colors.reset}${required}${description2}`
|
467
|
-
);
|
468
|
-
});
|
469
|
-
lines.push("");
|
470
|
-
}
|
471
|
-
if ((args2?.length ?? 0) > 0 || flags && Object.keys(flags).length > 0) {
|
472
|
-
lines.push(`${colors.subtitle}Current Context:${colors.reset}`);
|
473
|
-
if (args2?.length) {
|
474
|
-
lines.push(
|
475
|
-
` ${colors.info}Provided Arguments:${colors.reset} ${colors.code}${args2.join(" ")}${colors.reset}`
|
476
|
-
);
|
477
|
-
}
|
478
|
-
if (flags && Object.keys(flags).length > 0) {
|
479
|
-
lines.push(` ${colors.info}Provided Flags:${colors.reset}`);
|
480
|
-
Object.keys(flags).forEach((flagKey) => {
|
481
|
-
const flagValue = flags[flagKey];
|
482
|
-
const valueDisplay = flagValue !== void 0 && flagValue !== null ? ` = ${colors.code}${flagValue}${colors.reset}` : "";
|
483
|
-
lines.push(
|
484
|
-
` ${colors.flag}${flagKey}${colors.reset}${valueDisplay}`
|
485
|
-
);
|
486
|
-
});
|
487
|
-
}
|
488
|
-
lines.push("");
|
489
|
-
}
|
490
|
-
if (helpText && (Array.isArray(helpText) ? helpText.some((line) => line.includes("example")) : helpText.includes("example"))) {
|
491
|
-
lines.push(`${colors.subtitle}Examples:${colors.reset}`);
|
492
|
-
const examples = Array.isArray(helpText) ? helpText.filter((line) => line.includes("example")) : [helpText.split("example")[1].trim()];
|
493
|
-
examples.forEach((example) => {
|
494
|
-
lines.push(` ${colors.code}${example}${colors.reset}`);
|
495
|
-
});
|
496
|
-
lines.push("");
|
497
|
-
}
|
498
|
-
return lines.join("\n");
|
499
|
-
};
|
500
|
-
static validateContext = (target) => {
|
501
|
-
const errorChain = Array.from(
|
502
|
-
MetadataStore.get(target, VALIDATION_ERROR_SYMBOL) || []
|
503
|
-
);
|
504
|
-
if (errorChain.length) {
|
505
|
-
const colors = {
|
506
|
-
error: "\x1B[0;31m",
|
507
|
-
// Red
|
508
|
-
title: "\x1B[1;31m",
|
509
|
-
// Bright red
|
510
|
-
reset: "\x1B[0m",
|
511
|
-
// Reset
|
512
|
-
info: "\x1B[0;34m",
|
513
|
-
// Blue
|
514
|
-
code: "\x1B[0;32m"
|
515
|
-
// Green
|
516
|
-
};
|
517
|
-
console.error(`${colors.title}\u274C Validation Errors:${colors.reset}`);
|
518
|
-
console.error("");
|
519
|
-
errorChain.forEach((error, index) => {
|
520
|
-
const errorNumber = `${colors.info}${index + 1}.${colors.reset}`;
|
521
|
-
const errorType = `${colors.error}${error.type.toUpperCase()}${colors.reset}`;
|
522
|
-
const errorName = `${colors.code}${error.name}${colors.reset}`;
|
523
|
-
console.error(
|
524
|
-
` ${errorNumber} ${errorType} ${errorName}: ${colors.error}${error.message}${colors.reset}`
|
525
|
-
);
|
526
|
-
});
|
527
|
-
console.error("");
|
528
|
-
console.error(
|
529
|
-
`${colors.info}\u{1F4A1} Tip: Use --help for usage information${colors.reset}`
|
530
|
-
);
|
531
|
-
nativeExit.exit(1);
|
532
|
-
}
|
533
|
-
};
|
534
|
-
};
|
535
|
-
|
536
|
-
// src/decorators/command/flag.ts
|
537
|
-
var flag = (options) => {
|
538
|
-
return (target, propertyKey) => {
|
539
|
-
const currentCommandName = getCalledCommandName();
|
540
|
-
if (!currentCommandName || currentCommandName !== target.commandName) {
|
541
|
-
return;
|
542
|
-
}
|
543
|
-
const primaryFlagName = options.name || propertyKey;
|
544
|
-
const parsedFlags = parseCliArgsAndFlags().flags;
|
545
|
-
const flagAliases = options.aliases || [];
|
546
|
-
const allFlagVariants = [primaryFlagName, ...flagAliases];
|
547
|
-
let resolvedFlagValue = options.defaultValue;
|
548
|
-
for (const flagVariant of allFlagVariants) {
|
549
|
-
const possibleNames = [
|
550
|
-
flagVariant,
|
551
|
-
`-${flagVariant}`,
|
552
|
-
`--${flagVariant}`
|
553
|
-
];
|
554
|
-
for (const flagName of possibleNames) {
|
555
|
-
if (flagName in parsedFlags) {
|
556
|
-
resolvedFlagValue = parsedFlags[flagName];
|
557
|
-
break;
|
558
|
-
}
|
559
|
-
}
|
560
|
-
if (resolvedFlagValue !== options.defaultValue) {
|
561
|
-
break;
|
562
|
-
}
|
563
|
-
}
|
564
|
-
MetadataStore.set(target, propertyKey, {
|
565
|
-
type: "flag",
|
566
|
-
name: primaryFlagName,
|
567
|
-
aliases: flagAliases || [],
|
568
|
-
description: options.description
|
569
|
-
});
|
570
|
-
if (options.required && !resolvedFlagValue) {
|
571
|
-
const errorChain = MetadataStore.get(target, VALIDATION_ERROR_SYMBOL);
|
572
|
-
MetadataStore.set(target, VALIDATION_ERROR_SYMBOL, [
|
573
|
-
...errorChain || [],
|
574
|
-
{
|
575
|
-
type: "flag",
|
576
|
-
name: primaryFlagName,
|
577
|
-
message: "Required flag not provided"
|
578
|
-
}
|
579
|
-
]);
|
580
|
-
return;
|
581
|
-
}
|
582
|
-
Object.defineProperty(target, propertyKey, {
|
583
|
-
value: resolvedFlagValue,
|
584
|
-
enumerable: true,
|
585
|
-
configurable: true,
|
586
|
-
writable: true
|
587
|
-
});
|
588
|
-
};
|
589
|
-
};
|
590
|
-
|
591
|
-
// src/runtime/native_fs.ts
|
592
|
-
var NativeFs = class {
|
593
|
-
async readFile(path) {
|
594
|
-
switch (runtime.type) {
|
595
|
-
case "node":
|
596
|
-
const fs = await import("fs/promises");
|
597
|
-
const buffer = await fs.readFile(path);
|
598
|
-
return new Uint8Array(buffer);
|
599
|
-
case "bun":
|
600
|
-
const arrayBuffer = await Bun.file(path).arrayBuffer();
|
601
|
-
return new Uint8Array(arrayBuffer);
|
602
|
-
case "deno":
|
603
|
-
return new Uint8Array(await Deno.readFile(path));
|
604
|
-
}
|
605
|
-
}
|
606
|
-
async writeFile(path, data) {
|
607
|
-
switch (runtime.type) {
|
608
|
-
case "node":
|
609
|
-
const fs = await import("fs/promises");
|
610
|
-
await fs.writeFile(path, data);
|
611
|
-
break;
|
612
|
-
case "bun":
|
613
|
-
await Bun.write(path, data);
|
614
|
-
break;
|
615
|
-
case "deno":
|
616
|
-
await Deno.writeFile(path, data);
|
617
|
-
break;
|
618
|
-
}
|
619
|
-
}
|
620
|
-
async stat(path) {
|
621
|
-
switch (runtime.type) {
|
622
|
-
case "node":
|
623
|
-
const fs = await import("fs/promises");
|
624
|
-
const stats = await fs.stat(path);
|
625
|
-
return {
|
626
|
-
isDirectory: stats.isDirectory(),
|
627
|
-
isFile: stats.isFile(),
|
628
|
-
isSymbolicLink: stats.isSymbolicLink(),
|
629
|
-
size: stats.size
|
630
|
-
};
|
631
|
-
case "bun":
|
632
|
-
const bunStats = await Bun.file(path).stat();
|
633
|
-
return {
|
634
|
-
isDirectory: bunStats.isDirectory(),
|
635
|
-
isFile: bunStats.isFile(),
|
636
|
-
isSymbolicLink: bunStats.isSymbolicLink(),
|
637
|
-
size: bunStats.size
|
638
|
-
};
|
639
|
-
case "deno":
|
640
|
-
const denoStats = await Deno.stat(path);
|
641
|
-
return {
|
642
|
-
isDirectory: denoStats.isDirectory,
|
643
|
-
isFile: denoStats.isFile,
|
644
|
-
isSymbolicLink: false,
|
645
|
-
size: denoStats.size
|
646
|
-
};
|
647
|
-
}
|
648
|
-
}
|
649
|
-
async unlink(path) {
|
650
|
-
switch (runtime.type) {
|
651
|
-
case "node":
|
652
|
-
const fs = await import("fs/promises");
|
653
|
-
await fs.unlink(path);
|
654
|
-
break;
|
655
|
-
case "bun":
|
656
|
-
await Bun.file(path).delete();
|
657
|
-
break;
|
658
|
-
case "deno":
|
659
|
-
await Deno.remove(path);
|
660
|
-
break;
|
661
|
-
default:
|
662
|
-
throw new Error("Unsupported runtime");
|
663
|
-
}
|
664
|
-
}
|
665
|
-
};
|
666
|
-
var nativeFs = new NativeFs();
|
667
|
-
|
668
|
-
// src/commands/base_commands/generate_plugin.ts
|
669
|
-
var GeneratePluginCommand = class extends Command {
|
670
|
-
static commandName = "generate-plugin";
|
671
|
-
static description = "Generate a new plugin in the specified path";
|
672
|
-
static help = [
|
673
|
-
"Generate a new plugin in the specified path",
|
674
|
-
"Example: npx balda generate-plugin my-plugin -p src/plugins"
|
675
|
-
];
|
676
|
-
static pluginName;
|
677
|
-
static pluginPath;
|
678
|
-
static async handle() {
|
679
|
-
const pluginTemplate = this.getPluginTemplate();
|
680
|
-
this.pluginPath = join(this.pluginPath, `${this.pluginName}.ts`);
|
681
|
-
await nativeFs.writeFile(
|
682
|
-
this.pluginPath,
|
683
|
-
new TextEncoder().encode(pluginTemplate)
|
684
|
-
);
|
685
|
-
this.logger.info(
|
686
|
-
`Plugin ${this.name} created successfully at ${this.pluginPath}`
|
687
|
-
);
|
688
|
-
}
|
689
|
-
static getPluginTemplate() {
|
690
|
-
return `import { BasePlugin, Request, Response, NextFunction, ServerRouteMiddleware } from "balda";
|
691
|
-
|
692
|
-
export default class extends BasePlugin {
|
693
|
-
async handle(): Promise<ServerRouteMiddleware> {
|
694
|
-
return async (req: Request, res: Response, next: NextFunction) => {
|
695
|
-
console.log("${this.pluginName} plugin is running");
|
696
|
-
await next();
|
697
|
-
};
|
698
|
-
}
|
699
|
-
}`;
|
700
|
-
}
|
701
|
-
};
|
702
|
-
__decorateClass([
|
703
|
-
arg({
|
704
|
-
description: "The name of the plugin to generate",
|
705
|
-
required: true
|
706
|
-
})
|
707
|
-
], GeneratePluginCommand, "pluginName", 2);
|
708
|
-
__decorateClass([
|
709
|
-
flag({
|
710
|
-
description: "The path to the plugin to generate, default is src/plugins",
|
711
|
-
type: "string",
|
712
|
-
aliases: "p",
|
713
|
-
name: "path",
|
714
|
-
required: false,
|
715
|
-
defaultValue: "src/plugins"
|
716
|
-
})
|
717
|
-
], GeneratePluginCommand, "pluginPath", 2);
|
718
|
-
|
719
|
-
// src/commands/base_commands/generate_command.ts
|
720
|
-
import { join as join2 } from "path";
|
721
|
-
var GenerateCommand = class extends Command {
|
722
|
-
static commandName = "generate-command";
|
723
|
-
static description = "Generate a new command in the specified path";
|
724
|
-
static help = [
|
725
|
-
"Generate a new cli command in the specified path",
|
726
|
-
"Example: npx balda generate-command my-command -p src/commands"
|
727
|
-
];
|
728
|
-
static name;
|
729
|
-
static path;
|
730
|
-
static async handle() {
|
731
|
-
const commandTemplate = this.getCommandTemplate();
|
732
|
-
this.path = join2(this.path, `${this.name}.ts`);
|
733
|
-
await nativeFs.writeFile(
|
734
|
-
this.path,
|
735
|
-
new TextEncoder().encode(commandTemplate)
|
736
|
-
);
|
737
|
-
this.logger.info(
|
738
|
-
`Command ${this.name} created successfully at ${this.path}`
|
739
|
-
);
|
740
|
-
}
|
741
|
-
static getCommandTemplate() {
|
742
|
-
return `import { Command } from "balda";
|
743
|
-
|
744
|
-
export default class extends Command {
|
745
|
-
static commandName = "${this.name}";
|
746
|
-
static description = "${this.description}";
|
747
|
-
|
748
|
-
static options = {};
|
749
|
-
|
750
|
-
static async handle(): Promise<void> {
|
751
|
-
// Implement your command logic here
|
752
|
-
}
|
753
|
-
}`;
|
754
|
-
}
|
755
|
-
};
|
756
|
-
__decorateClass([
|
757
|
-
arg({
|
758
|
-
description: "The name of the command to generate",
|
759
|
-
required: true
|
760
|
-
})
|
761
|
-
], GenerateCommand, "name", 2);
|
762
|
-
__decorateClass([
|
763
|
-
flag({
|
764
|
-
description: "The path to the command to generate, default is src/commands",
|
765
|
-
type: "string",
|
766
|
-
aliases: "p",
|
767
|
-
name: "path",
|
768
|
-
required: false,
|
769
|
-
defaultValue: "src/commands"
|
770
|
-
})
|
771
|
-
], GenerateCommand, "path", 2);
|
772
|
-
|
773
|
-
// src/commands/base_commands/generate_cron.ts
|
774
|
-
import { join as join3 } from "path";
|
775
|
-
var GenerateCron = class extends Command {
|
776
|
-
static commandName = "generate-cron";
|
777
|
-
static description = "Generate a new cron job in the specified path";
|
778
|
-
static help = [
|
779
|
-
"Generate a new cron job in the specified path",
|
780
|
-
"Example: npx balda generate-cron my-cron -p src/cron"
|
781
|
-
];
|
782
|
-
static fileName;
|
783
|
-
static path;
|
784
|
-
static async handle() {
|
785
|
-
const cronTemplate = this.getCronTemplate();
|
786
|
-
this.path = join3(this.path, `${this.fileName}.ts`);
|
787
|
-
await nativeFs.writeFile(this.path, new TextEncoder().encode(cronTemplate));
|
788
|
-
this.logger.info(
|
789
|
-
`Cron job ${this.fileName} created successfully at ${this.path}`
|
790
|
-
);
|
791
|
-
}
|
792
|
-
static getCronTemplate() {
|
793
|
-
return `import { cron } from "balda-js";
|
794
|
-
|
795
|
-
export default class {
|
796
|
-
@cron("* * * * *")
|
797
|
-
handle() {
|
798
|
-
// Implement your cron job logic here
|
799
|
-
}
|
800
|
-
}`;
|
801
|
-
}
|
802
|
-
};
|
803
|
-
__decorateClass([
|
804
|
-
arg({
|
805
|
-
description: "The name of the cron job file to generate",
|
806
|
-
required: true
|
807
|
-
})
|
808
|
-
], GenerateCron, "fileName", 2);
|
809
|
-
__decorateClass([
|
810
|
-
flag({
|
811
|
-
description: "The path to the cron job to generate, default is src/cron",
|
812
|
-
type: "string",
|
813
|
-
aliases: "p",
|
814
|
-
name: "path",
|
815
|
-
required: false,
|
816
|
-
defaultValue: "src/cron"
|
817
|
-
})
|
818
|
-
], GenerateCron, "path", 2);
|
819
|
-
|
820
|
-
// src/commands/command_registry.ts
|
821
|
-
var CommandRegistry = class _CommandRegistry {
|
822
|
-
commands;
|
823
|
-
static commandsPattern = "commands/**/*.{ts,js}";
|
824
|
-
static logger = logger;
|
825
|
-
/**
|
826
|
-
* Private constructor to prevent direct instantiation
|
827
|
-
* @internal Not meant to be used outside by the user
|
828
|
-
*/
|
829
|
-
constructor() {
|
830
|
-
this.commands = /* @__PURE__ */ new Map();
|
831
|
-
}
|
832
|
-
static getInstance() {
|
833
|
-
return new _CommandRegistry();
|
834
|
-
}
|
835
|
-
static setCommandsPattern(pattern) {
|
836
|
-
this.commandsPattern = pattern;
|
837
|
-
}
|
838
|
-
getCommand(name) {
|
839
|
-
return this.commands.get(name) ?? null;
|
840
|
-
}
|
841
|
-
getCommands() {
|
842
|
-
return Array.from(this.commands.values());
|
843
|
-
}
|
844
|
-
async loadCommands(commandsPattern) {
|
845
|
-
_CommandRegistry.logger.info(`Loading commands from ${commandsPattern}`);
|
846
|
-
const commandFiles = await glob(commandsPattern);
|
847
|
-
for (const commandFile of commandFiles) {
|
848
|
-
const command = await import(commandFile).then((module) => {
|
849
|
-
if (module.default) {
|
850
|
-
return module.default;
|
851
|
-
}
|
852
|
-
return module;
|
853
|
-
}).catch((error) => {
|
854
|
-
_CommandRegistry.logger.error(
|
855
|
-
`Error loading command ${commandFile}: ${error}`
|
856
|
-
);
|
857
|
-
return null;
|
858
|
-
});
|
859
|
-
if (command) {
|
860
|
-
this.commands.set(command.commandName, command);
|
861
|
-
}
|
862
|
-
}
|
863
|
-
const baseCommands = [
|
864
|
-
GeneratePluginCommand,
|
865
|
-
GenerateCommand,
|
866
|
-
GenerateCron
|
867
|
-
];
|
868
|
-
for (const command of baseCommands) {
|
869
|
-
this.commands.set(command.commandName, command);
|
870
|
-
}
|
871
|
-
}
|
872
|
-
};
|
873
|
-
var commandRegistry = CommandRegistry.getInstance();
|
874
|
-
|
875
|
-
// src/cli.ts
|
876
|
-
var cli = async () => {
|
877
|
-
await commandRegistry.loadCommands(CommandRegistry.commandsPattern);
|
878
|
-
const commandName = nativeArgs.getCliArgs()[0];
|
879
|
-
if (!commandName) {
|
880
|
-
console.error(
|
881
|
-
`No command provided, available commands: ${commandRegistry.getCommands().map((command) => command.commandName).join(", ")}`
|
882
|
-
);
|
883
|
-
nativeExit.exit(1);
|
884
|
-
return;
|
885
|
-
}
|
886
|
-
const CommandClass = commandRegistry.getCommand(commandName);
|
887
|
-
if (!CommandClass) {
|
888
|
-
console.error(
|
889
|
-
findSimilarCommands(
|
890
|
-
commandName,
|
891
|
-
commandRegistry.getCommands().map((command) => command.commandName)
|
892
|
-
) || `Command ${commandName} not found`
|
893
|
-
);
|
894
|
-
nativeExit.exit(1);
|
895
|
-
return;
|
896
|
-
}
|
897
|
-
const commandClass = CommandClass;
|
898
|
-
commandClass.handleHelpFlag(commandClass.flags);
|
899
|
-
commandClass.validateContext(commandClass);
|
900
|
-
await commandClass.handle();
|
901
|
-
const keepAlive = CommandClass.options?.keepAlive ?? false;
|
902
|
-
if (!keepAlive) {
|
903
|
-
nativeExit.exit(0);
|
904
|
-
}
|
905
|
-
};
|
906
|
-
if (typeof process !== "undefined") {
|
907
|
-
import("module").then(({ register }) => {
|
908
|
-
register("ts-node/esm", import.meta.url);
|
909
|
-
cli().catch((err) => {
|
910
|
-
CommandRegistry.logger.error(err);
|
911
|
-
process.exit(1);
|
912
|
-
});
|
913
|
-
}).catch(() => {
|
914
|
-
CommandRegistry.logger.error(
|
915
|
-
`Failed to register ts-node/esm, you need to install it in your project in order to use typescript in the cli
|
916
|
-
try running: npm install -D ts-node`
|
917
|
-
);
|
918
|
-
process.exit(1);
|
919
|
-
});
|
920
|
-
} else {
|
921
|
-
cli().catch((err) => {
|
922
|
-
CommandRegistry.logger.error(err);
|
923
|
-
nativeExit.exit(1);
|
924
|
-
});
|
925
|
-
}
|
926
|
-
export {
|
927
|
-
cli
|
928
|
-
};
|
929
|
-
//# sourceMappingURL=cli.js.map
|