@reliverse/rempts 1.7.50 → 1.7.52
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/LICENSE +1 -1
- package/README.md +1 -52
- package/dist-npm/bin/mod.d.mts +62 -607
- package/dist-npm/bin/mod.mjs +629 -2071
- package/package.json +3 -41
package/dist-npm/bin/mod.mjs
CHANGED
|
@@ -16,22 +16,13 @@ import readline__default from 'node:readline';
|
|
|
16
16
|
import { ReadStream, WriteStream } from 'node:tty';
|
|
17
17
|
import readline$1 from 'node:readline/promises';
|
|
18
18
|
import { repeat, digit, buildRegExp, startOfString, endOfString } from 'ts-regex-builder';
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
19
|
+
import { realpathSync } from 'fs';
|
|
20
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
21
|
+
import path from 'path';
|
|
22
|
+
import readline$2 from 'readline';
|
|
23
23
|
import { homedir } from 'node:os';
|
|
24
|
-
import {
|
|
24
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
25
25
|
import { readPackageJSON } from 'pkg-types';
|
|
26
|
-
import { inspect } from 'node:util';
|
|
27
|
-
import * as trpcServer11 from '@trpc/server';
|
|
28
|
-
export { trpcServer11 as trpcServer };
|
|
29
|
-
import { Command, Option, Argument, InvalidArgumentError } from 'commander';
|
|
30
|
-
import * as zod4 from 'zod/v4/core';
|
|
31
|
-
import zodToJsonSchema from 'zod-to-json-schema';
|
|
32
|
-
import * as zod from 'zod';
|
|
33
|
-
export { zod };
|
|
34
|
-
export { z } from 'zod/v4';
|
|
35
26
|
|
|
36
27
|
const colorMap = {
|
|
37
28
|
// @reliverse/relico
|
|
@@ -1373,7 +1364,275 @@ async function datePrompt(opts) {
|
|
|
1373
1364
|
}
|
|
1374
1365
|
}
|
|
1375
1366
|
|
|
1376
|
-
|
|
1367
|
+
class TerminalInterface {
|
|
1368
|
+
rl;
|
|
1369
|
+
_width;
|
|
1370
|
+
_height;
|
|
1371
|
+
keyListeners = [];
|
|
1372
|
+
resizeListeners = [];
|
|
1373
|
+
constructor() {
|
|
1374
|
+
this.rl = readline$2.createInterface({
|
|
1375
|
+
input: process.stdin,
|
|
1376
|
+
output: process.stdout,
|
|
1377
|
+
terminal: true
|
|
1378
|
+
});
|
|
1379
|
+
this._width = process.stdout.columns || 80;
|
|
1380
|
+
this._height = process.stdout.rows || 24;
|
|
1381
|
+
process.stdout.on("resize", () => {
|
|
1382
|
+
this._width = process.stdout.columns || 80;
|
|
1383
|
+
this._height = process.stdout.rows || 24;
|
|
1384
|
+
this.resizeListeners.forEach((listener) => listener(this._width, this._height));
|
|
1385
|
+
});
|
|
1386
|
+
process.stdin.setRawMode(true);
|
|
1387
|
+
process.stdin.resume();
|
|
1388
|
+
process.stdin.setEncoding("utf8");
|
|
1389
|
+
process.stdin.on("data", (data) => {
|
|
1390
|
+
const key = this.parseKey(data);
|
|
1391
|
+
if (key) {
|
|
1392
|
+
this.keyListeners.forEach(
|
|
1393
|
+
(listener) => listener(key, [], {
|
|
1394
|
+
isCharacter: this.isCharacter(key),
|
|
1395
|
+
code: data,
|
|
1396
|
+
codepoint: data.toString().charCodeAt(0)
|
|
1397
|
+
})
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
parseKey(data) {
|
|
1403
|
+
const str = data.toString();
|
|
1404
|
+
if (str === "") return "CTRL_C";
|
|
1405
|
+
if (str === "") return "CTRL_A";
|
|
1406
|
+
if (str === "") return "CTRL_O";
|
|
1407
|
+
if (str === "") return "CTRL_S";
|
|
1408
|
+
if (str === "") return "CTRL_X";
|
|
1409
|
+
if (str === "") return "CTRL_F";
|
|
1410
|
+
if (str === "\v") return "CTRL_K";
|
|
1411
|
+
if (str === "") return "CTRL_U";
|
|
1412
|
+
if (str === "") return "CTRL_T";
|
|
1413
|
+
if (str === " ") return "TAB";
|
|
1414
|
+
if (str === "\r" || str === "\n") return "ENTER";
|
|
1415
|
+
if (str === "\x7F" || str === "\b") return "BACKSPACE";
|
|
1416
|
+
if (str === "\x1B[3~") return "DELETE";
|
|
1417
|
+
if (str === "\x1B[A") return "UP";
|
|
1418
|
+
if (str === "\x1B[B") return "DOWN";
|
|
1419
|
+
if (str === "\x1B[C") return "RIGHT";
|
|
1420
|
+
if (str === "\x1B[D") return "LEFT";
|
|
1421
|
+
if (str === "\x1B[5~") return "PAGE_UP";
|
|
1422
|
+
if (str === "\x1B[6~") return "PAGE_DOWN";
|
|
1423
|
+
if (str === "\x1B[H") return "HOME";
|
|
1424
|
+
if (str === "\x1B[F") return "END";
|
|
1425
|
+
if (str === "\x1B[1;5H") return "CTRL_HOME";
|
|
1426
|
+
if (str === "\x1B[1;5F") return "CTRL_END";
|
|
1427
|
+
if (str === "\x1B[1;3C") return "ALT_C";
|
|
1428
|
+
if (str === "\x1B[2;2~") return "SHIFT_INSERT";
|
|
1429
|
+
if (str === "\x1B[2;5~") return "CTRL_INSERT";
|
|
1430
|
+
return str.length === 1 ? str : "";
|
|
1431
|
+
}
|
|
1432
|
+
isCharacter(key) {
|
|
1433
|
+
return key.length === 1 && !key.startsWith("\x1B") && ![
|
|
1434
|
+
"CTRL_C",
|
|
1435
|
+
"CTRL_A",
|
|
1436
|
+
"CTRL_O",
|
|
1437
|
+
"CTRL_S",
|
|
1438
|
+
"CTRL_X",
|
|
1439
|
+
"CTRL_F",
|
|
1440
|
+
"CTRL_K",
|
|
1441
|
+
"CTRL_U",
|
|
1442
|
+
"CTRL_T",
|
|
1443
|
+
"TAB",
|
|
1444
|
+
"ENTER",
|
|
1445
|
+
"BACKSPACE",
|
|
1446
|
+
"DELETE",
|
|
1447
|
+
"UP",
|
|
1448
|
+
"DOWN",
|
|
1449
|
+
"RIGHT",
|
|
1450
|
+
"LEFT",
|
|
1451
|
+
"PAGE_UP",
|
|
1452
|
+
"PAGE_DOWN",
|
|
1453
|
+
"HOME",
|
|
1454
|
+
"END",
|
|
1455
|
+
"CTRL_HOME",
|
|
1456
|
+
"CTRL_END",
|
|
1457
|
+
"ALT_C",
|
|
1458
|
+
"SHIFT_INSERT",
|
|
1459
|
+
"CTRL_INSERT"
|
|
1460
|
+
].includes(key);
|
|
1461
|
+
}
|
|
1462
|
+
get width() {
|
|
1463
|
+
return this._width;
|
|
1464
|
+
}
|
|
1465
|
+
get height() {
|
|
1466
|
+
return this._height;
|
|
1467
|
+
}
|
|
1468
|
+
fullscreen(enabled) {
|
|
1469
|
+
if (enabled) {
|
|
1470
|
+
process.stdout.write("\x1B[?1049h");
|
|
1471
|
+
} else {
|
|
1472
|
+
process.stdout.write("\x1B[?1049l");
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
grabInput(enabled) {
|
|
1476
|
+
if (enabled) {
|
|
1477
|
+
process.stdin.setRawMode(true);
|
|
1478
|
+
} else {
|
|
1479
|
+
process.stdin.setRawMode(false);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
on(event, listener) {
|
|
1483
|
+
if (event === "key") {
|
|
1484
|
+
this.keyListeners.push(listener);
|
|
1485
|
+
} else if (event === "resize") {
|
|
1486
|
+
this.resizeListeners.push(listener);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
off(event, listener) {
|
|
1490
|
+
if (event === "key") {
|
|
1491
|
+
const index = this.keyListeners.indexOf(listener);
|
|
1492
|
+
if (index > -1) this.keyListeners.splice(index, 1);
|
|
1493
|
+
} else if (event === "resize") {
|
|
1494
|
+
const index = this.resizeListeners.indexOf(listener);
|
|
1495
|
+
if (index > -1) this.resizeListeners.splice(index, 1);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
moveTo(x, y) {
|
|
1499
|
+
process.stdout.write(ansiEscapes.cursorTo(x, y));
|
|
1500
|
+
}
|
|
1501
|
+
clear() {
|
|
1502
|
+
process.stdout.write(ansiEscapes.clearScreen);
|
|
1503
|
+
}
|
|
1504
|
+
eraseLine() {
|
|
1505
|
+
process.stdout.write(ansiEscapes.eraseLine);
|
|
1506
|
+
}
|
|
1507
|
+
eraseLineAfter() {
|
|
1508
|
+
process.stdout.write(ansiEscapes.eraseLine);
|
|
1509
|
+
}
|
|
1510
|
+
hideCursor() {
|
|
1511
|
+
process.stdout.write(cursor.hide);
|
|
1512
|
+
}
|
|
1513
|
+
restoreCursor() {
|
|
1514
|
+
process.stdout.write(cursor.show);
|
|
1515
|
+
}
|
|
1516
|
+
styleReset() {
|
|
1517
|
+
process.stdout.write(ansiEscapes.cursorShow + "\x1B[0m");
|
|
1518
|
+
}
|
|
1519
|
+
bgColor(color) {
|
|
1520
|
+
const colorMap = {
|
|
1521
|
+
black: "\x1B[40m",
|
|
1522
|
+
white: "\x1B[47m",
|
|
1523
|
+
red: "\x1B[41m",
|
|
1524
|
+
green: "\x1B[42m",
|
|
1525
|
+
yellow: "\x1B[43m",
|
|
1526
|
+
blue: "\x1B[44m",
|
|
1527
|
+
magenta: "\x1B[45m",
|
|
1528
|
+
cyan: "\x1B[46m",
|
|
1529
|
+
brown: "\x1B[43m"
|
|
1530
|
+
};
|
|
1531
|
+
process.stdout.write(colorMap[color] || "");
|
|
1532
|
+
return this;
|
|
1533
|
+
}
|
|
1534
|
+
color(color) {
|
|
1535
|
+
const colorMap = {
|
|
1536
|
+
black: "\x1B[30m",
|
|
1537
|
+
white: "\x1B[37m",
|
|
1538
|
+
red: "\x1B[31m",
|
|
1539
|
+
green: "\x1B[32m",
|
|
1540
|
+
yellow: "\x1B[33m",
|
|
1541
|
+
blue: "\x1B[34m",
|
|
1542
|
+
magenta: "\x1B[35m",
|
|
1543
|
+
cyan: "\x1B[36m",
|
|
1544
|
+
gray: "\x1B[90m"
|
|
1545
|
+
};
|
|
1546
|
+
process.stdout.write(colorMap[color] || "");
|
|
1547
|
+
return this;
|
|
1548
|
+
}
|
|
1549
|
+
inputField(options) {
|
|
1550
|
+
return {
|
|
1551
|
+
promise: new Promise((resolve) => {
|
|
1552
|
+
const prompt = "> ";
|
|
1553
|
+
process.stdout.write(prompt);
|
|
1554
|
+
let input = "";
|
|
1555
|
+
const onData = (data) => {
|
|
1556
|
+
const char = data.toString();
|
|
1557
|
+
if (char === "\n" || char === "\r") {
|
|
1558
|
+
process.stdout.write("\n");
|
|
1559
|
+
process.stdin.removeListener("data", onData);
|
|
1560
|
+
resolve(input);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
if (char === "") {
|
|
1564
|
+
process.stdout.write("\n");
|
|
1565
|
+
process.stdin.removeListener("data", onData);
|
|
1566
|
+
resolve("");
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
if (char === "\x7F" || char === "\b") {
|
|
1570
|
+
if (input.length > 0) {
|
|
1571
|
+
input = input.slice(0, -1);
|
|
1572
|
+
process.stdout.write("\b \b");
|
|
1573
|
+
}
|
|
1574
|
+
} else if (options.echo) {
|
|
1575
|
+
input += char;
|
|
1576
|
+
process.stdout.write(char);
|
|
1577
|
+
} else {
|
|
1578
|
+
input += char;
|
|
1579
|
+
process.stdout.write("*");
|
|
1580
|
+
}
|
|
1581
|
+
};
|
|
1582
|
+
process.stdin.on("data", onData);
|
|
1583
|
+
})
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
yesOrNo(options) {
|
|
1587
|
+
return {
|
|
1588
|
+
promise: new Promise((resolve) => {
|
|
1589
|
+
const prompt = "(y/N) ";
|
|
1590
|
+
process.stdout.write(prompt);
|
|
1591
|
+
const onData = (data) => {
|
|
1592
|
+
const char = data.toString().toLowerCase();
|
|
1593
|
+
if (char === "\n" || char === "\r") {
|
|
1594
|
+
process.stdout.write("\n");
|
|
1595
|
+
process.stdin.removeListener("data", onData);
|
|
1596
|
+
resolve(false);
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (char === "") {
|
|
1600
|
+
process.stdout.write("\n");
|
|
1601
|
+
process.stdin.removeListener("data", onData);
|
|
1602
|
+
resolve(null);
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
if (options.yes.includes(char)) {
|
|
1606
|
+
process.stdout.write(char + "\n");
|
|
1607
|
+
process.stdin.removeListener("data", onData);
|
|
1608
|
+
resolve(true);
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
if (options.no.includes(char)) {
|
|
1612
|
+
process.stdout.write(char + "\n");
|
|
1613
|
+
process.stdin.removeListener("data", onData);
|
|
1614
|
+
resolve(false);
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
process.stdin.on("data", onData);
|
|
1619
|
+
})
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
// Callable interface for writing text
|
|
1623
|
+
write(text) {
|
|
1624
|
+
process.stdout.write(text);
|
|
1625
|
+
}
|
|
1626
|
+
red(text) {
|
|
1627
|
+
process.stdout.write("\x1B[31m" + text + "\x1B[0m");
|
|
1628
|
+
}
|
|
1629
|
+
destroy() {
|
|
1630
|
+
this.rl.close();
|
|
1631
|
+
process.stdin.setRawMode(false);
|
|
1632
|
+
process.stdin.pause();
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
const term = new TerminalInterface();
|
|
1377
1636
|
let state = {
|
|
1378
1637
|
lines: [""],
|
|
1379
1638
|
// Document content as an array of strings
|
|
@@ -1423,24 +1682,6 @@ let state = {
|
|
|
1423
1682
|
exitResolver: null,
|
|
1424
1683
|
exitRejecter: null
|
|
1425
1684
|
};
|
|
1426
|
-
async function loadEditorConfig(cwd = process.cwd(), overrides = {}) {
|
|
1427
|
-
const { config } = await loadConfig({
|
|
1428
|
-
name: "minedit",
|
|
1429
|
-
cwd,
|
|
1430
|
-
defaults: {
|
|
1431
|
-
// Low priority defaults
|
|
1432
|
-
syntaxHighlighting: false,
|
|
1433
|
-
theme: "auto",
|
|
1434
|
-
defaultAllowSaveAs: true,
|
|
1435
|
-
defaultAllowOpen: true,
|
|
1436
|
-
defaultAutoCloseOnSave: false,
|
|
1437
|
-
defaultReturnContentOnSave: false
|
|
1438
|
-
},
|
|
1439
|
-
// user provided overrides during programmatic call have higher priority
|
|
1440
|
-
overrides
|
|
1441
|
-
});
|
|
1442
|
-
return config || {};
|
|
1443
|
-
}
|
|
1444
1685
|
function setupTheme(configTheme) {
|
|
1445
1686
|
let mode = configTheme;
|
|
1446
1687
|
if (mode === "auto") {
|
|
@@ -1499,13 +1740,13 @@ function renderStatusBar() {
|
|
|
1499
1740
|
const middlePart = hints + " ".repeat(hintPadding);
|
|
1500
1741
|
const statusBar = leftPart + middlePart + rightPart;
|
|
1501
1742
|
term.moveTo(1, term.height - 1);
|
|
1502
|
-
term(state.theme.statusBarBg(state.theme.statusBarText(statusBar.padEnd(width))));
|
|
1743
|
+
term.write(state.theme.statusBarBg(state.theme.statusBarText(statusBar.padEnd(width))));
|
|
1503
1744
|
}
|
|
1504
1745
|
function renderMessageBar() {
|
|
1505
1746
|
term.moveTo(1, term.height);
|
|
1506
1747
|
term.eraseLine();
|
|
1507
1748
|
if (state.statusMessage) {
|
|
1508
|
-
term(state.theme.highlight(state.statusMessage.slice(0, term.width)));
|
|
1749
|
+
term.write(state.theme.highlight(state.statusMessage.slice(0, term.width)));
|
|
1509
1750
|
setTimeout(() => {
|
|
1510
1751
|
if (state.isRunning) {
|
|
1511
1752
|
state.statusMessage = "";
|
|
@@ -1548,11 +1789,11 @@ function renderEditor() {
|
|
|
1548
1789
|
term.moveTo(1, y + 1);
|
|
1549
1790
|
if (fileLineIndex < state.lines.length) {
|
|
1550
1791
|
const lineNum = String(fileLineIndex + 1).padStart(3);
|
|
1551
|
-
term(state.theme.lineNumber(`${lineNum} `));
|
|
1792
|
+
term.write(state.theme.lineNumber(`${lineNum} `));
|
|
1552
1793
|
const line = state.lines[fileLineIndex];
|
|
1553
1794
|
const displayLine = line?.substring(state.leftCol, state.leftCol + displayWidth);
|
|
1554
1795
|
const highlightedDisplayLine = applySyntaxHighlighting(displayLine ?? "");
|
|
1555
|
-
term(highlightedDisplayLine);
|
|
1796
|
+
term.write(highlightedDisplayLine);
|
|
1556
1797
|
term.eraseLineAfter();
|
|
1557
1798
|
} else {
|
|
1558
1799
|
term.eraseLine();
|
|
@@ -1692,13 +1933,15 @@ async function promptForFilename(promptMessage = "File path: ") {
|
|
|
1692
1933
|
renderMessageBar();
|
|
1693
1934
|
term.moveTo(1, term.height);
|
|
1694
1935
|
term.eraseLine();
|
|
1695
|
-
term(promptMessage);
|
|
1936
|
+
term.write(promptMessage);
|
|
1696
1937
|
try {
|
|
1697
1938
|
const input = await term.inputField({ echo: true }).promise;
|
|
1698
|
-
term.moveTo(1, term.height)
|
|
1939
|
+
term.moveTo(1, term.height);
|
|
1940
|
+
term.eraseLine();
|
|
1699
1941
|
return input ? input.trim() : null;
|
|
1700
1942
|
} catch (_error) {
|
|
1701
|
-
term.moveTo(1, term.height)
|
|
1943
|
+
term.moveTo(1, term.height);
|
|
1944
|
+
term.eraseLine();
|
|
1702
1945
|
state.statusMessage = "Cancelled";
|
|
1703
1946
|
render();
|
|
1704
1947
|
return null;
|
|
@@ -1709,16 +1952,18 @@ async function confirmAction(promptMessage = "Are you sure? (y/N)") {
|
|
|
1709
1952
|
renderMessageBar();
|
|
1710
1953
|
term.moveTo(1, term.height);
|
|
1711
1954
|
term.eraseLine();
|
|
1712
|
-
term(`${promptMessage} `);
|
|
1955
|
+
term.write(`${promptMessage} `);
|
|
1713
1956
|
try {
|
|
1714
1957
|
const confirm = await term.yesOrNo({
|
|
1715
1958
|
yes: ["y", "Y"],
|
|
1716
1959
|
no: ["n", "N", "ENTER"]
|
|
1717
1960
|
}).promise;
|
|
1718
|
-
term.moveTo(1, term.height)
|
|
1961
|
+
term.moveTo(1, term.height);
|
|
1962
|
+
term.eraseLine();
|
|
1719
1963
|
return confirm ?? false;
|
|
1720
1964
|
} catch (_error) {
|
|
1721
|
-
term.moveTo(1, term.height)
|
|
1965
|
+
term.moveTo(1, term.height);
|
|
1966
|
+
term.eraseLine();
|
|
1722
1967
|
state.statusMessage = "Cancelled";
|
|
1723
1968
|
render();
|
|
1724
1969
|
return false;
|
|
@@ -1765,7 +2010,7 @@ async function saveFile() {
|
|
|
1765
2010
|
return true;
|
|
1766
2011
|
}
|
|
1767
2012
|
try {
|
|
1768
|
-
await
|
|
2013
|
+
await writeFile(state.filename, contentToSave);
|
|
1769
2014
|
state.originalContent = contentToSave;
|
|
1770
2015
|
state.modified = false;
|
|
1771
2016
|
state.statusMessage = `Saved to ${state.filename}`;
|
|
@@ -1831,7 +2076,7 @@ async function loadFile(filePath) {
|
|
|
1831
2076
|
const absolutePath = path.resolve(cwd, filePath);
|
|
1832
2077
|
let content = "";
|
|
1833
2078
|
try {
|
|
1834
|
-
content = await
|
|
2079
|
+
content = await readFile(absolutePath, "utf-8");
|
|
1835
2080
|
state.statusMessage = `Opened ${absolutePath}`;
|
|
1836
2081
|
} catch (error) {
|
|
1837
2082
|
if (error && error.code === "ENOENT") {
|
|
@@ -2055,7 +2300,7 @@ async function cleanupAndExit(saved = false, content = null) {
|
|
|
2055
2300
|
}
|
|
2056
2301
|
term.off("key", handleInputWrapper);
|
|
2057
2302
|
term.off("resize", handleResize);
|
|
2058
|
-
term.hideCursor(
|
|
2303
|
+
term.hideCursor();
|
|
2059
2304
|
term.grabInput(false);
|
|
2060
2305
|
term.fullscreen(false);
|
|
2061
2306
|
term.styleReset();
|
|
@@ -2140,8 +2385,15 @@ async function initializeEditorState(options) {
|
|
|
2140
2385
|
// Reset toggle state
|
|
2141
2386
|
};
|
|
2142
2387
|
try {
|
|
2143
|
-
|
|
2144
|
-
|
|
2388
|
+
state.editorConfig = {
|
|
2389
|
+
defaultAllowSaveAs: true,
|
|
2390
|
+
defaultAllowOpen: true,
|
|
2391
|
+
defaultAutoCloseOnSave: false,
|
|
2392
|
+
defaultReturnContentOnSave: false,
|
|
2393
|
+
syntaxHighlighting: false,
|
|
2394
|
+
theme: "light",
|
|
2395
|
+
...options.configOverrides
|
|
2396
|
+
};
|
|
2145
2397
|
state.options.allowSaveAs = options.allowSaveAs ?? state.editorConfig.defaultAllowSaveAs ?? true;
|
|
2146
2398
|
state.options.allowOpen = options.allowOpen ?? state.editorConfig.defaultAllowOpen ?? true;
|
|
2147
2399
|
state.options.autoCloseOnSave = options.autoCloseOnSave ?? state.editorConfig.defaultAutoCloseOnSave ?? false;
|
|
@@ -2215,8 +2467,8 @@ async function startEditor(options = {}) {
|
|
|
2215
2467
|
}
|
|
2216
2468
|
const isDirectRun = (() => {
|
|
2217
2469
|
try {
|
|
2218
|
-
const scriptPath =
|
|
2219
|
-
const modulePath =
|
|
2470
|
+
const scriptPath = realpathSync(process.argv[1] || "");
|
|
2471
|
+
const modulePath = realpathSync(import.meta.filename);
|
|
2220
2472
|
return scriptPath === modulePath;
|
|
2221
2473
|
} catch (_e) {
|
|
2222
2474
|
return false;
|
|
@@ -3111,6 +3363,278 @@ async function introPrompt(optionsOrTitle) {
|
|
|
3111
3363
|
const startPrompt = introPrompt;
|
|
3112
3364
|
const intro = introPrompt;
|
|
3113
3365
|
|
|
3366
|
+
const NEGATIVE_NUMBER_REGEX = /^[0-9]+(\.[0-9]+)?$/;
|
|
3367
|
+
function isAsciiLetter(ch) {
|
|
3368
|
+
const code = ch.charCodeAt(0);
|
|
3369
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
3370
|
+
}
|
|
3371
|
+
function reliArgParser(argv, opts = {}) {
|
|
3372
|
+
const context = createParserContext(opts);
|
|
3373
|
+
prePopulateDefaults(context);
|
|
3374
|
+
let i = 0;
|
|
3375
|
+
const argvLength = argv.length;
|
|
3376
|
+
while (i < argvLength) {
|
|
3377
|
+
const arg = argv[i];
|
|
3378
|
+
if (!arg) {
|
|
3379
|
+
i++;
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3382
|
+
if (arg === "--") {
|
|
3383
|
+
context.result._.push(...argv.slice(i + 1));
|
|
3384
|
+
break;
|
|
3385
|
+
}
|
|
3386
|
+
if (context.allowNegativeNumbers && isNegativeNumber(arg)) {
|
|
3387
|
+
if (context.stopEarly) {
|
|
3388
|
+
context.result._.push(...argv.slice(i));
|
|
3389
|
+
break;
|
|
3390
|
+
} else {
|
|
3391
|
+
context.result._.push(arg);
|
|
3392
|
+
i++;
|
|
3393
|
+
continue;
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
if (shouldHandleNegatedBoolean(arg, context)) {
|
|
3397
|
+
handleNegatedBooleanFlag(arg, context);
|
|
3398
|
+
i++;
|
|
3399
|
+
continue;
|
|
3400
|
+
}
|
|
3401
|
+
if (arg.length > 2 && arg[0] === "-" && arg[1] === "-") {
|
|
3402
|
+
i = handleLongFlag(argv, i, context);
|
|
3403
|
+
continue;
|
|
3404
|
+
}
|
|
3405
|
+
if (arg.length > 1 && arg[0] === "-" && arg[1] !== "-") {
|
|
3406
|
+
i = handleShortFlags(argv, i, context);
|
|
3407
|
+
continue;
|
|
3408
|
+
}
|
|
3409
|
+
if (context.stopEarly) {
|
|
3410
|
+
context.result._.push(...argv.slice(i));
|
|
3411
|
+
break;
|
|
3412
|
+
}
|
|
3413
|
+
context.result._.push(arg);
|
|
3414
|
+
i++;
|
|
3415
|
+
}
|
|
3416
|
+
return context.result;
|
|
3417
|
+
}
|
|
3418
|
+
function createParserContext(opts) {
|
|
3419
|
+
const booleanFlags = new Set(opts.boolean || []);
|
|
3420
|
+
const arrayFlags = new Set(opts.array || []);
|
|
3421
|
+
const stringFlags = new Set(opts.string || []);
|
|
3422
|
+
const aliasMap = buildAliasMap(opts.alias || {});
|
|
3423
|
+
const result = { _: [] };
|
|
3424
|
+
return {
|
|
3425
|
+
result,
|
|
3426
|
+
booleanFlags,
|
|
3427
|
+
arrayFlags,
|
|
3428
|
+
stringFlags,
|
|
3429
|
+
aliasMap,
|
|
3430
|
+
options: opts,
|
|
3431
|
+
stopEarlyTriggered: false,
|
|
3432
|
+
// Cache frequently accessed options for performance
|
|
3433
|
+
allowNegativeNumbers: opts.allowNegativeNumbers !== false,
|
|
3434
|
+
negatedBoolean: opts.negatedBoolean !== false,
|
|
3435
|
+
parseNumbers: opts.parseNumbers || false,
|
|
3436
|
+
stopEarly: opts.stopEarly || false,
|
|
3437
|
+
warnOnUnknown: opts.warnOnUnknown || false,
|
|
3438
|
+
strict: opts.strict || false
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
function prePopulateDefaults(context) {
|
|
3442
|
+
const { defaults = {} } = context.options;
|
|
3443
|
+
for (const [key, val] of Object.entries(defaults)) {
|
|
3444
|
+
context.result[key] = val;
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
function buildAliasMap(aliasObj) {
|
|
3448
|
+
const map = /* @__PURE__ */ new Map();
|
|
3449
|
+
for (const [key, value] of Object.entries(aliasObj)) {
|
|
3450
|
+
if (Array.isArray(value)) {
|
|
3451
|
+
const canonical = value[0];
|
|
3452
|
+
if (canonical) {
|
|
3453
|
+
map.set(key, canonical);
|
|
3454
|
+
for (const alias of value) {
|
|
3455
|
+
map.set(alias, canonical);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
} else {
|
|
3459
|
+
map.set(key, value);
|
|
3460
|
+
map.set(value, value);
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
return map;
|
|
3464
|
+
}
|
|
3465
|
+
function isNegativeNumber(arg) {
|
|
3466
|
+
if (arg.length < 2 || arg[0] !== "-") return false;
|
|
3467
|
+
if (arg[1] === "-") return false;
|
|
3468
|
+
return NEGATIVE_NUMBER_REGEX.test(arg.slice(1));
|
|
3469
|
+
}
|
|
3470
|
+
function shouldHandleNegatedBoolean(arg, context) {
|
|
3471
|
+
return context.negatedBoolean && arg.length > 5 && arg[0] === "-" && arg[1] === "-" && arg[2] === "n" && arg[3] === "o" && arg[4] === "-";
|
|
3472
|
+
}
|
|
3473
|
+
function handleNegatedBooleanFlag(arg, context) {
|
|
3474
|
+
const flagName = arg.slice(5);
|
|
3475
|
+
const resolvedName = resolveFlagName(flagName, context);
|
|
3476
|
+
if (context.booleanFlags.has(resolvedName)) {
|
|
3477
|
+
setFlagValue(resolvedName, false, context);
|
|
3478
|
+
} else {
|
|
3479
|
+
handleUnknownFlag(resolvedName, context);
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
function handleLongFlag(argv, index, context) {
|
|
3483
|
+
const arg = argv[index];
|
|
3484
|
+
if (arg === void 0) {
|
|
3485
|
+
return index + 1;
|
|
3486
|
+
}
|
|
3487
|
+
const flagBody = arg.slice(2);
|
|
3488
|
+
const eqIndex = flagBody.indexOf("=");
|
|
3489
|
+
let rawFlagName = flagBody;
|
|
3490
|
+
let value = true;
|
|
3491
|
+
let nextIndex = index;
|
|
3492
|
+
if (eqIndex !== -1) {
|
|
3493
|
+
rawFlagName = flagBody.slice(0, eqIndex);
|
|
3494
|
+
value = flagBody.slice(eqIndex + 1);
|
|
3495
|
+
} else {
|
|
3496
|
+
const nextArg = argv[index + 1];
|
|
3497
|
+
if (nextArg && nextArg.length > 0 && nextArg[0] !== "-") {
|
|
3498
|
+
value = nextArg;
|
|
3499
|
+
nextIndex++;
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
const flagName = resolveFlagName(rawFlagName, context);
|
|
3503
|
+
const parsedValue = parseValue(value, flagName, context);
|
|
3504
|
+
setFlagValue(flagName, parsedValue, context);
|
|
3505
|
+
validateOrWarn(flagName, context);
|
|
3506
|
+
return nextIndex + 1;
|
|
3507
|
+
}
|
|
3508
|
+
function handleShortFlags(argv, index, context) {
|
|
3509
|
+
const arg = argv[index];
|
|
3510
|
+
if (arg === void 0) {
|
|
3511
|
+
return index + 1;
|
|
3512
|
+
}
|
|
3513
|
+
const shortFlags = arg.slice(1);
|
|
3514
|
+
const booleanFlags = context.booleanFlags;
|
|
3515
|
+
const aliasMap = context.aliasMap;
|
|
3516
|
+
const shortFlagsLength = shortFlags.length;
|
|
3517
|
+
let j = 0;
|
|
3518
|
+
while (j < shortFlagsLength) {
|
|
3519
|
+
const flagChar = shortFlags[j];
|
|
3520
|
+
if (!flagChar) {
|
|
3521
|
+
j++;
|
|
3522
|
+
continue;
|
|
3523
|
+
}
|
|
3524
|
+
const resolvedName = aliasMap.get(flagChar) || flagChar;
|
|
3525
|
+
const nextChar = shortFlags[j + 1];
|
|
3526
|
+
if (booleanFlags.has(resolvedName)) {
|
|
3527
|
+
if (nextChar === "=") {
|
|
3528
|
+
const attachedValue = shortFlags.slice(j + 2);
|
|
3529
|
+
const parsed = parseValue(attachedValue, resolvedName, context);
|
|
3530
|
+
setFlagValue(resolvedName, parsed, context);
|
|
3531
|
+
j = shortFlagsLength;
|
|
3532
|
+
} else if (nextChar && !isAsciiLetter(nextChar)) {
|
|
3533
|
+
const attachedValue = shortFlags.slice(j + 1);
|
|
3534
|
+
const parsed = parseValue(attachedValue, resolvedName, context);
|
|
3535
|
+
setFlagValue(resolvedName, parsed, context);
|
|
3536
|
+
j = shortFlagsLength;
|
|
3537
|
+
} else {
|
|
3538
|
+
setFlagValue(resolvedName, true, context);
|
|
3539
|
+
j++;
|
|
3540
|
+
}
|
|
3541
|
+
} else {
|
|
3542
|
+
const remainder = shortFlags.slice(j + 1);
|
|
3543
|
+
if (remainder.startsWith("=")) {
|
|
3544
|
+
const val = remainder.slice(1);
|
|
3545
|
+
const parsedVal = parseValue(val, resolvedName, context);
|
|
3546
|
+
setFlagValue(resolvedName, parsedVal, context);
|
|
3547
|
+
validateOrWarn(resolvedName, context);
|
|
3548
|
+
j = shortFlagsLength;
|
|
3549
|
+
} else if (remainder.length > 0) {
|
|
3550
|
+
const parsedVal = parseValue(remainder, resolvedName, context);
|
|
3551
|
+
setFlagValue(resolvedName, parsedVal, context);
|
|
3552
|
+
validateOrWarn(resolvedName, context);
|
|
3553
|
+
j = shortFlagsLength;
|
|
3554
|
+
} else {
|
|
3555
|
+
const nextArgIndex = index + 1;
|
|
3556
|
+
if (nextArgIndex < argv.length) {
|
|
3557
|
+
const nextArg = argv[nextArgIndex];
|
|
3558
|
+
if (nextArg && nextArg.length > 0 && nextArg[0] !== "-") {
|
|
3559
|
+
const parsedVal = parseValue(nextArg, resolvedName, context);
|
|
3560
|
+
setFlagValue(resolvedName, parsedVal, context);
|
|
3561
|
+
validateOrWarn(resolvedName, context);
|
|
3562
|
+
return index + 2;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
setFlagValue(resolvedName, true, context);
|
|
3566
|
+
validateOrWarn(resolvedName, context);
|
|
3567
|
+
break;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
return index + 1;
|
|
3572
|
+
}
|
|
3573
|
+
function resolveFlagName(rawName, context) {
|
|
3574
|
+
return context.aliasMap.get(rawName) || rawName;
|
|
3575
|
+
}
|
|
3576
|
+
function setFlagValue(flagName, value, context) {
|
|
3577
|
+
if (context.arrayFlags.has(flagName)) {
|
|
3578
|
+
if (!Array.isArray(context.result[flagName])) {
|
|
3579
|
+
context.result[flagName] = [];
|
|
3580
|
+
}
|
|
3581
|
+
context.result[flagName].push(value);
|
|
3582
|
+
} else {
|
|
3583
|
+
context.result[flagName] = value;
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
function parseValue(val, flagName, context) {
|
|
3587
|
+
if (typeof val === "boolean") {
|
|
3588
|
+
return val;
|
|
3589
|
+
}
|
|
3590
|
+
const strVal = String(val);
|
|
3591
|
+
if (context.stringFlags.has(flagName)) {
|
|
3592
|
+
return strVal;
|
|
3593
|
+
}
|
|
3594
|
+
if (context.booleanFlags.has(flagName)) {
|
|
3595
|
+
if (strVal === "true") return true;
|
|
3596
|
+
if (strVal === "false") return false;
|
|
3597
|
+
return strVal;
|
|
3598
|
+
}
|
|
3599
|
+
if (context.parseNumbers && strVal.length > 0) {
|
|
3600
|
+
const firstChar = strVal.charAt(0);
|
|
3601
|
+
const lastChar = strVal.charAt(strVal.length - 1);
|
|
3602
|
+
if (firstChar >= "0" && firstChar <= "9" || firstChar === "-" || firstChar === "+") {
|
|
3603
|
+
if (lastChar >= "0" && lastChar <= "9") {
|
|
3604
|
+
const maybeNum = Number(strVal);
|
|
3605
|
+
if (!Number.isNaN(maybeNum)) {
|
|
3606
|
+
return maybeNum;
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
return strVal;
|
|
3612
|
+
}
|
|
3613
|
+
function validateOrWarn(flagName, context) {
|
|
3614
|
+
const { unknown, defaults } = context.options;
|
|
3615
|
+
if (unknown) {
|
|
3616
|
+
if (!unknown(flagName)) {
|
|
3617
|
+
handleUnknownFlag(flagName, context);
|
|
3618
|
+
}
|
|
3619
|
+
return;
|
|
3620
|
+
}
|
|
3621
|
+
if (context.booleanFlags.has(flagName) || context.arrayFlags.has(flagName) || context.stringFlags.has(flagName) || context.aliasMap.has(flagName)) {
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3624
|
+
if (defaults && Object.hasOwn(defaults, flagName)) {
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
3627
|
+
handleUnknownFlag(flagName, context);
|
|
3628
|
+
}
|
|
3629
|
+
function handleUnknownFlag(flagName, context) {
|
|
3630
|
+
if (context.strict) {
|
|
3631
|
+
throw new Error(`Unknown flag: --${flagName}`);
|
|
3632
|
+
}
|
|
3633
|
+
if (context.warnOnUnknown) {
|
|
3634
|
+
console.warn(`Unknown flag: --${flagName}`);
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3114
3638
|
async function callCmd(command, input, options = {}) {
|
|
3115
3639
|
const { autoExit = false, debug = false, useLifecycleHooks = true, parserOptions = {} } = options;
|
|
3116
3640
|
const debugLog = (...args) => {
|
|
@@ -3338,1944 +3862,57 @@ function castArgValue$1(def, rawVal, argName) {
|
|
|
3338
3862
|
}
|
|
3339
3863
|
}
|
|
3340
3864
|
|
|
3341
|
-
function
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
function addCommandCompletions(command, cTreeNode) {
|
|
3345
|
-
command.commands.forEach((c) => {
|
|
3346
|
-
const node = cTreeNode[c.name()] ||= {};
|
|
3347
|
-
Object.defineProperty(node, commandSymbol, {
|
|
3348
|
-
value: c,
|
|
3349
|
-
enumerable: false
|
|
3350
|
-
});
|
|
3351
|
-
addCommandCompletions(c, node);
|
|
3352
|
-
});
|
|
3353
|
-
}
|
|
3354
|
-
addCommandCompletions(program, cTree);
|
|
3355
|
-
completion.on("complete", (fragment, params) => {
|
|
3356
|
-
const segments = params.line.split(/ +/).slice(1, params.fragment);
|
|
3357
|
-
const last = segments.at(-1);
|
|
3358
|
-
let node = cTree;
|
|
3359
|
-
const existingFlags = /* @__PURE__ */ new Set();
|
|
3360
|
-
for (const segment of segments) {
|
|
3361
|
-
if (segment.startsWith("-")) {
|
|
3362
|
-
existingFlags.add(segment);
|
|
3363
|
-
continue;
|
|
3364
|
-
}
|
|
3365
|
-
if (existingFlags.size > 0) continue;
|
|
3366
|
-
node = node[segment];
|
|
3367
|
-
if (!node) return;
|
|
3368
|
-
}
|
|
3369
|
-
const correspondingCommand = node[commandSymbol];
|
|
3370
|
-
if (correspondingCommand?.options?.length) {
|
|
3371
|
-
const suggestions = [];
|
|
3372
|
-
for (const o of correspondingCommand.options) {
|
|
3373
|
-
if (last === o.long || last === o.short) {
|
|
3374
|
-
if (o.argChoices) suggestions.push(...o.argChoices);
|
|
3375
|
-
if (!o.isBoolean()) break;
|
|
3376
|
-
}
|
|
3377
|
-
if (existingFlags.has(o.long)) continue;
|
|
3378
|
-
if (existingFlags.has(o.short)) continue;
|
|
3379
|
-
suggestions.push(o.long);
|
|
3380
|
-
}
|
|
3381
|
-
return params.reply(suggestions);
|
|
3382
|
-
}
|
|
3383
|
-
});
|
|
3384
|
-
completion.tree(cTree).init();
|
|
3385
|
-
}
|
|
3386
|
-
|
|
3387
|
-
class CliValidationError extends Error {
|
|
3388
|
-
}
|
|
3389
|
-
class FailedToExitError extends Error {
|
|
3390
|
-
exitCode;
|
|
3391
|
-
constructor(message, { exitCode, cause }) {
|
|
3392
|
-
const fullMessage = `${message}. The process was expected to exit with exit code ${exitCode} but did not. This may be because a custom \`process\` parameter was used. The exit reason is in the \`cause\` property.`;
|
|
3393
|
-
super(fullMessage, { cause });
|
|
3394
|
-
this.exitCode = exitCode;
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
|
|
3398
|
-
const commandToJSON = (command) => {
|
|
3399
|
-
const json = {};
|
|
3400
|
-
const name = command.name();
|
|
3401
|
-
if (name) json.name = name;
|
|
3402
|
-
const version = command.version();
|
|
3403
|
-
if (version) json.version = version;
|
|
3404
|
-
const description = command.description();
|
|
3405
|
-
if (description) json.description = description;
|
|
3406
|
-
const usage = command.usage();
|
|
3407
|
-
if (usage) json.usage = usage;
|
|
3408
|
-
json.arguments = command.registeredArguments.map((arg) => {
|
|
3409
|
-
const result = { name: arg.name() };
|
|
3410
|
-
result.variadic = arg.variadic;
|
|
3411
|
-
result.required = arg.required;
|
|
3412
|
-
if (arg.description) result.description = arg.description;
|
|
3413
|
-
if (arg.defaultValue) result.defaultValue = arg.defaultValue;
|
|
3414
|
-
if (arg.defaultValueDescription) result.defaultValueDescription = arg.defaultValueDescription;
|
|
3415
|
-
if (arg.argChoices) result.choices = arg.argChoices;
|
|
3416
|
-
return result;
|
|
3417
|
-
});
|
|
3418
|
-
json.options = command.options.map((o) => {
|
|
3419
|
-
const result = { name: o.name() };
|
|
3420
|
-
result.required = o.required;
|
|
3421
|
-
result.optional = o.optional;
|
|
3422
|
-
result.negate = o.negate;
|
|
3423
|
-
result.variadic = o.variadic;
|
|
3424
|
-
if (o.flags) result.flags = o.flags;
|
|
3425
|
-
if (o.short) result.short = o.short;
|
|
3426
|
-
if (o.description) result.description = o.description;
|
|
3427
|
-
if (o.argChoices) result.choices = o.argChoices;
|
|
3428
|
-
const attributeName = o.attributeName();
|
|
3429
|
-
if (attributeName) result.attributeName = attributeName;
|
|
3430
|
-
if (o.defaultValue) result.defaultValue = o.defaultValue;
|
|
3431
|
-
if (o.defaultValueDescription) result.defaultValueDescription = o.defaultValueDescription;
|
|
3432
|
-
return result;
|
|
3433
|
-
});
|
|
3434
|
-
json.commands = command.commands.map((c) => commandToJSON(c));
|
|
3435
|
-
return json;
|
|
3436
|
-
};
|
|
3437
|
-
|
|
3438
|
-
const capitaliseFromCamelCase = (camel) => {
|
|
3439
|
-
const parts = camel.split(/(?=[A-Z])/);
|
|
3440
|
-
return capitalise(parts.map((p) => p.toLowerCase()).join(" "));
|
|
3441
|
-
};
|
|
3442
|
-
const capitalise = (s) => s.slice(0, 1).toUpperCase() + s.slice(1);
|
|
3443
|
-
const flattenedProperties = (sch) => {
|
|
3444
|
-
if ("properties" in sch) {
|
|
3445
|
-
return sch.properties;
|
|
3446
|
-
}
|
|
3447
|
-
if ("allOf" in sch) {
|
|
3448
|
-
return Object.fromEntries(
|
|
3449
|
-
sch.allOf.flatMap(
|
|
3450
|
-
(subSchema) => Object.entries(flattenedProperties(subSchema))
|
|
3451
|
-
)
|
|
3452
|
-
);
|
|
3453
|
-
}
|
|
3454
|
-
if ("anyOf" in sch) {
|
|
3455
|
-
const isExcluded = (v) => Object.keys(v).join(",") === "not";
|
|
3456
|
-
const entries = sch.anyOf.flatMap((subSchema) => {
|
|
3457
|
-
const flattened = flattenedProperties(subSchema);
|
|
3458
|
-
const excluded = Object.entries(flattened).flatMap(([name, propSchema]) => {
|
|
3459
|
-
return isExcluded(propSchema) ? [`--${name}`] : [];
|
|
3460
|
-
});
|
|
3461
|
-
return Object.entries(flattened).map(([k, v]) => {
|
|
3462
|
-
if (!isExcluded(v) && excluded.length > 0) {
|
|
3463
|
-
return [k, { ...v, "Do not use with": excluded }];
|
|
3464
|
-
}
|
|
3465
|
-
return [k, v];
|
|
3466
|
-
});
|
|
3467
|
-
});
|
|
3468
|
-
return Object.fromEntries(
|
|
3469
|
-
entries.sort((a, b) => {
|
|
3470
|
-
const scores = [a, b].map(([_k, v]) => isExcluded(v) ? 0 : 1);
|
|
3471
|
-
return scores[0] - scores[1];
|
|
3472
|
-
})
|
|
3473
|
-
);
|
|
3474
|
-
}
|
|
3475
|
-
return {};
|
|
3476
|
-
};
|
|
3477
|
-
const incompatiblePropertyPairs = (sch) => {
|
|
3478
|
-
const isUnion = "anyOf" in sch;
|
|
3479
|
-
if (!isUnion) return [];
|
|
3480
|
-
const sets = sch.anyOf.map((subSchema) => {
|
|
3481
|
-
const keys = Object.keys(flattenedProperties(subSchema));
|
|
3482
|
-
return { keys, set: new Set(keys) };
|
|
3483
|
-
});
|
|
3484
|
-
const compatiblityEntries = sets.flatMap(({ keys }) => {
|
|
3485
|
-
return keys.map((key) => {
|
|
3486
|
-
return [
|
|
3487
|
-
key,
|
|
3488
|
-
new Set(sets.filter((other) => other.set.has(key)).flatMap((other) => other.keys))
|
|
3489
|
-
];
|
|
3490
|
-
});
|
|
3491
|
-
});
|
|
3492
|
-
const allKeys = sets.flatMap(({ keys }) => keys);
|
|
3493
|
-
return compatiblityEntries.flatMap(([key, compatibleWith]) => {
|
|
3494
|
-
const incompatibleEntries = allKeys.filter((other) => key < other && !compatibleWith.has(other)).map((other) => [key, other]);
|
|
3495
|
-
return incompatibleEntries;
|
|
3496
|
-
});
|
|
3497
|
-
};
|
|
3498
|
-
const getDescription = (v, depth = 0) => {
|
|
3499
|
-
if ("items" in v && v.items) {
|
|
3500
|
-
const { items, ...rest } = v;
|
|
3501
|
-
return [getDescription(items, 1), getDescription(rest), "array"].filter(Boolean).join(" ");
|
|
3502
|
-
}
|
|
3503
|
-
return Object.entries(v).filter(([k, vv]) => {
|
|
3504
|
-
if (k === "default" || k === "additionalProperties" || k === "optional") return false;
|
|
3505
|
-
if (k === "type" && typeof vv === "string") return depth > 0;
|
|
3506
|
-
if (k.startsWith("$")) return false;
|
|
3507
|
-
if (k === "maximum" && vv === Number.MAX_SAFE_INTEGER) return false;
|
|
3508
|
-
if (depth <= 1 && k === "enum" && getEnumChoices(v)?.type === "string_enum") return false;
|
|
3865
|
+
async function pathExists(path2) {
|
|
3866
|
+
try {
|
|
3867
|
+
await stat(path2);
|
|
3509
3868
|
return true;
|
|
3510
|
-
}
|
|
3511
|
-
|
|
3512
|
-
return scores[0] - scores[1];
|
|
3513
|
-
}).map(([k, vv], i) => {
|
|
3514
|
-
if (k === "type" && Array.isArray(vv)) return `type: ${vv.join(" or ")}`;
|
|
3515
|
-
if (k === "description" && i === 0) return String(vv);
|
|
3516
|
-
if (k === "properties") return "Object (json formatted)";
|
|
3517
|
-
if (typeof vv === "object") return `${capitaliseFromCamelCase(k)}: ${JSON.stringify(vv)}`;
|
|
3518
|
-
return `${capitaliseFromCamelCase(k)}: ${vv}`;
|
|
3519
|
-
}).join("; ") || "";
|
|
3520
|
-
};
|
|
3521
|
-
const getSchemaTypes = (propertyValue) => {
|
|
3522
|
-
const array = [];
|
|
3523
|
-
if ("type" in propertyValue) {
|
|
3524
|
-
array.push(...[propertyValue.type].flat());
|
|
3525
|
-
}
|
|
3526
|
-
if ("enum" in propertyValue && Array.isArray(propertyValue.enum)) {
|
|
3527
|
-
array.push(...propertyValue.enum.flatMap((s) => typeof s));
|
|
3528
|
-
}
|
|
3529
|
-
if ("const" in propertyValue && propertyValue.const === null) {
|
|
3530
|
-
array.push("null");
|
|
3531
|
-
} else if ("const" in propertyValue) {
|
|
3532
|
-
array.push(typeof propertyValue.const);
|
|
3533
|
-
}
|
|
3534
|
-
if ("oneOf" in propertyValue) {
|
|
3535
|
-
array.push(...propertyValue.oneOf.flatMap(getSchemaTypes));
|
|
3536
|
-
}
|
|
3537
|
-
if ("anyOf" in propertyValue) {
|
|
3538
|
-
array.push(...propertyValue.anyOf.flatMap(getSchemaTypes));
|
|
3869
|
+
} catch (error) {
|
|
3870
|
+
return false;
|
|
3539
3871
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
const
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
}
|
|
3549
|
-
return false;
|
|
3550
|
-
})) {
|
|
3551
|
-
return {
|
|
3552
|
-
type: "string_enum",
|
|
3553
|
-
choices: propertyValue.anyOf.map((subSchema) => subSchema.const)
|
|
3554
|
-
};
|
|
3872
|
+
}
|
|
3873
|
+
function buildExampleArgs(args) {
|
|
3874
|
+
const parts = [];
|
|
3875
|
+
const positionalKeys = Object.keys(args || {}).filter((k) => args?.[k]?.type === "positional");
|
|
3876
|
+
positionalKeys.forEach((key) => {
|
|
3877
|
+
const def = args?.[key];
|
|
3878
|
+
if (def && (def.required || Math.random() > 0.5)) {
|
|
3879
|
+
parts.push(String(def.default ?? `<${key}>`));
|
|
3555
3880
|
}
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3881
|
+
});
|
|
3882
|
+
const otherKeys = Object.keys(args || {}).filter((k) => args?.[k]?.type !== "positional");
|
|
3883
|
+
for (const key of otherKeys) {
|
|
3884
|
+
const def = args?.[key];
|
|
3885
|
+
if (def && (def.required || Math.random() > 0.7)) {
|
|
3886
|
+
switch (def.type) {
|
|
3887
|
+
case "boolean":
|
|
3888
|
+
if (def.default === true) {
|
|
3889
|
+
if (Math.random() > 0.5) parts.push(`--no-${key}`);
|
|
3890
|
+
} else {
|
|
3891
|
+
parts.push(`--${key}`);
|
|
3892
|
+
}
|
|
3893
|
+
break;
|
|
3894
|
+
case "string":
|
|
3895
|
+
parts.push(`--${key}=${String(def.default ?? key)}`);
|
|
3896
|
+
break;
|
|
3897
|
+
case "number":
|
|
3898
|
+
parts.push(`--${key}=${String(def.default ?? 42)}`);
|
|
3899
|
+
break;
|
|
3900
|
+
case "array":
|
|
3901
|
+
parts.push(`--${key}=${String(def.default ?? key)}`);
|
|
3902
|
+
break;
|
|
3559
3903
|
}
|
|
3560
|
-
return false;
|
|
3561
|
-
})) {
|
|
3562
|
-
return {
|
|
3563
|
-
type: "number_enum",
|
|
3564
|
-
choices: propertyValue.anyOf.map((subSchema) => subSchema.const)
|
|
3565
|
-
};
|
|
3566
3904
|
}
|
|
3567
|
-
return null;
|
|
3568
|
-
}
|
|
3569
|
-
if (propertyValue.enum.every((s) => typeof s === "string")) {
|
|
3570
|
-
return {
|
|
3571
|
-
type: "string_enum",
|
|
3572
|
-
choices: propertyValue.enum
|
|
3573
|
-
};
|
|
3574
3905
|
}
|
|
3575
|
-
|
|
3576
|
-
return {
|
|
3577
|
-
type: "number_enum",
|
|
3578
|
-
choices: propertyValue.enum
|
|
3579
|
-
};
|
|
3580
|
-
}
|
|
3581
|
-
return null;
|
|
3582
|
-
};
|
|
3583
|
-
|
|
3584
|
-
const lineByLineLogger = getLoggerTransformer((log) => {
|
|
3585
|
-
const wrapper = (args, depth) => {
|
|
3586
|
-
if (args.length === 1 && Array.isArray(args[0]) && depth === 0) {
|
|
3587
|
-
args[0].forEach((item) => wrapper([item], 1));
|
|
3588
|
-
} else if (args.every(isPrimitive)) {
|
|
3589
|
-
log(...args);
|
|
3590
|
-
} else if (args.length === 1) {
|
|
3591
|
-
log(JSON.stringify(args[0], null, 2));
|
|
3592
|
-
} else {
|
|
3593
|
-
log(JSON.stringify(args, null, 2));
|
|
3594
|
-
}
|
|
3595
|
-
};
|
|
3596
|
-
return (...args) => wrapper(args, 0);
|
|
3597
|
-
});
|
|
3598
|
-
const isPrimitive = (value) => {
|
|
3599
|
-
const type = typeof value;
|
|
3600
|
-
return type === "string" || type === "number" || type === "boolean";
|
|
3601
|
-
};
|
|
3602
|
-
function getLoggerTransformer(transform) {
|
|
3603
|
-
return (logger) => {
|
|
3604
|
-
const info = logger.info && transform(logger.info);
|
|
3605
|
-
const error = logger.error && transform(logger.error);
|
|
3606
|
-
return { info, error };
|
|
3607
|
-
};
|
|
3906
|
+
return parts.join(" ");
|
|
3608
3907
|
}
|
|
3609
|
-
const
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
const jsonSchemaConverters = getJsonSchemaConverters(dependencies);
|
|
3614
|
-
const vendor = getVendor(input);
|
|
3615
|
-
if (vendor && vendor in jsonSchemaConverters) {
|
|
3616
|
-
const converter = jsonSchemaConverters[vendor];
|
|
3617
|
-
const converted = converter(input);
|
|
3618
|
-
return { success: true, value: converted };
|
|
3619
|
-
}
|
|
3620
|
-
return { success: false, error: "Schema not convertible to JSON schema" };
|
|
3621
|
-
} catch (e) {
|
|
3622
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
3623
|
-
return {
|
|
3624
|
-
success: false,
|
|
3625
|
-
error: `Failed to convert input to JSON Schema: ${message}`
|
|
3626
|
-
};
|
|
3908
|
+
const isDebugMode = process$1.argv.includes("--debug");
|
|
3909
|
+
function debugLog(...args) {
|
|
3910
|
+
if (isDebugMode) {
|
|
3911
|
+
relinka("log", "[DEBUG]", ...args);
|
|
3627
3912
|
}
|
|
3628
3913
|
}
|
|
3629
|
-
function
|
|
3630
|
-
return
|
|
3631
|
-
}
|
|
3632
|
-
function parseProcedureInputs(inputs, dependencies) {
|
|
3633
|
-
if (inputs.length === 0) {
|
|
3634
|
-
return {
|
|
3635
|
-
success: true,
|
|
3636
|
-
value: {
|
|
3637
|
-
positionalParameters: [],
|
|
3638
|
-
optionsJsonSchema: {},
|
|
3639
|
-
getPojoInput: () => ({})
|
|
3640
|
-
}
|
|
3641
|
-
};
|
|
3642
|
-
}
|
|
3643
|
-
const allJsonSchemaable = inputs.every((input) => looksJsonSchemaable(input));
|
|
3644
|
-
if (!allJsonSchemaable) {
|
|
3645
|
-
return {
|
|
3646
|
-
success: false,
|
|
3647
|
-
error: `Invalid input type ${inputs.map((s) => s?.constructor.name).join(", ")}, only inputs that can be converted to JSON Schema are supported`
|
|
3648
|
-
};
|
|
3649
|
-
}
|
|
3650
|
-
if (inputs.length > 1) {
|
|
3651
|
-
return parseMultiInputs(inputs, dependencies);
|
|
3652
|
-
}
|
|
3653
|
-
const mergedSchemaResult = toJsonSchema(inputs[0], dependencies);
|
|
3654
|
-
if (!mergedSchemaResult.success) {
|
|
3655
|
-
return {
|
|
3656
|
-
success: false,
|
|
3657
|
-
error: mergedSchemaResult.error
|
|
3658
|
-
};
|
|
3659
|
-
}
|
|
3660
|
-
const mergedSchema = mergedSchemaResult.value;
|
|
3661
|
-
return handleMergedSchema(mergedSchema);
|
|
3662
|
-
}
|
|
3663
|
-
function handleMergedSchema(mergedSchema) {
|
|
3664
|
-
if (mergedSchema.additionalProperties) {
|
|
3665
|
-
return {
|
|
3666
|
-
success: false,
|
|
3667
|
-
error: "Inputs with additional properties are not currently supported"
|
|
3668
|
-
};
|
|
3669
|
-
}
|
|
3670
|
-
if (mergedSchema.type === "string") {
|
|
3671
|
-
return {
|
|
3672
|
-
success: true,
|
|
3673
|
-
value: {
|
|
3674
|
-
positionalParameters: [
|
|
3675
|
-
{
|
|
3676
|
-
type: "string",
|
|
3677
|
-
array: false,
|
|
3678
|
-
description: mergedSchema.description || "",
|
|
3679
|
-
name: mergedSchema.title || "string",
|
|
3680
|
-
required: !isOptional(mergedSchema)
|
|
3681
|
-
}
|
|
3682
|
-
],
|
|
3683
|
-
optionsJsonSchema: {},
|
|
3684
|
-
getPojoInput: (argv) => argv.positionalValues[0]
|
|
3685
|
-
}
|
|
3686
|
-
};
|
|
3687
|
-
}
|
|
3688
|
-
if (acceptedPrimitiveTypes(mergedSchema).length > 0) {
|
|
3689
|
-
return parsePrimitiveInput(mergedSchema);
|
|
3690
|
-
}
|
|
3691
|
-
if (isTuple(mergedSchema)) {
|
|
3692
|
-
return parseTupleInput(mergedSchema);
|
|
3693
|
-
}
|
|
3694
|
-
if (mergedSchema.type === "array") {
|
|
3695
|
-
return parseArrayInput(mergedSchema);
|
|
3696
|
-
}
|
|
3697
|
-
if (mergedSchema.anyOf) {
|
|
3698
|
-
const allObjects = mergedSchema.anyOf.every((sub) => acceptsObject(toRoughJsonSchema7(sub)));
|
|
3699
|
-
if (allObjects) {
|
|
3700
|
-
return {
|
|
3701
|
-
success: true,
|
|
3702
|
-
value: {
|
|
3703
|
-
positionalParameters: [],
|
|
3704
|
-
optionsJsonSchema: mergedSchema,
|
|
3705
|
-
getPojoInput: (argv) => argv.options
|
|
3706
|
-
}
|
|
3707
|
-
};
|
|
3708
|
-
}
|
|
3709
|
-
if (mergedSchema.anyOf.length === 2 && JSON.stringify(mergedSchema.anyOf[0]) === '{"not":{}}') {
|
|
3710
|
-
return handleMergedSchema(mergedSchema.anyOf[1]);
|
|
3711
|
-
}
|
|
3712
|
-
}
|
|
3713
|
-
if (mergedSchema.type !== "object") {
|
|
3714
|
-
return {
|
|
3715
|
-
success: false,
|
|
3716
|
-
error: `Invalid input type ${inspect(mergedSchema, { depth: 2, breakLength: Number.POSITIVE_INFINITY })}, expected object or tuple.`
|
|
3717
|
-
};
|
|
3718
|
-
}
|
|
3719
|
-
return {
|
|
3720
|
-
success: true,
|
|
3721
|
-
value: {
|
|
3722
|
-
positionalParameters: [],
|
|
3723
|
-
optionsJsonSchema: mergedSchema,
|
|
3724
|
-
getPojoInput: (argv) => argv.options
|
|
3725
|
-
}
|
|
3726
|
-
};
|
|
3727
|
-
}
|
|
3728
|
-
function isOptional(schema) {
|
|
3729
|
-
if (schema && typeof schema === "object" && "optional" in schema) return schema.optional === true;
|
|
3730
|
-
const anyOf = schemaDefPropValue(schema, "anyOf");
|
|
3731
|
-
if (anyOf?.length === 2 && JSON.stringify(anyOf[0]) === '{"not":{}}') return true;
|
|
3732
|
-
if (anyOf?.some((sub) => isOptional(sub))) return true;
|
|
3733
|
-
return false;
|
|
3734
|
-
}
|
|
3735
|
-
function parsePrimitiveInput(schema) {
|
|
3736
|
-
const typeName = acceptedPrimitiveTypes(schema).join(" | ");
|
|
3737
|
-
const name = (schema.title || schema.description || /\W/.test(typeName) ? "value" : typeName).replaceAll(/\s+/g, "_");
|
|
3738
|
-
return {
|
|
3739
|
-
success: true,
|
|
3740
|
-
value: {
|
|
3741
|
-
positionalParameters: [
|
|
3742
|
-
{
|
|
3743
|
-
name,
|
|
3744
|
-
array: false,
|
|
3745
|
-
description: schema.description || "",
|
|
3746
|
-
required: !isOptional(schema),
|
|
3747
|
-
type: typeName
|
|
3748
|
-
}
|
|
3749
|
-
],
|
|
3750
|
-
optionsJsonSchema: {},
|
|
3751
|
-
getPojoInput: (argv) => convertPositional(schema, argv.positionalValues[0])
|
|
3752
|
-
}
|
|
3753
|
-
};
|
|
3754
|
-
}
|
|
3755
|
-
const schemaDefPropValue = (schema, prop) => {
|
|
3756
|
-
if (schema && typeof schema === "object" && prop in schema) return schema[prop];
|
|
3757
|
-
return;
|
|
3758
|
-
};
|
|
3759
|
-
const primitiveCandidateTypes = ["string", "number", "boolean", "integer"];
|
|
3760
|
-
function acceptedPrimitiveTypes(schema) {
|
|
3761
|
-
let constVals = [
|
|
3762
|
-
toRoughJsonSchema7(schema).const,
|
|
3763
|
-
toRoughJsonSchema7(schema).enum
|
|
3764
|
-
].flat().filter(Boolean).map((s) => typeof s);
|
|
3765
|
-
if (constVals.length === 0) constVals = void 0;
|
|
3766
|
-
const typeList = constVals || schemaDefPropValue(schema, "type") || schemaDefPropValue(schema, "oneOf")?.flatMap((s) => acceptedPrimitiveTypes(s)) || schemaDefPropValue(schema, "anyOf")?.flatMap((s) => acceptedPrimitiveTypes(s));
|
|
3767
|
-
const acceptedJsonSchemaTypes = new Set([typeList].flat().filter(Boolean));
|
|
3768
|
-
return primitiveCandidateTypes.filter((c) => acceptedJsonSchemaTypes.has(c));
|
|
3769
|
-
}
|
|
3770
|
-
function parseMultiInputs(inputs, dependencies) {
|
|
3771
|
-
const parsedIndividually = inputs.map((input) => parseProcedureInputs([input], dependencies));
|
|
3772
|
-
const failures = parsedIndividually.flatMap((p) => p.success ? [] : [p.error]);
|
|
3773
|
-
if (failures.length > 0) {
|
|
3774
|
-
return { success: false, error: failures.join("\n") };
|
|
3775
|
-
}
|
|
3776
|
-
const allObjects = parsedIndividually.every(
|
|
3777
|
-
(p) => p.success && p.value.positionalParameters.length === 0
|
|
3778
|
-
);
|
|
3779
|
-
if (!allObjects) {
|
|
3780
|
-
return {
|
|
3781
|
-
success: false,
|
|
3782
|
-
error: `Can't use positional parameters with multi-input type.`
|
|
3783
|
-
};
|
|
3784
|
-
}
|
|
3785
|
-
return {
|
|
3786
|
-
success: true,
|
|
3787
|
-
value: {
|
|
3788
|
-
positionalParameters: [],
|
|
3789
|
-
optionsJsonSchema: {
|
|
3790
|
-
allOf: parsedIndividually.map((p) => {
|
|
3791
|
-
const successful = p;
|
|
3792
|
-
const optionsSchema = successful.value.optionsJsonSchema;
|
|
3793
|
-
if ("additionalProperties" in optionsSchema && optionsSchema.additionalProperties === false) {
|
|
3794
|
-
const { additionalProperties, ...rest } = optionsSchema;
|
|
3795
|
-
return rest;
|
|
3796
|
-
}
|
|
3797
|
-
return optionsSchema;
|
|
3798
|
-
})
|
|
3799
|
-
},
|
|
3800
|
-
getPojoInput: (argv) => argv.options
|
|
3801
|
-
}
|
|
3802
|
-
};
|
|
3803
|
-
}
|
|
3804
|
-
function isNullable(schema) {
|
|
3805
|
-
if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
|
|
3806
|
-
if (schema.type === "null") return true;
|
|
3807
|
-
if ((schema.anyOf || schema.oneOf)?.some((sub) => isNullable(toRoughJsonSchema7(sub))))
|
|
3808
|
-
return true;
|
|
3809
|
-
if (schema.const === null) return true;
|
|
3810
|
-
return false;
|
|
3811
|
-
}
|
|
3812
|
-
const tupleItemsSchemas = (schema) => {
|
|
3813
|
-
if (!schema || typeof schema !== "object") return;
|
|
3814
|
-
if (Array.isArray(schema.items)) return schema.items;
|
|
3815
|
-
if ("prefixItems" in schema && Array.isArray(schema.prefixItems))
|
|
3816
|
-
return schema.prefixItems;
|
|
3817
|
-
return;
|
|
3818
|
-
};
|
|
3819
|
-
function isTuple(schema) {
|
|
3820
|
-
return Array.isArray(tupleItemsSchemas(schema));
|
|
3821
|
-
}
|
|
3822
|
-
function parseArrayInput(array) {
|
|
3823
|
-
if (looksLikeJsonSchema(array.items) && isNullable(array.items)) {
|
|
3824
|
-
return {
|
|
3825
|
-
success: false,
|
|
3826
|
-
error: `Invalid input type Array<${getSchemaTypes(array.items).join(" | ")}>. Nullable arrays are not supported.`
|
|
3827
|
-
};
|
|
3828
|
-
}
|
|
3829
|
-
return {
|
|
3830
|
-
success: true,
|
|
3831
|
-
value: {
|
|
3832
|
-
positionalParameters: [
|
|
3833
|
-
{
|
|
3834
|
-
name: parameterName(array, 1),
|
|
3835
|
-
array: true,
|
|
3836
|
-
description: array.description || "",
|
|
3837
|
-
required: !isOptional(array),
|
|
3838
|
-
type: "string"
|
|
3839
|
-
}
|
|
3840
|
-
],
|
|
3841
|
-
optionsJsonSchema: {},
|
|
3842
|
-
getPojoInput: (argv) => argv.positionalValues.at(-1).map(
|
|
3843
|
-
(s) => convertPositional(array.items, s)
|
|
3844
|
-
)
|
|
3845
|
-
}
|
|
3846
|
-
};
|
|
3847
|
-
}
|
|
3848
|
-
function parseTupleInput(tuple) {
|
|
3849
|
-
const items = tupleItemsSchemas(tuple);
|
|
3850
|
-
if (!Array.isArray(items)) throw new Error(".items is not an array, is this really a tuple?");
|
|
3851
|
-
const flagsSchemaIndex = items.findIndex((item) => {
|
|
3852
|
-
if (acceptedPrimitiveTypes(item).length > 0) {
|
|
3853
|
-
return false;
|
|
3854
|
-
}
|
|
3855
|
-
if (looksLikeArray(item) && acceptedPrimitiveTypes(item.items).length > 0) {
|
|
3856
|
-
return false;
|
|
3857
|
-
}
|
|
3858
|
-
return true;
|
|
3859
|
-
});
|
|
3860
|
-
const types = `[${items.map((s) => schemaDefPropValue(s, "type")).join(", ")}]`;
|
|
3861
|
-
if (flagsSchemaIndex > -1 && flagsSchemaIndex !== items.length - 1) {
|
|
3862
|
-
return {
|
|
3863
|
-
success: false,
|
|
3864
|
-
error: `Invalid input type ${types}. Positional parameters must be strings, numbers or booleans.`
|
|
3865
|
-
};
|
|
3866
|
-
}
|
|
3867
|
-
const flagsSchema = flagsSchemaIndex === -1 ? null : items[flagsSchemaIndex];
|
|
3868
|
-
if (flagsSchema && !acceptsObject(flagsSchema)) {
|
|
3869
|
-
return {
|
|
3870
|
-
success: false,
|
|
3871
|
-
error: `Invalid input type ${types}. The last type must accept object inputs.`
|
|
3872
|
-
};
|
|
3873
|
-
}
|
|
3874
|
-
const positionalSchemas = flagsSchemaIndex === -1 ? items : items.slice(0, flagsSchemaIndex);
|
|
3875
|
-
return {
|
|
3876
|
-
success: true,
|
|
3877
|
-
value: {
|
|
3878
|
-
positionalParameters: positionalSchemas.map((schema, i) => ({
|
|
3879
|
-
name: parameterName(schema, i + 1),
|
|
3880
|
-
array: looksLikeArray(schema),
|
|
3881
|
-
description: schemaDefPropValue(schema, "description") || "",
|
|
3882
|
-
required: !isOptional(schema),
|
|
3883
|
-
type: getSchemaTypes(toRoughJsonSchema7(schema)).join(" | ")
|
|
3884
|
-
})),
|
|
3885
|
-
optionsJsonSchema: flagsSchema && typeof flagsSchema === "object" ? flagsSchema : {},
|
|
3886
|
-
getPojoInput: (commandArgs) => {
|
|
3887
|
-
const inputs = commandArgs.positionalValues.map((v, i) => {
|
|
3888
|
-
const correspondingSchema = positionalSchemas[i];
|
|
3889
|
-
if (!correspondingSchema) {
|
|
3890
|
-
throw new CliValidationError(`No schema found for position ${i}`);
|
|
3891
|
-
}
|
|
3892
|
-
if (looksLikeArray(correspondingSchema)) {
|
|
3893
|
-
if (!Array.isArray(v)) {
|
|
3894
|
-
throw new CliValidationError(`Expected array at position ${i}, got ${typeof v}`);
|
|
3895
|
-
}
|
|
3896
|
-
return v.map((s) => {
|
|
3897
|
-
if (!correspondingSchema.items || Array.isArray(correspondingSchema.items)) return s;
|
|
3898
|
-
return convertPositional(correspondingSchema.items, s);
|
|
3899
|
-
});
|
|
3900
|
-
}
|
|
3901
|
-
if (typeof v !== "string" && v !== void 0) {
|
|
3902
|
-
throw new CliValidationError(`Expected string at position ${i}, got ${typeof v}`);
|
|
3903
|
-
}
|
|
3904
|
-
return convertPositional(correspondingSchema, v);
|
|
3905
|
-
});
|
|
3906
|
-
if (flagsSchema) {
|
|
3907
|
-
inputs.push(commandArgs.options);
|
|
3908
|
-
}
|
|
3909
|
-
return inputs;
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
|
-
};
|
|
3913
|
-
}
|
|
3914
|
-
const convertPositional = (schema, value) => {
|
|
3915
|
-
let preprocessed;
|
|
3916
|
-
const acceptedTypes = new Set(acceptedPrimitiveTypes(schema));
|
|
3917
|
-
if (acceptedTypes.has("string")) {
|
|
3918
|
-
preprocessed = value;
|
|
3919
|
-
}
|
|
3920
|
-
if (acceptedTypes.has("boolean")) {
|
|
3921
|
-
if (value === "true") preprocessed = true;
|
|
3922
|
-
else if (value === "false") preprocessed = false;
|
|
3923
|
-
}
|
|
3924
|
-
if (acceptedTypes.has("number")) {
|
|
3925
|
-
const number = Number(value);
|
|
3926
|
-
if (!Number.isNaN(number)) {
|
|
3927
|
-
preprocessed = number;
|
|
3928
|
-
}
|
|
3929
|
-
}
|
|
3930
|
-
if (acceptedTypes.has("integer")) {
|
|
3931
|
-
const num = Number(value);
|
|
3932
|
-
if (Number.isInteger(num)) {
|
|
3933
|
-
preprocessed = num;
|
|
3934
|
-
} else if (!Number.isNaN(num) && acceptedTypes === void 0) {
|
|
3935
|
-
preprocessed = value;
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
if (preprocessed === void 0) {
|
|
3939
|
-
return value;
|
|
3940
|
-
}
|
|
3941
|
-
return preprocessed;
|
|
3942
|
-
};
|
|
3943
|
-
const looksLikeArray = (schema) => {
|
|
3944
|
-
return schemaDefPropValue(schema, "type") === "array";
|
|
3945
|
-
};
|
|
3946
|
-
const toRoughJsonSchema7 = (schema) => {
|
|
3947
|
-
if (!schema || typeof schema !== "object") {
|
|
3948
|
-
return {};
|
|
3949
|
-
}
|
|
3950
|
-
return schema;
|
|
3951
|
-
};
|
|
3952
|
-
const parameterName = (s, position) => {
|
|
3953
|
-
if (looksLikeArray(s)) {
|
|
3954
|
-
const items = toRoughJsonSchema7(s).items;
|
|
3955
|
-
const elementName = parameterName(!items || Array.isArray(items) ? {} : items, position);
|
|
3956
|
-
return `[${elementName.slice(1, -1)}...]`;
|
|
3957
|
-
}
|
|
3958
|
-
let name = schemaDefPropValue(s, "title") || schemaDefPropValue(s, "description") || `parameter_${position}`;
|
|
3959
|
-
name = name.replaceAll(/\W+/g, " ").trim();
|
|
3960
|
-
return isOptional(s) ? `[${name}]` : `<${name}>`;
|
|
3961
|
-
};
|
|
3962
|
-
const acceptsObject = (schema) => {
|
|
3963
|
-
return (schema.type === "object" || schema.anyOf?.some((sub) => acceptsObject(toRoughJsonSchema7(sub)))) ?? false;
|
|
3964
|
-
};
|
|
3965
|
-
const getJsonSchemaConverters = (dependencies) => {
|
|
3966
|
-
return {
|
|
3967
|
-
zod: (input) => {
|
|
3968
|
-
if (input._zod?.version?.major === 4) {
|
|
3969
|
-
return zod4.toJSONSchema(input, {
|
|
3970
|
-
// todo[zod@>=4.0.0] remove the line if https://github.com/colinhacks/zod/issues/4167 is resolved, or this comment if it's closed
|
|
3971
|
-
io: "input",
|
|
3972
|
-
// todo[zod@>=4.0.0] remove the override if https://github.com/colinhacks/zod/issues/4164 is resolved, or this comment if it's closed
|
|
3973
|
-
unrepresentable: "any",
|
|
3974
|
-
// todo[zod@>=4.0.0] remove the override if https://github.com/colinhacks/zod/issues/4164 is resolved, or this comment if it's closed
|
|
3975
|
-
override: (ctx) => {
|
|
3976
|
-
if (ctx.zodSchema?.constructor?.name === "ZodOptional") {
|
|
3977
|
-
ctx.jsonSchema.optional = true;
|
|
3978
|
-
}
|
|
3979
|
-
}
|
|
3980
|
-
});
|
|
3981
|
-
}
|
|
3982
|
-
return zodToJsonSchema(input);
|
|
3983
|
-
},
|
|
3984
|
-
arktype: (input) => {
|
|
3985
|
-
const type = prepareArktypeType(input);
|
|
3986
|
-
return type.toJsonSchema({
|
|
3987
|
-
fallback: (ctx) => {
|
|
3988
|
-
if (ctx.code === "unit" && ctx.unit === void 0) return { ...ctx.base, optional: true };
|
|
3989
|
-
return ctx.base;
|
|
3990
|
-
}
|
|
3991
|
-
});
|
|
3992
|
-
},
|
|
3993
|
-
valibot: (input) => {
|
|
3994
|
-
let valibotToJsonSchemaLib = dependencies["@valibot/to-json-schema"];
|
|
3995
|
-
if (!valibotToJsonSchemaLib) {
|
|
3996
|
-
try {
|
|
3997
|
-
valibotToJsonSchemaLib = require("@valibot/to-json-schema");
|
|
3998
|
-
} catch (e) {
|
|
3999
|
-
throw new Error(
|
|
4000
|
-
"@valibot/to-json-schema could not be found - try installing it and re-running",
|
|
4001
|
-
{ cause: e }
|
|
4002
|
-
);
|
|
4003
|
-
}
|
|
4004
|
-
}
|
|
4005
|
-
const valibotToJsonSchema = valibotToJsonSchemaLib?.toJsonSchema;
|
|
4006
|
-
if (!valibotToJsonSchema) {
|
|
4007
|
-
throw new Error(
|
|
4008
|
-
`no 'toJsonSchema' function found in @valibot/to-json-schema - check you are using a supported version`
|
|
4009
|
-
);
|
|
4010
|
-
}
|
|
4011
|
-
let v;
|
|
4012
|
-
try {
|
|
4013
|
-
v = require("valibot");
|
|
4014
|
-
} catch {
|
|
4015
|
-
return valibotToJsonSchema(input);
|
|
4016
|
-
}
|
|
4017
|
-
const parent = valibotToJsonSchema(
|
|
4018
|
-
v.object({ child: input }),
|
|
4019
|
-
{
|
|
4020
|
-
errorMode: "ignore"
|
|
4021
|
-
}
|
|
4022
|
-
);
|
|
4023
|
-
const child = parent.properties.child;
|
|
4024
|
-
return parent.required?.length === 0 ? Object.assign(child, { optional: true }) : child;
|
|
4025
|
-
},
|
|
4026
|
-
effect: (input) => {
|
|
4027
|
-
const effect = dependencies.effect || (() => {
|
|
4028
|
-
try {
|
|
4029
|
-
return require("effect");
|
|
4030
|
-
} catch {
|
|
4031
|
-
return null;
|
|
4032
|
-
}
|
|
4033
|
-
})();
|
|
4034
|
-
if (!effect) {
|
|
4035
|
-
throw new Error("effect dependency could not be found - try installing it and re-running");
|
|
4036
|
-
}
|
|
4037
|
-
if (!effect.Schema.isSchema(input)) {
|
|
4038
|
-
const message = "input was not an effect schema - please use effect version 3.14.2 or higher. See https://github.com/mmkal/trpc-cli/pull/63";
|
|
4039
|
-
throw new Error(message);
|
|
4040
|
-
}
|
|
4041
|
-
return effect.JSONSchema.make(input);
|
|
4042
|
-
}
|
|
4043
|
-
};
|
|
4044
|
-
};
|
|
4045
|
-
function getVendor(schema) {
|
|
4046
|
-
return schema?.["~standard"]?.vendor ?? null;
|
|
4047
|
-
}
|
|
4048
|
-
const jsonSchemaVendorNames = new Set(Object.keys(getJsonSchemaConverters({})));
|
|
4049
|
-
function looksJsonSchemaable(value) {
|
|
4050
|
-
const vendor = getVendor(value);
|
|
4051
|
-
return !!vendor && jsonSchemaVendorNames.has(vendor);
|
|
4052
|
-
}
|
|
4053
|
-
function prepareArktypeType(type) {
|
|
4054
|
-
let innerType = type;
|
|
4055
|
-
while (innerType) {
|
|
4056
|
-
if (innerType?.in && innerType.in !== innerType) {
|
|
4057
|
-
innerType = innerType.in;
|
|
4058
|
-
} else {
|
|
4059
|
-
break;
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
|
-
return innerType;
|
|
4063
|
-
}
|
|
4064
|
-
|
|
4065
|
-
const parseUpstreamOptionInfo = (value) => {
|
|
4066
|
-
if (typeof value !== "string" || !value.startsWith("{")) return null;
|
|
4067
|
-
try {
|
|
4068
|
-
const info = JSON.parse(value);
|
|
4069
|
-
if (info.typeName !== "UpstreamOptionInfo") return null;
|
|
4070
|
-
return info;
|
|
4071
|
-
} catch {
|
|
4072
|
-
return null;
|
|
4073
|
-
}
|
|
4074
|
-
};
|
|
4075
|
-
const parseUpstreamArgumentInfo = (value) => {
|
|
4076
|
-
if (typeof value !== "string" || !value.startsWith("{")) return null;
|
|
4077
|
-
try {
|
|
4078
|
-
const info = JSON.parse(value);
|
|
4079
|
-
if (info.typeName !== "UpstreamArgumentInfo") return null;
|
|
4080
|
-
return info;
|
|
4081
|
-
} catch {
|
|
4082
|
-
return null;
|
|
4083
|
-
}
|
|
4084
|
-
};
|
|
4085
|
-
const getDefaultSubcommand = (command) => {
|
|
4086
|
-
const defaultChild = /Available subcommands:.* (\S+) \(default\)/.exec(
|
|
4087
|
-
command.description()
|
|
4088
|
-
)?.[1];
|
|
4089
|
-
return defaultChild ? command.commands.find((c) => c.name() === defaultChild) : void 0;
|
|
4090
|
-
};
|
|
4091
|
-
const createShadowCommand = (command, onAnalyze) => {
|
|
4092
|
-
const shadow = new Command(command.name());
|
|
4093
|
-
shadow.exitOverride();
|
|
4094
|
-
shadow.configureOutput({
|
|
4095
|
-
writeOut: () => {
|
|
4096
|
-
},
|
|
4097
|
-
writeErr: () => {
|
|
4098
|
-
}
|
|
4099
|
-
});
|
|
4100
|
-
const argumentsMap = /* @__PURE__ */ new Map();
|
|
4101
|
-
const optionsMap = /* @__PURE__ */ new Map();
|
|
4102
|
-
command.options.forEach((original) => {
|
|
4103
|
-
const id = Date.now().toString() + Math.random().toString().slice(1);
|
|
4104
|
-
const shadowOption = new Option(
|
|
4105
|
-
original.flags.replace("<", "[").replace(">", "]"),
|
|
4106
|
-
JSON.stringify([`id=${id}`, original.description])
|
|
4107
|
-
);
|
|
4108
|
-
const upstreamOptionInfo = {
|
|
4109
|
-
typeName: "UpstreamOptionInfo",
|
|
4110
|
-
id,
|
|
4111
|
-
specified: false
|
|
4112
|
-
};
|
|
4113
|
-
shadowOption.default(JSON.stringify(upstreamOptionInfo));
|
|
4114
|
-
shadowOption.argParser(
|
|
4115
|
-
(value) => JSON.stringify({ ...upstreamOptionInfo, specified: true, value })
|
|
4116
|
-
);
|
|
4117
|
-
shadow.addOption(shadowOption);
|
|
4118
|
-
optionsMap.set(id, { shadow: shadowOption, original });
|
|
4119
|
-
});
|
|
4120
|
-
command.registeredArguments.forEach((original) => {
|
|
4121
|
-
const shadowArgument = new Argument(original.name(), original.description);
|
|
4122
|
-
const id = Date.now().toString() + Math.random().toString().slice(1);
|
|
4123
|
-
shadowArgument.argOptional();
|
|
4124
|
-
const upstreamArgumentInfo = {
|
|
4125
|
-
typeName: "UpstreamArgumentInfo",
|
|
4126
|
-
id,
|
|
4127
|
-
specified: false
|
|
4128
|
-
};
|
|
4129
|
-
shadowArgument.default(JSON.stringify(upstreamArgumentInfo));
|
|
4130
|
-
shadowArgument.argParser(
|
|
4131
|
-
(value) => JSON.stringify({ ...upstreamArgumentInfo, specified: true, value })
|
|
4132
|
-
);
|
|
4133
|
-
shadow.addArgument(shadowArgument);
|
|
4134
|
-
argumentsMap.set(id, { shadow: shadowArgument, original });
|
|
4135
|
-
});
|
|
4136
|
-
const analysis = {
|
|
4137
|
-
command: { shadow, original: command },
|
|
4138
|
-
arguments: [],
|
|
4139
|
-
options: []
|
|
4140
|
-
};
|
|
4141
|
-
shadow.action(async (...args) => {
|
|
4142
|
-
const positionalValues = args.slice(0, -2);
|
|
4143
|
-
const options = shadow.opts();
|
|
4144
|
-
if (args.at(-2) !== options) {
|
|
4145
|
-
throw new Error("Unexpected args format, second last arg is not the options object", {
|
|
4146
|
-
cause: args
|
|
4147
|
-
});
|
|
4148
|
-
}
|
|
4149
|
-
if (args.at(-1) !== shadow) {
|
|
4150
|
-
throw new Error("Unexpected args format, last arg is not the Command instance", {
|
|
4151
|
-
cause: args
|
|
4152
|
-
});
|
|
4153
|
-
}
|
|
4154
|
-
positionalValues.forEach((value) => {
|
|
4155
|
-
const argumentInfo = parseUpstreamArgumentInfo(value);
|
|
4156
|
-
if (argumentInfo) {
|
|
4157
|
-
analysis.arguments.push({
|
|
4158
|
-
...argumentsMap.get(argumentInfo.id),
|
|
4159
|
-
value: argumentInfo.value,
|
|
4160
|
-
specified: argumentInfo.specified
|
|
4161
|
-
});
|
|
4162
|
-
}
|
|
4163
|
-
});
|
|
4164
|
-
Object.values(options).forEach((value) => {
|
|
4165
|
-
const upstreamOptionInfo = parseUpstreamOptionInfo(value);
|
|
4166
|
-
if (upstreamOptionInfo) {
|
|
4167
|
-
analysis.options.push({
|
|
4168
|
-
...optionsMap.get(upstreamOptionInfo.id),
|
|
4169
|
-
value: upstreamOptionInfo.value,
|
|
4170
|
-
specified: upstreamOptionInfo.specified
|
|
4171
|
-
});
|
|
4172
|
-
}
|
|
4173
|
-
});
|
|
4174
|
-
await onAnalyze(analysis);
|
|
4175
|
-
});
|
|
4176
|
-
command.commands.forEach((subcommand) => {
|
|
4177
|
-
const shadowSubcommand = createShadowCommand(subcommand, onAnalyze);
|
|
4178
|
-
shadow.addCommand(shadowSubcommand);
|
|
4179
|
-
});
|
|
4180
|
-
return shadow;
|
|
4181
|
-
};
|
|
4182
|
-
const inquirerPrompter = (prompts) => {
|
|
4183
|
-
return prompts;
|
|
4184
|
-
};
|
|
4185
|
-
const clackPrompter = (prompts) => {
|
|
4186
|
-
const clack = prompts;
|
|
4187
|
-
class ExitPromptError extends Error {
|
|
4188
|
-
}
|
|
4189
|
-
const throwOnCancel = (value) => {
|
|
4190
|
-
if (clack.isCancel(value)) throw new ExitPromptError();
|
|
4191
|
-
return value;
|
|
4192
|
-
};
|
|
4193
|
-
return {
|
|
4194
|
-
input: async (params) => {
|
|
4195
|
-
return clack.text({
|
|
4196
|
-
message: params.message,
|
|
4197
|
-
initialValue: params.default,
|
|
4198
|
-
defaultValue: params.default,
|
|
4199
|
-
placeholder: params.default,
|
|
4200
|
-
validate: params.validate ? (input) => {
|
|
4201
|
-
const result = params.validate(input);
|
|
4202
|
-
if (result === true) return;
|
|
4203
|
-
if (result === false) return "Invalid input";
|
|
4204
|
-
return result;
|
|
4205
|
-
} : void 0
|
|
4206
|
-
}).then(throwOnCancel);
|
|
4207
|
-
},
|
|
4208
|
-
checkbox: async (params) => {
|
|
4209
|
-
return clack.multiselect({
|
|
4210
|
-
message: params.message,
|
|
4211
|
-
options: params.choices.map((c) => ({
|
|
4212
|
-
label: c.name,
|
|
4213
|
-
value: c.value
|
|
4214
|
-
})),
|
|
4215
|
-
initialValues: params.choices.flatMap((c) => c.checked ? [c.value] : [])
|
|
4216
|
-
}).then(throwOnCancel);
|
|
4217
|
-
},
|
|
4218
|
-
confirm: async (params) => {
|
|
4219
|
-
return clack.confirm({
|
|
4220
|
-
message: params.message,
|
|
4221
|
-
initialValue: params.default
|
|
4222
|
-
}).then(throwOnCancel);
|
|
4223
|
-
},
|
|
4224
|
-
select: async (params) => {
|
|
4225
|
-
return clack.select({
|
|
4226
|
-
message: params.message,
|
|
4227
|
-
options: params.choices.map((sorc) => {
|
|
4228
|
-
const c = typeof sorc === "string" ? { name: sorc, value: sorc } : sorc;
|
|
4229
|
-
return {
|
|
4230
|
-
label: c.name,
|
|
4231
|
-
value: c.value,
|
|
4232
|
-
hint: c.description
|
|
4233
|
-
};
|
|
4234
|
-
}),
|
|
4235
|
-
initialValue: params.default
|
|
4236
|
-
}).then(throwOnCancel);
|
|
4237
|
-
}
|
|
4238
|
-
};
|
|
4239
|
-
};
|
|
4240
|
-
const promptsPrompter = (prompts) => {
|
|
4241
|
-
const p = prompts;
|
|
4242
|
-
function x() {
|
|
4243
|
-
return (value) => value.x;
|
|
4244
|
-
}
|
|
4245
|
-
return {
|
|
4246
|
-
input: async (params) => {
|
|
4247
|
-
return p({
|
|
4248
|
-
name: "x",
|
|
4249
|
-
type: "text",
|
|
4250
|
-
message: params.message,
|
|
4251
|
-
validate: params.validate,
|
|
4252
|
-
initial: params.default
|
|
4253
|
-
}).then(x());
|
|
4254
|
-
},
|
|
4255
|
-
confirm: async (params) => {
|
|
4256
|
-
return p({
|
|
4257
|
-
name: "x",
|
|
4258
|
-
type: "confirm",
|
|
4259
|
-
message: params.message,
|
|
4260
|
-
active: params.default ? "yes" : "no"
|
|
4261
|
-
}).then(x());
|
|
4262
|
-
},
|
|
4263
|
-
select: async (params) => {
|
|
4264
|
-
const choicesObjects = params.choices.map(
|
|
4265
|
-
(c) => typeof c === "string" ? { name: c, value: c } : c
|
|
4266
|
-
);
|
|
4267
|
-
return p({
|
|
4268
|
-
name: "x",
|
|
4269
|
-
type: "select",
|
|
4270
|
-
message: params.message,
|
|
4271
|
-
active: params.default,
|
|
4272
|
-
choices: choicesObjects.map((c) => ({
|
|
4273
|
-
title: c.name || c.value,
|
|
4274
|
-
value: c.value
|
|
4275
|
-
})),
|
|
4276
|
-
initial: params.default ? choicesObjects.findIndex((c) => c.value === params.default) : void 0
|
|
4277
|
-
}).then(x());
|
|
4278
|
-
},
|
|
4279
|
-
checkbox: async (params) => {
|
|
4280
|
-
const choicesObjects = params.choices.map(
|
|
4281
|
-
(c) => typeof c === "string" ? { name: c, value: c } : c
|
|
4282
|
-
);
|
|
4283
|
-
return p({
|
|
4284
|
-
name: "x",
|
|
4285
|
-
type: "multiselect",
|
|
4286
|
-
message: params.message,
|
|
4287
|
-
choices: choicesObjects.map((c) => ({
|
|
4288
|
-
title: c.name || c.value,
|
|
4289
|
-
value: c.value,
|
|
4290
|
-
selected: c.checked
|
|
4291
|
-
}))
|
|
4292
|
-
}).then(x());
|
|
4293
|
-
}
|
|
4294
|
-
};
|
|
4295
|
-
};
|
|
4296
|
-
const enquirerPrompter = (prompts) => {
|
|
4297
|
-
const enquirer = prompts;
|
|
4298
|
-
function x() {
|
|
4299
|
-
return (value) => value.x;
|
|
4300
|
-
}
|
|
4301
|
-
return {
|
|
4302
|
-
input: async (params) => {
|
|
4303
|
-
return enquirer.prompt({
|
|
4304
|
-
type: "input",
|
|
4305
|
-
name: "x",
|
|
4306
|
-
message: params.message,
|
|
4307
|
-
validate: params.validate,
|
|
4308
|
-
initial: params.default
|
|
4309
|
-
}).then(x());
|
|
4310
|
-
},
|
|
4311
|
-
confirm: async (params) => {
|
|
4312
|
-
return enquirer.prompt({
|
|
4313
|
-
type: "confirm",
|
|
4314
|
-
name: "x",
|
|
4315
|
-
message: params.message,
|
|
4316
|
-
validate: params.validate,
|
|
4317
|
-
initial: params.default
|
|
4318
|
-
}).then(x());
|
|
4319
|
-
},
|
|
4320
|
-
select: async (params) => {
|
|
4321
|
-
return enquirer.prompt({
|
|
4322
|
-
type: "select",
|
|
4323
|
-
name: "x",
|
|
4324
|
-
message: params.message,
|
|
4325
|
-
// @ts-expect-error not sure why this is an error, in the IDE it infers the type correctly
|
|
4326
|
-
choices: params.choices.slice(),
|
|
4327
|
-
validate: params.validate,
|
|
4328
|
-
initial: params.default
|
|
4329
|
-
}).then(x());
|
|
4330
|
-
},
|
|
4331
|
-
checkbox: async (params) => {
|
|
4332
|
-
return enquirer.prompt({
|
|
4333
|
-
type: "multiselect",
|
|
4334
|
-
name: "x",
|
|
4335
|
-
message: params.message,
|
|
4336
|
-
// @ts-expect-error not sure why this is an error, in the IDE it infers the type correctly
|
|
4337
|
-
choices: params.choices.slice().map((c) => ({
|
|
4338
|
-
name: c.name,
|
|
4339
|
-
value: c.value
|
|
4340
|
-
})),
|
|
4341
|
-
// validate: params.validate ? v => params.validate!([{value: v}]) : undefined,
|
|
4342
|
-
initial: params.choices.flatMap((c, i) => c.checked ? [i] : [])
|
|
4343
|
-
}).then(x());
|
|
4344
|
-
}
|
|
4345
|
-
};
|
|
4346
|
-
};
|
|
4347
|
-
const promptify = (program, prompts) => {
|
|
4348
|
-
let promptsInput = prompts;
|
|
4349
|
-
if (promptsInput?.default) promptsInput = promptsInput.default;
|
|
4350
|
-
let prompter;
|
|
4351
|
-
if (typeof promptsInput === "function" && typeof promptsInput.inject === "function") {
|
|
4352
|
-
prompter = promptsPrompter(promptsInput);
|
|
4353
|
-
} else if (promptsInput?.name === "Enquirer") {
|
|
4354
|
-
prompter = enquirerPrompter(promptsInput);
|
|
4355
|
-
} else if (typeof promptsInput?.rawlist === "function") {
|
|
4356
|
-
prompter = inquirerPrompter(promptsInput);
|
|
4357
|
-
} else if (typeof promptsInput?.intro === "function") {
|
|
4358
|
-
prompter = clackPrompter(promptsInput);
|
|
4359
|
-
} else if (typeof promptsInput === "function") {
|
|
4360
|
-
prompter = promptsInput(program);
|
|
4361
|
-
} else {
|
|
4362
|
-
prompter = promptsInput;
|
|
4363
|
-
}
|
|
4364
|
-
const command = program;
|
|
4365
|
-
const analyseThenParse = async (argv, parseOptions) => {
|
|
4366
|
-
if (parseOptions?.from === "electron") {
|
|
4367
|
-
console.warn(
|
|
4368
|
-
`Warning: using prompts in electron mode is untested. The first two args of $0 are not available in electron mode. Assuming that the first two args of ${JSON.stringify(argv)} are electron-related and not intended for the CLI.`
|
|
4369
|
-
);
|
|
4370
|
-
}
|
|
4371
|
-
if (parseOptions?.from !== "user") {
|
|
4372
|
-
argv = argv.slice(2);
|
|
4373
|
-
parseOptions = { from: "user" };
|
|
4374
|
-
}
|
|
4375
|
-
const f = { command, args: [...argv] };
|
|
4376
|
-
const nextArgv = [...f.args];
|
|
4377
|
-
let analysis;
|
|
4378
|
-
const maxAttempts = 100;
|
|
4379
|
-
for (let i = maxAttempts; i >= 0 && !analysis; i--) {
|
|
4380
|
-
analysis = await new Promise((resolve, reject) => {
|
|
4381
|
-
const shadow = createShadowCommand(f.command, async (an) => {
|
|
4382
|
-
if (an.command.original.commands.length === 0) {
|
|
4383
|
-
resolve(an);
|
|
4384
|
-
return;
|
|
4385
|
-
}
|
|
4386
|
-
const defaultSubcommand = getDefaultSubcommand(an.command.original);
|
|
4387
|
-
if (defaultSubcommand) {
|
|
4388
|
-
resolve(an);
|
|
4389
|
-
return;
|
|
4390
|
-
}
|
|
4391
|
-
const name = await prompter.select(
|
|
4392
|
-
{
|
|
4393
|
-
message: `Select a ${an.command.original.name() || ""} subcommand`.replace(" ", " "),
|
|
4394
|
-
choices: an.command.original.commands.map((c) => ({
|
|
4395
|
-
name: c.name(),
|
|
4396
|
-
value: c.name(),
|
|
4397
|
-
description: c.description()
|
|
4398
|
-
}))
|
|
4399
|
-
},
|
|
4400
|
-
{}
|
|
4401
|
-
);
|
|
4402
|
-
nextArgv.push(name);
|
|
4403
|
-
resolve(void 0);
|
|
4404
|
-
});
|
|
4405
|
-
shadow.parseAsync(nextArgv, parseOptions).catch((e) => {
|
|
4406
|
-
if (e?.constructor?.name === "CommanderError") {
|
|
4407
|
-
resolve({
|
|
4408
|
-
command: { shadow: f.command, original: f.command },
|
|
4409
|
-
arguments: [],
|
|
4410
|
-
options: []
|
|
4411
|
-
});
|
|
4412
|
-
} else {
|
|
4413
|
-
reject(e);
|
|
4414
|
-
}
|
|
4415
|
-
});
|
|
4416
|
-
});
|
|
4417
|
-
}
|
|
4418
|
-
if (!analysis) {
|
|
4419
|
-
const message = `Failed to find a subcommand after ${maxAttempts} attempts - failing to avoid an infinite loop. This is probably a bug in @reliverse/rempts.`;
|
|
4420
|
-
throw new Error(message);
|
|
4421
|
-
}
|
|
4422
|
-
const getMessage = (argOrOpt) => {
|
|
4423
|
-
const name = "long" in argOrOpt ? argOrOpt.flags : `[${argOrOpt.name()}]`;
|
|
4424
|
-
const parts = [
|
|
4425
|
-
name,
|
|
4426
|
-
argOrOpt.description,
|
|
4427
|
-
argOrOpt.defaultValue && `(default: ${argOrOpt.defaultValue})`,
|
|
4428
|
-
!argOrOpt.defaultValue && !argOrOpt.required && "(optional)"
|
|
4429
|
-
];
|
|
4430
|
-
return `${parts.filter(Boolean).join(" ").trim()}:`;
|
|
4431
|
-
};
|
|
4432
|
-
const baseContext = {
|
|
4433
|
-
command: analysis.command.original,
|
|
4434
|
-
inputs: {
|
|
4435
|
-
argv,
|
|
4436
|
-
arguments: analysis.arguments.map((a) => ({
|
|
4437
|
-
name: a.original.name(),
|
|
4438
|
-
specified: a.specified,
|
|
4439
|
-
value: a.value
|
|
4440
|
-
})),
|
|
4441
|
-
options: analysis.options.map((o) => ({
|
|
4442
|
-
name: o.original.name(),
|
|
4443
|
-
specified: o.specified,
|
|
4444
|
-
value: o.value
|
|
4445
|
-
}))
|
|
4446
|
-
}
|
|
4447
|
-
};
|
|
4448
|
-
await prompter.setup?.(baseContext);
|
|
4449
|
-
let shouldPrompt;
|
|
4450
|
-
{
|
|
4451
|
-
const someRequiredArgsUnspecified = analysis.arguments.some(
|
|
4452
|
-
(a) => a.original.required && !a.specified
|
|
4453
|
-
);
|
|
4454
|
-
const someRequiredOptionsUnspecified = analysis.options.some(
|
|
4455
|
-
(o) => o.original.required && !o.specified
|
|
4456
|
-
);
|
|
4457
|
-
shouldPrompt = someRequiredArgsUnspecified || someRequiredOptionsUnspecified;
|
|
4458
|
-
}
|
|
4459
|
-
if (shouldPrompt) {
|
|
4460
|
-
for (const arg of analysis.arguments) {
|
|
4461
|
-
const ctx = { ...baseContext, argument: arg.original };
|
|
4462
|
-
if (!arg.specified) {
|
|
4463
|
-
const parseArg = "parseArg" in arg.original && typeof arg.original.parseArg === "function" ? arg.original.parseArg : void 0;
|
|
4464
|
-
const promptedValue = await prompter.input(
|
|
4465
|
-
{
|
|
4466
|
-
message: getMessage(arg.original),
|
|
4467
|
-
required: arg.original.required,
|
|
4468
|
-
default: arg.value,
|
|
4469
|
-
validate: (input) => {
|
|
4470
|
-
try {
|
|
4471
|
-
parseArg?.(input);
|
|
4472
|
-
return true;
|
|
4473
|
-
} catch (e) {
|
|
4474
|
-
return e?.message || e;
|
|
4475
|
-
}
|
|
4476
|
-
}
|
|
4477
|
-
},
|
|
4478
|
-
ctx
|
|
4479
|
-
);
|
|
4480
|
-
nextArgv.push(promptedValue);
|
|
4481
|
-
}
|
|
4482
|
-
}
|
|
4483
|
-
for (const option of analysis.options) {
|
|
4484
|
-
const ctx = { ...baseContext, option: option.original };
|
|
4485
|
-
if (!option.specified) {
|
|
4486
|
-
const fullFlag = option.original.long || `--${option.original.name()}`;
|
|
4487
|
-
const isBoolean = option.original.isBoolean() || option.original.flags.includes("[boolean]");
|
|
4488
|
-
if (isBoolean) {
|
|
4489
|
-
const promptedValue = await prompter.confirm(
|
|
4490
|
-
{
|
|
4491
|
-
message: getMessage(option.original),
|
|
4492
|
-
default: option.original.defaultValue ?? false
|
|
4493
|
-
},
|
|
4494
|
-
ctx
|
|
4495
|
-
);
|
|
4496
|
-
if (promptedValue) nextArgv.push(fullFlag);
|
|
4497
|
-
} else if (option.original.variadic && option.original.argChoices) {
|
|
4498
|
-
const choices = option.original.argChoices.slice();
|
|
4499
|
-
const results = await prompter.checkbox(
|
|
4500
|
-
{
|
|
4501
|
-
message: getMessage(option.original),
|
|
4502
|
-
choices: choices.map((choice) => ({
|
|
4503
|
-
value: choice,
|
|
4504
|
-
name: choice,
|
|
4505
|
-
checked: true
|
|
4506
|
-
}))
|
|
4507
|
-
},
|
|
4508
|
-
ctx
|
|
4509
|
-
);
|
|
4510
|
-
results.forEach((result) => {
|
|
4511
|
-
if (typeof result === "string") nextArgv.push(fullFlag, result);
|
|
4512
|
-
});
|
|
4513
|
-
} else if (option.original.argChoices) {
|
|
4514
|
-
const choices = option.original.argChoices.slice();
|
|
4515
|
-
const set = new Set(choices);
|
|
4516
|
-
const promptedValue = await prompter.select(
|
|
4517
|
-
{
|
|
4518
|
-
message: getMessage(option.original),
|
|
4519
|
-
choices,
|
|
4520
|
-
default: option.original.defaultValue
|
|
4521
|
-
// required: option.original.required,
|
|
4522
|
-
},
|
|
4523
|
-
ctx
|
|
4524
|
-
);
|
|
4525
|
-
if (set.has(promptedValue)) {
|
|
4526
|
-
nextArgv.push(fullFlag, promptedValue);
|
|
4527
|
-
}
|
|
4528
|
-
} else if (option.original.variadic) {
|
|
4529
|
-
const values = [];
|
|
4530
|
-
do {
|
|
4531
|
-
const promptedValue = await prompter.input(
|
|
4532
|
-
{
|
|
4533
|
-
message: getMessage(option.original),
|
|
4534
|
-
default: option.original.defaultValue?.[values.length]
|
|
4535
|
-
},
|
|
4536
|
-
ctx
|
|
4537
|
-
);
|
|
4538
|
-
if (!promptedValue) break;
|
|
4539
|
-
values.push(fullFlag, promptedValue);
|
|
4540
|
-
} while (values);
|
|
4541
|
-
nextArgv.push(...values);
|
|
4542
|
-
} else {
|
|
4543
|
-
const getParsedValue = (input) => {
|
|
4544
|
-
return option.original.parseArg ? option.original.parseArg(input, void 0) : input;
|
|
4545
|
-
};
|
|
4546
|
-
const promptedValue = await prompter.input(
|
|
4547
|
-
{
|
|
4548
|
-
message: getMessage(option.original),
|
|
4549
|
-
default: option.value,
|
|
4550
|
-
required: option.original.required,
|
|
4551
|
-
validate: (input) => {
|
|
4552
|
-
const parsed = getParsedValue(input);
|
|
4553
|
-
if (parsed == null && input != null) return "Invalid value";
|
|
4554
|
-
return true;
|
|
4555
|
-
}
|
|
4556
|
-
},
|
|
4557
|
-
ctx
|
|
4558
|
-
);
|
|
4559
|
-
if (promptedValue)
|
|
4560
|
-
nextArgv.push(fullFlag, getParsedValue(promptedValue) ?? promptedValue);
|
|
4561
|
-
}
|
|
4562
|
-
}
|
|
4563
|
-
}
|
|
4564
|
-
}
|
|
4565
|
-
await prompter.teardown?.(baseContext);
|
|
4566
|
-
return f.command.parseAsync(nextArgv, parseOptions);
|
|
4567
|
-
};
|
|
4568
|
-
const parseAsync = (args, parseOptions) => analyseThenParse(args, parseOptions).catch((e) => {
|
|
4569
|
-
if (e?.constructor?.name === "ExitPromptError") return;
|
|
4570
|
-
throw e;
|
|
4571
|
-
});
|
|
4572
|
-
return new Proxy(program, {
|
|
4573
|
-
get(target, prop, receiver) {
|
|
4574
|
-
if (prop === "parseAsync") return parseAsync;
|
|
4575
|
-
return Reflect.get(target, prop, receiver);
|
|
4576
|
-
}
|
|
4577
|
-
});
|
|
4578
|
-
};
|
|
4579
|
-
|
|
4580
|
-
const looksLikeStandardSchemaFailure = (error) => {
|
|
4581
|
-
return !!error && typeof error === "object" && "issues" in error && Array.isArray(error.issues);
|
|
4582
|
-
};
|
|
4583
|
-
const looksLikeStandardSchema = (thing) => {
|
|
4584
|
-
return !!thing && typeof thing === "object" && "~standard" in thing && typeof thing["~standard"] === "object";
|
|
4585
|
-
};
|
|
4586
|
-
|
|
4587
|
-
const prettifyStandardSchemaError = (error) => {
|
|
4588
|
-
if (!looksLikeStandardSchemaFailure(error)) return null;
|
|
4589
|
-
const issues = [...error.issues].map((issue) => {
|
|
4590
|
-
const path = issue.path || [];
|
|
4591
|
-
const primitivePathSegments = path.map((segment) => {
|
|
4592
|
-
if (typeof segment === "string" || typeof segment === "number" || typeof segment === "symbol")
|
|
4593
|
-
return segment;
|
|
4594
|
-
return segment.key;
|
|
4595
|
-
});
|
|
4596
|
-
const dotPath = toDotPath(primitivePathSegments);
|
|
4597
|
-
return {
|
|
4598
|
-
issue,
|
|
4599
|
-
path,
|
|
4600
|
-
primitivePathSegments,
|
|
4601
|
-
dotPath
|
|
4602
|
-
};
|
|
4603
|
-
}).sort((a, b) => a.path.length - b.path.length);
|
|
4604
|
-
const lines = [];
|
|
4605
|
-
for (const { issue, dotPath } of issues) {
|
|
4606
|
-
let message = `\u2716 ${issue.message}`;
|
|
4607
|
-
if (dotPath) message += ` \u2192 at ${dotPath}`;
|
|
4608
|
-
lines.push(message);
|
|
4609
|
-
}
|
|
4610
|
-
return lines.join("\n");
|
|
4611
|
-
};
|
|
4612
|
-
function toDotPath(path) {
|
|
4613
|
-
const segs = [];
|
|
4614
|
-
for (const seg of path) {
|
|
4615
|
-
if (typeof seg === "number") segs.push(`[${seg}]`);
|
|
4616
|
-
else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
|
|
4617
|
-
else if (/[^\w$]/.test(seg)) segs.push(`[${JSON.stringify(seg)}]`);
|
|
4618
|
-
else {
|
|
4619
|
-
if (segs.length) segs.push(".");
|
|
4620
|
-
segs.push(seg);
|
|
4621
|
-
}
|
|
4622
|
-
}
|
|
4623
|
-
return segs.join("");
|
|
4624
|
-
}
|
|
4625
|
-
class StandardSchemaV1Error extends Error {
|
|
4626
|
-
issues;
|
|
4627
|
-
constructor(failure, options) {
|
|
4628
|
-
super("Standard Schema error - details in `issues`.", options);
|
|
4629
|
-
this.issues = failure.issues;
|
|
4630
|
-
}
|
|
4631
|
-
}
|
|
4632
|
-
|
|
4633
|
-
const isTrpc11Procedure = (procedure) => {
|
|
4634
|
-
return "type" in procedure._def && typeof procedure._def.type === "string";
|
|
4635
|
-
};
|
|
4636
|
-
const isTrpc11Router = (router) => {
|
|
4637
|
-
if (isOrpcRouter(router)) return false;
|
|
4638
|
-
const procedure = Object.values(router._def.procedures)[0];
|
|
4639
|
-
return Boolean(procedure && isTrpc11Procedure(procedure));
|
|
4640
|
-
};
|
|
4641
|
-
const isOrpcRouter = (router) => {
|
|
4642
|
-
return !("_def" in router) || router._def && "~orpc" in router._def;
|
|
4643
|
-
};
|
|
4644
|
-
|
|
4645
|
-
const looksLikeInstanceof = (value, target) => {
|
|
4646
|
-
let current = value?.constructor;
|
|
4647
|
-
while (current?.name) {
|
|
4648
|
-
if (current?.name === (typeof target === "string" ? target : target.name)) return true;
|
|
4649
|
-
current = Object.getPrototypeOf(current);
|
|
4650
|
-
}
|
|
4651
|
-
return false;
|
|
4652
|
-
};
|
|
4653
|
-
|
|
4654
|
-
class TrpcCommand extends Command {
|
|
4655
|
-
/** @internal track the commands that have been run, so that we can find the `__result` of the last command */
|
|
4656
|
-
__ran = [];
|
|
4657
|
-
__input;
|
|
4658
|
-
/** @internal stash the return value of the underlying procedure on the command so to pass to `FailedToExitError` for use in a pinch */
|
|
4659
|
-
__result;
|
|
4660
|
-
}
|
|
4661
|
-
const parseRouter = ({ router, ...params }) => {
|
|
4662
|
-
if (isOrpcRouter(router)) return parseOrpcRouter({ router, ...params });
|
|
4663
|
-
return parseTrpcRouter({ router, ...params });
|
|
4664
|
-
};
|
|
4665
|
-
const parseTrpcRouter = ({
|
|
4666
|
-
router,
|
|
4667
|
-
...params
|
|
4668
|
-
}) => {
|
|
4669
|
-
const defEntries = Object.entries(router._def.procedures);
|
|
4670
|
-
return defEntries.map(([procedurePath, procedure]) => {
|
|
4671
|
-
const meta = getMeta(procedure);
|
|
4672
|
-
if (meta.jsonInput) {
|
|
4673
|
-
return [
|
|
4674
|
-
procedurePath,
|
|
4675
|
-
{
|
|
4676
|
-
meta,
|
|
4677
|
-
parsedProcedure: jsonProcedureInputs(),
|
|
4678
|
-
incompatiblePairs: [],
|
|
4679
|
-
procedure
|
|
4680
|
-
}
|
|
4681
|
-
];
|
|
4682
|
-
}
|
|
4683
|
-
const procedureInputsResult = parseProcedureInputs(procedure._def.inputs, params);
|
|
4684
|
-
if (!procedureInputsResult.success) {
|
|
4685
|
-
const procedureInputs2 = jsonProcedureInputs(
|
|
4686
|
-
`procedure's schema couldn't be converted to CLI arguments: ${procedureInputsResult.error}`
|
|
4687
|
-
);
|
|
4688
|
-
return [
|
|
4689
|
-
procedurePath,
|
|
4690
|
-
{
|
|
4691
|
-
meta,
|
|
4692
|
-
parsedProcedure: procedureInputs2,
|
|
4693
|
-
incompatiblePairs: [],
|
|
4694
|
-
procedure
|
|
4695
|
-
}
|
|
4696
|
-
];
|
|
4697
|
-
}
|
|
4698
|
-
const procedureInputs = procedureInputsResult.value;
|
|
4699
|
-
const incompatiblePairs = incompatiblePropertyPairs(procedureInputs.optionsJsonSchema);
|
|
4700
|
-
return [
|
|
4701
|
-
procedurePath,
|
|
4702
|
-
{
|
|
4703
|
-
meta: getMeta(procedure),
|
|
4704
|
-
parsedProcedure: procedureInputs,
|
|
4705
|
-
incompatiblePairs,
|
|
4706
|
-
procedure
|
|
4707
|
-
}
|
|
4708
|
-
];
|
|
4709
|
-
});
|
|
4710
|
-
};
|
|
4711
|
-
const parseOrpcRouter = (params) => {
|
|
4712
|
-
const entries = [];
|
|
4713
|
-
const { traverseContractProcedures, isProcedure } = (() => {
|
|
4714
|
-
try {
|
|
4715
|
-
return require("@orpc/server");
|
|
4716
|
-
} catch (e) {
|
|
4717
|
-
throw new Error(
|
|
4718
|
-
"@orpc/server dependency could not be found - try installing it and re-running",
|
|
4719
|
-
{ cause: e }
|
|
4720
|
-
);
|
|
4721
|
-
}
|
|
4722
|
-
})();
|
|
4723
|
-
const router = params.router;
|
|
4724
|
-
const lazyRoutes = traverseContractProcedures({ path: [], router }, ({ contract, path }) => {
|
|
4725
|
-
let procedure = params.router;
|
|
4726
|
-
for (const p of path) procedure = procedure[p];
|
|
4727
|
-
if (!isProcedure(procedure)) return;
|
|
4728
|
-
const procedureInputsResult = parseProcedureInputs([contract["~orpc"].inputSchema], {
|
|
4729
|
-
"@valibot/to-json-schema": params["@valibot/to-json-schema"],
|
|
4730
|
-
effect: params.effect
|
|
4731
|
-
});
|
|
4732
|
-
const procedurePath = path.join(".");
|
|
4733
|
-
const procedureish = {
|
|
4734
|
-
_def: { meta: contract["~orpc"].meta }
|
|
4735
|
-
};
|
|
4736
|
-
const meta = getMeta(procedureish);
|
|
4737
|
-
if (meta.jsonInput) {
|
|
4738
|
-
entries.push([
|
|
4739
|
-
procedurePath,
|
|
4740
|
-
{
|
|
4741
|
-
meta,
|
|
4742
|
-
parsedProcedure: jsonProcedureInputs(),
|
|
4743
|
-
incompatiblePairs: [],
|
|
4744
|
-
procedure
|
|
4745
|
-
}
|
|
4746
|
-
]);
|
|
4747
|
-
return;
|
|
4748
|
-
}
|
|
4749
|
-
if (!procedureInputsResult.success) {
|
|
4750
|
-
const parsedProcedure2 = jsonProcedureInputs(
|
|
4751
|
-
`procedure's schema couldn't be converted to CLI arguments: ${procedureInputsResult.error}`
|
|
4752
|
-
);
|
|
4753
|
-
entries.push([
|
|
4754
|
-
procedurePath,
|
|
4755
|
-
{
|
|
4756
|
-
meta,
|
|
4757
|
-
parsedProcedure: parsedProcedure2,
|
|
4758
|
-
incompatiblePairs: [],
|
|
4759
|
-
procedure
|
|
4760
|
-
}
|
|
4761
|
-
]);
|
|
4762
|
-
return;
|
|
4763
|
-
}
|
|
4764
|
-
const parsedProcedure = procedureInputsResult.value;
|
|
4765
|
-
const incompatiblePairs = incompatiblePropertyPairs(parsedProcedure.optionsJsonSchema);
|
|
4766
|
-
entries.push([procedurePath, { procedure, meta, incompatiblePairs, parsedProcedure }]);
|
|
4767
|
-
});
|
|
4768
|
-
if (lazyRoutes.length) {
|
|
4769
|
-
const suggestion = `Please use \`import {unlazyRouter} from '@orpc/server'\` to unlazy the router before passing it to @reliverse/rempts`;
|
|
4770
|
-
const routes = lazyRoutes.map(({ path }) => path.join(".")).join(", ");
|
|
4771
|
-
throw new Error(
|
|
4772
|
-
`Lazy routers are not supported. ${suggestion}. Lazy routes detected: ${routes}`
|
|
4773
|
-
);
|
|
4774
|
-
}
|
|
4775
|
-
return entries;
|
|
4776
|
-
};
|
|
4777
|
-
const jsonProcedureInputs = (reason) => {
|
|
4778
|
-
let description = "Input formatted as JSON";
|
|
4779
|
-
if (reason) description += ` (${reason})`;
|
|
4780
|
-
return {
|
|
4781
|
-
positionalParameters: [],
|
|
4782
|
-
optionsJsonSchema: {
|
|
4783
|
-
type: "object",
|
|
4784
|
-
properties: {
|
|
4785
|
-
input: { type: "json", description }
|
|
4786
|
-
}
|
|
4787
|
-
},
|
|
4788
|
-
getPojoInput: (parsedCliParams) => {
|
|
4789
|
-
if (parsedCliParams.options.input == null) return parsedCliParams.options.input;
|
|
4790
|
-
return JSON.parse(parsedCliParams.options.input);
|
|
4791
|
-
}
|
|
4792
|
-
};
|
|
4793
|
-
};
|
|
4794
|
-
function createRpcCli({
|
|
4795
|
-
router,
|
|
4796
|
-
...params
|
|
4797
|
-
}) {
|
|
4798
|
-
const procedureEntries = parseRouter({ router, ...params });
|
|
4799
|
-
function buildProgram(runParams) {
|
|
4800
|
-
const logger = { ...lineByLineConsoleLogger, ...runParams?.logger };
|
|
4801
|
-
const program = new TrpcCommand(params.name);
|
|
4802
|
-
if (params.version) program.version(params.version);
|
|
4803
|
-
if (params.description) program.description(params.description);
|
|
4804
|
-
if (params.usage) [params.usage].flat().forEach((usage) => program.usage(usage));
|
|
4805
|
-
program.showHelpAfterError();
|
|
4806
|
-
program.showSuggestionAfterError();
|
|
4807
|
-
const commandTree = {
|
|
4808
|
-
"": program
|
|
4809
|
-
// Root level
|
|
4810
|
-
};
|
|
4811
|
-
const defaultCommands = {};
|
|
4812
|
-
const _process = runParams?.process || process;
|
|
4813
|
-
const configureCommand = (command, procedurePath, { meta, parsedProcedure, incompatiblePairs, procedure }) => {
|
|
4814
|
-
const optionJsonSchemaProperties = flattenedProperties(parsedProcedure.optionsJsonSchema);
|
|
4815
|
-
command.exitOverride((ec) => {
|
|
4816
|
-
_process.exit(ec.exitCode);
|
|
4817
|
-
throw new FailedToExitError(`Command ${command.name()} exitOverride`, {
|
|
4818
|
-
exitCode: ec.exitCode,
|
|
4819
|
-
cause: ec
|
|
4820
|
-
});
|
|
4821
|
-
});
|
|
4822
|
-
command.configureOutput({
|
|
4823
|
-
writeOut: (str) => {
|
|
4824
|
-
logger.info?.(str);
|
|
4825
|
-
},
|
|
4826
|
-
writeErr: (str) => {
|
|
4827
|
-
logger.error?.(str);
|
|
4828
|
-
}
|
|
4829
|
-
});
|
|
4830
|
-
command.showHelpAfterError();
|
|
4831
|
-
if (meta.usage) command.usage([meta.usage].flat().join("\n"));
|
|
4832
|
-
if (meta.examples)
|
|
4833
|
-
command.addHelpText("after", `
|
|
4834
|
-
Examples:
|
|
4835
|
-
${[meta.examples].flat().join("\n")}`);
|
|
4836
|
-
meta?.aliases?.command?.forEach((alias) => {
|
|
4837
|
-
command.alias(alias);
|
|
4838
|
-
});
|
|
4839
|
-
command.description(meta?.description || "");
|
|
4840
|
-
parsedProcedure.positionalParameters.forEach((param) => {
|
|
4841
|
-
const descriptionParts = [
|
|
4842
|
-
param.type === "string" ? "" : param.type,
|
|
4843
|
-
// "string" is the default assumption, don't bother showing it
|
|
4844
|
-
param.description,
|
|
4845
|
-
param.required ? "(required)" : ""
|
|
4846
|
-
];
|
|
4847
|
-
const argument = new Argument(param.name, descriptionParts.filter(Boolean).join(" "));
|
|
4848
|
-
if (param.type === "number") {
|
|
4849
|
-
argument.argParser((value) => {
|
|
4850
|
-
const number = numberParser(value, { fallback: null });
|
|
4851
|
-
if (number == null) throw new InvalidArgumentError(`Invalid number: ${value}`);
|
|
4852
|
-
return value;
|
|
4853
|
-
});
|
|
4854
|
-
}
|
|
4855
|
-
argument.required = param.required;
|
|
4856
|
-
argument.variadic = param.array;
|
|
4857
|
-
command.addArgument(argument);
|
|
4858
|
-
});
|
|
4859
|
-
const unusedOptionAliases = {
|
|
4860
|
-
...meta.aliases?.options
|
|
4861
|
-
};
|
|
4862
|
-
const addOptionForProperty = ([propertyKey, propertyValue]) => {
|
|
4863
|
-
const description = getDescription(propertyValue);
|
|
4864
|
-
const longOption = `--${kebabCase(propertyKey)}`;
|
|
4865
|
-
let flags = longOption;
|
|
4866
|
-
const alias = meta.aliases?.options?.[propertyKey];
|
|
4867
|
-
if (alias) {
|
|
4868
|
-
let prefix = "-";
|
|
4869
|
-
if (alias.startsWith("-")) prefix = "";
|
|
4870
|
-
else if (alias.length > 1) prefix = "--";
|
|
4871
|
-
flags = `${prefix}${alias}, ${flags}`;
|
|
4872
|
-
delete unusedOptionAliases[propertyKey];
|
|
4873
|
-
}
|
|
4874
|
-
const defaultValue = "default" in propertyValue ? { exists: true, value: propertyValue.default } : { exists: false };
|
|
4875
|
-
const rootTypes = getSchemaTypes(propertyValue).sort();
|
|
4876
|
-
const getValueParser = (types) => {
|
|
4877
|
-
types = types.map((t) => t === "integer" ? "number" : t);
|
|
4878
|
-
if (types.length === 2 && types[0] === "boolean" && types[1] === "number") {
|
|
4879
|
-
return {
|
|
4880
|
-
type: "boolean|number",
|
|
4881
|
-
parser: (value) => booleanParser(value, { fallback: null }) ?? numberParser(value)
|
|
4882
|
-
};
|
|
4883
|
-
}
|
|
4884
|
-
if (types.length === 1 && types[0] === "boolean") {
|
|
4885
|
-
return {
|
|
4886
|
-
type: "boolean",
|
|
4887
|
-
parser: (value) => booleanParser(value)
|
|
4888
|
-
};
|
|
4889
|
-
}
|
|
4890
|
-
if (types.length === 1 && types[0] === "number") {
|
|
4891
|
-
return {
|
|
4892
|
-
type: "number",
|
|
4893
|
-
parser: (value) => numberParser(value)
|
|
4894
|
-
};
|
|
4895
|
-
}
|
|
4896
|
-
if (types.length === 1 && types[0] === "string") {
|
|
4897
|
-
return { type: "string", parser: null };
|
|
4898
|
-
}
|
|
4899
|
-
return {
|
|
4900
|
-
type: "json",
|
|
4901
|
-
parser: (value) => {
|
|
4902
|
-
let parsed;
|
|
4903
|
-
try {
|
|
4904
|
-
parsed = JSON.parse(value);
|
|
4905
|
-
} catch {
|
|
4906
|
-
throw new InvalidArgumentError("Malformed JSON.");
|
|
4907
|
-
}
|
|
4908
|
-
const jsonSchemaType = Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed;
|
|
4909
|
-
if (!types.includes(jsonSchemaType)) {
|
|
4910
|
-
throw new InvalidArgumentError(
|
|
4911
|
-
`Got ${jsonSchemaType} but expected ${types.join(" or ")}`
|
|
4912
|
-
);
|
|
4913
|
-
}
|
|
4914
|
-
return parsed;
|
|
4915
|
-
}
|
|
4916
|
-
};
|
|
4917
|
-
};
|
|
4918
|
-
const propertyType = rootTypes[0];
|
|
4919
|
-
const isValueRequired = "required" in parsedProcedure.optionsJsonSchema && parsedProcedure.optionsJsonSchema.required?.includes(propertyKey);
|
|
4920
|
-
const isCliOptionRequired = isValueRequired && propertyType !== "boolean" && !defaultValue.exists;
|
|
4921
|
-
function negate() {
|
|
4922
|
-
const negation = new Option(
|
|
4923
|
-
longOption.replace("--", "--no-"),
|
|
4924
|
-
`Negate \`${longOption}\` option.`.trim()
|
|
4925
|
-
);
|
|
4926
|
-
command.addOption(negation);
|
|
4927
|
-
}
|
|
4928
|
-
const bracketise = (name) => isCliOptionRequired ? `<${name}>` : `[${name}]`;
|
|
4929
|
-
if (rootTypes.length === 2 && rootTypes[0] === "boolean" && rootTypes[1] === "string") {
|
|
4930
|
-
const option2 = new Option(`${flags} [value]`, description);
|
|
4931
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
4932
|
-
command.addOption(option2);
|
|
4933
|
-
negate();
|
|
4934
|
-
return;
|
|
4935
|
-
}
|
|
4936
|
-
if (rootTypes.length === 2 && rootTypes[0] === "boolean" && rootTypes[1] === "number") {
|
|
4937
|
-
const option2 = new Option(`${flags} [value]`, description);
|
|
4938
|
-
option2.argParser(getValueParser(rootTypes).parser);
|
|
4939
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
4940
|
-
command.addOption(option2);
|
|
4941
|
-
negate();
|
|
4942
|
-
return;
|
|
4943
|
-
}
|
|
4944
|
-
if (rootTypes.length === 2 && rootTypes[0] === "number" && rootTypes[1] === "string") {
|
|
4945
|
-
const option2 = new Option(`${flags} ${bracketise("value")}`, description);
|
|
4946
|
-
option2.argParser((value) => {
|
|
4947
|
-
const number = numberParser(value, { fallback: null });
|
|
4948
|
-
return number ?? value;
|
|
4949
|
-
});
|
|
4950
|
-
if (defaultValue.exists) option2.default(defaultValue.value);
|
|
4951
|
-
command.addOption(option2);
|
|
4952
|
-
return;
|
|
4953
|
-
}
|
|
4954
|
-
if (rootTypes.length !== 1) {
|
|
4955
|
-
const option2 = new Option(
|
|
4956
|
-
`${flags} ${bracketise("json")}`,
|
|
4957
|
-
`${description} (value will be parsed as JSON)`
|
|
4958
|
-
);
|
|
4959
|
-
option2.argParser(getValueParser(rootTypes).parser);
|
|
4960
|
-
command.addOption(option2);
|
|
4961
|
-
return;
|
|
4962
|
-
}
|
|
4963
|
-
if (propertyType === "boolean" && isValueRequired) {
|
|
4964
|
-
const option2 = new Option(flags, description);
|
|
4965
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
4966
|
-
command.addOption(option2);
|
|
4967
|
-
negate();
|
|
4968
|
-
return;
|
|
4969
|
-
}
|
|
4970
|
-
if (propertyType === "boolean") {
|
|
4971
|
-
const option2 = new Option(`${flags} [boolean]`, description);
|
|
4972
|
-
option2.argParser((value) => booleanParser(value));
|
|
4973
|
-
if (defaultValue.exists) option2.default(defaultValue.value);
|
|
4974
|
-
command.addOption(option2);
|
|
4975
|
-
negate();
|
|
4976
|
-
return;
|
|
4977
|
-
}
|
|
4978
|
-
let option;
|
|
4979
|
-
if (propertyType === "string") {
|
|
4980
|
-
option = new Option(`${flags} ${bracketise("string")}`, description);
|
|
4981
|
-
} else if (propertyType === "boolean") {
|
|
4982
|
-
option = new Option(flags, description);
|
|
4983
|
-
} else if (propertyType === "number" || propertyType === "integer") {
|
|
4984
|
-
option = new Option(`${flags} ${bracketise("number")}`, description);
|
|
4985
|
-
option.argParser((value) => numberParser(value, { fallback: null }));
|
|
4986
|
-
} else if (propertyType === "array") {
|
|
4987
|
-
option = new Option(`${flags} [values...]`, description);
|
|
4988
|
-
if (defaultValue.exists) option.default(defaultValue.value);
|
|
4989
|
-
else if (isValueRequired) option.default([]);
|
|
4990
|
-
const itemsProp = "items" in propertyValue ? propertyValue.items : null;
|
|
4991
|
-
const itemTypes = itemsProp ? getSchemaTypes(itemsProp) : [];
|
|
4992
|
-
const itemEnumTypes = itemsProp && getEnumChoices(itemsProp);
|
|
4993
|
-
if (itemEnumTypes?.type === "string_enum") {
|
|
4994
|
-
option.choices(itemEnumTypes.choices);
|
|
4995
|
-
}
|
|
4996
|
-
const itemParser = getValueParser(itemTypes);
|
|
4997
|
-
if (itemParser.parser) {
|
|
4998
|
-
option.argParser((value, previous) => {
|
|
4999
|
-
const parsed = itemParser.parser(value);
|
|
5000
|
-
if (Array.isArray(previous)) return [...previous, parsed];
|
|
5001
|
-
return [parsed];
|
|
5002
|
-
});
|
|
5003
|
-
}
|
|
5004
|
-
}
|
|
5005
|
-
option ||= new Option(`${flags} [json]`, description);
|
|
5006
|
-
if (defaultValue.exists && option.defaultValue !== defaultValue.value) {
|
|
5007
|
-
option.default(defaultValue.value);
|
|
5008
|
-
}
|
|
5009
|
-
if (option.flags.includes("<")) {
|
|
5010
|
-
option.makeOptionMandatory();
|
|
5011
|
-
}
|
|
5012
|
-
const enumChoices = getEnumChoices(propertyValue);
|
|
5013
|
-
if (enumChoices?.type === "string_enum") {
|
|
5014
|
-
option.choices(enumChoices.choices);
|
|
5015
|
-
}
|
|
5016
|
-
option.conflicts(
|
|
5017
|
-
incompatiblePairs.flatMap((pair) => {
|
|
5018
|
-
const filtered = pair.filter((p) => p !== propertyKey);
|
|
5019
|
-
if (filtered.length === pair.length) return [];
|
|
5020
|
-
return filtered;
|
|
5021
|
-
})
|
|
5022
|
-
);
|
|
5023
|
-
command.addOption(option);
|
|
5024
|
-
if (propertyType === "boolean") negate();
|
|
5025
|
-
};
|
|
5026
|
-
Object.entries(optionJsonSchemaProperties).forEach(addOptionForProperty);
|
|
5027
|
-
const invalidOptionAliases = Object.entries(unusedOptionAliases).map(
|
|
5028
|
-
([option, alias]) => `${option}: ${alias}`
|
|
5029
|
-
);
|
|
5030
|
-
if (invalidOptionAliases.length) {
|
|
5031
|
-
throw new Error(`Invalid option aliases: ${invalidOptionAliases.join(", ")}`);
|
|
5032
|
-
}
|
|
5033
|
-
command.action(async (...args) => {
|
|
5034
|
-
program.__ran ||= [];
|
|
5035
|
-
program.__ran.push(command);
|
|
5036
|
-
const options = command.opts();
|
|
5037
|
-
if (args.at(-2) !== options) {
|
|
5038
|
-
throw new Error("Unexpected args format, second last arg is not the options object", {
|
|
5039
|
-
cause: args
|
|
5040
|
-
});
|
|
5041
|
-
}
|
|
5042
|
-
if (args.at(-1) !== command) {
|
|
5043
|
-
throw new Error("Unexpected args format, last arg is not the Command instance", {
|
|
5044
|
-
cause: args
|
|
5045
|
-
});
|
|
5046
|
-
}
|
|
5047
|
-
const positionalValues = args.slice(0, -2);
|
|
5048
|
-
const input = parsedProcedure.getPojoInput({
|
|
5049
|
-
positionalValues,
|
|
5050
|
-
options
|
|
5051
|
-
});
|
|
5052
|
-
const resolvedTrpcServer = await (params.trpcServer || trpcServer11);
|
|
5053
|
-
let caller;
|
|
5054
|
-
const deprecatedCreateCaller = Reflect.get(params, "createCallerFactory");
|
|
5055
|
-
if (deprecatedCreateCaller) {
|
|
5056
|
-
const message = `Using deprecated \`createCallerFactory\` option. Use \`trpcServer\` instead. e.g. \`createRpcCli({router: myRouter, trpcServer: import('@trpc/server')})\``;
|
|
5057
|
-
logger.error?.(message);
|
|
5058
|
-
caller = deprecatedCreateCaller(router)(params.context);
|
|
5059
|
-
} else if (isOrpcRouter(router)) {
|
|
5060
|
-
const { call } = (() => {
|
|
5061
|
-
try {
|
|
5062
|
-
return require("@orpc/server");
|
|
5063
|
-
} catch (e) {
|
|
5064
|
-
throw new Error(
|
|
5065
|
-
"@orpc/server dependency could not be found - try installing it and re-running",
|
|
5066
|
-
{ cause: e }
|
|
5067
|
-
);
|
|
5068
|
-
}
|
|
5069
|
-
})();
|
|
5070
|
-
caller = {
|
|
5071
|
-
[procedurePath]: (_input) => call(procedure, _input, { context: params.context })
|
|
5072
|
-
};
|
|
5073
|
-
} else {
|
|
5074
|
-
const createCallerFactor = resolvedTrpcServer.initTRPC.create().createCallerFactory;
|
|
5075
|
-
caller = createCallerFactor(router)(params.context);
|
|
5076
|
-
}
|
|
5077
|
-
const result = await (caller[procedurePath]?.(input)).catch((err) => {
|
|
5078
|
-
throw transformError(err, command);
|
|
5079
|
-
});
|
|
5080
|
-
command.__result = result;
|
|
5081
|
-
if (result != null) logger.info?.(result);
|
|
5082
|
-
});
|
|
5083
|
-
};
|
|
5084
|
-
procedureEntries.forEach(([procedurePath, commandConfig]) => {
|
|
5085
|
-
const segments = procedurePath.split(".");
|
|
5086
|
-
let currentPath = "";
|
|
5087
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
5088
|
-
const segment = segments[i];
|
|
5089
|
-
if (!segment) continue;
|
|
5090
|
-
const parentPath2 = currentPath;
|
|
5091
|
-
currentPath = currentPath ? `${currentPath}.${segment}` : segment;
|
|
5092
|
-
if (!commandTree[currentPath]) {
|
|
5093
|
-
const parentCommand2 = commandTree[parentPath2];
|
|
5094
|
-
if (!parentCommand2) continue;
|
|
5095
|
-
const newCommand = new TrpcCommand(kebabCase(segment));
|
|
5096
|
-
newCommand.showHelpAfterError();
|
|
5097
|
-
parentCommand2.addCommand(newCommand);
|
|
5098
|
-
commandTree[currentPath] = newCommand;
|
|
5099
|
-
}
|
|
5100
|
-
}
|
|
5101
|
-
const leafName = segments.at(-1);
|
|
5102
|
-
if (!leafName) return;
|
|
5103
|
-
const parentPath = segments.length > 1 ? segments.slice(0, -1).join(".") : "";
|
|
5104
|
-
const parentCommand = commandTree[parentPath];
|
|
5105
|
-
if (!parentCommand) return;
|
|
5106
|
-
const leafCommand = new TrpcCommand(kebabCase(leafName));
|
|
5107
|
-
configureCommand(leafCommand, procedurePath, commandConfig);
|
|
5108
|
-
parentCommand.addCommand(leafCommand);
|
|
5109
|
-
const meta = commandConfig.meta;
|
|
5110
|
-
if (meta.default === true) {
|
|
5111
|
-
parentCommand.allowExcessArguments();
|
|
5112
|
-
parentCommand.allowUnknownOption();
|
|
5113
|
-
parentCommand.addHelpText("after", leafCommand.helpInformation());
|
|
5114
|
-
parentCommand.action(async () => {
|
|
5115
|
-
await leafCommand.parseAsync([...parentCommand.args], {
|
|
5116
|
-
from: "user"
|
|
5117
|
-
});
|
|
5118
|
-
});
|
|
5119
|
-
defaultCommands[parentPath] = {
|
|
5120
|
-
procedurePath,
|
|
5121
|
-
config: commandConfig,
|
|
5122
|
-
command: leafCommand
|
|
5123
|
-
};
|
|
5124
|
-
}
|
|
5125
|
-
});
|
|
5126
|
-
Object.entries(commandTree).forEach(([path, command]) => {
|
|
5127
|
-
if (command.commands.length === 0) return;
|
|
5128
|
-
const subcommandNames = command.commands.map((cmd) => cmd.name());
|
|
5129
|
-
const defaultCommand = defaultCommands[path]?.command.name();
|
|
5130
|
-
const formattedSubcommands = subcommandNames.map((name) => name === defaultCommand ? `${name} (default)` : name).join(", ");
|
|
5131
|
-
const existingDescription = command.description() || "";
|
|
5132
|
-
const descriptionParts = [
|
|
5133
|
-
existingDescription,
|
|
5134
|
-
`Available subcommands: ${formattedSubcommands}`
|
|
5135
|
-
];
|
|
5136
|
-
command.description(descriptionParts.filter(Boolean).join("\n"));
|
|
5137
|
-
});
|
|
5138
|
-
return program;
|
|
5139
|
-
}
|
|
5140
|
-
const run = async (runParams, program = buildProgram(runParams)) => {
|
|
5141
|
-
if (!looksLikeInstanceof(program, "TrpcCommand"))
|
|
5142
|
-
throw new Error("program is not a TrpcCommand instance");
|
|
5143
|
-
const opts = runParams?.argv ? { from: "user" } : void 0;
|
|
5144
|
-
const argv = [...runParams?.argv || process.argv];
|
|
5145
|
-
const _process = runParams?.process || process;
|
|
5146
|
-
const logger = { ...lineByLineConsoleLogger, ...runParams?.logger };
|
|
5147
|
-
program.exitOverride((exit) => {
|
|
5148
|
-
_process.exit(exit.exitCode);
|
|
5149
|
-
throw new FailedToExitError("Root command exitOverride", {
|
|
5150
|
-
exitCode: exit.exitCode,
|
|
5151
|
-
cause: exit
|
|
5152
|
-
});
|
|
5153
|
-
});
|
|
5154
|
-
program.configureOutput({
|
|
5155
|
-
writeOut: (str) => logger.info?.(str),
|
|
5156
|
-
writeErr: (str) => logger.error?.(str)
|
|
5157
|
-
});
|
|
5158
|
-
if (runParams?.completion) {
|
|
5159
|
-
const completion = typeof runParams.completion === "function" ? await runParams.completion() : runParams.completion;
|
|
5160
|
-
addCompletions(program, completion);
|
|
5161
|
-
}
|
|
5162
|
-
const formatError = runParams?.formatError || ((err) => {
|
|
5163
|
-
if (err instanceof CliValidationError) {
|
|
5164
|
-
return err.message;
|
|
5165
|
-
}
|
|
5166
|
-
return inspect(err);
|
|
5167
|
-
});
|
|
5168
|
-
if (runParams?.prompts) {
|
|
5169
|
-
program = promptify(program, runParams.prompts);
|
|
5170
|
-
}
|
|
5171
|
-
await program.parseAsync(argv, opts).catch((err) => {
|
|
5172
|
-
if (err instanceof FailedToExitError) throw err;
|
|
5173
|
-
const logMessage = looksLikeInstanceof(err, Error) ? formatError(err) || err.message : `Non-error of type ${typeof err} thrown: ${err}`;
|
|
5174
|
-
logger.error?.(logMessage);
|
|
5175
|
-
_process.exit(1);
|
|
5176
|
-
throw new FailedToExitError("Program exit after failure", {
|
|
5177
|
-
exitCode: 1,
|
|
5178
|
-
cause: err
|
|
5179
|
-
});
|
|
5180
|
-
});
|
|
5181
|
-
_process.exit(0);
|
|
5182
|
-
throw new FailedToExitError("Program exit after success", {
|
|
5183
|
-
exitCode: 0,
|
|
5184
|
-
cause: program.__ran.at(-1)?.__result
|
|
5185
|
-
});
|
|
5186
|
-
};
|
|
5187
|
-
return {
|
|
5188
|
-
run,
|
|
5189
|
-
buildProgram,
|
|
5190
|
-
toJSON: (program = buildProgram()) => commandToJSON(program)
|
|
5191
|
-
};
|
|
5192
|
-
}
|
|
5193
|
-
function getMeta(procedure) {
|
|
5194
|
-
const meta = procedure._def.meta;
|
|
5195
|
-
return meta?.cliMeta || meta || {};
|
|
5196
|
-
}
|
|
5197
|
-
function kebabCase(propName) {
|
|
5198
|
-
return propName.replaceAll(/([A-Z])/g, "-$1").toLowerCase();
|
|
5199
|
-
}
|
|
5200
|
-
function transformError(err, command) {
|
|
5201
|
-
if (looksLikeInstanceof(err, Error) && err.message.includes("This is a client-only function")) {
|
|
5202
|
-
return new Error(
|
|
5203
|
-
"Failed to create trpc caller. If using trpc v10, either upgrade to v11 or pass in the `@trpc/server` module to `createRpcCli` explicitly"
|
|
5204
|
-
);
|
|
5205
|
-
}
|
|
5206
|
-
if (looksLikeInstanceof(err, "TRPCError")) {
|
|
5207
|
-
const cause = err.cause;
|
|
5208
|
-
if (looksLikeStandardSchemaFailure(cause)) {
|
|
5209
|
-
const prettyMessage = prettifyStandardSchemaError(cause);
|
|
5210
|
-
return new CliValidationError(`${prettyMessage}
|
|
5211
|
-
|
|
5212
|
-
${command.helpInformation()}`);
|
|
5213
|
-
}
|
|
5214
|
-
if (err.code === "BAD_REQUEST" && (err.cause?.constructor?.name === "TraversalError" || // arktype error
|
|
5215
|
-
err.cause?.constructor?.name === "StandardSchemaV1Error")) {
|
|
5216
|
-
return new CliValidationError(`${err.cause.message}
|
|
5217
|
-
|
|
5218
|
-
${command.helpInformation()}`);
|
|
5219
|
-
}
|
|
5220
|
-
if (err.code === "INTERNAL_SERVER_ERROR") {
|
|
5221
|
-
return cause;
|
|
5222
|
-
}
|
|
5223
|
-
}
|
|
5224
|
-
return err;
|
|
5225
|
-
}
|
|
5226
|
-
const numberParser = (val, { fallback = val } = {}) => {
|
|
5227
|
-
const number = Number(val);
|
|
5228
|
-
return Number.isNaN(number) ? fallback : number;
|
|
5229
|
-
};
|
|
5230
|
-
const booleanParser = (val, { fallback = val } = {}) => {
|
|
5231
|
-
if (val === "true") return true;
|
|
5232
|
-
if (val === "false") return false;
|
|
5233
|
-
return fallback;
|
|
5234
|
-
};
|
|
5235
|
-
|
|
5236
|
-
function buildExampleArgs(args) {
|
|
5237
|
-
const parts = [];
|
|
5238
|
-
const positionalKeys = Object.keys(args || {}).filter((k) => args?.[k]?.type === "positional");
|
|
5239
|
-
positionalKeys.forEach((key) => {
|
|
5240
|
-
const def = args?.[key];
|
|
5241
|
-
if (def && (def.required || Math.random() > 0.5)) {
|
|
5242
|
-
parts.push(String(def.default ?? `<${key}>`));
|
|
5243
|
-
}
|
|
5244
|
-
});
|
|
5245
|
-
const otherKeys = Object.keys(args || {}).filter((k) => args?.[k]?.type !== "positional");
|
|
5246
|
-
for (const key of otherKeys) {
|
|
5247
|
-
const def = args?.[key];
|
|
5248
|
-
if (def && (def.required || Math.random() > 0.7)) {
|
|
5249
|
-
switch (def.type) {
|
|
5250
|
-
case "boolean":
|
|
5251
|
-
if (def.default === true) {
|
|
5252
|
-
if (Math.random() > 0.5) parts.push(`--no-${key}`);
|
|
5253
|
-
} else {
|
|
5254
|
-
parts.push(`--${key}`);
|
|
5255
|
-
}
|
|
5256
|
-
break;
|
|
5257
|
-
case "string":
|
|
5258
|
-
parts.push(`--${key}=${String(def.default ?? key)}`);
|
|
5259
|
-
break;
|
|
5260
|
-
case "number":
|
|
5261
|
-
parts.push(`--${key}=${String(def.default ?? 42)}`);
|
|
5262
|
-
break;
|
|
5263
|
-
case "array":
|
|
5264
|
-
parts.push(`--${key}=${String(def.default ?? key)}`);
|
|
5265
|
-
break;
|
|
5266
|
-
}
|
|
5267
|
-
}
|
|
5268
|
-
}
|
|
5269
|
-
return parts.join(" ");
|
|
5270
|
-
}
|
|
5271
|
-
const isDebugMode = process$1.argv.includes("--debug");
|
|
5272
|
-
function debugLog(...args) {
|
|
5273
|
-
if (isDebugMode) {
|
|
5274
|
-
relinka("log", "[DEBUG]", ...args);
|
|
5275
|
-
}
|
|
5276
|
-
}
|
|
5277
|
-
function isFlag(str) {
|
|
5278
|
-
return str.startsWith("-");
|
|
3914
|
+
function isFlag(str) {
|
|
3915
|
+
return str.startsWith("-");
|
|
5279
3916
|
}
|
|
5280
3917
|
function defineCommand(options) {
|
|
5281
3918
|
const onCmdInit = options.onCmdInit || options.setup;
|
|
@@ -5295,7 +3932,6 @@ function defineCommand(options) {
|
|
|
5295
3932
|
onCmdExit,
|
|
5296
3933
|
onLauncherInit,
|
|
5297
3934
|
onLauncherExit,
|
|
5298
|
-
router: options.router,
|
|
5299
3935
|
// Backward-compatible aliases
|
|
5300
3936
|
setup: onCmdInit,
|
|
5301
3937
|
cleanup: onCmdExit
|
|
@@ -5329,7 +3965,7 @@ async function getDefaultCliNameAndVersion() {
|
|
|
5329
3965
|
}
|
|
5330
3966
|
async function findRecursiveFileBasedCommands(baseDir, currentPath = []) {
|
|
5331
3967
|
const results = [];
|
|
5332
|
-
const items = await
|
|
3968
|
+
const items = await readdir(path.join(baseDir, ...currentPath), {
|
|
5333
3969
|
withFileTypes: true
|
|
5334
3970
|
});
|
|
5335
3971
|
for (const dirent of items) {
|
|
@@ -5337,7 +3973,7 @@ async function findRecursiveFileBasedCommands(baseDir, currentPath = []) {
|
|
|
5337
3973
|
const newPath = [...currentPath, dirent.name];
|
|
5338
3974
|
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
5339
3975
|
const fpath = path.join(baseDir, ...newPath, fname);
|
|
5340
|
-
if (await
|
|
3976
|
+
if (await pathExists(fpath)) {
|
|
5341
3977
|
try {
|
|
5342
3978
|
const imported = await import(path.resolve(fpath));
|
|
5343
3979
|
if (imported.default && !imported.default.meta?.hidden) {
|
|
@@ -5595,84 +4231,6 @@ function createCli(options, legacyParserOptions) {
|
|
|
5595
4231
|
};
|
|
5596
4232
|
}
|
|
5597
4233
|
const execute = async (_ctx) => {
|
|
5598
|
-
if (options && typeof options === "object" && "rpc" in options && options.rpc) {
|
|
5599
|
-
const rpcOptions = options.rpc;
|
|
5600
|
-
const rpcRunParams = options.rpcRunParams || {};
|
|
5601
|
-
debugLog("RPC integration detected, creating RPC CLI...");
|
|
5602
|
-
try {
|
|
5603
|
-
require("tsx/cjs");
|
|
5604
|
-
await import('tsx/esm');
|
|
5605
|
-
debugLog("tsx loaded successfully for TypeScript support");
|
|
5606
|
-
} catch {
|
|
5607
|
-
debugLog("tsx not available, continuing without TypeScript support");
|
|
5608
|
-
}
|
|
5609
|
-
const getRouterMeta = (router) => {
|
|
5610
|
-
if ("_def" in router && router._def && "meta" in router._def) {
|
|
5611
|
-
return router._def.meta;
|
|
5612
|
-
}
|
|
5613
|
-
return;
|
|
5614
|
-
};
|
|
5615
|
-
const routerMeta = getRouterMeta(rpcOptions.router);
|
|
5616
|
-
const rpcCli = createRpcCli({
|
|
5617
|
-
router: rpcOptions.router,
|
|
5618
|
-
name: globalCliMeta.name || routerMeta?.name,
|
|
5619
|
-
version: globalCliMeta.version || routerMeta?.version,
|
|
5620
|
-
description: globalCliMeta.description || routerMeta?.description,
|
|
5621
|
-
usage: rpcOptions.usage,
|
|
5622
|
-
context: rpcOptions.context,
|
|
5623
|
-
trpcServer: rpcOptions.trpcServer,
|
|
5624
|
-
"@valibot/to-json-schema": rpcOptions["@valibot/to-json-schema"],
|
|
5625
|
-
effect: rpcOptions.effect
|
|
5626
|
-
});
|
|
5627
|
-
debugLog("RPC CLI created, running with argv:", rpcRunParams.argv || process$1.argv.slice(2));
|
|
5628
|
-
await rpcCli.run({
|
|
5629
|
-
argv: rpcRunParams.argv || process$1.argv.slice(2),
|
|
5630
|
-
logger: rpcRunParams.logger || {
|
|
5631
|
-
info: console.log,
|
|
5632
|
-
error: console.error
|
|
5633
|
-
},
|
|
5634
|
-
completion: rpcRunParams.completion,
|
|
5635
|
-
prompts: rpcRunParams.prompts,
|
|
5636
|
-
formatError: rpcRunParams.formatError,
|
|
5637
|
-
process: rpcRunParams.process
|
|
5638
|
-
});
|
|
5639
|
-
return;
|
|
5640
|
-
}
|
|
5641
|
-
if (command.router) {
|
|
5642
|
-
debugLog("Router detected in command, automatically enabling RPC mode...");
|
|
5643
|
-
try {
|
|
5644
|
-
require("tsx/cjs");
|
|
5645
|
-
await import('tsx/esm');
|
|
5646
|
-
debugLog("tsx loaded successfully for TypeScript support");
|
|
5647
|
-
} catch {
|
|
5648
|
-
debugLog("tsx not available, continuing without TypeScript support");
|
|
5649
|
-
}
|
|
5650
|
-
const getRouterMeta = (router) => {
|
|
5651
|
-
if ("_def" in router && router._def && "meta" in router._def) {
|
|
5652
|
-
return router._def.meta;
|
|
5653
|
-
}
|
|
5654
|
-
return;
|
|
5655
|
-
};
|
|
5656
|
-
const routerMeta = getRouterMeta(command.router);
|
|
5657
|
-
const rpcCli = createRpcCli({
|
|
5658
|
-
router: command.router,
|
|
5659
|
-
name: globalCliMeta.name || command.meta?.name || routerMeta?.name,
|
|
5660
|
-
version: globalCliMeta.version || command.meta?.version || routerMeta?.version,
|
|
5661
|
-
description: globalCliMeta.description || command.meta?.description || routerMeta?.description
|
|
5662
|
-
});
|
|
5663
|
-
debugLog("RPC CLI created from command router, running with argv:", process$1.argv.slice(2));
|
|
5664
|
-
await rpcCli.run({
|
|
5665
|
-
argv: process$1.argv.slice(2),
|
|
5666
|
-
logger: {
|
|
5667
|
-
info: console.log,
|
|
5668
|
-
error: console.error
|
|
5669
|
-
},
|
|
5670
|
-
process: {
|
|
5671
|
-
exit: process$1.exit
|
|
5672
|
-
}
|
|
5673
|
-
});
|
|
5674
|
-
return;
|
|
5675
|
-
}
|
|
5676
4234
|
if (typeof command.onLauncherInit === "function") {
|
|
5677
4235
|
try {
|
|
5678
4236
|
await command.onLauncherInit();
|
|
@@ -5686,7 +4244,7 @@ function createCli(options, legacyParserOptions) {
|
|
|
5686
4244
|
if (!parserOptions.fileBased && !command.commands) {
|
|
5687
4245
|
const mainEntry = process$1.argv[1] ? path.dirname(path.resolve(process$1.argv[1])) : process$1.cwd();
|
|
5688
4246
|
const defaultCmdsRoot = path.join(mainEntry, "src", "app");
|
|
5689
|
-
const exists = await
|
|
4247
|
+
const exists = await pathExists(defaultCmdsRoot);
|
|
5690
4248
|
const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
|
|
5691
4249
|
parserOptions.fileBased = {
|
|
5692
4250
|
enable: true,
|
|
@@ -5695,10 +4253,10 @@ function createCli(options, legacyParserOptions) {
|
|
|
5695
4253
|
}
|
|
5696
4254
|
const rawArgv = process$1.argv.slice(2);
|
|
5697
4255
|
const autoExit = parserOptions.autoExit !== false;
|
|
5698
|
-
if (!(parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run
|
|
4256
|
+
if (!(parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run)) {
|
|
5699
4257
|
relinka(
|
|
5700
4258
|
"error",
|
|
5701
|
-
"Invalid CLI configuration: No file-based commands, subCommands, run() handler
|
|
4259
|
+
"Invalid CLI configuration: No file-based commands, subCommands, or run() handler are defined. This CLI will not do anything.\n\u2502 To fix: add file-based commands (./app), or provide at least one subCommand, or a run() handler."
|
|
5702
4260
|
);
|
|
5703
4261
|
process$1.exit(1);
|
|
5704
4262
|
}
|
|
@@ -5880,7 +4438,7 @@ async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, par
|
|
|
5880
4438
|
if (args.length === 0 || args[0] && isFlag(args[0])) {
|
|
5881
4439
|
const possibleFiles2 = [path.join(baseDir, "cmd.js"), path.join(baseDir, "cmd.ts")];
|
|
5882
4440
|
for (const file of possibleFiles2) {
|
|
5883
|
-
if (await
|
|
4441
|
+
if (await pathExists(file)) {
|
|
5884
4442
|
return { importPath: file, leftoverArgv: args };
|
|
5885
4443
|
}
|
|
5886
4444
|
}
|
|
@@ -5892,12 +4450,12 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
5892
4450
|
);
|
|
5893
4451
|
}
|
|
5894
4452
|
const nextDir = path.join(baseDir, args[0] || "");
|
|
5895
|
-
if (await
|
|
4453
|
+
if (await pathExists(nextDir) && (await stat(nextDir)).isDirectory()) {
|
|
5896
4454
|
return resolveCmdPath(nextDir, args.slice(1));
|
|
5897
4455
|
}
|
|
5898
4456
|
const possibleFiles = [path.join(baseDir, "cmd.js"), path.join(baseDir, "cmd.ts")];
|
|
5899
4457
|
for (const file of possibleFiles) {
|
|
5900
|
-
if (await
|
|
4458
|
+
if (await pathExists(file)) {
|
|
5901
4459
|
return { importPath: file, leftoverArgv: args };
|
|
5902
4460
|
}
|
|
5903
4461
|
}
|
|
@@ -5909,7 +4467,7 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
5909
4467
|
);
|
|
5910
4468
|
}
|
|
5911
4469
|
const startDir = path.join(fileCmdOpts.cmdsRootPath, subName);
|
|
5912
|
-
if (!await
|
|
4470
|
+
if (!await pathExists(startDir) || !(await stat(startDir)).isDirectory()) {
|
|
5913
4471
|
const attempted = [subName, ...argv].join(" ");
|
|
5914
4472
|
const expectedPath = path.relative(
|
|
5915
4473
|
process$1.cwd(),
|
|
@@ -6032,7 +4590,7 @@ async function runCommandWithArgs(command, argv, parserOptions, globalCliMeta, r
|
|
|
6032
4590
|
if (command.run) {
|
|
6033
4591
|
await command.run(ctx);
|
|
6034
4592
|
} else {
|
|
6035
|
-
const isDispatcher = parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0
|
|
4593
|
+
const isDispatcher = parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0;
|
|
6036
4594
|
const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
|
|
6037
4595
|
if (isDispatcher && noSubcommandArgInCurrentCall) {
|
|
6038
4596
|
relinka("warn", "Please specify a command");
|
|
@@ -6224,7 +4782,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
|
6224
4782
|
let leftover = [...argv];
|
|
6225
4783
|
while (leftover.length > 0 && leftover[0] && !isFlag(leftover[0])) {
|
|
6226
4784
|
const nextDir = path.join(currentDir, leftover[0]);
|
|
6227
|
-
if (await
|
|
4785
|
+
if (await pathExists(nextDir) && (await stat(nextDir)).isDirectory()) {
|
|
6228
4786
|
currentDir = nextDir;
|
|
6229
4787
|
pathSegments.push(leftover[0]);
|
|
6230
4788
|
leftover = leftover.slice(1);
|
|
@@ -6234,7 +4792,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
|
6234
4792
|
}
|
|
6235
4793
|
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
6236
4794
|
const fpath = path.join(currentDir, fname);
|
|
6237
|
-
if (await
|
|
4795
|
+
if (await pathExists(fpath)) {
|
|
6238
4796
|
const imported = await import(path.resolve(fpath));
|
|
6239
4797
|
if (imported.default) {
|
|
6240
4798
|
return {
|
|
@@ -8218,4 +6776,4 @@ function normalizeName(name) {
|
|
|
8218
6776
|
return lastSegment.replace(/[^a-zA-Z0-9-]/g, "");
|
|
8219
6777
|
}
|
|
8220
6778
|
|
|
8221
|
-
export { CANCEL,
|
|
6779
|
+
export { CANCEL, animateText, animationMap, anykeyPrompt, applyVariant, bar, block, breakLines, callCmd, cancel, colorMap, colorize, completePrompt, confirm, confirmPrompt, countLines$1 as countLines, createAsciiArt, createCancel, createCli, createMultiStep, createStep, datePrompt, defineArgs, defineCommand, deleteLastLine, deleteLastLines, endPrompt, errorHandler, fallbackSymbols, figures, fmt, getColumns, getExactTerminalWidth, getTerminalHeight, getTerminalWidth$1 as getTerminalWidth, group, input, inputPrompt, intro, introPrompt, isCancel, isTerminalInteractive, isValidName, isValidVariant, isWindows, log, mainSymbols, msg, msgUndo, msgUndoAll, multiselect, multiselectPrompt, nextStepsPrompt, normalizeName, numMultiSelectPrompt, numSelectPrompt, numberPrompt, outro, outroPrompt, password, pm, preventUnsupportedTTY, preventWindowsHomeDirRoot, preventWrongTerminalSize, printLineBar, relinkaAsyncByRemptsDeprecated, relinkaByRemptsDeprecated, reliversePrompts, removeCursor, renderEndLine, renderEndLineInput, restoreCursor, resultPrompt, runMain, select, selectPrompt, selectSimple, setRawMode, showUsage, spinner, startEditor, startPrompt, streamText, streamTextBox, streamTextWithSpinner, symbols, taskProgressPrompt, taskSpinPrompt, text, throwError, toBaseColor, toSolidColor, togglePrompt, typographyMap, useSpinner, variantMap };
|