convoker 0.3.2 → 0.3.4
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/chunk-z5eko27R.mjs +13 -0
- package/dist/color-BuHvMolk.d.mts +158 -0
- package/dist/color-OlJQTTxb.mjs +172 -0
- package/dist/color.d.mts +2 -0
- package/dist/color.mjs +4 -0
- package/dist/command-BXmfoT-l.d.mts +331 -0
- package/dist/command-D2UiQBNA.mjs +583 -0
- package/dist/command.d.mts +5 -0
- package/dist/command.mjs +10 -0
- package/dist/error-C1S1gs8L.mjs +115 -0
- package/dist/error.d.mts +5 -0
- package/dist/error.mjs +3 -0
- package/dist/index-Dikc5KAP.d.mts +199 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.mjs +10 -0
- package/dist/input-B12iaqb8.d.mts +187 -0
- package/dist/input-DRy_sVxZ.mjs +174 -0
- package/dist/input.d.mts +3 -0
- package/dist/input.mjs +5 -0
- package/dist/prompt/index.d.mts +5 -0
- package/dist/prompt/index.mjs +8 -0
- package/dist/prompt/raw.d.mts +2 -0
- package/dist/prompt/raw.mjs +4 -0
- package/dist/prompt-Cvufljin.mjs +248 -0
- package/dist/raw--889icsd.mjs +105 -0
- package/dist/raw-BqvlveTU.d.mts +37 -0
- package/dist/standard-schema-DBXbMy6L.mjs +17 -0
- package/dist/standard-schema-DLeKaehR.d.mts +58 -0
- package/dist/utils-ChmY93uA.mjs +45 -0
- package/package.json +24 -19
- package/dist/color.d.ts +0 -153
- package/dist/color.js +0 -143
- package/dist/command.d.ts +0 -218
- package/dist/command.js +0 -531
- package/dist/error.d.ts +0 -107
- package/dist/error.js +0 -100
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -6
- package/dist/input.d.ts +0 -182
- package/dist/input.js +0 -185
- package/dist/log.d.ts +0 -61
- package/dist/log.js +0 -216
- package/dist/prompt/index.d.ts +0 -193
- package/dist/prompt/index.js +0 -273
- package/dist/prompt/raw.d.ts +0 -32
- package/dist/prompt/raw.js +0 -105
- package/dist/standard-schema.d.ts +0 -62
- package/dist/standard-schema.js +0 -16
- package/dist/utils.d.ts +0 -30
- package/dist/utils.js +0 -56
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { t as __export } from "./chunk-z5eko27R.mjs";
|
|
2
|
+
import { n as isDeno, r as isNode, t as isBun } from "./utils-ChmY93uA.mjs";
|
|
3
|
+
import { t as DEFAULT_THEME } from "./color-OlJQTTxb.mjs";
|
|
4
|
+
import { r as InputValidationError } from "./error-C1S1gs8L.mjs";
|
|
5
|
+
import { t as validate } from "./standard-schema-DBXbMy6L.mjs";
|
|
6
|
+
import { a as readKey, i as raw_exports, o as readLine, r as cursorUp, t as clearLines } from "./raw--889icsd.mjs";
|
|
7
|
+
|
|
8
|
+
//#region src/prompt/index.ts
|
|
9
|
+
var prompt_exports = /* @__PURE__ */ __export({
|
|
10
|
+
confirm: () => confirm,
|
|
11
|
+
editor: () => editor,
|
|
12
|
+
multiselect: () => multiselect,
|
|
13
|
+
password: () => password,
|
|
14
|
+
raw: () => raw_exports,
|
|
15
|
+
search: () => search,
|
|
16
|
+
select: () => select,
|
|
17
|
+
setTheme: () => setTheme,
|
|
18
|
+
text: () => text
|
|
19
|
+
});
|
|
20
|
+
let theme = DEFAULT_THEME;
|
|
21
|
+
/**
|
|
22
|
+
* Sets the theme of the prompts.
|
|
23
|
+
* @param t The new theme.
|
|
24
|
+
*/
|
|
25
|
+
function setTheme(t) {
|
|
26
|
+
theme = t;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Prompts the user for text input.
|
|
30
|
+
* @param opts Options for text input.
|
|
31
|
+
* @returns The text the user typed in, or the default.
|
|
32
|
+
*/
|
|
33
|
+
async function text(opts) {
|
|
34
|
+
const message = (opts.theme ?? theme).primary(opts.message) + " ";
|
|
35
|
+
const answer = await readLine(message, opts.default);
|
|
36
|
+
if (opts.minLength && answer.length < opts.minLength) throw new InputValidationError([`Must be at least ${opts.minLength} characters`]);
|
|
37
|
+
if (opts.maxLength && answer.length > opts.maxLength) throw new InputValidationError([`Must be at most ${opts.maxLength} characters`]);
|
|
38
|
+
if (typeof opts.validate === "function") {
|
|
39
|
+
if (!opts.validate(answer)) throw new InputValidationError(["Validation function returned a falsy value"]);
|
|
40
|
+
} else if (opts.validate) validate(opts.validate, answer);
|
|
41
|
+
return answer;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Prompts the user for a password.
|
|
45
|
+
* @param opts Options for password input.
|
|
46
|
+
* @returns The password.
|
|
47
|
+
*/
|
|
48
|
+
async function password(opts) {
|
|
49
|
+
const th = opts.theme ?? theme;
|
|
50
|
+
const first = await readLine(th.primary(opts.message) + " ", void 0, {
|
|
51
|
+
masked: true,
|
|
52
|
+
maskChar: opts.mask ?? "*"
|
|
53
|
+
});
|
|
54
|
+
if (opts.confirm) {
|
|
55
|
+
if (first !== await readLine(th.secondary("Confirm password: "), void 0, {
|
|
56
|
+
masked: true,
|
|
57
|
+
maskChar: opts.mask ?? "*"
|
|
58
|
+
})) throw new Error(th.error("Passwords do not match"));
|
|
59
|
+
}
|
|
60
|
+
return first;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Prompts the user to select a single option.
|
|
64
|
+
* @param opts Options for select input.
|
|
65
|
+
* @returns The selected option's value.
|
|
66
|
+
*/
|
|
67
|
+
async function select(opts) {
|
|
68
|
+
const th = opts.theme ?? theme;
|
|
69
|
+
const options = opts.options;
|
|
70
|
+
let index = opts.initialIndex ?? 0;
|
|
71
|
+
const render = () => {
|
|
72
|
+
clearLines(options.length + 1);
|
|
73
|
+
console.log(th.primary(opts.message));
|
|
74
|
+
for (let i = 0; i < options.length; i++) {
|
|
75
|
+
const o = options[i];
|
|
76
|
+
const prefix = i === index ? th.accent?.("> ") ?? "> " : " ";
|
|
77
|
+
const label = o.disabled ? th.secondary(o.label) : th.foreground?.(o.label) ?? o.label;
|
|
78
|
+
console.log(prefix + label);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
console.log(th.primary(opts.message));
|
|
82
|
+
options.forEach((o, i) => console.log(`${i === index ? "> " : " "}${o.label}`));
|
|
83
|
+
while (true) {
|
|
84
|
+
const key = await readKey();
|
|
85
|
+
if (key === "up" && index > 0) index--;
|
|
86
|
+
else if (key === "down" && index < options.length - 1) index++;
|
|
87
|
+
else if (key === "enter") {
|
|
88
|
+
const choice = options[index];
|
|
89
|
+
if (choice.disabled) continue;
|
|
90
|
+
clearLines(options.length + 1);
|
|
91
|
+
console.log(th.success(`${th.symbols?.success ?? "✔"} ${choice.label}`));
|
|
92
|
+
return choice.value;
|
|
93
|
+
}
|
|
94
|
+
render();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Prompts the user to select multiple options.
|
|
99
|
+
* @param opts Options for select input.
|
|
100
|
+
* @returns The selected options.
|
|
101
|
+
*/
|
|
102
|
+
async function multiselect(opts) {
|
|
103
|
+
const th = opts.theme ?? theme;
|
|
104
|
+
const options = opts.options;
|
|
105
|
+
let index = opts.initialIndex ?? 0;
|
|
106
|
+
const selected = /* @__PURE__ */ new Set();
|
|
107
|
+
const render = () => {
|
|
108
|
+
clearLines();
|
|
109
|
+
console.log(th.primary(opts.message));
|
|
110
|
+
options.forEach((opt, i) => {
|
|
111
|
+
const prefix = i === index ? th.accent?.("> ") ?? "> " : " ";
|
|
112
|
+
const mark = selected.has(i) ? th.success("[x]") : "[ ]";
|
|
113
|
+
console.log(prefix + mark + " " + opt.label);
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
render();
|
|
117
|
+
while (true) {
|
|
118
|
+
const key = await readKey();
|
|
119
|
+
if (key === "up" && index > 0) index--;
|
|
120
|
+
else if (key === "down" && index < options.length - 1) index++;
|
|
121
|
+
else if (key === "space") if (selected.has(index)) selected.delete(index);
|
|
122
|
+
else selected.add(index);
|
|
123
|
+
else if (key === "return") {
|
|
124
|
+
const chosen = Array.from(selected).map((i) => options[i].value);
|
|
125
|
+
clearLines(options.length + 1);
|
|
126
|
+
console.log(th.success(`${opts.message} ${chosen.length} selected`));
|
|
127
|
+
return chosen;
|
|
128
|
+
}
|
|
129
|
+
cursorUp(options.length);
|
|
130
|
+
render();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Prompts the user to search through a list of options.
|
|
135
|
+
* @param opts Options for search input.
|
|
136
|
+
* @returns The selected option.
|
|
137
|
+
*/
|
|
138
|
+
async function search(opts) {
|
|
139
|
+
const th = opts.theme ?? theme;
|
|
140
|
+
let query = "";
|
|
141
|
+
const filter = opts.filter ?? ((q, o) => o.label.toLowerCase().includes(q.toLowerCase()));
|
|
142
|
+
while (true) {
|
|
143
|
+
clearLines();
|
|
144
|
+
console.log(th.primary(opts.message));
|
|
145
|
+
const matches = opts.options.filter((o) => filter(query, o));
|
|
146
|
+
matches.forEach((o) => console.log(" " + (th.foreground?.(o.label) ?? o.label)));
|
|
147
|
+
const input = await readLine(th.secondary(`Search: ${query}`));
|
|
148
|
+
if (input === "") continue;
|
|
149
|
+
query = input;
|
|
150
|
+
if (matches.length === 1) return matches[0].value;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Prompts the user to confirm an action.
|
|
155
|
+
* @param opts Options for confirm input.
|
|
156
|
+
* @returns If the user picked Yes.
|
|
157
|
+
*/
|
|
158
|
+
async function confirm(opts) {
|
|
159
|
+
const th = opts.theme ?? theme;
|
|
160
|
+
const yes = opts.yesLabel ?? "y";
|
|
161
|
+
const no = opts.noLabel ?? "n";
|
|
162
|
+
const def = opts.default ? yes : no;
|
|
163
|
+
const res = await readLine(`${th.primary(opts.message)} ${th.secondary(`[${yes}/${no}] (default: ${def})`)} `);
|
|
164
|
+
if (!res) return !!opts.default;
|
|
165
|
+
return /^y/i.test(res.trim());
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Opens the system editor, or asks for input in the terminal as fallback.
|
|
169
|
+
* @param opts Options for opening the system editor.
|
|
170
|
+
* @returns The result of the system editor.
|
|
171
|
+
*/
|
|
172
|
+
async function editor(opts) {
|
|
173
|
+
const th = opts.theme ?? {
|
|
174
|
+
primary: (s) => s,
|
|
175
|
+
secondary: (s) => s
|
|
176
|
+
};
|
|
177
|
+
console.log(th.primary(opts.message ?? "Please enter text:"));
|
|
178
|
+
console.log(th.secondary("Press Ctrl+D (or save & close editor) when done."));
|
|
179
|
+
try {
|
|
180
|
+
const result = await openSystemEditor(opts.initial ?? "");
|
|
181
|
+
if (opts.required && !result.trim()) throw new Error("Input required.");
|
|
182
|
+
return result;
|
|
183
|
+
} catch {
|
|
184
|
+
const value = await readLine("", opts.initial, { multiline: true });
|
|
185
|
+
if (opts.required && !value.trim()) throw new Error("Input required.");
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Opens the system editor on a temporary file.
|
|
191
|
+
* @param initial Initial contents of the file.
|
|
192
|
+
* @returns The contents of the file after saving.
|
|
193
|
+
*/
|
|
194
|
+
async function openSystemEditor(initial) {
|
|
195
|
+
const tmpFile = `edit-${Date.now()}.txt`;
|
|
196
|
+
if (isDeno) {
|
|
197
|
+
const path = `${Deno.env.get("TMPDIR") ?? "/tmp"}/${tmpFile}`;
|
|
198
|
+
await Deno.writeTextFile(path, initial ?? "");
|
|
199
|
+
const editor$1 = Deno.env.get("EDITOR") ?? "vi";
|
|
200
|
+
const status = await new Deno.Command(editor$1, {
|
|
201
|
+
args: [path],
|
|
202
|
+
stdin: "inherit",
|
|
203
|
+
stdout: "inherit",
|
|
204
|
+
stderr: "inherit"
|
|
205
|
+
}).spawn().status;
|
|
206
|
+
if (!status.success) throw new Error(`${editor$1} exited with ${status.code}`);
|
|
207
|
+
const text$1 = await Deno.readTextFile(path);
|
|
208
|
+
await Deno.remove(path).catch(() => {});
|
|
209
|
+
return text$1;
|
|
210
|
+
}
|
|
211
|
+
if (isBun) {
|
|
212
|
+
const { $ } = await import("bun");
|
|
213
|
+
const path = `/tmp/${tmpFile}`;
|
|
214
|
+
await Bun.write(path, initial ?? "");
|
|
215
|
+
await $`${process.env.EDITOR ?? "vi"} ${path}`;
|
|
216
|
+
const text$1 = await Bun.file(path).text();
|
|
217
|
+
await Bun.write(path, "");
|
|
218
|
+
return text$1;
|
|
219
|
+
}
|
|
220
|
+
if (isNode) {
|
|
221
|
+
const { tmpdir } = await import("node:os");
|
|
222
|
+
const { join } = await import("node:path");
|
|
223
|
+
const { promises: fs } = await import("node:fs");
|
|
224
|
+
const { spawn } = await import("node:child_process");
|
|
225
|
+
const path = join(tmpdir(), tmpFile);
|
|
226
|
+
await fs.writeFile(path, initial ?? "", "utf8");
|
|
227
|
+
const editor$1 = process.env.EDITOR || process.env.VISUAL || (process.platform === "win32" ? "notepad" : "vi");
|
|
228
|
+
return new Promise((resolve, reject) => {
|
|
229
|
+
spawn(editor$1, [path], { stdio: "inherit" }).on("exit", async (code) => {
|
|
230
|
+
if (code !== 0) {
|
|
231
|
+
reject(/* @__PURE__ */ new Error(`${editor$1} exited with code ${code}`));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const data = await fs.readFile(path, "utf8");
|
|
236
|
+
await fs.unlink(path).catch(() => {});
|
|
237
|
+
resolve(data);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
reject(err);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
throw new Error("Unsupported runtime for system editor.");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
export { prompt_exports as a, setTheme as c, password as i, text as l, editor as n, search as o, multiselect as r, select as s, confirm as t };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { t as __export } from "./chunk-z5eko27R.mjs";
|
|
2
|
+
import { n as isDeno } from "./utils-ChmY93uA.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/prompt/raw.ts
|
|
5
|
+
var raw_exports = /* @__PURE__ */ __export({
|
|
6
|
+
clearLines: () => clearLines,
|
|
7
|
+
cursorDown: () => cursorDown,
|
|
8
|
+
cursorUp: () => cursorUp,
|
|
9
|
+
readKey: () => readKey,
|
|
10
|
+
readLine: () => readLine
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Reads a line from standard input.
|
|
14
|
+
* @param message The message.
|
|
15
|
+
* @param def Default value.
|
|
16
|
+
* @param opts Options for reading a line.
|
|
17
|
+
* @returns The line that was read.
|
|
18
|
+
*/
|
|
19
|
+
async function readLine(message = "", def, opts) {
|
|
20
|
+
if (isDeno) {
|
|
21
|
+
await Deno.stdout.write(new TextEncoder().encode(message));
|
|
22
|
+
const decoder = new TextDecoder();
|
|
23
|
+
const buf = new Uint8Array(1024);
|
|
24
|
+
let input = "";
|
|
25
|
+
while (true) {
|
|
26
|
+
const n = await Deno.stdin.read(buf);
|
|
27
|
+
if (!n) break;
|
|
28
|
+
const chunk = decoder.decode(buf.subarray(0, n));
|
|
29
|
+
if (chunk.includes("\n")) {
|
|
30
|
+
input += chunk.split("\n")[0];
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
input += chunk;
|
|
34
|
+
}
|
|
35
|
+
return input.trim() || def || "";
|
|
36
|
+
}
|
|
37
|
+
const readline = await import("node:readline");
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const rl = readline.createInterface({
|
|
40
|
+
input: process.stdin,
|
|
41
|
+
output: process.stdout,
|
|
42
|
+
terminal: true
|
|
43
|
+
});
|
|
44
|
+
if (opts?.masked) {
|
|
45
|
+
const write = rl._writeToOutput.bind(rl);
|
|
46
|
+
rl._writeToOutput = (str) => {
|
|
47
|
+
if (str.match(/^\x1b/)) return write(str);
|
|
48
|
+
if (str.endsWith("\n") || str.endsWith("\r")) return write(str);
|
|
49
|
+
write((opts.maskChar ?? "*").repeat(str.length));
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
rl.question(message, (answer) => {
|
|
53
|
+
rl.close();
|
|
54
|
+
resolve(answer || def || "");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads a single key from stdin.
|
|
60
|
+
* @returns The key that was read.
|
|
61
|
+
*/
|
|
62
|
+
async function readKey() {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const stdin = process.stdin;
|
|
65
|
+
stdin.setRawMode(true);
|
|
66
|
+
stdin.resume();
|
|
67
|
+
stdin.once("data", (data) => {
|
|
68
|
+
const s = data.toString();
|
|
69
|
+
stdin.setRawMode(false);
|
|
70
|
+
stdin.pause();
|
|
71
|
+
if (s === "\r" || s === "\n") return resolve("enter");
|
|
72
|
+
if (s === " ") return resolve("space");
|
|
73
|
+
if (s === "\x1B[A") return resolve("up");
|
|
74
|
+
if (s === "\x1B[B") return resolve("down");
|
|
75
|
+
if (s === "\x1B[C") return resolve("right");
|
|
76
|
+
if (s === "\x1B[D") return resolve("left");
|
|
77
|
+
return resolve(s);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Clears `lines` amount of lines.
|
|
83
|
+
* @param lines Amount of lines to clear.
|
|
84
|
+
*/
|
|
85
|
+
function clearLines(lines = 1) {
|
|
86
|
+
for (let i = 0; i < lines; i++) process.stdout.write("\x1B[2K\x1B[1A");
|
|
87
|
+
process.stdout.write("\x1B[2K\r");
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Moves the cursor up `n` times.
|
|
91
|
+
* @param n The amount of steps to move.
|
|
92
|
+
*/
|
|
93
|
+
function cursorUp(n = 1) {
|
|
94
|
+
process.stdout.write(`\x1b[${n}A`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Moves the cursor down `n` times.
|
|
98
|
+
* @param n The amount of steps to move.
|
|
99
|
+
*/
|
|
100
|
+
function cursorDown(n = 1) {
|
|
101
|
+
process.stdout.write(`\x1b[${n}B`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { readKey as a, raw_exports as i, cursorDown as n, readLine as o, cursorUp as r, clearLines as t };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
declare namespace raw_d_exports {
|
|
2
|
+
export { clearLines, cursorDown, cursorUp, readKey, readLine };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Reads a line from standard input.
|
|
6
|
+
* @param message The message.
|
|
7
|
+
* @param def Default value.
|
|
8
|
+
* @param opts Options for reading a line.
|
|
9
|
+
* @returns The line that was read.
|
|
10
|
+
*/
|
|
11
|
+
declare function readLine(message?: string, def?: string, opts?: {
|
|
12
|
+
masked?: boolean;
|
|
13
|
+
maskChar?: string;
|
|
14
|
+
multiline?: boolean;
|
|
15
|
+
}): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Reads a single key from stdin.
|
|
18
|
+
* @returns The key that was read.
|
|
19
|
+
*/
|
|
20
|
+
declare function readKey(): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Clears `lines` amount of lines.
|
|
23
|
+
* @param lines Amount of lines to clear.
|
|
24
|
+
*/
|
|
25
|
+
declare function clearLines(lines?: number): void;
|
|
26
|
+
/**
|
|
27
|
+
* Moves the cursor up `n` times.
|
|
28
|
+
* @param n The amount of steps to move.
|
|
29
|
+
*/
|
|
30
|
+
declare function cursorUp(n?: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Moves the cursor down `n` times.
|
|
33
|
+
* @param n The amount of steps to move.
|
|
34
|
+
*/
|
|
35
|
+
declare function cursorDown(n?: number): void;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { readKey as a, raw_d_exports as i, cursorDown as n, readLine as o, cursorUp as r, clearLines as t };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { r as InputValidationError } from "./error-C1S1gs8L.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/standard-schema.ts
|
|
4
|
+
/**
|
|
5
|
+
* Validates a value.
|
|
6
|
+
* @param entry The Standard Schema validator.
|
|
7
|
+
* @param value The value to validate.
|
|
8
|
+
* @returns The validated value.
|
|
9
|
+
*/
|
|
10
|
+
async function validate(entry, value) {
|
|
11
|
+
const result = await entry["~standard"].validate(value);
|
|
12
|
+
if (result.issues) throw new InputValidationError(result.issues.map((i) => i.message));
|
|
13
|
+
return result.value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { validate as t };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/standard-schema.d.ts
|
|
2
|
+
/** The Standard Schema interface. */
|
|
3
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
4
|
+
/** The Standard Schema properties. */
|
|
5
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
6
|
+
}
|
|
7
|
+
declare namespace StandardSchemaV1 {
|
|
8
|
+
/** The Standard Schema properties interface. */
|
|
9
|
+
interface Props<Input = unknown, Output = Input> {
|
|
10
|
+
/** The version number of the standard. */
|
|
11
|
+
readonly version: 1;
|
|
12
|
+
/** The vendor name of the schema library. */
|
|
13
|
+
readonly vendor: string;
|
|
14
|
+
/** Validates unknown input values. */
|
|
15
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
16
|
+
/** Inferred types associated with the schema. */
|
|
17
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** The result interface of the validate function. */
|
|
20
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
21
|
+
/** The result interface if validation succeeds. */
|
|
22
|
+
interface SuccessResult<Output> {
|
|
23
|
+
/** The typed output value. */
|
|
24
|
+
readonly value: Output;
|
|
25
|
+
/** The non-existent issues. */
|
|
26
|
+
readonly issues?: undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The result interface if validation fails. */
|
|
29
|
+
interface FailureResult {
|
|
30
|
+
/** The issues of failed validation. */
|
|
31
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
32
|
+
}
|
|
33
|
+
/** The issue interface of the failure output. */
|
|
34
|
+
interface Issue {
|
|
35
|
+
/** The error message of the issue. */
|
|
36
|
+
readonly message: string;
|
|
37
|
+
/** The path of the issue, if any. */
|
|
38
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
39
|
+
}
|
|
40
|
+
/** The path segment interface of the issue. */
|
|
41
|
+
interface PathSegment {
|
|
42
|
+
/** The key representing a path segment. */
|
|
43
|
+
readonly key: PropertyKey;
|
|
44
|
+
}
|
|
45
|
+
/** The Standard Schema types interface. */
|
|
46
|
+
interface Types<Input = unknown, Output = Input> {
|
|
47
|
+
/** The input type of the schema. */
|
|
48
|
+
readonly input: Input;
|
|
49
|
+
/** The output type of the schema. */
|
|
50
|
+
readonly output: Output;
|
|
51
|
+
}
|
|
52
|
+
/** Infers the input type of a Standard Schema. */
|
|
53
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
54
|
+
/** Infers the output type of a Standard Schema. */
|
|
55
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { StandardSchemaV1 as t };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* If the runtime is Node.js.
|
|
4
|
+
*/
|
|
5
|
+
const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
6
|
+
/**
|
|
7
|
+
* If the runtime is Deno.
|
|
8
|
+
*/
|
|
9
|
+
const isDeno = typeof Deno !== "undefined" && typeof Deno.version?.deno === "string";
|
|
10
|
+
/**
|
|
11
|
+
* If the runtime is Bun.
|
|
12
|
+
*/
|
|
13
|
+
const isBun = typeof Bun !== "undefined" && typeof Bun.version === "string";
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a value is a plain object.
|
|
16
|
+
* @param value The value to check.
|
|
17
|
+
* @returns If the value is a plain object.
|
|
18
|
+
*/
|
|
19
|
+
function isPlainObject(value) {
|
|
20
|
+
return value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Merges two objects deeply.
|
|
24
|
+
* @param source The source object.
|
|
25
|
+
* @param target The target object.
|
|
26
|
+
* @returns The merged objects.
|
|
27
|
+
*/
|
|
28
|
+
function merge(source, target) {
|
|
29
|
+
if (Array.isArray(source) && Array.isArray(target)) return target;
|
|
30
|
+
if (isPlainObject(source) && isPlainObject(target)) {
|
|
31
|
+
const result = {};
|
|
32
|
+
new Set([...Object.keys(source), ...Object.keys(target)]).forEach((key) => {
|
|
33
|
+
const sourceVal = source[key];
|
|
34
|
+
const targetVal = target[key];
|
|
35
|
+
if (sourceVal !== void 0 && targetVal !== void 0) result[key] = merge(sourceVal, targetVal);
|
|
36
|
+
else if (targetVal !== void 0) result[key] = targetVal;
|
|
37
|
+
else result[key] = sourceVal;
|
|
38
|
+
});
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
return target;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { merge as i, isDeno as n, isNode as r, isBun as t };
|
package/package.json
CHANGED
|
@@ -1,37 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "convoker",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "A simple, type safe CLI framework for TypeScript.",
|
|
5
|
-
"
|
|
6
|
-
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/trailfrost/convoker"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
7
11
|
"exports": {
|
|
8
12
|
".": {
|
|
9
|
-
"types": "./dist/index.d.
|
|
10
|
-
"
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"import": "./dist/index.mjs"
|
|
11
15
|
},
|
|
12
16
|
"./command": {
|
|
13
|
-
"types": "./dist/command.d.
|
|
14
|
-
"
|
|
17
|
+
"types": "./dist/command.d.mts",
|
|
18
|
+
"import": "./dist/command.mjs"
|
|
15
19
|
},
|
|
16
20
|
"./input": {
|
|
17
|
-
"types": "./dist/types.d.
|
|
18
|
-
"
|
|
21
|
+
"types": "./dist/types.d.mts",
|
|
22
|
+
"import": "./dist/input.mjs"
|
|
19
23
|
},
|
|
20
24
|
"./color": {
|
|
21
|
-
"types": "./dist/color.d.
|
|
22
|
-
"
|
|
25
|
+
"types": "./dist/color.d.mts",
|
|
26
|
+
"import": "./dist/color.mjs"
|
|
23
27
|
},
|
|
24
28
|
"./prompt": {
|
|
25
|
-
"types": "./dist/prompt/index.d.
|
|
26
|
-
"
|
|
29
|
+
"types": "./dist/prompt/index.d.mts",
|
|
30
|
+
"import": "./dist/prompt/index.mjs"
|
|
27
31
|
},
|
|
28
32
|
"./prompt/raw": {
|
|
29
|
-
"types": "./dist/prompt/raw.d.
|
|
30
|
-
"
|
|
33
|
+
"types": "./dist/prompt/raw.d.mts",
|
|
34
|
+
"import": "./dist/prompt/raw.mjs"
|
|
31
35
|
},
|
|
32
36
|
"./error": {
|
|
33
|
-
"types": "./dist/error.d.
|
|
34
|
-
"
|
|
37
|
+
"types": "./dist/error.d.mts",
|
|
38
|
+
"import": "./dist/error.mjs"
|
|
35
39
|
}
|
|
36
40
|
},
|
|
37
41
|
"type": "module",
|
|
@@ -52,7 +56,7 @@
|
|
|
52
56
|
"eslint": "^9.36.0",
|
|
53
57
|
"globals": "^16.4.0",
|
|
54
58
|
"prettier": "^3.6.2",
|
|
55
|
-
"
|
|
59
|
+
"tsdown": "^0.16.0",
|
|
56
60
|
"typescript": "^5.9.2",
|
|
57
61
|
"typescript-eslint": "^8.45.0",
|
|
58
62
|
"valibot": "^1.1.0",
|
|
@@ -60,7 +64,8 @@
|
|
|
60
64
|
},
|
|
61
65
|
"scripts": {
|
|
62
66
|
"test": "vitest tests",
|
|
63
|
-
"build": "
|
|
67
|
+
"build": "tsdown",
|
|
68
|
+
"check": "tsc -b tsconfig.app.json",
|
|
64
69
|
"format": "prettier --check .",
|
|
65
70
|
"format!": "prettier --write .",
|
|
66
71
|
"lint": "eslint .",
|