@reliverse/rempts 1.7.49 → 1.7.51
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 +117 -697
- package/dist-npm/bin/mod.mjs +767 -2453
- package/package.json +7 -45
package/dist-npm/bin/mod.mjs
CHANGED
|
@@ -16,23 +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 {
|
|
25
|
-
import { reliArgParser } from '@reliverse/reliarg';
|
|
24
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
26
25
|
import { readPackageJSON } from 'pkg-types';
|
|
27
|
-
import { inspect } from 'node:util';
|
|
28
|
-
import * as trpcServer11 from '@trpc/server';
|
|
29
|
-
export { trpcServer11 as trpcServer };
|
|
30
|
-
import { Command, Option, Argument, InvalidArgumentError } from 'commander';
|
|
31
|
-
import * as zod4 from 'zod/v4/core';
|
|
32
|
-
import zodToJsonSchema from 'zod-to-json-schema';
|
|
33
|
-
import * as zod from 'zod';
|
|
34
|
-
export { zod };
|
|
35
|
-
export { z } from 'zod/v4';
|
|
36
26
|
|
|
37
27
|
const colorMap = {
|
|
38
28
|
// @reliverse/relico
|
|
@@ -1374,7 +1364,275 @@ async function datePrompt(opts) {
|
|
|
1374
1364
|
}
|
|
1375
1365
|
}
|
|
1376
1366
|
|
|
1377
|
-
|
|
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();
|
|
1378
1636
|
let state = {
|
|
1379
1637
|
lines: [""],
|
|
1380
1638
|
// Document content as an array of strings
|
|
@@ -1424,24 +1682,6 @@ let state = {
|
|
|
1424
1682
|
exitResolver: null,
|
|
1425
1683
|
exitRejecter: null
|
|
1426
1684
|
};
|
|
1427
|
-
async function loadEditorConfig(cwd = process.cwd(), overrides = {}) {
|
|
1428
|
-
const { config } = await loadConfig({
|
|
1429
|
-
name: "minedit",
|
|
1430
|
-
cwd,
|
|
1431
|
-
defaults: {
|
|
1432
|
-
// Low priority defaults
|
|
1433
|
-
syntaxHighlighting: false,
|
|
1434
|
-
theme: "auto",
|
|
1435
|
-
defaultAllowSaveAs: true,
|
|
1436
|
-
defaultAllowOpen: true,
|
|
1437
|
-
defaultAutoCloseOnSave: false,
|
|
1438
|
-
defaultReturnContentOnSave: false
|
|
1439
|
-
},
|
|
1440
|
-
// user provided overrides during programmatic call have higher priority
|
|
1441
|
-
overrides
|
|
1442
|
-
});
|
|
1443
|
-
return config || {};
|
|
1444
|
-
}
|
|
1445
1685
|
function setupTheme(configTheme) {
|
|
1446
1686
|
let mode = configTheme;
|
|
1447
1687
|
if (mode === "auto") {
|
|
@@ -1500,13 +1740,13 @@ function renderStatusBar() {
|
|
|
1500
1740
|
const middlePart = hints + " ".repeat(hintPadding);
|
|
1501
1741
|
const statusBar = leftPart + middlePart + rightPart;
|
|
1502
1742
|
term.moveTo(1, term.height - 1);
|
|
1503
|
-
term(state.theme.statusBarBg(state.theme.statusBarText(statusBar.padEnd(width))));
|
|
1743
|
+
term.write(state.theme.statusBarBg(state.theme.statusBarText(statusBar.padEnd(width))));
|
|
1504
1744
|
}
|
|
1505
1745
|
function renderMessageBar() {
|
|
1506
1746
|
term.moveTo(1, term.height);
|
|
1507
1747
|
term.eraseLine();
|
|
1508
1748
|
if (state.statusMessage) {
|
|
1509
|
-
term(state.theme.highlight(state.statusMessage.slice(0, term.width)));
|
|
1749
|
+
term.write(state.theme.highlight(state.statusMessage.slice(0, term.width)));
|
|
1510
1750
|
setTimeout(() => {
|
|
1511
1751
|
if (state.isRunning) {
|
|
1512
1752
|
state.statusMessage = "";
|
|
@@ -1549,11 +1789,11 @@ function renderEditor() {
|
|
|
1549
1789
|
term.moveTo(1, y + 1);
|
|
1550
1790
|
if (fileLineIndex < state.lines.length) {
|
|
1551
1791
|
const lineNum = String(fileLineIndex + 1).padStart(3);
|
|
1552
|
-
term(state.theme.lineNumber(`${lineNum} `));
|
|
1792
|
+
term.write(state.theme.lineNumber(`${lineNum} `));
|
|
1553
1793
|
const line = state.lines[fileLineIndex];
|
|
1554
1794
|
const displayLine = line?.substring(state.leftCol, state.leftCol + displayWidth);
|
|
1555
1795
|
const highlightedDisplayLine = applySyntaxHighlighting(displayLine ?? "");
|
|
1556
|
-
term(highlightedDisplayLine);
|
|
1796
|
+
term.write(highlightedDisplayLine);
|
|
1557
1797
|
term.eraseLineAfter();
|
|
1558
1798
|
} else {
|
|
1559
1799
|
term.eraseLine();
|
|
@@ -1693,13 +1933,15 @@ async function promptForFilename(promptMessage = "File path: ") {
|
|
|
1693
1933
|
renderMessageBar();
|
|
1694
1934
|
term.moveTo(1, term.height);
|
|
1695
1935
|
term.eraseLine();
|
|
1696
|
-
term(promptMessage);
|
|
1936
|
+
term.write(promptMessage);
|
|
1697
1937
|
try {
|
|
1698
1938
|
const input = await term.inputField({ echo: true }).promise;
|
|
1699
|
-
term.moveTo(1, term.height)
|
|
1939
|
+
term.moveTo(1, term.height);
|
|
1940
|
+
term.eraseLine();
|
|
1700
1941
|
return input ? input.trim() : null;
|
|
1701
1942
|
} catch (_error) {
|
|
1702
|
-
term.moveTo(1, term.height)
|
|
1943
|
+
term.moveTo(1, term.height);
|
|
1944
|
+
term.eraseLine();
|
|
1703
1945
|
state.statusMessage = "Cancelled";
|
|
1704
1946
|
render();
|
|
1705
1947
|
return null;
|
|
@@ -1710,16 +1952,18 @@ async function confirmAction(promptMessage = "Are you sure? (y/N)") {
|
|
|
1710
1952
|
renderMessageBar();
|
|
1711
1953
|
term.moveTo(1, term.height);
|
|
1712
1954
|
term.eraseLine();
|
|
1713
|
-
term(`${promptMessage} `);
|
|
1955
|
+
term.write(`${promptMessage} `);
|
|
1714
1956
|
try {
|
|
1715
1957
|
const confirm = await term.yesOrNo({
|
|
1716
1958
|
yes: ["y", "Y"],
|
|
1717
1959
|
no: ["n", "N", "ENTER"]
|
|
1718
1960
|
}).promise;
|
|
1719
|
-
term.moveTo(1, term.height)
|
|
1961
|
+
term.moveTo(1, term.height);
|
|
1962
|
+
term.eraseLine();
|
|
1720
1963
|
return confirm ?? false;
|
|
1721
1964
|
} catch (_error) {
|
|
1722
|
-
term.moveTo(1, term.height)
|
|
1965
|
+
term.moveTo(1, term.height);
|
|
1966
|
+
term.eraseLine();
|
|
1723
1967
|
state.statusMessage = "Cancelled";
|
|
1724
1968
|
render();
|
|
1725
1969
|
return false;
|
|
@@ -1766,7 +2010,7 @@ async function saveFile() {
|
|
|
1766
2010
|
return true;
|
|
1767
2011
|
}
|
|
1768
2012
|
try {
|
|
1769
|
-
await
|
|
2013
|
+
await writeFile(state.filename, contentToSave);
|
|
1770
2014
|
state.originalContent = contentToSave;
|
|
1771
2015
|
state.modified = false;
|
|
1772
2016
|
state.statusMessage = `Saved to ${state.filename}`;
|
|
@@ -1832,7 +2076,7 @@ async function loadFile(filePath) {
|
|
|
1832
2076
|
const absolutePath = path.resolve(cwd, filePath);
|
|
1833
2077
|
let content = "";
|
|
1834
2078
|
try {
|
|
1835
|
-
content = await
|
|
2079
|
+
content = await readFile(absolutePath, "utf-8");
|
|
1836
2080
|
state.statusMessage = `Opened ${absolutePath}`;
|
|
1837
2081
|
} catch (error) {
|
|
1838
2082
|
if (error && error.code === "ENOENT") {
|
|
@@ -2056,7 +2300,7 @@ async function cleanupAndExit(saved = false, content = null) {
|
|
|
2056
2300
|
}
|
|
2057
2301
|
term.off("key", handleInputWrapper);
|
|
2058
2302
|
term.off("resize", handleResize);
|
|
2059
|
-
term.hideCursor(
|
|
2303
|
+
term.hideCursor();
|
|
2060
2304
|
term.grabInput(false);
|
|
2061
2305
|
term.fullscreen(false);
|
|
2062
2306
|
term.styleReset();
|
|
@@ -2141,8 +2385,15 @@ async function initializeEditorState(options) {
|
|
|
2141
2385
|
// Reset toggle state
|
|
2142
2386
|
};
|
|
2143
2387
|
try {
|
|
2144
|
-
|
|
2145
|
-
|
|
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
|
+
};
|
|
2146
2397
|
state.options.allowSaveAs = options.allowSaveAs ?? state.editorConfig.defaultAllowSaveAs ?? true;
|
|
2147
2398
|
state.options.allowOpen = options.allowOpen ?? state.editorConfig.defaultAllowOpen ?? true;
|
|
2148
2399
|
state.options.autoCloseOnSave = options.autoCloseOnSave ?? state.editorConfig.defaultAutoCloseOnSave ?? false;
|
|
@@ -2216,8 +2467,8 @@ async function startEditor(options = {}) {
|
|
|
2216
2467
|
}
|
|
2217
2468
|
const isDirectRun = (() => {
|
|
2218
2469
|
try {
|
|
2219
|
-
const scriptPath =
|
|
2220
|
-
const modulePath =
|
|
2470
|
+
const scriptPath = realpathSync(process.argv[1] || "");
|
|
2471
|
+
const modulePath = realpathSync(import.meta.filename);
|
|
2221
2472
|
return scriptPath === modulePath;
|
|
2222
2473
|
} catch (_e) {
|
|
2223
2474
|
return false;
|
|
@@ -3112,2208 +3363,513 @@ async function introPrompt(optionsOrTitle) {
|
|
|
3112
3363
|
const startPrompt = introPrompt;
|
|
3113
3364
|
const intro = introPrompt;
|
|
3114
3365
|
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
}
|
|
3120
|
-
|
|
3121
|
-
const
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
const
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
}
|
|
3131
|
-
for (const line of stack) {
|
|
3132
|
-
const match = /\((.*):(\d+):(\d+)\)/.exec(line) || /at (.*):(\d+):(\d+)/.exec(line);
|
|
3133
|
-
if (match?.[1]) {
|
|
3134
|
-
const filePath = match[1];
|
|
3135
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3136
|
-
relinka("log", `Checking file path: ${filePath}`);
|
|
3137
|
-
}
|
|
3138
|
-
if (!filePath.includes("node_modules") && !filePath.includes("command-runner") && !filePath.includes("command-typed") && !filePath.includes("launcher-mod") && !filePath.includes("launcher-types") && !filePath.endsWith("mod.mjs") && // Skip compiled output
|
|
3139
|
-
!filePath.endsWith("mod.js") && // Skip compiled output
|
|
3140
|
-
!filePath.endsWith("mod.ts")) {
|
|
3141
|
-
try {
|
|
3142
|
-
const fileDir = dirname(filePath);
|
|
3143
|
-
let currentDir2 = fileDir;
|
|
3144
|
-
let packageRoot = null;
|
|
3145
|
-
while (currentDir2 !== dirname(currentDir2)) {
|
|
3146
|
-
try {
|
|
3147
|
-
const packageJsonPath = resolve(currentDir2, "package.json");
|
|
3148
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3149
|
-
packageRoot = currentDir2;
|
|
3150
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3151
|
-
relinka("log", `Found package.json at: ${packageRoot}`);
|
|
3152
|
-
}
|
|
3153
|
-
const cwdPackageJsonPath = resolve(cwd, "package.json");
|
|
3154
|
-
if (await fs.pathExists(cwdPackageJsonPath)) {
|
|
3155
|
-
try {
|
|
3156
|
-
const callerPackage = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
|
|
3157
|
-
const cwdPackage = JSON.parse(await fs.readFile(cwdPackageJsonPath, "utf-8"));
|
|
3158
|
-
if (callerPackage.name !== cwdPackage.name || callerPackage.version !== cwdPackage.version) {
|
|
3159
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3160
|
-
relinka("log", `Using caller package root: ${packageRoot} (${callerPackage.name}@${callerPackage.version})`);
|
|
3161
|
-
}
|
|
3162
|
-
return packageRoot;
|
|
3163
|
-
}
|
|
3164
|
-
} catch {
|
|
3165
|
-
if (resolve(packageRoot) !== resolve(cwd)) {
|
|
3166
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3167
|
-
relinka("log", `Using caller package root (different path): ${packageRoot}`);
|
|
3168
|
-
}
|
|
3169
|
-
return packageRoot;
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
|
-
} else {
|
|
3173
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3174
|
-
relinka("log", `Using caller package root (no CWD package.json): ${packageRoot}`);
|
|
3175
|
-
}
|
|
3176
|
-
return packageRoot;
|
|
3177
|
-
}
|
|
3178
|
-
break;
|
|
3179
|
-
}
|
|
3180
|
-
} catch {
|
|
3181
|
-
}
|
|
3182
|
-
currentDir2 = dirname(currentDir2);
|
|
3183
|
-
}
|
|
3184
|
-
const resolvedFileDir = resolve(fileDir);
|
|
3185
|
-
const resolvedCwd = resolve(cwd);
|
|
3186
|
-
if (resolvedFileDir !== resolvedCwd && !resolvedFileDir.startsWith(resolvedCwd)) {
|
|
3187
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3188
|
-
relinka("log", `Using caller directory (different from CWD): ${fileDir}`);
|
|
3189
|
-
}
|
|
3190
|
-
return packageRoot || fileDir;
|
|
3191
|
-
}
|
|
3192
|
-
} catch {
|
|
3193
|
-
continue;
|
|
3194
|
-
}
|
|
3195
|
-
}
|
|
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;
|
|
3196
3381
|
}
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
if (match?.[1]) {
|
|
3201
|
-
const filePath = match[1];
|
|
3202
|
-
if (filePath.includes("node_modules")) {
|
|
3203
|
-
try {
|
|
3204
|
-
const nodeModulesMatch = filePath.match(/(.+\/node_modules\/[^\/]+)/);
|
|
3205
|
-
if (nodeModulesMatch?.[1]) {
|
|
3206
|
-
const packageDir = nodeModulesMatch[1];
|
|
3207
|
-
const packageJsonPath = resolve(packageDir, "package.json");
|
|
3208
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3209
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3210
|
-
relinka("log", `Found command package in node_modules: ${packageDir}`);
|
|
3211
|
-
}
|
|
3212
|
-
return packageDir;
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
} catch {
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
}
|
|
3382
|
+
if (arg === "--") {
|
|
3383
|
+
context.result._.push(...argv.slice(i + 1));
|
|
3384
|
+
break;
|
|
3219
3385
|
}
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
}
|
|
3229
|
-
return currentDir;
|
|
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;
|
|
3230
3394
|
}
|
|
3231
|
-
} catch {
|
|
3232
3395
|
}
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
}
|
|
3238
|
-
return process$1.cwd();
|
|
3239
|
-
};
|
|
3240
|
-
const getNodeModulesPackageDirsFromStack = async () => {
|
|
3241
|
-
const stack = new Error().stack?.split("\n") ?? [];
|
|
3242
|
-
const packageDirs = /* @__PURE__ */ new Set();
|
|
3243
|
-
for (const line of stack) {
|
|
3244
|
-
const match = /\((.*):(\d+):(\d+)\)/.exec(line) || /at (.*):(\d+):(\d+)/.exec(line);
|
|
3245
|
-
if (!match?.[1]) continue;
|
|
3246
|
-
const filePath = match[1];
|
|
3247
|
-
if (!filePath.includes("node_modules")) continue;
|
|
3248
|
-
try {
|
|
3249
|
-
const nodeModulesMatch = filePath.match(/(.+\\node_modules\\(?:@[^\\/]+\\)?[^\\/]+)|(.+\/node_modules\/(?:@[^\/]+\/)?[^\/]+)/);
|
|
3250
|
-
const packageDir = (nodeModulesMatch?.[1] || nodeModulesMatch?.[2])?.trim();
|
|
3251
|
-
if (!packageDir) continue;
|
|
3252
|
-
const packageJsonPath = resolve(packageDir, "package.json");
|
|
3253
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
3254
|
-
packageDirs.add(packageDir);
|
|
3255
|
-
}
|
|
3256
|
-
} catch {
|
|
3396
|
+
if (shouldHandleNegatedBoolean(arg, context)) {
|
|
3397
|
+
handleNegatedBooleanFlag(arg, context);
|
|
3398
|
+
i++;
|
|
3399
|
+
continue;
|
|
3257
3400
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
}
|
|
3270
|
-
};
|
|
3271
|
-
const generateCandidatePaths = async (resolvedPath) => {
|
|
3272
|
-
if (!await fs.pathExists(resolvedPath)) {
|
|
3273
|
-
return COMMAND_EXTENSIONS.map((ext) => `${resolvedPath}${ext}`);
|
|
3274
|
-
}
|
|
3275
|
-
if (await fs.isDirectory(resolvedPath)) {
|
|
3276
|
-
return COMMAND_FILENAMES.map((filename) => resolve(resolvedPath, filename));
|
|
3277
|
-
}
|
|
3278
|
-
return [resolvedPath];
|
|
3279
|
-
};
|
|
3280
|
-
const generateAlternativePaths = async (cmdPath, callerDir) => {
|
|
3281
|
-
const normalizedCmdPath = cmdPath.replace(/^\.\//, "");
|
|
3282
|
-
const paths = [];
|
|
3283
|
-
const commonCommandLocations = [
|
|
3284
|
-
// Direct command file
|
|
3285
|
-
resolve(callerDir, `${normalizedCmdPath}.ts`),
|
|
3286
|
-
resolve(callerDir, `${normalizedCmdPath}.js`),
|
|
3287
|
-
// Command in cmd subdirectory
|
|
3288
|
-
resolve(callerDir, normalizedCmdPath, "cmd.ts"),
|
|
3289
|
-
resolve(callerDir, normalizedCmdPath, "cmd.js"),
|
|
3290
|
-
// Command in app subdirectory
|
|
3291
|
-
resolve(callerDir, "app", normalizedCmdPath, "cmd.ts"),
|
|
3292
|
-
resolve(callerDir, "app", normalizedCmdPath, "cmd.js"),
|
|
3293
|
-
// Command in src subdirectory
|
|
3294
|
-
resolve(callerDir, "src", normalizedCmdPath, "cmd.ts"),
|
|
3295
|
-
resolve(callerDir, "src", normalizedCmdPath, "cmd.js"),
|
|
3296
|
-
// Command in src/app subdirectory
|
|
3297
|
-
resolve(callerDir, "src", "app", normalizedCmdPath, "cmd.ts"),
|
|
3298
|
-
resolve(callerDir, "src", "app", normalizedCmdPath, "cmd.js"),
|
|
3299
|
-
// Command in src-ts subdirectory
|
|
3300
|
-
resolve(callerDir, "src-ts", normalizedCmdPath, "cmd.ts"),
|
|
3301
|
-
resolve(callerDir, "src-ts", normalizedCmdPath, "cmd.js"),
|
|
3302
|
-
// Command in src-ts/app subdirectory (for dler-like structures)
|
|
3303
|
-
resolve(callerDir, "src-ts", "app", normalizedCmdPath, "cmd.ts"),
|
|
3304
|
-
resolve(callerDir, "src-ts", "app", normalizedCmdPath, "cmd.js"),
|
|
3305
|
-
// Command in lib subdirectory
|
|
3306
|
-
resolve(callerDir, "lib", normalizedCmdPath, "cmd.ts"),
|
|
3307
|
-
resolve(callerDir, "lib", normalizedCmdPath, "cmd.js"),
|
|
3308
|
-
// Command in lib/app subdirectory
|
|
3309
|
-
resolve(callerDir, "lib", "app", normalizedCmdPath, "cmd.ts"),
|
|
3310
|
-
resolve(callerDir, "lib", "app", normalizedCmdPath, "cmd.js"),
|
|
3311
|
-
// Command in dist subdirectory (compiled)
|
|
3312
|
-
resolve(callerDir, "dist", normalizedCmdPath, "cmd.js"),
|
|
3313
|
-
resolve(callerDir, "dist", "app", normalizedCmdPath, "cmd.js"),
|
|
3314
|
-
// Command in bin subdirectory
|
|
3315
|
-
resolve(callerDir, "bin", normalizedCmdPath, "cmd.ts"),
|
|
3316
|
-
resolve(callerDir, "bin", normalizedCmdPath, "cmd.js"),
|
|
3317
|
-
// Command in bin/app subdirectory (common for CLI tools)
|
|
3318
|
-
resolve(callerDir, "bin", "app", normalizedCmdPath, "cmd.ts"),
|
|
3319
|
-
resolve(callerDir, "bin", "app", normalizedCmdPath, "cmd.js"),
|
|
3320
|
-
// Command in commands subdirectory
|
|
3321
|
-
resolve(callerDir, "commands", normalizedCmdPath, "cmd.ts"),
|
|
3322
|
-
resolve(callerDir, "commands", normalizedCmdPath, "cmd.js"),
|
|
3323
|
-
// Command in cli subdirectory
|
|
3324
|
-
resolve(callerDir, "cli", normalizedCmdPath, "cmd.ts"),
|
|
3325
|
-
resolve(callerDir, "cli", normalizedCmdPath, "cmd.js"),
|
|
3326
|
-
// Command in cli/commands subdirectory
|
|
3327
|
-
resolve(callerDir, "cli", "commands", normalizedCmdPath, "cmd.ts"),
|
|
3328
|
-
resolve(callerDir, "cli", "commands", normalizedCmdPath, "cmd.js"),
|
|
3329
|
-
// Command in tools subdirectory
|
|
3330
|
-
resolve(callerDir, "tools", normalizedCmdPath, "cmd.ts"),
|
|
3331
|
-
resolve(callerDir, "tools", normalizedCmdPath, "cmd.js"),
|
|
3332
|
-
// Command in scripts subdirectory
|
|
3333
|
-
resolve(callerDir, "scripts", normalizedCmdPath, "cmd.ts"),
|
|
3334
|
-
resolve(callerDir, "scripts", normalizedCmdPath, "cmd.js")
|
|
3335
|
-
];
|
|
3336
|
-
for (const path of commonCommandLocations) {
|
|
3337
|
-
if (await fs.pathExists(path)) {
|
|
3338
|
-
paths.push(path);
|
|
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;
|
|
3339
3412
|
}
|
|
3413
|
+
context.result._.push(arg);
|
|
3414
|
+
i++;
|
|
3340
3415
|
}
|
|
3341
|
-
return
|
|
3342
|
-
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
if (
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3382
|
-
relinka("log", `Trying alternative paths in base ${baseDir}: ${alternativePaths.join(", ")}`);
|
|
3383
|
-
}
|
|
3384
|
-
searchedPaths.push(...alternativePaths);
|
|
3385
|
-
for (const path of alternativePaths) {
|
|
3386
|
-
const command = await tryLoadCommand(path);
|
|
3387
|
-
if (command) {
|
|
3388
|
-
if (process$1.env.NODE_ENV === "development") {
|
|
3389
|
-
relinka("log", `Successfully loaded command from alternative path: ${path}`);
|
|
3390
|
-
}
|
|
3391
|
-
return command;
|
|
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);
|
|
3392
3456
|
}
|
|
3393
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;
|
|
3394
3523
|
}
|
|
3395
|
-
const
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
if (
|
|
3399
|
-
|
|
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++;
|
|
3400
3540
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
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;
|
|
3407
3563
|
}
|
|
3408
|
-
return command;
|
|
3409
3564
|
}
|
|
3565
|
+
setFlagValue(resolvedName, true, context);
|
|
3566
|
+
validateOrWarn(resolvedName, context);
|
|
3567
|
+
break;
|
|
3410
3568
|
}
|
|
3411
3569
|
}
|
|
3412
|
-
throw createCommandNotFoundError(cmdPath, searchedPaths);
|
|
3413
|
-
} catch (error) {
|
|
3414
|
-
if (error instanceof Error && error.message.includes("No command file found")) {
|
|
3415
|
-
throw error;
|
|
3416
|
-
}
|
|
3417
|
-
relinka("error", `Failed to load command from ${cmdPath}:`, error);
|
|
3418
|
-
throw createLoadError(cmdPath, error);
|
|
3419
3570
|
}
|
|
3571
|
+
return index + 1;
|
|
3420
3572
|
}
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
if (o.argChoices) suggestions.push(...o.argChoices);
|
|
3456
|
-
if (!o.isBoolean()) break;
|
|
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;
|
|
3457
3607
|
}
|
|
3458
|
-
if (existingFlags.has(o.long)) continue;
|
|
3459
|
-
if (existingFlags.has(o.short)) continue;
|
|
3460
|
-
suggestions.push(o.long);
|
|
3461
3608
|
}
|
|
3462
|
-
return params.reply(suggestions);
|
|
3463
3609
|
}
|
|
3464
|
-
});
|
|
3465
|
-
completion.tree(cTree).init();
|
|
3466
|
-
}
|
|
3467
|
-
|
|
3468
|
-
class CliValidationError extends Error {
|
|
3469
|
-
}
|
|
3470
|
-
class FailedToExitError extends Error {
|
|
3471
|
-
exitCode;
|
|
3472
|
-
constructor(message, { exitCode, cause }) {
|
|
3473
|
-
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.`;
|
|
3474
|
-
super(fullMessage, { cause });
|
|
3475
|
-
this.exitCode = exitCode;
|
|
3476
3610
|
}
|
|
3611
|
+
return strVal;
|
|
3477
3612
|
}
|
|
3478
|
-
|
|
3479
|
-
const
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
const description = command.description();
|
|
3486
|
-
if (description) json.description = description;
|
|
3487
|
-
const usage = command.usage();
|
|
3488
|
-
if (usage) json.usage = usage;
|
|
3489
|
-
json.arguments = command.registeredArguments.map((arg) => {
|
|
3490
|
-
const result = { name: arg.name() };
|
|
3491
|
-
result.variadic = arg.variadic;
|
|
3492
|
-
result.required = arg.required;
|
|
3493
|
-
if (arg.description) result.description = arg.description;
|
|
3494
|
-
if (arg.defaultValue) result.defaultValue = arg.defaultValue;
|
|
3495
|
-
if (arg.defaultValueDescription) result.defaultValueDescription = arg.defaultValueDescription;
|
|
3496
|
-
if (arg.argChoices) result.choices = arg.argChoices;
|
|
3497
|
-
return result;
|
|
3498
|
-
});
|
|
3499
|
-
json.options = command.options.map((o) => {
|
|
3500
|
-
const result = { name: o.name() };
|
|
3501
|
-
result.required = o.required;
|
|
3502
|
-
result.optional = o.optional;
|
|
3503
|
-
result.negate = o.negate;
|
|
3504
|
-
result.variadic = o.variadic;
|
|
3505
|
-
if (o.flags) result.flags = o.flags;
|
|
3506
|
-
if (o.short) result.short = o.short;
|
|
3507
|
-
if (o.description) result.description = o.description;
|
|
3508
|
-
if (o.argChoices) result.choices = o.argChoices;
|
|
3509
|
-
const attributeName = o.attributeName();
|
|
3510
|
-
if (attributeName) result.attributeName = attributeName;
|
|
3511
|
-
if (o.defaultValue) result.defaultValue = o.defaultValue;
|
|
3512
|
-
if (o.defaultValueDescription) result.defaultValueDescription = o.defaultValueDescription;
|
|
3513
|
-
return result;
|
|
3514
|
-
});
|
|
3515
|
-
json.commands = command.commands.map((c) => commandToJSON(c));
|
|
3516
|
-
return json;
|
|
3517
|
-
};
|
|
3518
|
-
|
|
3519
|
-
const capitaliseFromCamelCase = (camel) => {
|
|
3520
|
-
const parts = camel.split(/(?=[A-Z])/);
|
|
3521
|
-
return capitalise(parts.map((p) => p.toLowerCase()).join(" "));
|
|
3522
|
-
};
|
|
3523
|
-
const capitalise = (s) => s.slice(0, 1).toUpperCase() + s.slice(1);
|
|
3524
|
-
const flattenedProperties = (sch) => {
|
|
3525
|
-
if ("properties" in sch) {
|
|
3526
|
-
return sch.properties;
|
|
3527
|
-
}
|
|
3528
|
-
if ("allOf" in sch) {
|
|
3529
|
-
return Object.fromEntries(
|
|
3530
|
-
sch.allOf.flatMap(
|
|
3531
|
-
(subSchema) => Object.entries(flattenedProperties(subSchema))
|
|
3532
|
-
)
|
|
3533
|
-
);
|
|
3534
|
-
}
|
|
3535
|
-
if ("anyOf" in sch) {
|
|
3536
|
-
const isExcluded = (v) => Object.keys(v).join(",") === "not";
|
|
3537
|
-
const entries = sch.anyOf.flatMap((subSchema) => {
|
|
3538
|
-
const flattened = flattenedProperties(subSchema);
|
|
3539
|
-
const excluded = Object.entries(flattened).flatMap(([name, propSchema]) => {
|
|
3540
|
-
return isExcluded(propSchema) ? [`--${name}`] : [];
|
|
3541
|
-
});
|
|
3542
|
-
return Object.entries(flattened).map(([k, v]) => {
|
|
3543
|
-
if (!isExcluded(v) && excluded.length > 0) {
|
|
3544
|
-
return [k, { ...v, "Do not use with": excluded }];
|
|
3545
|
-
}
|
|
3546
|
-
return [k, v];
|
|
3547
|
-
});
|
|
3548
|
-
});
|
|
3549
|
-
return Object.fromEntries(
|
|
3550
|
-
entries.sort((a, b) => {
|
|
3551
|
-
const scores = [a, b].map(([_k, v]) => isExcluded(v) ? 0 : 1);
|
|
3552
|
-
return scores[0] - scores[1];
|
|
3553
|
-
})
|
|
3554
|
-
);
|
|
3555
|
-
}
|
|
3556
|
-
return {};
|
|
3557
|
-
};
|
|
3558
|
-
const incompatiblePropertyPairs = (sch) => {
|
|
3559
|
-
const isUnion = "anyOf" in sch;
|
|
3560
|
-
if (!isUnion) return [];
|
|
3561
|
-
const sets = sch.anyOf.map((subSchema) => {
|
|
3562
|
-
const keys = Object.keys(flattenedProperties(subSchema));
|
|
3563
|
-
return { keys, set: new Set(keys) };
|
|
3564
|
-
});
|
|
3565
|
-
const compatiblityEntries = sets.flatMap(({ keys }) => {
|
|
3566
|
-
return keys.map((key) => {
|
|
3567
|
-
return [
|
|
3568
|
-
key,
|
|
3569
|
-
new Set(sets.filter((other) => other.set.has(key)).flatMap((other) => other.keys))
|
|
3570
|
-
];
|
|
3571
|
-
});
|
|
3572
|
-
});
|
|
3573
|
-
const allKeys = sets.flatMap(({ keys }) => keys);
|
|
3574
|
-
return compatiblityEntries.flatMap(([key, compatibleWith]) => {
|
|
3575
|
-
const incompatibleEntries = allKeys.filter((other) => key < other && !compatibleWith.has(other)).map((other) => [key, other]);
|
|
3576
|
-
return incompatibleEntries;
|
|
3577
|
-
});
|
|
3578
|
-
};
|
|
3579
|
-
const getDescription = (v, depth = 0) => {
|
|
3580
|
-
if ("items" in v && v.items) {
|
|
3581
|
-
const { items, ...rest } = v;
|
|
3582
|
-
return [getDescription(items, 1), getDescription(rest), "array"].filter(Boolean).join(" ");
|
|
3583
|
-
}
|
|
3584
|
-
return Object.entries(v).filter(([k, vv]) => {
|
|
3585
|
-
if (k === "default" || k === "additionalProperties" || k === "optional") return false;
|
|
3586
|
-
if (k === "type" && typeof vv === "string") return depth > 0;
|
|
3587
|
-
if (k.startsWith("$")) return false;
|
|
3588
|
-
if (k === "maximum" && vv === Number.MAX_SAFE_INTEGER) return false;
|
|
3589
|
-
if (depth <= 1 && k === "enum" && getEnumChoices(v)?.type === "string_enum") return false;
|
|
3590
|
-
return true;
|
|
3591
|
-
}).sort(([a], [b]) => {
|
|
3592
|
-
const scores = [a, b].map((k) => k === "description" ? 0 : 1);
|
|
3593
|
-
return scores[0] - scores[1];
|
|
3594
|
-
}).map(([k, vv], i) => {
|
|
3595
|
-
if (k === "type" && Array.isArray(vv)) return `type: ${vv.join(" or ")}`;
|
|
3596
|
-
if (k === "description" && i === 0) return String(vv);
|
|
3597
|
-
if (k === "properties") return "Object (json formatted)";
|
|
3598
|
-
if (typeof vv === "object") return `${capitaliseFromCamelCase(k)}: ${JSON.stringify(vv)}`;
|
|
3599
|
-
return `${capitaliseFromCamelCase(k)}: ${vv}`;
|
|
3600
|
-
}).join("; ") || "";
|
|
3601
|
-
};
|
|
3602
|
-
const getSchemaTypes = (propertyValue) => {
|
|
3603
|
-
const array = [];
|
|
3604
|
-
if ("type" in propertyValue) {
|
|
3605
|
-
array.push(...[propertyValue.type].flat());
|
|
3606
|
-
}
|
|
3607
|
-
if ("enum" in propertyValue && Array.isArray(propertyValue.enum)) {
|
|
3608
|
-
array.push(...propertyValue.enum.flatMap((s) => typeof s));
|
|
3609
|
-
}
|
|
3610
|
-
if ("const" in propertyValue && propertyValue.const === null) {
|
|
3611
|
-
array.push("null");
|
|
3612
|
-
} else if ("const" in propertyValue) {
|
|
3613
|
-
array.push(typeof propertyValue.const);
|
|
3614
|
-
}
|
|
3615
|
-
if ("oneOf" in propertyValue) {
|
|
3616
|
-
array.push(...propertyValue.oneOf.flatMap(getSchemaTypes));
|
|
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;
|
|
3617
3620
|
}
|
|
3618
|
-
if (
|
|
3619
|
-
|
|
3621
|
+
if (context.booleanFlags.has(flagName) || context.arrayFlags.has(flagName) || context.stringFlags.has(flagName) || context.aliasMap.has(flagName)) {
|
|
3622
|
+
return;
|
|
3620
3623
|
}
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
const getEnumChoices = (propertyValue) => {
|
|
3624
|
-
if (!propertyValue) return null;
|
|
3625
|
-
if (!("enum" in propertyValue && Array.isArray(propertyValue.enum))) {
|
|
3626
|
-
if ("anyOf" in propertyValue && propertyValue.anyOf?.every((subSchema) => {
|
|
3627
|
-
if (subSchema && "const" in subSchema && Object.keys(subSchema).length === 1 && typeof subSchema.const === "string") {
|
|
3628
|
-
return true;
|
|
3629
|
-
}
|
|
3630
|
-
return false;
|
|
3631
|
-
})) {
|
|
3632
|
-
return {
|
|
3633
|
-
type: "string_enum",
|
|
3634
|
-
choices: propertyValue.anyOf.map((subSchema) => subSchema.const)
|
|
3635
|
-
};
|
|
3636
|
-
}
|
|
3637
|
-
if ("anyOf" in propertyValue && propertyValue.anyOf?.every((subSchema) => {
|
|
3638
|
-
if (subSchema && "const" in subSchema && Object.keys(subSchema).length === 1 && typeof subSchema.const === "number") {
|
|
3639
|
-
return true;
|
|
3640
|
-
}
|
|
3641
|
-
return false;
|
|
3642
|
-
})) {
|
|
3643
|
-
return {
|
|
3644
|
-
type: "number_enum",
|
|
3645
|
-
choices: propertyValue.anyOf.map((subSchema) => subSchema.const)
|
|
3646
|
-
};
|
|
3647
|
-
}
|
|
3648
|
-
return null;
|
|
3624
|
+
if (defaults && Object.hasOwn(defaults, flagName)) {
|
|
3625
|
+
return;
|
|
3649
3626
|
}
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
};
|
|
3627
|
+
handleUnknownFlag(flagName, context);
|
|
3628
|
+
}
|
|
3629
|
+
function handleUnknownFlag(flagName, context) {
|
|
3630
|
+
if (context.strict) {
|
|
3631
|
+
throw new Error(`Unknown flag: --${flagName}`);
|
|
3655
3632
|
}
|
|
3656
|
-
if (
|
|
3657
|
-
|
|
3658
|
-
type: "number_enum",
|
|
3659
|
-
choices: propertyValue.enum
|
|
3660
|
-
};
|
|
3633
|
+
if (context.warnOnUnknown) {
|
|
3634
|
+
console.warn(`Unknown flag: --${flagName}`);
|
|
3661
3635
|
}
|
|
3662
|
-
|
|
3663
|
-
};
|
|
3636
|
+
}
|
|
3664
3637
|
|
|
3665
|
-
|
|
3666
|
-
const
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
log(...args);
|
|
3671
|
-
} else if (args.length === 1) {
|
|
3672
|
-
log(JSON.stringify(args[0], null, 2));
|
|
3673
|
-
} else {
|
|
3674
|
-
log(JSON.stringify(args, null, 2));
|
|
3638
|
+
async function callCmd(command, input, options = {}) {
|
|
3639
|
+
const { autoExit = false, debug = false, useLifecycleHooks = true, parserOptions = {} } = options;
|
|
3640
|
+
const debugLog = (...args) => {
|
|
3641
|
+
if (debug) {
|
|
3642
|
+
relinka("log", "[callCmd DEBUG]", ...args);
|
|
3675
3643
|
}
|
|
3676
3644
|
};
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
const isPrimitive = (value) => {
|
|
3680
|
-
const type = typeof value;
|
|
3681
|
-
return type === "string" || type === "number" || type === "boolean";
|
|
3682
|
-
};
|
|
3683
|
-
function getLoggerTransformer(transform) {
|
|
3684
|
-
return (logger) => {
|
|
3685
|
-
const info = logger.info && transform(logger.info);
|
|
3686
|
-
const error = logger.error && transform(logger.error);
|
|
3687
|
-
return { info, error };
|
|
3688
|
-
};
|
|
3689
|
-
}
|
|
3690
|
-
const lineByLineConsoleLogger = lineByLineLogger(console);
|
|
3691
|
-
|
|
3692
|
-
function toJsonSchema(input, dependencies) {
|
|
3645
|
+
debugLog("Calling command with input:", input);
|
|
3646
|
+
debugLog("Command meta:", command.meta);
|
|
3693
3647
|
try {
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
success: true,
|
|
3717
|
-
value: {
|
|
3718
|
-
positionalParameters: [],
|
|
3719
|
-
optionsJsonSchema: {},
|
|
3720
|
-
getPojoInput: () => ({})
|
|
3648
|
+
let ctx;
|
|
3649
|
+
if (Array.isArray(input)) {
|
|
3650
|
+
debugLog("Processing argv input:", input);
|
|
3651
|
+
ctx = await parseArgsFromArgv(command, input, parserOptions);
|
|
3652
|
+
} else {
|
|
3653
|
+
debugLog("Processing object input:", input);
|
|
3654
|
+
ctx = await createContextFromArgs(command, input);
|
|
3655
|
+
}
|
|
3656
|
+
debugLog("Created context:", ctx);
|
|
3657
|
+
if (useLifecycleHooks && command.onCmdInit) {
|
|
3658
|
+
debugLog("Calling onCmdInit hook");
|
|
3659
|
+
await command.onCmdInit(ctx);
|
|
3660
|
+
}
|
|
3661
|
+
if (command.run) {
|
|
3662
|
+
debugLog("Executing command run function");
|
|
3663
|
+
await command.run(ctx);
|
|
3664
|
+
} else {
|
|
3665
|
+
const error = "Command has no run function defined";
|
|
3666
|
+
debugLog(error);
|
|
3667
|
+
if (autoExit) {
|
|
3668
|
+
relinka("error", error);
|
|
3669
|
+
process$1.exit(1);
|
|
3721
3670
|
}
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
}
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
success: false,
|
|
3738
|
-
error: mergedSchemaResult.error
|
|
3739
|
-
};
|
|
3671
|
+
throw new Error(error);
|
|
3672
|
+
}
|
|
3673
|
+
if (useLifecycleHooks && command.onCmdExit) {
|
|
3674
|
+
debugLog("Calling onCmdExit hook");
|
|
3675
|
+
await command.onCmdExit(ctx);
|
|
3676
|
+
}
|
|
3677
|
+
debugLog("Command execution completed successfully");
|
|
3678
|
+
return ctx;
|
|
3679
|
+
} catch (error) {
|
|
3680
|
+
debugLog("Error during command execution:", error);
|
|
3681
|
+
if (autoExit) {
|
|
3682
|
+
relinka("error", `Error while executing command: ${String(error)}`);
|
|
3683
|
+
process$1.exit(1);
|
|
3684
|
+
}
|
|
3685
|
+
throw error;
|
|
3740
3686
|
}
|
|
3741
|
-
const mergedSchema = mergedSchemaResult.value;
|
|
3742
|
-
return handleMergedSchema(mergedSchema);
|
|
3743
3687
|
}
|
|
3744
|
-
function
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
success: false,
|
|
3748
|
-
error: "Inputs with additional properties are not currently supported"
|
|
3749
|
-
};
|
|
3750
|
-
}
|
|
3751
|
-
if (mergedSchema.type === "string") {
|
|
3752
|
-
return {
|
|
3753
|
-
success: true,
|
|
3754
|
-
value: {
|
|
3755
|
-
positionalParameters: [
|
|
3756
|
-
{
|
|
3757
|
-
type: "string",
|
|
3758
|
-
array: false,
|
|
3759
|
-
description: mergedSchema.description || "",
|
|
3760
|
-
name: mergedSchema.title || "string",
|
|
3761
|
-
required: !isOptional(mergedSchema)
|
|
3762
|
-
}
|
|
3763
|
-
],
|
|
3764
|
-
optionsJsonSchema: {},
|
|
3765
|
-
getPojoInput: (argv) => argv.positionalValues[0]
|
|
3766
|
-
}
|
|
3767
|
-
};
|
|
3768
|
-
}
|
|
3769
|
-
if (acceptedPrimitiveTypes(mergedSchema).length > 0) {
|
|
3770
|
-
return parsePrimitiveInput(mergedSchema);
|
|
3771
|
-
}
|
|
3772
|
-
if (isTuple(mergedSchema)) {
|
|
3773
|
-
return parseTupleInput(mergedSchema);
|
|
3774
|
-
}
|
|
3775
|
-
if (mergedSchema.type === "array") {
|
|
3776
|
-
return parseArrayInput(mergedSchema);
|
|
3777
|
-
}
|
|
3778
|
-
if (mergedSchema.anyOf) {
|
|
3779
|
-
const allObjects = mergedSchema.anyOf.every((sub) => acceptsObject(toRoughJsonSchema7(sub)));
|
|
3780
|
-
if (allObjects) {
|
|
3781
|
-
return {
|
|
3782
|
-
success: true,
|
|
3783
|
-
value: {
|
|
3784
|
-
positionalParameters: [],
|
|
3785
|
-
optionsJsonSchema: mergedSchema,
|
|
3786
|
-
getPojoInput: (argv) => argv.options
|
|
3787
|
-
}
|
|
3788
|
-
};
|
|
3789
|
-
}
|
|
3790
|
-
if (mergedSchema.anyOf.length === 2 && JSON.stringify(mergedSchema.anyOf[0]) === '{"not":{}}') {
|
|
3791
|
-
return handleMergedSchema(mergedSchema.anyOf[1]);
|
|
3792
|
-
}
|
|
3793
|
-
}
|
|
3794
|
-
if (mergedSchema.type !== "object") {
|
|
3795
|
-
return {
|
|
3796
|
-
success: false,
|
|
3797
|
-
error: `Invalid input type ${inspect(mergedSchema, { depth: 2, breakLength: Number.POSITIVE_INFINITY })}, expected object or tuple.`
|
|
3798
|
-
};
|
|
3799
|
-
}
|
|
3800
|
-
return {
|
|
3801
|
-
success: true,
|
|
3802
|
-
value: {
|
|
3803
|
-
positionalParameters: [],
|
|
3804
|
-
optionsJsonSchema: mergedSchema,
|
|
3805
|
-
getPojoInput: (argv) => argv.options
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3808
|
-
}
|
|
3809
|
-
function isOptional(schema) {
|
|
3810
|
-
if (schema && typeof schema === "object" && "optional" in schema) return schema.optional === true;
|
|
3811
|
-
const anyOf = schemaDefPropValue(schema, "anyOf");
|
|
3812
|
-
if (anyOf?.length === 2 && JSON.stringify(anyOf[0]) === '{"not":{}}') return true;
|
|
3813
|
-
if (anyOf?.some((sub) => isOptional(sub))) return true;
|
|
3814
|
-
return false;
|
|
3815
|
-
}
|
|
3816
|
-
function parsePrimitiveInput(schema) {
|
|
3817
|
-
const typeName = acceptedPrimitiveTypes(schema).join(" | ");
|
|
3818
|
-
const name = (schema.title || schema.description || /\W/.test(typeName) ? "value" : typeName).replaceAll(/\s+/g, "_");
|
|
3819
|
-
return {
|
|
3820
|
-
success: true,
|
|
3821
|
-
value: {
|
|
3822
|
-
positionalParameters: [
|
|
3823
|
-
{
|
|
3824
|
-
name,
|
|
3825
|
-
array: false,
|
|
3826
|
-
description: schema.description || "",
|
|
3827
|
-
required: !isOptional(schema),
|
|
3828
|
-
type: typeName
|
|
3829
|
-
}
|
|
3830
|
-
],
|
|
3831
|
-
optionsJsonSchema: {},
|
|
3832
|
-
getPojoInput: (argv) => convertPositional(schema, argv.positionalValues[0])
|
|
3833
|
-
}
|
|
3834
|
-
};
|
|
3835
|
-
}
|
|
3836
|
-
const schemaDefPropValue = (schema, prop) => {
|
|
3837
|
-
if (schema && typeof schema === "object" && prop in schema) return schema[prop];
|
|
3838
|
-
return;
|
|
3839
|
-
};
|
|
3840
|
-
const primitiveCandidateTypes = ["string", "number", "boolean", "integer"];
|
|
3841
|
-
function acceptedPrimitiveTypes(schema) {
|
|
3842
|
-
let constVals = [
|
|
3843
|
-
toRoughJsonSchema7(schema).const,
|
|
3844
|
-
toRoughJsonSchema7(schema).enum
|
|
3845
|
-
].flat().filter(Boolean).map((s) => typeof s);
|
|
3846
|
-
if (constVals.length === 0) constVals = void 0;
|
|
3847
|
-
const typeList = constVals || schemaDefPropValue(schema, "type") || schemaDefPropValue(schema, "oneOf")?.flatMap((s) => acceptedPrimitiveTypes(s)) || schemaDefPropValue(schema, "anyOf")?.flatMap((s) => acceptedPrimitiveTypes(s));
|
|
3848
|
-
const acceptedJsonSchemaTypes = new Set([typeList].flat().filter(Boolean));
|
|
3849
|
-
return primitiveCandidateTypes.filter((c) => acceptedJsonSchemaTypes.has(c));
|
|
3850
|
-
}
|
|
3851
|
-
function parseMultiInputs(inputs, dependencies) {
|
|
3852
|
-
const parsedIndividually = inputs.map((input) => parseProcedureInputs([input], dependencies));
|
|
3853
|
-
const failures = parsedIndividually.flatMap((p) => p.success ? [] : [p.error]);
|
|
3854
|
-
if (failures.length > 0) {
|
|
3855
|
-
return { success: false, error: failures.join("\n") };
|
|
3856
|
-
}
|
|
3857
|
-
const allObjects = parsedIndividually.every(
|
|
3858
|
-
(p) => p.success && p.value.positionalParameters.length === 0
|
|
3688
|
+
async function parseArgsFromArgv(command, argv, parserOptions) {
|
|
3689
|
+
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
3690
|
+
(k) => command.args?.[k]?.type === "boolean"
|
|
3859
3691
|
);
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
}
|
|
3865
|
-
|
|
3866
|
-
return {
|
|
3867
|
-
success: true,
|
|
3868
|
-
value: {
|
|
3869
|
-
positionalParameters: [],
|
|
3870
|
-
optionsJsonSchema: {
|
|
3871
|
-
allOf: parsedIndividually.map((p) => {
|
|
3872
|
-
const successful = p;
|
|
3873
|
-
const optionsSchema = successful.value.optionsJsonSchema;
|
|
3874
|
-
if ("additionalProperties" in optionsSchema && optionsSchema.additionalProperties === false) {
|
|
3875
|
-
const { additionalProperties, ...rest } = optionsSchema;
|
|
3876
|
-
return rest;
|
|
3877
|
-
}
|
|
3878
|
-
return optionsSchema;
|
|
3879
|
-
})
|
|
3880
|
-
},
|
|
3881
|
-
getPojoInput: (argv) => argv.options
|
|
3882
|
-
}
|
|
3883
|
-
};
|
|
3884
|
-
}
|
|
3885
|
-
function isNullable(schema) {
|
|
3886
|
-
if (Array.isArray(schema.type) && schema.type.includes("null")) return true;
|
|
3887
|
-
if (schema.type === "null") return true;
|
|
3888
|
-
if ((schema.anyOf || schema.oneOf)?.some((sub) => isNullable(toRoughJsonSchema7(sub))))
|
|
3889
|
-
return true;
|
|
3890
|
-
if (schema.const === null) return true;
|
|
3891
|
-
return false;
|
|
3892
|
-
}
|
|
3893
|
-
const tupleItemsSchemas = (schema) => {
|
|
3894
|
-
if (!schema || typeof schema !== "object") return;
|
|
3895
|
-
if (Array.isArray(schema.items)) return schema.items;
|
|
3896
|
-
if ("prefixItems" in schema && Array.isArray(schema.prefixItems))
|
|
3897
|
-
return schema.prefixItems;
|
|
3898
|
-
return;
|
|
3899
|
-
};
|
|
3900
|
-
function isTuple(schema) {
|
|
3901
|
-
return Array.isArray(tupleItemsSchemas(schema));
|
|
3902
|
-
}
|
|
3903
|
-
function parseArrayInput(array) {
|
|
3904
|
-
if (looksLikeJsonSchema(array.items) && isNullable(array.items)) {
|
|
3905
|
-
return {
|
|
3906
|
-
success: false,
|
|
3907
|
-
error: `Invalid input type Array<${getSchemaTypes(array.items).join(" | ")}>. Nullable arrays are not supported.`
|
|
3908
|
-
};
|
|
3909
|
-
}
|
|
3910
|
-
return {
|
|
3911
|
-
success: true,
|
|
3912
|
-
value: {
|
|
3913
|
-
positionalParameters: [
|
|
3914
|
-
{
|
|
3915
|
-
name: parameterName(array, 1),
|
|
3916
|
-
array: true,
|
|
3917
|
-
description: array.description || "",
|
|
3918
|
-
required: !isOptional(array),
|
|
3919
|
-
type: "string"
|
|
3920
|
-
}
|
|
3921
|
-
],
|
|
3922
|
-
optionsJsonSchema: {},
|
|
3923
|
-
getPojoInput: (argv) => argv.positionalValues.at(-1).map(
|
|
3924
|
-
(s) => convertPositional(array.items, s)
|
|
3925
|
-
)
|
|
3926
|
-
}
|
|
3927
|
-
};
|
|
3928
|
-
}
|
|
3929
|
-
function parseTupleInput(tuple) {
|
|
3930
|
-
const items = tupleItemsSchemas(tuple);
|
|
3931
|
-
if (!Array.isArray(items)) throw new Error(".items is not an array, is this really a tuple?");
|
|
3932
|
-
const flagsSchemaIndex = items.findIndex((item) => {
|
|
3933
|
-
if (acceptedPrimitiveTypes(item).length > 0) {
|
|
3934
|
-
return false;
|
|
3935
|
-
}
|
|
3936
|
-
if (looksLikeArray(item) && acceptedPrimitiveTypes(item.items).length > 0) {
|
|
3937
|
-
return false;
|
|
3938
|
-
}
|
|
3939
|
-
return true;
|
|
3940
|
-
});
|
|
3941
|
-
const types = `[${items.map((s) => schemaDefPropValue(s, "type")).join(", ")}]`;
|
|
3942
|
-
if (flagsSchemaIndex > -1 && flagsSchemaIndex !== items.length - 1) {
|
|
3943
|
-
return {
|
|
3944
|
-
success: false,
|
|
3945
|
-
error: `Invalid input type ${types}. Positional parameters must be strings, numbers or booleans.`
|
|
3946
|
-
};
|
|
3947
|
-
}
|
|
3948
|
-
const flagsSchema = flagsSchemaIndex === -1 ? null : items[flagsSchemaIndex];
|
|
3949
|
-
if (flagsSchema && !acceptsObject(flagsSchema)) {
|
|
3950
|
-
return {
|
|
3951
|
-
success: false,
|
|
3952
|
-
error: `Invalid input type ${types}. The last type must accept object inputs.`
|
|
3953
|
-
};
|
|
3954
|
-
}
|
|
3955
|
-
const positionalSchemas = flagsSchemaIndex === -1 ? items : items.slice(0, flagsSchemaIndex);
|
|
3956
|
-
return {
|
|
3957
|
-
success: true,
|
|
3958
|
-
value: {
|
|
3959
|
-
positionalParameters: positionalSchemas.map((schema, i) => ({
|
|
3960
|
-
name: parameterName(schema, i + 1),
|
|
3961
|
-
array: looksLikeArray(schema),
|
|
3962
|
-
description: schemaDefPropValue(schema, "description") || "",
|
|
3963
|
-
required: !isOptional(schema),
|
|
3964
|
-
type: getSchemaTypes(toRoughJsonSchema7(schema)).join(" | ")
|
|
3965
|
-
})),
|
|
3966
|
-
optionsJsonSchema: flagsSchema && typeof flagsSchema === "object" ? flagsSchema : {},
|
|
3967
|
-
getPojoInput: (commandArgs) => {
|
|
3968
|
-
const inputs = commandArgs.positionalValues.map((v, i) => {
|
|
3969
|
-
const correspondingSchema = positionalSchemas[i];
|
|
3970
|
-
if (!correspondingSchema) {
|
|
3971
|
-
throw new CliValidationError(`No schema found for position ${i}`);
|
|
3972
|
-
}
|
|
3973
|
-
if (looksLikeArray(correspondingSchema)) {
|
|
3974
|
-
if (!Array.isArray(v)) {
|
|
3975
|
-
throw new CliValidationError(`Expected array at position ${i}, got ${typeof v}`);
|
|
3976
|
-
}
|
|
3977
|
-
return v.map((s) => {
|
|
3978
|
-
if (!correspondingSchema.items || Array.isArray(correspondingSchema.items)) return s;
|
|
3979
|
-
return convertPositional(correspondingSchema.items, s);
|
|
3980
|
-
});
|
|
3981
|
-
}
|
|
3982
|
-
if (typeof v !== "string" && v !== void 0) {
|
|
3983
|
-
throw new CliValidationError(`Expected string at position ${i}, got ${typeof v}`);
|
|
3984
|
-
}
|
|
3985
|
-
return convertPositional(correspondingSchema, v);
|
|
3986
|
-
});
|
|
3987
|
-
if (flagsSchema) {
|
|
3988
|
-
inputs.push(commandArgs.options);
|
|
3989
|
-
}
|
|
3990
|
-
return inputs;
|
|
3991
|
-
}
|
|
3992
|
-
}
|
|
3993
|
-
};
|
|
3994
|
-
}
|
|
3995
|
-
const convertPositional = (schema, value) => {
|
|
3996
|
-
let preprocessed;
|
|
3997
|
-
const acceptedTypes = new Set(acceptedPrimitiveTypes(schema));
|
|
3998
|
-
if (acceptedTypes.has("string")) {
|
|
3999
|
-
preprocessed = value;
|
|
4000
|
-
}
|
|
4001
|
-
if (acceptedTypes.has("boolean")) {
|
|
4002
|
-
if (value === "true") preprocessed = true;
|
|
4003
|
-
else if (value === "false") preprocessed = false;
|
|
4004
|
-
}
|
|
4005
|
-
if (acceptedTypes.has("number")) {
|
|
4006
|
-
const number = Number(value);
|
|
4007
|
-
if (!Number.isNaN(number)) {
|
|
4008
|
-
preprocessed = number;
|
|
4009
|
-
}
|
|
4010
|
-
}
|
|
4011
|
-
if (acceptedTypes.has("integer")) {
|
|
4012
|
-
const num = Number(value);
|
|
4013
|
-
if (Number.isInteger(num)) {
|
|
4014
|
-
preprocessed = num;
|
|
4015
|
-
} else if (!Number.isNaN(num) && acceptedTypes === void 0) {
|
|
4016
|
-
preprocessed = value;
|
|
4017
|
-
}
|
|
4018
|
-
}
|
|
4019
|
-
if (preprocessed === void 0) {
|
|
4020
|
-
return value;
|
|
4021
|
-
}
|
|
4022
|
-
return preprocessed;
|
|
4023
|
-
};
|
|
4024
|
-
const looksLikeArray = (schema) => {
|
|
4025
|
-
return schemaDefPropValue(schema, "type") === "array";
|
|
4026
|
-
};
|
|
4027
|
-
const toRoughJsonSchema7 = (schema) => {
|
|
4028
|
-
if (!schema || typeof schema !== "object") {
|
|
4029
|
-
return {};
|
|
4030
|
-
}
|
|
4031
|
-
return schema;
|
|
4032
|
-
};
|
|
4033
|
-
const parameterName = (s, position) => {
|
|
4034
|
-
if (looksLikeArray(s)) {
|
|
4035
|
-
const items = toRoughJsonSchema7(s).items;
|
|
4036
|
-
const elementName = parameterName(!items || Array.isArray(items) ? {} : items, position);
|
|
4037
|
-
return `[${elementName.slice(1, -1)}...]`;
|
|
4038
|
-
}
|
|
4039
|
-
let name = schemaDefPropValue(s, "title") || schemaDefPropValue(s, "description") || `parameter_${position}`;
|
|
4040
|
-
name = name.replaceAll(/\W+/g, " ").trim();
|
|
4041
|
-
return isOptional(s) ? `[${name}]` : `<${name}>`;
|
|
4042
|
-
};
|
|
4043
|
-
const acceptsObject = (schema) => {
|
|
4044
|
-
return (schema.type === "object" || schema.anyOf?.some((sub) => acceptsObject(toRoughJsonSchema7(sub)))) ?? false;
|
|
4045
|
-
};
|
|
4046
|
-
const getJsonSchemaConverters = (dependencies) => {
|
|
4047
|
-
return {
|
|
4048
|
-
zod: (input) => {
|
|
4049
|
-
if (input._zod?.version?.major === 4) {
|
|
4050
|
-
return zod4.toJSONSchema(input, {
|
|
4051
|
-
// 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
|
|
4052
|
-
io: "input",
|
|
4053
|
-
// 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
|
|
4054
|
-
unrepresentable: "any",
|
|
4055
|
-
// 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
|
|
4056
|
-
override: (ctx) => {
|
|
4057
|
-
if (ctx.zodSchema?.constructor?.name === "ZodOptional") {
|
|
4058
|
-
ctx.jsonSchema.optional = true;
|
|
4059
|
-
}
|
|
4060
|
-
}
|
|
4061
|
-
});
|
|
4062
|
-
}
|
|
4063
|
-
return zodToJsonSchema(input);
|
|
4064
|
-
},
|
|
4065
|
-
arktype: (input) => {
|
|
4066
|
-
const type = prepareArktypeType(input);
|
|
4067
|
-
return type.toJsonSchema({
|
|
4068
|
-
fallback: (ctx) => {
|
|
4069
|
-
if (ctx.code === "unit" && ctx.unit === void 0) return { ...ctx.base, optional: true };
|
|
4070
|
-
return ctx.base;
|
|
4071
|
-
}
|
|
4072
|
-
});
|
|
4073
|
-
},
|
|
4074
|
-
valibot: (input) => {
|
|
4075
|
-
let valibotToJsonSchemaLib = dependencies["@valibot/to-json-schema"];
|
|
4076
|
-
if (!valibotToJsonSchemaLib) {
|
|
4077
|
-
try {
|
|
4078
|
-
valibotToJsonSchemaLib = require("@valibot/to-json-schema");
|
|
4079
|
-
} catch (e) {
|
|
4080
|
-
throw new Error(
|
|
4081
|
-
"@valibot/to-json-schema could not be found - try installing it and re-running",
|
|
4082
|
-
{ cause: e }
|
|
4083
|
-
);
|
|
4084
|
-
}
|
|
4085
|
-
}
|
|
4086
|
-
const valibotToJsonSchema = valibotToJsonSchemaLib?.toJsonSchema;
|
|
4087
|
-
if (!valibotToJsonSchema) {
|
|
4088
|
-
throw new Error(
|
|
4089
|
-
`no 'toJsonSchema' function found in @valibot/to-json-schema - check you are using a supported version`
|
|
4090
|
-
);
|
|
4091
|
-
}
|
|
4092
|
-
let v;
|
|
4093
|
-
try {
|
|
4094
|
-
v = require("valibot");
|
|
4095
|
-
} catch {
|
|
4096
|
-
return valibotToJsonSchema(input);
|
|
4097
|
-
}
|
|
4098
|
-
const parent = valibotToJsonSchema(
|
|
4099
|
-
v.object({ child: input }),
|
|
4100
|
-
{
|
|
4101
|
-
errorMode: "ignore"
|
|
4102
|
-
}
|
|
4103
|
-
);
|
|
4104
|
-
const child = parent.properties.child;
|
|
4105
|
-
return parent.required?.length === 0 ? Object.assign(child, { optional: true }) : child;
|
|
4106
|
-
},
|
|
4107
|
-
effect: (input) => {
|
|
4108
|
-
const effect = dependencies.effect || (() => {
|
|
4109
|
-
try {
|
|
4110
|
-
return require("effect");
|
|
4111
|
-
} catch {
|
|
4112
|
-
return null;
|
|
4113
|
-
}
|
|
4114
|
-
})();
|
|
4115
|
-
if (!effect) {
|
|
4116
|
-
throw new Error("effect dependency could not be found - try installing it and re-running");
|
|
4117
|
-
}
|
|
4118
|
-
if (!effect.Schema.isSchema(input)) {
|
|
4119
|
-
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";
|
|
4120
|
-
throw new Error(message);
|
|
4121
|
-
}
|
|
4122
|
-
return effect.JSONSchema.make(input);
|
|
4123
|
-
}
|
|
4124
|
-
};
|
|
4125
|
-
};
|
|
4126
|
-
function getVendor(schema) {
|
|
4127
|
-
return schema?.["~standard"]?.vendor ?? null;
|
|
4128
|
-
}
|
|
4129
|
-
const jsonSchemaVendorNames = new Set(Object.keys(getJsonSchemaConverters({})));
|
|
4130
|
-
function looksJsonSchemaable(value) {
|
|
4131
|
-
const vendor = getVendor(value);
|
|
4132
|
-
return !!vendor && jsonSchemaVendorNames.has(vendor);
|
|
4133
|
-
}
|
|
4134
|
-
function prepareArktypeType(type) {
|
|
4135
|
-
let innerType = type;
|
|
4136
|
-
while (innerType) {
|
|
4137
|
-
if (innerType?.in && innerType.in !== innerType) {
|
|
4138
|
-
innerType = innerType.in;
|
|
4139
|
-
} else {
|
|
4140
|
-
break;
|
|
4141
|
-
}
|
|
4142
|
-
}
|
|
4143
|
-
return innerType;
|
|
4144
|
-
}
|
|
4145
|
-
|
|
4146
|
-
const parseUpstreamOptionInfo = (value) => {
|
|
4147
|
-
if (typeof value !== "string" || !value.startsWith("{")) return null;
|
|
4148
|
-
try {
|
|
4149
|
-
const info = JSON.parse(value);
|
|
4150
|
-
if (info.typeName !== "UpstreamOptionInfo") return null;
|
|
4151
|
-
return info;
|
|
4152
|
-
} catch {
|
|
4153
|
-
return null;
|
|
4154
|
-
}
|
|
4155
|
-
};
|
|
4156
|
-
const parseUpstreamArgumentInfo = (value) => {
|
|
4157
|
-
if (typeof value !== "string" || !value.startsWith("{")) return null;
|
|
4158
|
-
try {
|
|
4159
|
-
const info = JSON.parse(value);
|
|
4160
|
-
if (info.typeName !== "UpstreamArgumentInfo") return null;
|
|
4161
|
-
return info;
|
|
4162
|
-
} catch {
|
|
4163
|
-
return null;
|
|
4164
|
-
}
|
|
4165
|
-
};
|
|
4166
|
-
const getDefaultSubcommand = (command) => {
|
|
4167
|
-
const defaultChild = /Available subcommands:.* (\S+) \(default\)/.exec(
|
|
4168
|
-
command.description()
|
|
4169
|
-
)?.[1];
|
|
4170
|
-
return defaultChild ? command.commands.find((c) => c.name() === defaultChild) : void 0;
|
|
4171
|
-
};
|
|
4172
|
-
const createShadowCommand = (command, onAnalyze) => {
|
|
4173
|
-
const shadow = new Command(command.name());
|
|
4174
|
-
shadow.exitOverride();
|
|
4175
|
-
shadow.configureOutput({
|
|
4176
|
-
writeOut: () => {
|
|
4177
|
-
},
|
|
4178
|
-
writeErr: () => {
|
|
4179
|
-
}
|
|
4180
|
-
});
|
|
4181
|
-
const argumentsMap = /* @__PURE__ */ new Map();
|
|
4182
|
-
const optionsMap = /* @__PURE__ */ new Map();
|
|
4183
|
-
command.options.forEach((original) => {
|
|
4184
|
-
const id = Date.now().toString() + Math.random().toString().slice(1);
|
|
4185
|
-
const shadowOption = new Option(
|
|
4186
|
-
original.flags.replace("<", "[").replace(">", "]"),
|
|
4187
|
-
JSON.stringify([`id=${id}`, original.description])
|
|
4188
|
-
);
|
|
4189
|
-
const upstreamOptionInfo = {
|
|
4190
|
-
typeName: "UpstreamOptionInfo",
|
|
4191
|
-
id,
|
|
4192
|
-
specified: false
|
|
4193
|
-
};
|
|
4194
|
-
shadowOption.default(JSON.stringify(upstreamOptionInfo));
|
|
4195
|
-
shadowOption.argParser(
|
|
4196
|
-
(value) => JSON.stringify({ ...upstreamOptionInfo, specified: true, value })
|
|
4197
|
-
);
|
|
4198
|
-
shadow.addOption(shadowOption);
|
|
4199
|
-
optionsMap.set(id, { shadow: shadowOption, original });
|
|
4200
|
-
});
|
|
4201
|
-
command.registeredArguments.forEach((original) => {
|
|
4202
|
-
const shadowArgument = new Argument(original.name(), original.description);
|
|
4203
|
-
const id = Date.now().toString() + Math.random().toString().slice(1);
|
|
4204
|
-
shadowArgument.argOptional();
|
|
4205
|
-
const upstreamArgumentInfo = {
|
|
4206
|
-
typeName: "UpstreamArgumentInfo",
|
|
4207
|
-
id,
|
|
4208
|
-
specified: false
|
|
4209
|
-
};
|
|
4210
|
-
shadowArgument.default(JSON.stringify(upstreamArgumentInfo));
|
|
4211
|
-
shadowArgument.argParser(
|
|
4212
|
-
(value) => JSON.stringify({ ...upstreamArgumentInfo, specified: true, value })
|
|
4213
|
-
);
|
|
4214
|
-
shadow.addArgument(shadowArgument);
|
|
4215
|
-
argumentsMap.set(id, { shadow: shadowArgument, original });
|
|
4216
|
-
});
|
|
4217
|
-
const analysis = {
|
|
4218
|
-
command: { shadow, original: command },
|
|
4219
|
-
arguments: [],
|
|
4220
|
-
options: []
|
|
4221
|
-
};
|
|
4222
|
-
shadow.action(async (...args) => {
|
|
4223
|
-
const positionalValues = args.slice(0, -2);
|
|
4224
|
-
const options = shadow.opts();
|
|
4225
|
-
if (args.at(-2) !== options) {
|
|
4226
|
-
throw new Error("Unexpected args format, second last arg is not the options object", {
|
|
4227
|
-
cause: args
|
|
4228
|
-
});
|
|
4229
|
-
}
|
|
4230
|
-
if (args.at(-1) !== shadow) {
|
|
4231
|
-
throw new Error("Unexpected args format, last arg is not the Command instance", {
|
|
4232
|
-
cause: args
|
|
4233
|
-
});
|
|
4234
|
-
}
|
|
4235
|
-
positionalValues.forEach((value) => {
|
|
4236
|
-
const argumentInfo = parseUpstreamArgumentInfo(value);
|
|
4237
|
-
if (argumentInfo) {
|
|
4238
|
-
analysis.arguments.push({
|
|
4239
|
-
...argumentsMap.get(argumentInfo.id),
|
|
4240
|
-
value: argumentInfo.value,
|
|
4241
|
-
specified: argumentInfo.specified
|
|
4242
|
-
});
|
|
4243
|
-
}
|
|
4244
|
-
});
|
|
4245
|
-
Object.values(options).forEach((value) => {
|
|
4246
|
-
const upstreamOptionInfo = parseUpstreamOptionInfo(value);
|
|
4247
|
-
if (upstreamOptionInfo) {
|
|
4248
|
-
analysis.options.push({
|
|
4249
|
-
...optionsMap.get(upstreamOptionInfo.id),
|
|
4250
|
-
value: upstreamOptionInfo.value,
|
|
4251
|
-
specified: upstreamOptionInfo.specified
|
|
4252
|
-
});
|
|
4253
|
-
}
|
|
4254
|
-
});
|
|
4255
|
-
await onAnalyze(analysis);
|
|
4256
|
-
});
|
|
4257
|
-
command.commands.forEach((subcommand) => {
|
|
4258
|
-
const shadowSubcommand = createShadowCommand(subcommand, onAnalyze);
|
|
4259
|
-
shadow.addCommand(shadowSubcommand);
|
|
4260
|
-
});
|
|
4261
|
-
return shadow;
|
|
4262
|
-
};
|
|
4263
|
-
const inquirerPrompter = (prompts) => {
|
|
4264
|
-
return prompts;
|
|
4265
|
-
};
|
|
4266
|
-
const clackPrompter = (prompts) => {
|
|
4267
|
-
const clack = prompts;
|
|
4268
|
-
class ExitPromptError extends Error {
|
|
4269
|
-
}
|
|
4270
|
-
const throwOnCancel = (value) => {
|
|
4271
|
-
if (clack.isCancel(value)) throw new ExitPromptError();
|
|
4272
|
-
return value;
|
|
4273
|
-
};
|
|
4274
|
-
return {
|
|
4275
|
-
input: async (params) => {
|
|
4276
|
-
return clack.text({
|
|
4277
|
-
message: params.message,
|
|
4278
|
-
initialValue: params.default,
|
|
4279
|
-
defaultValue: params.default,
|
|
4280
|
-
placeholder: params.default,
|
|
4281
|
-
validate: params.validate ? (input) => {
|
|
4282
|
-
const result = params.validate(input);
|
|
4283
|
-
if (result === true) return;
|
|
4284
|
-
if (result === false) return "Invalid input";
|
|
4285
|
-
return result;
|
|
4286
|
-
} : void 0
|
|
4287
|
-
}).then(throwOnCancel);
|
|
4288
|
-
},
|
|
4289
|
-
checkbox: async (params) => {
|
|
4290
|
-
return clack.multiselect({
|
|
4291
|
-
message: params.message,
|
|
4292
|
-
options: params.choices.map((c) => ({
|
|
4293
|
-
label: c.name,
|
|
4294
|
-
value: c.value
|
|
4295
|
-
})),
|
|
4296
|
-
initialValues: params.choices.flatMap((c) => c.checked ? [c.value] : [])
|
|
4297
|
-
}).then(throwOnCancel);
|
|
4298
|
-
},
|
|
4299
|
-
confirm: async (params) => {
|
|
4300
|
-
return clack.confirm({
|
|
4301
|
-
message: params.message,
|
|
4302
|
-
initialValue: params.default
|
|
4303
|
-
}).then(throwOnCancel);
|
|
4304
|
-
},
|
|
4305
|
-
select: async (params) => {
|
|
4306
|
-
return clack.select({
|
|
4307
|
-
message: params.message,
|
|
4308
|
-
options: params.choices.map((sorc) => {
|
|
4309
|
-
const c = typeof sorc === "string" ? { name: sorc, value: sorc } : sorc;
|
|
4310
|
-
return {
|
|
4311
|
-
label: c.name,
|
|
4312
|
-
value: c.value,
|
|
4313
|
-
hint: c.description
|
|
4314
|
-
};
|
|
4315
|
-
}),
|
|
4316
|
-
initialValue: params.default
|
|
4317
|
-
}).then(throwOnCancel);
|
|
4318
|
-
}
|
|
4319
|
-
};
|
|
4320
|
-
};
|
|
4321
|
-
const promptsPrompter = (prompts) => {
|
|
4322
|
-
const p = prompts;
|
|
4323
|
-
function x() {
|
|
4324
|
-
return (value) => value.x;
|
|
4325
|
-
}
|
|
4326
|
-
return {
|
|
4327
|
-
input: async (params) => {
|
|
4328
|
-
return p({
|
|
4329
|
-
name: "x",
|
|
4330
|
-
type: "text",
|
|
4331
|
-
message: params.message,
|
|
4332
|
-
validate: params.validate,
|
|
4333
|
-
initial: params.default
|
|
4334
|
-
}).then(x());
|
|
4335
|
-
},
|
|
4336
|
-
confirm: async (params) => {
|
|
4337
|
-
return p({
|
|
4338
|
-
name: "x",
|
|
4339
|
-
type: "confirm",
|
|
4340
|
-
message: params.message,
|
|
4341
|
-
active: params.default ? "yes" : "no"
|
|
4342
|
-
}).then(x());
|
|
4343
|
-
},
|
|
4344
|
-
select: async (params) => {
|
|
4345
|
-
const choicesObjects = params.choices.map(
|
|
4346
|
-
(c) => typeof c === "string" ? { name: c, value: c } : c
|
|
4347
|
-
);
|
|
4348
|
-
return p({
|
|
4349
|
-
name: "x",
|
|
4350
|
-
type: "select",
|
|
4351
|
-
message: params.message,
|
|
4352
|
-
active: params.default,
|
|
4353
|
-
choices: choicesObjects.map((c) => ({
|
|
4354
|
-
title: c.name || c.value,
|
|
4355
|
-
value: c.value
|
|
4356
|
-
})),
|
|
4357
|
-
initial: params.default ? choicesObjects.findIndex((c) => c.value === params.default) : void 0
|
|
4358
|
-
}).then(x());
|
|
4359
|
-
},
|
|
4360
|
-
checkbox: async (params) => {
|
|
4361
|
-
const choicesObjects = params.choices.map(
|
|
4362
|
-
(c) => typeof c === "string" ? { name: c, value: c } : c
|
|
4363
|
-
);
|
|
4364
|
-
return p({
|
|
4365
|
-
name: "x",
|
|
4366
|
-
type: "multiselect",
|
|
4367
|
-
message: params.message,
|
|
4368
|
-
choices: choicesObjects.map((c) => ({
|
|
4369
|
-
title: c.name || c.value,
|
|
4370
|
-
value: c.value,
|
|
4371
|
-
selected: c.checked
|
|
4372
|
-
}))
|
|
4373
|
-
}).then(x());
|
|
4374
|
-
}
|
|
4375
|
-
};
|
|
4376
|
-
};
|
|
4377
|
-
const enquirerPrompter = (prompts) => {
|
|
4378
|
-
const enquirer = prompts;
|
|
4379
|
-
function x() {
|
|
4380
|
-
return (value) => value.x;
|
|
4381
|
-
}
|
|
4382
|
-
return {
|
|
4383
|
-
input: async (params) => {
|
|
4384
|
-
return enquirer.prompt({
|
|
4385
|
-
type: "input",
|
|
4386
|
-
name: "x",
|
|
4387
|
-
message: params.message,
|
|
4388
|
-
validate: params.validate,
|
|
4389
|
-
initial: params.default
|
|
4390
|
-
}).then(x());
|
|
4391
|
-
},
|
|
4392
|
-
confirm: async (params) => {
|
|
4393
|
-
return enquirer.prompt({
|
|
4394
|
-
type: "confirm",
|
|
4395
|
-
name: "x",
|
|
4396
|
-
message: params.message,
|
|
4397
|
-
validate: params.validate,
|
|
4398
|
-
initial: params.default
|
|
4399
|
-
}).then(x());
|
|
4400
|
-
},
|
|
4401
|
-
select: async (params) => {
|
|
4402
|
-
return enquirer.prompt({
|
|
4403
|
-
type: "select",
|
|
4404
|
-
name: "x",
|
|
4405
|
-
message: params.message,
|
|
4406
|
-
// @ts-expect-error not sure why this is an error, in the IDE it infers the type correctly
|
|
4407
|
-
choices: params.choices.slice(),
|
|
4408
|
-
validate: params.validate,
|
|
4409
|
-
initial: params.default
|
|
4410
|
-
}).then(x());
|
|
4411
|
-
},
|
|
4412
|
-
checkbox: async (params) => {
|
|
4413
|
-
return enquirer.prompt({
|
|
4414
|
-
type: "multiselect",
|
|
4415
|
-
name: "x",
|
|
4416
|
-
message: params.message,
|
|
4417
|
-
// @ts-expect-error not sure why this is an error, in the IDE it infers the type correctly
|
|
4418
|
-
choices: params.choices.slice().map((c) => ({
|
|
4419
|
-
name: c.name,
|
|
4420
|
-
value: c.value
|
|
4421
|
-
})),
|
|
4422
|
-
// validate: params.validate ? v => params.validate!([{value: v}]) : undefined,
|
|
4423
|
-
initial: params.choices.flatMap((c, i) => c.checked ? [i] : [])
|
|
4424
|
-
}).then(x());
|
|
3692
|
+
const defaultMap = {};
|
|
3693
|
+
for (const [argKey, def] of Object.entries(command.args || {})) {
|
|
3694
|
+
if (def.type === "boolean") {
|
|
3695
|
+
defaultMap[argKey] = def.default !== void 0 ? def.default : false;
|
|
3696
|
+
} else if (def.default !== void 0) {
|
|
3697
|
+
defaultMap[argKey] = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
|
|
4425
3698
|
}
|
|
4426
|
-
};
|
|
4427
|
-
};
|
|
4428
|
-
const promptify = (program, prompts) => {
|
|
4429
|
-
let promptsInput = prompts;
|
|
4430
|
-
if (promptsInput?.default) promptsInput = promptsInput.default;
|
|
4431
|
-
let prompter;
|
|
4432
|
-
if (typeof promptsInput === "function" && typeof promptsInput.inject === "function") {
|
|
4433
|
-
prompter = promptsPrompter(promptsInput);
|
|
4434
|
-
} else if (promptsInput?.name === "Enquirer") {
|
|
4435
|
-
prompter = enquirerPrompter(promptsInput);
|
|
4436
|
-
} else if (typeof promptsInput?.rawlist === "function") {
|
|
4437
|
-
prompter = inquirerPrompter(promptsInput);
|
|
4438
|
-
} else if (typeof promptsInput?.intro === "function") {
|
|
4439
|
-
prompter = clackPrompter(promptsInput);
|
|
4440
|
-
} else if (typeof promptsInput === "function") {
|
|
4441
|
-
prompter = promptsInput(program);
|
|
4442
|
-
} else {
|
|
4443
|
-
prompter = promptsInput;
|
|
4444
3699
|
}
|
|
4445
|
-
const
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
`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.`
|
|
4450
|
-
);
|
|
4451
|
-
}
|
|
4452
|
-
if (parseOptions?.from !== "user") {
|
|
4453
|
-
argv = argv.slice(2);
|
|
4454
|
-
parseOptions = { from: "user" };
|
|
4455
|
-
}
|
|
4456
|
-
const f = { command, args: [...argv] };
|
|
4457
|
-
const nextArgv = [...f.args];
|
|
4458
|
-
let analysis;
|
|
4459
|
-
const maxAttempts = 100;
|
|
4460
|
-
for (let i = maxAttempts; i >= 0 && !analysis; i--) {
|
|
4461
|
-
analysis = await new Promise((resolve, reject) => {
|
|
4462
|
-
const shadow = createShadowCommand(f.command, async (an) => {
|
|
4463
|
-
if (an.command.original.commands.length === 0) {
|
|
4464
|
-
resolve(an);
|
|
4465
|
-
return;
|
|
4466
|
-
}
|
|
4467
|
-
const defaultSubcommand = getDefaultSubcommand(an.command.original);
|
|
4468
|
-
if (defaultSubcommand) {
|
|
4469
|
-
resolve(an);
|
|
4470
|
-
return;
|
|
4471
|
-
}
|
|
4472
|
-
const name = await prompter.select(
|
|
4473
|
-
{
|
|
4474
|
-
message: `Select a ${an.command.original.name() || ""} subcommand`.replace(" ", " "),
|
|
4475
|
-
choices: an.command.original.commands.map((c) => ({
|
|
4476
|
-
name: c.name(),
|
|
4477
|
-
value: c.name(),
|
|
4478
|
-
description: c.description()
|
|
4479
|
-
}))
|
|
4480
|
-
},
|
|
4481
|
-
{}
|
|
4482
|
-
);
|
|
4483
|
-
nextArgv.push(name);
|
|
4484
|
-
resolve(void 0);
|
|
4485
|
-
});
|
|
4486
|
-
shadow.parseAsync(nextArgv, parseOptions).catch((e) => {
|
|
4487
|
-
if (e?.constructor?.name === "CommanderError") {
|
|
4488
|
-
resolve({
|
|
4489
|
-
command: { shadow: f.command, original: f.command },
|
|
4490
|
-
arguments: [],
|
|
4491
|
-
options: []
|
|
4492
|
-
});
|
|
4493
|
-
} else {
|
|
4494
|
-
reject(e);
|
|
4495
|
-
}
|
|
4496
|
-
});
|
|
4497
|
-
});
|
|
4498
|
-
}
|
|
4499
|
-
if (!analysis) {
|
|
4500
|
-
const message = `Failed to find a subcommand after ${maxAttempts} attempts - failing to avoid an infinite loop. This is probably a bug in @reliverse/rempts.`;
|
|
4501
|
-
throw new Error(message);
|
|
4502
|
-
}
|
|
4503
|
-
const getMessage = (argOrOpt) => {
|
|
4504
|
-
const name = "long" in argOrOpt ? argOrOpt.flags : `[${argOrOpt.name()}]`;
|
|
4505
|
-
const parts = [
|
|
4506
|
-
name,
|
|
4507
|
-
argOrOpt.description,
|
|
4508
|
-
argOrOpt.defaultValue && `(default: ${argOrOpt.defaultValue})`,
|
|
4509
|
-
!argOrOpt.defaultValue && !argOrOpt.required && "(optional)"
|
|
4510
|
-
];
|
|
4511
|
-
return `${parts.filter(Boolean).join(" ").trim()}:`;
|
|
4512
|
-
};
|
|
4513
|
-
const baseContext = {
|
|
4514
|
-
command: analysis.command.original,
|
|
4515
|
-
inputs: {
|
|
4516
|
-
argv,
|
|
4517
|
-
arguments: analysis.arguments.map((a) => ({
|
|
4518
|
-
name: a.original.name(),
|
|
4519
|
-
specified: a.specified,
|
|
4520
|
-
value: a.value
|
|
4521
|
-
})),
|
|
4522
|
-
options: analysis.options.map((o) => ({
|
|
4523
|
-
name: o.original.name(),
|
|
4524
|
-
specified: o.specified,
|
|
4525
|
-
value: o.value
|
|
4526
|
-
}))
|
|
4527
|
-
}
|
|
4528
|
-
};
|
|
4529
|
-
await prompter.setup?.(baseContext);
|
|
4530
|
-
let shouldPrompt;
|
|
4531
|
-
{
|
|
4532
|
-
const someRequiredArgsUnspecified = analysis.arguments.some(
|
|
4533
|
-
(a) => a.original.required && !a.specified
|
|
4534
|
-
);
|
|
4535
|
-
const someRequiredOptionsUnspecified = analysis.options.some(
|
|
4536
|
-
(o) => o.original.required && !o.specified
|
|
4537
|
-
);
|
|
4538
|
-
shouldPrompt = someRequiredArgsUnspecified || someRequiredOptionsUnspecified;
|
|
4539
|
-
}
|
|
4540
|
-
if (shouldPrompt) {
|
|
4541
|
-
for (const arg of analysis.arguments) {
|
|
4542
|
-
const ctx = { ...baseContext, argument: arg.original };
|
|
4543
|
-
if (!arg.specified) {
|
|
4544
|
-
const parseArg = "parseArg" in arg.original && typeof arg.original.parseArg === "function" ? arg.original.parseArg : void 0;
|
|
4545
|
-
const promptedValue = await prompter.input(
|
|
4546
|
-
{
|
|
4547
|
-
message: getMessage(arg.original),
|
|
4548
|
-
required: arg.original.required,
|
|
4549
|
-
default: arg.value,
|
|
4550
|
-
validate: (input) => {
|
|
4551
|
-
try {
|
|
4552
|
-
parseArg?.(input);
|
|
4553
|
-
return true;
|
|
4554
|
-
} catch (e) {
|
|
4555
|
-
return e?.message || e;
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
},
|
|
4559
|
-
ctx
|
|
4560
|
-
);
|
|
4561
|
-
nextArgv.push(promptedValue);
|
|
4562
|
-
}
|
|
4563
|
-
}
|
|
4564
|
-
for (const option of analysis.options) {
|
|
4565
|
-
const ctx = { ...baseContext, option: option.original };
|
|
4566
|
-
if (!option.specified) {
|
|
4567
|
-
const fullFlag = option.original.long || `--${option.original.name()}`;
|
|
4568
|
-
const isBoolean = option.original.isBoolean() || option.original.flags.includes("[boolean]");
|
|
4569
|
-
if (isBoolean) {
|
|
4570
|
-
const promptedValue = await prompter.confirm(
|
|
4571
|
-
{
|
|
4572
|
-
message: getMessage(option.original),
|
|
4573
|
-
default: option.original.defaultValue ?? false
|
|
4574
|
-
},
|
|
4575
|
-
ctx
|
|
4576
|
-
);
|
|
4577
|
-
if (promptedValue) nextArgv.push(fullFlag);
|
|
4578
|
-
} else if (option.original.variadic && option.original.argChoices) {
|
|
4579
|
-
const choices = option.original.argChoices.slice();
|
|
4580
|
-
const results = await prompter.checkbox(
|
|
4581
|
-
{
|
|
4582
|
-
message: getMessage(option.original),
|
|
4583
|
-
choices: choices.map((choice) => ({
|
|
4584
|
-
value: choice,
|
|
4585
|
-
name: choice,
|
|
4586
|
-
checked: true
|
|
4587
|
-
}))
|
|
4588
|
-
},
|
|
4589
|
-
ctx
|
|
4590
|
-
);
|
|
4591
|
-
results.forEach((result) => {
|
|
4592
|
-
if (typeof result === "string") nextArgv.push(fullFlag, result);
|
|
4593
|
-
});
|
|
4594
|
-
} else if (option.original.argChoices) {
|
|
4595
|
-
const choices = option.original.argChoices.slice();
|
|
4596
|
-
const set = new Set(choices);
|
|
4597
|
-
const promptedValue = await prompter.select(
|
|
4598
|
-
{
|
|
4599
|
-
message: getMessage(option.original),
|
|
4600
|
-
choices,
|
|
4601
|
-
default: option.original.defaultValue
|
|
4602
|
-
// required: option.original.required,
|
|
4603
|
-
},
|
|
4604
|
-
ctx
|
|
4605
|
-
);
|
|
4606
|
-
if (set.has(promptedValue)) {
|
|
4607
|
-
nextArgv.push(fullFlag, promptedValue);
|
|
4608
|
-
}
|
|
4609
|
-
} else if (option.original.variadic) {
|
|
4610
|
-
const values = [];
|
|
4611
|
-
do {
|
|
4612
|
-
const promptedValue = await prompter.input(
|
|
4613
|
-
{
|
|
4614
|
-
message: getMessage(option.original),
|
|
4615
|
-
default: option.original.defaultValue?.[values.length]
|
|
4616
|
-
},
|
|
4617
|
-
ctx
|
|
4618
|
-
);
|
|
4619
|
-
if (!promptedValue) break;
|
|
4620
|
-
values.push(fullFlag, promptedValue);
|
|
4621
|
-
} while (values);
|
|
4622
|
-
nextArgv.push(...values);
|
|
4623
|
-
} else {
|
|
4624
|
-
const getParsedValue = (input) => {
|
|
4625
|
-
return option.original.parseArg ? option.original.parseArg(input, void 0) : input;
|
|
4626
|
-
};
|
|
4627
|
-
const promptedValue = await prompter.input(
|
|
4628
|
-
{
|
|
4629
|
-
message: getMessage(option.original),
|
|
4630
|
-
default: option.value,
|
|
4631
|
-
required: option.original.required,
|
|
4632
|
-
validate: (input) => {
|
|
4633
|
-
const parsed = getParsedValue(input);
|
|
4634
|
-
if (parsed == null && input != null) return "Invalid value";
|
|
4635
|
-
return true;
|
|
4636
|
-
}
|
|
4637
|
-
},
|
|
4638
|
-
ctx
|
|
4639
|
-
);
|
|
4640
|
-
if (promptedValue)
|
|
4641
|
-
nextArgv.push(fullFlag, getParsedValue(promptedValue) ?? promptedValue);
|
|
4642
|
-
}
|
|
4643
|
-
}
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
await prompter.teardown?.(baseContext);
|
|
4647
|
-
return f.command.parseAsync(nextArgv, parseOptions);
|
|
3700
|
+
const mergedParserOptions = {
|
|
3701
|
+
...parserOptions,
|
|
3702
|
+
boolean: [...parserOptions.boolean || [], ...booleanKeys],
|
|
3703
|
+
defaults: { ...defaultMap, ...parserOptions.defaults || {} }
|
|
4648
3704
|
};
|
|
4649
|
-
const
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
const looksLikeStandardSchemaFailure = (error) => {
|
|
4662
|
-
return !!error && typeof error === "object" && "issues" in error && Array.isArray(error.issues);
|
|
4663
|
-
};
|
|
4664
|
-
const looksLikeStandardSchema = (thing) => {
|
|
4665
|
-
return !!thing && typeof thing === "object" && "~standard" in thing && typeof thing["~standard"] === "object";
|
|
4666
|
-
};
|
|
4667
|
-
|
|
4668
|
-
const prettifyStandardSchemaError = (error) => {
|
|
4669
|
-
if (!looksLikeStandardSchemaFailure(error)) return null;
|
|
4670
|
-
const issues = [...error.issues].map((issue) => {
|
|
4671
|
-
const path = issue.path || [];
|
|
4672
|
-
const primitivePathSegments = path.map((segment) => {
|
|
4673
|
-
if (typeof segment === "string" || typeof segment === "number" || typeof segment === "symbol")
|
|
4674
|
-
return segment;
|
|
4675
|
-
return segment.key;
|
|
4676
|
-
});
|
|
4677
|
-
const dotPath = toDotPath(primitivePathSegments);
|
|
4678
|
-
return {
|
|
4679
|
-
issue,
|
|
4680
|
-
path,
|
|
4681
|
-
primitivePathSegments,
|
|
4682
|
-
dotPath
|
|
4683
|
-
};
|
|
4684
|
-
}).sort((a, b) => a.path.length - b.path.length);
|
|
4685
|
-
const lines = [];
|
|
4686
|
-
for (const { issue, dotPath } of issues) {
|
|
4687
|
-
let message = `\u2716 ${issue.message}`;
|
|
4688
|
-
if (dotPath) message += ` \u2192 at ${dotPath}`;
|
|
4689
|
-
lines.push(message);
|
|
4690
|
-
}
|
|
4691
|
-
return lines.join("\n");
|
|
4692
|
-
};
|
|
4693
|
-
function toDotPath(path) {
|
|
4694
|
-
const segs = [];
|
|
4695
|
-
for (const seg of path) {
|
|
4696
|
-
if (typeof seg === "number") segs.push(`[${seg}]`);
|
|
4697
|
-
else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
|
|
4698
|
-
else if (/[^\w$]/.test(seg)) segs.push(`[${JSON.stringify(seg)}]`);
|
|
4699
|
-
else {
|
|
4700
|
-
if (segs.length) segs.push(".");
|
|
4701
|
-
segs.push(seg);
|
|
4702
|
-
}
|
|
4703
|
-
}
|
|
4704
|
-
return segs.join("");
|
|
4705
|
-
}
|
|
4706
|
-
class StandardSchemaV1Error extends Error {
|
|
4707
|
-
issues;
|
|
4708
|
-
constructor(failure, options) {
|
|
4709
|
-
super("Standard Schema error - details in `issues`.", options);
|
|
4710
|
-
this.issues = failure.issues;
|
|
4711
|
-
}
|
|
4712
|
-
}
|
|
4713
|
-
|
|
4714
|
-
const isTrpc11Procedure = (procedure) => {
|
|
4715
|
-
return "type" in procedure._def && typeof procedure._def.type === "string";
|
|
4716
|
-
};
|
|
4717
|
-
const isTrpc11Router = (router) => {
|
|
4718
|
-
if (isOrpcRouter(router)) return false;
|
|
4719
|
-
const procedure = Object.values(router._def.procedures)[0];
|
|
4720
|
-
return Boolean(procedure && isTrpc11Procedure(procedure));
|
|
4721
|
-
};
|
|
4722
|
-
const isOrpcRouter = (router) => {
|
|
4723
|
-
return !("_def" in router) || router._def && "~orpc" in router._def;
|
|
4724
|
-
};
|
|
4725
|
-
|
|
4726
|
-
const looksLikeInstanceof = (value, target) => {
|
|
4727
|
-
let current = value?.constructor;
|
|
4728
|
-
while (current?.name) {
|
|
4729
|
-
if (current?.name === (typeof target === "string" ? target : target.name)) return true;
|
|
4730
|
-
current = Object.getPrototypeOf(current);
|
|
3705
|
+
const parsed = reliArgParser(argv, mergedParserOptions);
|
|
3706
|
+
const finalArgs = {};
|
|
3707
|
+
const positionalKeys = Object.keys(command.args || {}).filter(
|
|
3708
|
+
(k) => command.args?.[k]?.type === "positional"
|
|
3709
|
+
);
|
|
3710
|
+
const leftoverPositionals = [...parsed._ || []];
|
|
3711
|
+
for (let i = 0; i < positionalKeys.length; i++) {
|
|
3712
|
+
const key = positionalKeys[i];
|
|
3713
|
+
if (!key || !command.args) continue;
|
|
3714
|
+
const def = command.args[key];
|
|
3715
|
+
const val = leftoverPositionals[i];
|
|
3716
|
+
finalArgs[key] = val != null && def ? castArgValue$1(def, val, key) : def?.default;
|
|
4731
3717
|
}
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
}
|
|
4742
|
-
const parseRouter = ({ router, ...params }) => {
|
|
4743
|
-
if (isOrpcRouter(router)) return parseOrpcRouter({ router, ...params });
|
|
4744
|
-
return parseTrpcRouter({ router, ...params });
|
|
4745
|
-
};
|
|
4746
|
-
const parseTrpcRouter = ({
|
|
4747
|
-
router,
|
|
4748
|
-
...params
|
|
4749
|
-
}) => {
|
|
4750
|
-
const defEntries = Object.entries(router._def.procedures);
|
|
4751
|
-
return defEntries.map(([procedurePath, procedure]) => {
|
|
4752
|
-
const meta = getMeta(procedure);
|
|
4753
|
-
if (meta.jsonInput) {
|
|
4754
|
-
return [
|
|
4755
|
-
procedurePath,
|
|
4756
|
-
{
|
|
4757
|
-
meta,
|
|
4758
|
-
parsedProcedure: jsonProcedureInputs(),
|
|
4759
|
-
incompatiblePairs: [],
|
|
4760
|
-
procedure
|
|
4761
|
-
}
|
|
4762
|
-
];
|
|
4763
|
-
}
|
|
4764
|
-
const procedureInputsResult = parseProcedureInputs(procedure._def.inputs, params);
|
|
4765
|
-
if (!procedureInputsResult.success) {
|
|
4766
|
-
const procedureInputs2 = jsonProcedureInputs(
|
|
4767
|
-
`procedure's schema couldn't be converted to CLI arguments: ${procedureInputsResult.error}`
|
|
4768
|
-
);
|
|
4769
|
-
return [
|
|
4770
|
-
procedurePath,
|
|
4771
|
-
{
|
|
4772
|
-
meta,
|
|
4773
|
-
parsedProcedure: procedureInputs2,
|
|
4774
|
-
incompatiblePairs: [],
|
|
4775
|
-
procedure
|
|
4776
|
-
}
|
|
4777
|
-
];
|
|
4778
|
-
}
|
|
4779
|
-
const procedureInputs = procedureInputsResult.value;
|
|
4780
|
-
const incompatiblePairs = incompatiblePropertyPairs(procedureInputs.optionsJsonSchema);
|
|
4781
|
-
return [
|
|
4782
|
-
procedurePath,
|
|
4783
|
-
{
|
|
4784
|
-
meta: getMeta(procedure),
|
|
4785
|
-
parsedProcedure: procedureInputs,
|
|
4786
|
-
incompatiblePairs,
|
|
4787
|
-
procedure
|
|
4788
|
-
}
|
|
4789
|
-
];
|
|
4790
|
-
});
|
|
4791
|
-
};
|
|
4792
|
-
const parseOrpcRouter = (params) => {
|
|
4793
|
-
const entries = [];
|
|
4794
|
-
const { traverseContractProcedures, isProcedure } = (() => {
|
|
4795
|
-
try {
|
|
4796
|
-
return require("@orpc/server");
|
|
4797
|
-
} catch (e) {
|
|
4798
|
-
throw new Error(
|
|
4799
|
-
"@orpc/server dependency could not be found - try installing it and re-running",
|
|
4800
|
-
{ cause: e }
|
|
4801
|
-
);
|
|
4802
|
-
}
|
|
4803
|
-
})();
|
|
4804
|
-
const router = params.router;
|
|
4805
|
-
const lazyRoutes = traverseContractProcedures({ path: [], router }, ({ contract, path }) => {
|
|
4806
|
-
let procedure = params.router;
|
|
4807
|
-
for (const p of path) procedure = procedure[p];
|
|
4808
|
-
if (!isProcedure(procedure)) return;
|
|
4809
|
-
const procedureInputsResult = parseProcedureInputs([contract["~orpc"].inputSchema], {
|
|
4810
|
-
"@valibot/to-json-schema": params["@valibot/to-json-schema"],
|
|
4811
|
-
effect: params.effect
|
|
4812
|
-
});
|
|
4813
|
-
const procedurePath = path.join(".");
|
|
4814
|
-
const procedureish = {
|
|
4815
|
-
_def: { meta: contract["~orpc"].meta }
|
|
4816
|
-
};
|
|
4817
|
-
const meta = getMeta(procedureish);
|
|
4818
|
-
if (meta.jsonInput) {
|
|
4819
|
-
entries.push([
|
|
4820
|
-
procedurePath,
|
|
4821
|
-
{
|
|
4822
|
-
meta,
|
|
4823
|
-
parsedProcedure: jsonProcedureInputs(),
|
|
4824
|
-
incompatiblePairs: [],
|
|
4825
|
-
procedure
|
|
4826
|
-
}
|
|
4827
|
-
]);
|
|
4828
|
-
return;
|
|
4829
|
-
}
|
|
4830
|
-
if (!procedureInputsResult.success) {
|
|
4831
|
-
const parsedProcedure2 = jsonProcedureInputs(
|
|
4832
|
-
`procedure's schema couldn't be converted to CLI arguments: ${procedureInputsResult.error}`
|
|
4833
|
-
);
|
|
4834
|
-
entries.push([
|
|
4835
|
-
procedurePath,
|
|
4836
|
-
{
|
|
4837
|
-
meta,
|
|
4838
|
-
parsedProcedure: parsedProcedure2,
|
|
4839
|
-
incompatiblePairs: [],
|
|
4840
|
-
procedure
|
|
4841
|
-
}
|
|
4842
|
-
]);
|
|
4843
|
-
return;
|
|
3718
|
+
const otherKeys = Object.keys(command.args || {}).filter(
|
|
3719
|
+
(k) => command.args?.[k]?.type !== "positional"
|
|
3720
|
+
);
|
|
3721
|
+
for (const key of otherKeys) {
|
|
3722
|
+
const def = command.args?.[key];
|
|
3723
|
+
if (!def) continue;
|
|
3724
|
+
let rawVal = parsed[key];
|
|
3725
|
+
if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
|
|
3726
|
+
rawVal = [rawVal];
|
|
4844
3727
|
}
|
|
4845
|
-
const
|
|
4846
|
-
const
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
if (lazyRoutes.length) {
|
|
4850
|
-
const suggestion = `Please use \`import {unlazyRouter} from '@orpc/server'\` to unlazy the router before passing it to @reliverse/rempts`;
|
|
4851
|
-
const routes = lazyRoutes.map(({ path }) => path.join(".")).join(", ");
|
|
4852
|
-
throw new Error(
|
|
4853
|
-
`Lazy routers are not supported. ${suggestion}. Lazy routes detected: ${routes}`
|
|
4854
|
-
);
|
|
4855
|
-
}
|
|
4856
|
-
return entries;
|
|
4857
|
-
};
|
|
4858
|
-
const jsonProcedureInputs = (reason) => {
|
|
4859
|
-
let description = "Input formatted as JSON";
|
|
4860
|
-
if (reason) description += ` (${reason})`;
|
|
4861
|
-
return {
|
|
4862
|
-
positionalParameters: [],
|
|
4863
|
-
optionsJsonSchema: {
|
|
4864
|
-
type: "object",
|
|
4865
|
-
properties: {
|
|
4866
|
-
input: { type: "json", description }
|
|
4867
|
-
}
|
|
4868
|
-
},
|
|
4869
|
-
getPojoInput: (parsedCliParams) => {
|
|
4870
|
-
if (parsedCliParams.options.input == null) return parsedCliParams.options.input;
|
|
4871
|
-
return JSON.parse(parsedCliParams.options.input);
|
|
3728
|
+
const casted = rawVal !== void 0 ? castArgValue$1(def, rawVal, key) : def.default;
|
|
3729
|
+
const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
|
|
3730
|
+
if (casted == null && def.required) {
|
|
3731
|
+
throw new Error(`Missing required argument: --${key}`);
|
|
4872
3732
|
}
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
const program = new TrpcCommand(params.name);
|
|
4883
|
-
if (params.version) program.version(params.version);
|
|
4884
|
-
if (params.description) program.description(params.description);
|
|
4885
|
-
if (params.usage) [params.usage].flat().forEach((usage) => program.usage(usage));
|
|
4886
|
-
program.showHelpAfterError();
|
|
4887
|
-
program.showSuggestionAfterError();
|
|
4888
|
-
const commandTree = {
|
|
4889
|
-
"": program
|
|
4890
|
-
// Root level
|
|
4891
|
-
};
|
|
4892
|
-
const defaultCommands = {};
|
|
4893
|
-
const _process = runParams?.process || process;
|
|
4894
|
-
const configureCommand = (command, procedurePath, { meta, parsedProcedure, incompatiblePairs, procedure }) => {
|
|
4895
|
-
const optionJsonSchemaProperties = flattenedProperties(parsedProcedure.optionsJsonSchema);
|
|
4896
|
-
command.exitOverride((ec) => {
|
|
4897
|
-
_process.exit(ec.exitCode);
|
|
4898
|
-
throw new FailedToExitError(`Command ${command.name()} exitOverride`, {
|
|
4899
|
-
exitCode: ec.exitCode,
|
|
4900
|
-
cause: ec
|
|
4901
|
-
});
|
|
4902
|
-
});
|
|
4903
|
-
command.configureOutput({
|
|
4904
|
-
writeOut: (str) => {
|
|
4905
|
-
logger.info?.(str);
|
|
4906
|
-
},
|
|
4907
|
-
writeErr: (str) => {
|
|
4908
|
-
logger.error?.(str);
|
|
4909
|
-
}
|
|
4910
|
-
});
|
|
4911
|
-
command.showHelpAfterError();
|
|
4912
|
-
if (meta.usage) command.usage([meta.usage].flat().join("\n"));
|
|
4913
|
-
if (meta.examples)
|
|
4914
|
-
command.addHelpText("after", `
|
|
4915
|
-
Examples:
|
|
4916
|
-
${[meta.examples].flat().join("\n")}`);
|
|
4917
|
-
meta?.aliases?.command?.forEach((alias) => {
|
|
4918
|
-
command.alias(alias);
|
|
4919
|
-
});
|
|
4920
|
-
command.description(meta?.description || "");
|
|
4921
|
-
parsedProcedure.positionalParameters.forEach((param) => {
|
|
4922
|
-
const descriptionParts = [
|
|
4923
|
-
param.type === "string" ? "" : param.type,
|
|
4924
|
-
// "string" is the default assumption, don't bother showing it
|
|
4925
|
-
param.description,
|
|
4926
|
-
param.required ? "(required)" : ""
|
|
4927
|
-
];
|
|
4928
|
-
const argument = new Argument(param.name, descriptionParts.filter(Boolean).join(" "));
|
|
4929
|
-
if (param.type === "number") {
|
|
4930
|
-
argument.argParser((value) => {
|
|
4931
|
-
const number = numberParser(value, { fallback: null });
|
|
4932
|
-
if (number == null) throw new InvalidArgumentError(`Invalid number: ${value}`);
|
|
4933
|
-
return value;
|
|
4934
|
-
});
|
|
4935
|
-
}
|
|
4936
|
-
argument.required = param.required;
|
|
4937
|
-
argument.variadic = param.array;
|
|
4938
|
-
command.addArgument(argument);
|
|
4939
|
-
});
|
|
4940
|
-
const unusedOptionAliases = {
|
|
4941
|
-
...meta.aliases?.options
|
|
4942
|
-
};
|
|
4943
|
-
const addOptionForProperty = ([propertyKey, propertyValue]) => {
|
|
4944
|
-
const description = getDescription(propertyValue);
|
|
4945
|
-
const longOption = `--${kebabCase(propertyKey)}`;
|
|
4946
|
-
let flags = longOption;
|
|
4947
|
-
const alias = meta.aliases?.options?.[propertyKey];
|
|
4948
|
-
if (alias) {
|
|
4949
|
-
let prefix = "-";
|
|
4950
|
-
if (alias.startsWith("-")) prefix = "";
|
|
4951
|
-
else if (alias.length > 1) prefix = "--";
|
|
4952
|
-
flags = `${prefix}${alias}, ${flags}`;
|
|
4953
|
-
delete unusedOptionAliases[propertyKey];
|
|
4954
|
-
}
|
|
4955
|
-
const defaultValue = "default" in propertyValue ? { exists: true, value: propertyValue.default } : { exists: false };
|
|
4956
|
-
const rootTypes = getSchemaTypes(propertyValue).sort();
|
|
4957
|
-
const getValueParser = (types) => {
|
|
4958
|
-
types = types.map((t) => t === "integer" ? "number" : t);
|
|
4959
|
-
if (types.length === 2 && types[0] === "boolean" && types[1] === "number") {
|
|
4960
|
-
return {
|
|
4961
|
-
type: "boolean|number",
|
|
4962
|
-
parser: (value) => booleanParser(value, { fallback: null }) ?? numberParser(value)
|
|
4963
|
-
};
|
|
4964
|
-
}
|
|
4965
|
-
if (types.length === 1 && types[0] === "boolean") {
|
|
4966
|
-
return {
|
|
4967
|
-
type: "boolean",
|
|
4968
|
-
parser: (value) => booleanParser(value)
|
|
4969
|
-
};
|
|
4970
|
-
}
|
|
4971
|
-
if (types.length === 1 && types[0] === "number") {
|
|
4972
|
-
return {
|
|
4973
|
-
type: "number",
|
|
4974
|
-
parser: (value) => numberParser(value)
|
|
4975
|
-
};
|
|
4976
|
-
}
|
|
4977
|
-
if (types.length === 1 && types[0] === "string") {
|
|
4978
|
-
return { type: "string", parser: null };
|
|
4979
|
-
}
|
|
4980
|
-
return {
|
|
4981
|
-
type: "json",
|
|
4982
|
-
parser: (value) => {
|
|
4983
|
-
let parsed;
|
|
4984
|
-
try {
|
|
4985
|
-
parsed = JSON.parse(value);
|
|
4986
|
-
} catch {
|
|
4987
|
-
throw new InvalidArgumentError("Malformed JSON.");
|
|
4988
|
-
}
|
|
4989
|
-
const jsonSchemaType = Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed;
|
|
4990
|
-
if (!types.includes(jsonSchemaType)) {
|
|
4991
|
-
throw new InvalidArgumentError(
|
|
4992
|
-
`Got ${jsonSchemaType} but expected ${types.join(" or ")}`
|
|
4993
|
-
);
|
|
4994
|
-
}
|
|
4995
|
-
return parsed;
|
|
4996
|
-
}
|
|
4997
|
-
};
|
|
4998
|
-
};
|
|
4999
|
-
const propertyType = rootTypes[0];
|
|
5000
|
-
const isValueRequired = "required" in parsedProcedure.optionsJsonSchema && parsedProcedure.optionsJsonSchema.required?.includes(propertyKey);
|
|
5001
|
-
const isCliOptionRequired = isValueRequired && propertyType !== "boolean" && !defaultValue.exists;
|
|
5002
|
-
function negate() {
|
|
5003
|
-
const negation = new Option(
|
|
5004
|
-
longOption.replace("--", "--no-"),
|
|
5005
|
-
`Negate \`${longOption}\` option.`.trim()
|
|
5006
|
-
);
|
|
5007
|
-
command.addOption(negation);
|
|
5008
|
-
}
|
|
5009
|
-
const bracketise = (name) => isCliOptionRequired ? `<${name}>` : `[${name}]`;
|
|
5010
|
-
if (rootTypes.length === 2 && rootTypes[0] === "boolean" && rootTypes[1] === "string") {
|
|
5011
|
-
const option2 = new Option(`${flags} [value]`, description);
|
|
5012
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
5013
|
-
command.addOption(option2);
|
|
5014
|
-
negate();
|
|
5015
|
-
return;
|
|
5016
|
-
}
|
|
5017
|
-
if (rootTypes.length === 2 && rootTypes[0] === "boolean" && rootTypes[1] === "number") {
|
|
5018
|
-
const option2 = new Option(`${flags} [value]`, description);
|
|
5019
|
-
option2.argParser(getValueParser(rootTypes).parser);
|
|
5020
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
5021
|
-
command.addOption(option2);
|
|
5022
|
-
negate();
|
|
5023
|
-
return;
|
|
5024
|
-
}
|
|
5025
|
-
if (rootTypes.length === 2 && rootTypes[0] === "number" && rootTypes[1] === "string") {
|
|
5026
|
-
const option2 = new Option(`${flags} ${bracketise("value")}`, description);
|
|
5027
|
-
option2.argParser((value) => {
|
|
5028
|
-
const number = numberParser(value, { fallback: null });
|
|
5029
|
-
return number ?? value;
|
|
5030
|
-
});
|
|
5031
|
-
if (defaultValue.exists) option2.default(defaultValue.value);
|
|
5032
|
-
command.addOption(option2);
|
|
5033
|
-
return;
|
|
5034
|
-
}
|
|
5035
|
-
if (rootTypes.length !== 1) {
|
|
5036
|
-
const option2 = new Option(
|
|
5037
|
-
`${flags} ${bracketise("json")}`,
|
|
5038
|
-
`${description} (value will be parsed as JSON)`
|
|
5039
|
-
);
|
|
5040
|
-
option2.argParser(getValueParser(rootTypes).parser);
|
|
5041
|
-
command.addOption(option2);
|
|
5042
|
-
return;
|
|
5043
|
-
}
|
|
5044
|
-
if (propertyType === "boolean" && isValueRequired) {
|
|
5045
|
-
const option2 = new Option(flags, description);
|
|
5046
|
-
option2.default(defaultValue.exists ? defaultValue.value : false);
|
|
5047
|
-
command.addOption(option2);
|
|
5048
|
-
negate();
|
|
5049
|
-
return;
|
|
5050
|
-
}
|
|
5051
|
-
if (propertyType === "boolean") {
|
|
5052
|
-
const option2 = new Option(`${flags} [boolean]`, description);
|
|
5053
|
-
option2.argParser((value) => booleanParser(value));
|
|
5054
|
-
if (defaultValue.exists) option2.default(defaultValue.value);
|
|
5055
|
-
command.addOption(option2);
|
|
5056
|
-
negate();
|
|
5057
|
-
return;
|
|
5058
|
-
}
|
|
5059
|
-
let option;
|
|
5060
|
-
if (propertyType === "string") {
|
|
5061
|
-
option = new Option(`${flags} ${bracketise("string")}`, description);
|
|
5062
|
-
} else if (propertyType === "boolean") {
|
|
5063
|
-
option = new Option(flags, description);
|
|
5064
|
-
} else if (propertyType === "number" || propertyType === "integer") {
|
|
5065
|
-
option = new Option(`${flags} ${bracketise("number")}`, description);
|
|
5066
|
-
option.argParser((value) => numberParser(value, { fallback: null }));
|
|
5067
|
-
} else if (propertyType === "array") {
|
|
5068
|
-
option = new Option(`${flags} [values...]`, description);
|
|
5069
|
-
if (defaultValue.exists) option.default(defaultValue.value);
|
|
5070
|
-
else if (isValueRequired) option.default([]);
|
|
5071
|
-
const itemsProp = "items" in propertyValue ? propertyValue.items : null;
|
|
5072
|
-
const itemTypes = itemsProp ? getSchemaTypes(itemsProp) : [];
|
|
5073
|
-
const itemEnumTypes = itemsProp && getEnumChoices(itemsProp);
|
|
5074
|
-
if (itemEnumTypes?.type === "string_enum") {
|
|
5075
|
-
option.choices(itemEnumTypes.choices);
|
|
5076
|
-
}
|
|
5077
|
-
const itemParser = getValueParser(itemTypes);
|
|
5078
|
-
if (itemParser.parser) {
|
|
5079
|
-
option.argParser((value, previous) => {
|
|
5080
|
-
const parsed = itemParser.parser(value);
|
|
5081
|
-
if (Array.isArray(previous)) return [...previous, parsed];
|
|
5082
|
-
return [parsed];
|
|
5083
|
-
});
|
|
5084
|
-
}
|
|
5085
|
-
}
|
|
5086
|
-
option ||= new Option(`${flags} [json]`, description);
|
|
5087
|
-
if (defaultValue.exists && option.defaultValue !== defaultValue.value) {
|
|
5088
|
-
option.default(defaultValue.value);
|
|
5089
|
-
}
|
|
5090
|
-
if (option.flags.includes("<")) {
|
|
5091
|
-
option.makeOptionMandatory();
|
|
5092
|
-
}
|
|
5093
|
-
const enumChoices = getEnumChoices(propertyValue);
|
|
5094
|
-
if (enumChoices?.type === "string_enum") {
|
|
5095
|
-
option.choices(enumChoices.choices);
|
|
5096
|
-
}
|
|
5097
|
-
option.conflicts(
|
|
5098
|
-
incompatiblePairs.flatMap((pair) => {
|
|
5099
|
-
const filtered = pair.filter((p) => p !== propertyKey);
|
|
5100
|
-
if (filtered.length === pair.length) return [];
|
|
5101
|
-
return filtered;
|
|
5102
|
-
})
|
|
3733
|
+
if (argUsed && def.dependencies?.length) {
|
|
3734
|
+
const missingDeps = def.dependencies.filter((d) => {
|
|
3735
|
+
const depVal = parsed[d] ?? defaultMap[d];
|
|
3736
|
+
return !depVal;
|
|
3737
|
+
});
|
|
3738
|
+
if (missingDeps.length > 0) {
|
|
3739
|
+
const depsList = missingDeps.map((d) => `--${d}`).join(", ");
|
|
3740
|
+
throw new Error(
|
|
3741
|
+
`Argument --${key} can only be used when ${depsList} ${missingDeps.length === 1 ? "is" : "are"} set`
|
|
5103
3742
|
);
|
|
5104
|
-
command.addOption(option);
|
|
5105
|
-
if (propertyType === "boolean") negate();
|
|
5106
|
-
};
|
|
5107
|
-
Object.entries(optionJsonSchemaProperties).forEach(addOptionForProperty);
|
|
5108
|
-
const invalidOptionAliases = Object.entries(unusedOptionAliases).map(
|
|
5109
|
-
([option, alias]) => `${option}: ${alias}`
|
|
5110
|
-
);
|
|
5111
|
-
if (invalidOptionAliases.length) {
|
|
5112
|
-
throw new Error(`Invalid option aliases: ${invalidOptionAliases.join(", ")}`);
|
|
5113
3743
|
}
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
return require("@orpc/server");
|
|
5144
|
-
} catch (e) {
|
|
5145
|
-
throw new Error(
|
|
5146
|
-
"@orpc/server dependency could not be found - try installing it and re-running",
|
|
5147
|
-
{ cause: e }
|
|
5148
|
-
);
|
|
5149
|
-
}
|
|
5150
|
-
})();
|
|
5151
|
-
caller = {
|
|
5152
|
-
[procedurePath]: (_input) => call(procedure, _input, { context: params.context })
|
|
5153
|
-
};
|
|
5154
|
-
} else {
|
|
5155
|
-
const createCallerFactor = resolvedTrpcServer.initTRPC.create().createCallerFactory;
|
|
5156
|
-
caller = createCallerFactor(router)(params.context);
|
|
5157
|
-
}
|
|
5158
|
-
const result = await (caller[procedurePath]?.(input)).catch((err) => {
|
|
5159
|
-
throw transformError(err, command);
|
|
5160
|
-
});
|
|
5161
|
-
command.__result = result;
|
|
5162
|
-
if (result != null) logger.info?.(result);
|
|
3744
|
+
}
|
|
3745
|
+
finalArgs[key] = def.type === "boolean" ? Boolean(casted) : casted;
|
|
3746
|
+
}
|
|
3747
|
+
return {
|
|
3748
|
+
args: finalArgs,
|
|
3749
|
+
raw: argv
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
async function createContextFromArgs(command, inputArgs) {
|
|
3753
|
+
const finalArgs = {};
|
|
3754
|
+
for (const [key, def] of Object.entries(command.args || {})) {
|
|
3755
|
+
const inputValue = inputArgs[key];
|
|
3756
|
+
let value;
|
|
3757
|
+
if (inputValue !== void 0) {
|
|
3758
|
+
value = castArgValue$1(def, inputValue, key);
|
|
3759
|
+
} else if (def.default !== void 0) {
|
|
3760
|
+
value = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
|
|
3761
|
+
} else if (def.type === "boolean") {
|
|
3762
|
+
value = false;
|
|
3763
|
+
} else {
|
|
3764
|
+
value = void 0;
|
|
3765
|
+
}
|
|
3766
|
+
if (value == null && def.required) {
|
|
3767
|
+
throw new Error(`Missing required argument: ${key}`);
|
|
3768
|
+
}
|
|
3769
|
+
if (value != null && def.dependencies?.length) {
|
|
3770
|
+
const missingDeps = def.dependencies.filter((d) => {
|
|
3771
|
+
const depVal = inputArgs[d];
|
|
3772
|
+
return !depVal;
|
|
5163
3773
|
});
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
const segment = segments[i];
|
|
5170
|
-
if (!segment) continue;
|
|
5171
|
-
const parentPath2 = currentPath;
|
|
5172
|
-
currentPath = currentPath ? `${currentPath}.${segment}` : segment;
|
|
5173
|
-
if (!commandTree[currentPath]) {
|
|
5174
|
-
const parentCommand2 = commandTree[parentPath2];
|
|
5175
|
-
if (!parentCommand2) continue;
|
|
5176
|
-
const newCommand = new TrpcCommand(kebabCase(segment));
|
|
5177
|
-
newCommand.showHelpAfterError();
|
|
5178
|
-
parentCommand2.addCommand(newCommand);
|
|
5179
|
-
commandTree[currentPath] = newCommand;
|
|
5180
|
-
}
|
|
5181
|
-
}
|
|
5182
|
-
const leafName = segments.at(-1);
|
|
5183
|
-
if (!leafName) return;
|
|
5184
|
-
const parentPath = segments.length > 1 ? segments.slice(0, -1).join(".") : "";
|
|
5185
|
-
const parentCommand = commandTree[parentPath];
|
|
5186
|
-
if (!parentCommand) return;
|
|
5187
|
-
const leafCommand = new TrpcCommand(kebabCase(leafName));
|
|
5188
|
-
configureCommand(leafCommand, procedurePath, commandConfig);
|
|
5189
|
-
parentCommand.addCommand(leafCommand);
|
|
5190
|
-
const meta = commandConfig.meta;
|
|
5191
|
-
if (meta.default === true) {
|
|
5192
|
-
parentCommand.allowExcessArguments();
|
|
5193
|
-
parentCommand.allowUnknownOption();
|
|
5194
|
-
parentCommand.addHelpText("after", leafCommand.helpInformation());
|
|
5195
|
-
parentCommand.action(async () => {
|
|
5196
|
-
await leafCommand.parseAsync([...parentCommand.args], {
|
|
5197
|
-
from: "user"
|
|
5198
|
-
});
|
|
5199
|
-
});
|
|
5200
|
-
defaultCommands[parentPath] = {
|
|
5201
|
-
procedurePath,
|
|
5202
|
-
config: commandConfig,
|
|
5203
|
-
command: leafCommand
|
|
5204
|
-
};
|
|
3774
|
+
if (missingDeps.length > 0) {
|
|
3775
|
+
const depsList = missingDeps.join(", ");
|
|
3776
|
+
throw new Error(
|
|
3777
|
+
`Argument '${key}' can only be used when ${depsList} ${missingDeps.length === 1 ? "is" : "are"} provided`
|
|
3778
|
+
);
|
|
5205
3779
|
}
|
|
5206
|
-
});
|
|
5207
|
-
Object.entries(commandTree).forEach(([path, command]) => {
|
|
5208
|
-
if (command.commands.length === 0) return;
|
|
5209
|
-
const subcommandNames = command.commands.map((cmd) => cmd.name());
|
|
5210
|
-
const defaultCommand = defaultCommands[path]?.command.name();
|
|
5211
|
-
const formattedSubcommands = subcommandNames.map((name) => name === defaultCommand ? `${name} (default)` : name).join(", ");
|
|
5212
|
-
const existingDescription = command.description() || "";
|
|
5213
|
-
const descriptionParts = [
|
|
5214
|
-
existingDescription,
|
|
5215
|
-
`Available subcommands: ${formattedSubcommands}`
|
|
5216
|
-
];
|
|
5217
|
-
command.description(descriptionParts.filter(Boolean).join("\n"));
|
|
5218
|
-
});
|
|
5219
|
-
return program;
|
|
5220
|
-
}
|
|
5221
|
-
const run = async (runParams, program = buildProgram(runParams)) => {
|
|
5222
|
-
if (!looksLikeInstanceof(program, "TrpcCommand"))
|
|
5223
|
-
throw new Error("program is not a TrpcCommand instance");
|
|
5224
|
-
const opts = runParams?.argv ? { from: "user" } : void 0;
|
|
5225
|
-
const argv = [...runParams?.argv || process.argv];
|
|
5226
|
-
const _process = runParams?.process || process;
|
|
5227
|
-
const logger = { ...lineByLineConsoleLogger, ...runParams?.logger };
|
|
5228
|
-
program.exitOverride((exit) => {
|
|
5229
|
-
_process.exit(exit.exitCode);
|
|
5230
|
-
throw new FailedToExitError("Root command exitOverride", {
|
|
5231
|
-
exitCode: exit.exitCode,
|
|
5232
|
-
cause: exit
|
|
5233
|
-
});
|
|
5234
|
-
});
|
|
5235
|
-
program.configureOutput({
|
|
5236
|
-
writeOut: (str) => logger.info?.(str),
|
|
5237
|
-
writeErr: (str) => logger.error?.(str)
|
|
5238
|
-
});
|
|
5239
|
-
if (runParams?.completion) {
|
|
5240
|
-
const completion = typeof runParams.completion === "function" ? await runParams.completion() : runParams.completion;
|
|
5241
|
-
addCompletions(program, completion);
|
|
5242
3780
|
}
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
return err.message;
|
|
5246
|
-
}
|
|
5247
|
-
return inspect(err);
|
|
5248
|
-
});
|
|
5249
|
-
if (runParams?.prompts) {
|
|
5250
|
-
program = promptify(program, runParams.prompts);
|
|
5251
|
-
}
|
|
5252
|
-
await program.parseAsync(argv, opts).catch((err) => {
|
|
5253
|
-
if (err instanceof FailedToExitError) throw err;
|
|
5254
|
-
const logMessage = looksLikeInstanceof(err, Error) ? formatError(err) || err.message : `Non-error of type ${typeof err} thrown: ${err}`;
|
|
5255
|
-
logger.error?.(logMessage);
|
|
5256
|
-
_process.exit(1);
|
|
5257
|
-
throw new FailedToExitError("Program exit after failure", {
|
|
5258
|
-
exitCode: 1,
|
|
5259
|
-
cause: err
|
|
5260
|
-
});
|
|
5261
|
-
});
|
|
5262
|
-
_process.exit(0);
|
|
5263
|
-
throw new FailedToExitError("Program exit after success", {
|
|
5264
|
-
exitCode: 0,
|
|
5265
|
-
cause: program.__ran.at(-1)?.__result
|
|
5266
|
-
});
|
|
5267
|
-
};
|
|
3781
|
+
finalArgs[key] = value;
|
|
3782
|
+
}
|
|
5268
3783
|
return {
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
3784
|
+
args: finalArgs,
|
|
3785
|
+
raw: []
|
|
3786
|
+
// No raw argv for object input
|
|
5272
3787
|
};
|
|
5273
3788
|
}
|
|
5274
|
-
function
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
function kebabCase(propName) {
|
|
5279
|
-
return propName.replaceAll(/([A-Z])/g, "-$1").toLowerCase();
|
|
5280
|
-
}
|
|
5281
|
-
function transformError(err, command) {
|
|
5282
|
-
if (looksLikeInstanceof(err, Error) && err.message.includes("This is a client-only function")) {
|
|
5283
|
-
return new Error(
|
|
5284
|
-
"Failed to create trpc caller. If using trpc v10, either upgrade to v11 or pass in the `@trpc/server` module to `createRpcCli` explicitly"
|
|
5285
|
-
);
|
|
5286
|
-
}
|
|
5287
|
-
if (looksLikeInstanceof(err, "TRPCError")) {
|
|
5288
|
-
const cause = err.cause;
|
|
5289
|
-
if (looksLikeStandardSchemaFailure(cause)) {
|
|
5290
|
-
const prettyMessage = prettifyStandardSchemaError(cause);
|
|
5291
|
-
return new CliValidationError(`${prettyMessage}
|
|
5292
|
-
|
|
5293
|
-
${command.helpInformation()}`);
|
|
3789
|
+
function castArgValue$1(def, rawVal, argName) {
|
|
3790
|
+
if (rawVal == null) {
|
|
3791
|
+
if (def.type === "array" && typeof def.default === "string") {
|
|
3792
|
+
return [def.default];
|
|
5294
3793
|
}
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
3794
|
+
return def.default ?? void 0;
|
|
3795
|
+
}
|
|
3796
|
+
let castedValue;
|
|
3797
|
+
switch (def.type) {
|
|
3798
|
+
case "boolean":
|
|
3799
|
+
if (typeof rawVal === "string") {
|
|
3800
|
+
const lower = rawVal.toLowerCase();
|
|
3801
|
+
if (lower === "true") castedValue = true;
|
|
3802
|
+
else if (lower === "false") castedValue = false;
|
|
3803
|
+
else castedValue = Boolean(rawVal);
|
|
3804
|
+
} else {
|
|
3805
|
+
castedValue = Boolean(rawVal);
|
|
3806
|
+
}
|
|
3807
|
+
if (def.allowed && !def.allowed.includes(castedValue)) {
|
|
3808
|
+
throw new Error(
|
|
3809
|
+
`Invalid value for ${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
|
|
3810
|
+
);
|
|
3811
|
+
}
|
|
3812
|
+
return castedValue;
|
|
3813
|
+
case "string":
|
|
3814
|
+
castedValue = typeof rawVal === "string" ? rawVal : String(rawVal);
|
|
3815
|
+
if (def.allowed && !def.allowed.includes(castedValue)) {
|
|
3816
|
+
throw new Error(
|
|
3817
|
+
`Invalid value for ${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
return castedValue;
|
|
3821
|
+
case "number": {
|
|
3822
|
+
const n = Number(rawVal);
|
|
3823
|
+
if (Number.isNaN(n)) {
|
|
3824
|
+
throw new Error(`Invalid number provided for ${argName}: ${rawVal}`);
|
|
3825
|
+
}
|
|
3826
|
+
if (def.allowed && !def.allowed.includes(n)) {
|
|
3827
|
+
throw new Error(
|
|
3828
|
+
`Invalid value for ${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
|
|
3829
|
+
);
|
|
3830
|
+
}
|
|
3831
|
+
return n;
|
|
5300
3832
|
}
|
|
5301
|
-
|
|
5302
|
-
|
|
3833
|
+
case "positional":
|
|
3834
|
+
castedValue = String(rawVal);
|
|
3835
|
+
if (def.allowed && !def.allowed.includes(castedValue)) {
|
|
3836
|
+
throw new Error(
|
|
3837
|
+
`Invalid value for ${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3840
|
+
return castedValue;
|
|
3841
|
+
case "array": {
|
|
3842
|
+
const arrVal = Array.isArray(rawVal) ? rawVal : [String(rawVal)];
|
|
3843
|
+
const result = [];
|
|
3844
|
+
for (let v of arrVal.map(String)) {
|
|
3845
|
+
if (v.startsWith("[") && v.endsWith("]")) {
|
|
3846
|
+
v = v.slice(1, -1);
|
|
3847
|
+
}
|
|
3848
|
+
const parts = v.split(/\s*,\s*/).filter(Boolean);
|
|
3849
|
+
for (const p of parts) {
|
|
3850
|
+
if (def.allowed && !def.allowed.includes(p)) {
|
|
3851
|
+
throw new Error(
|
|
3852
|
+
`Invalid value in array ${argName}: ${p}. Allowed values are: ${def.allowed.join(", ")}`
|
|
3853
|
+
);
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
result.push(...parts);
|
|
3857
|
+
}
|
|
3858
|
+
return result;
|
|
5303
3859
|
}
|
|
3860
|
+
default:
|
|
3861
|
+
return rawVal;
|
|
5304
3862
|
}
|
|
5305
|
-
return err;
|
|
5306
3863
|
}
|
|
5307
|
-
const numberParser = (val, { fallback = val } = {}) => {
|
|
5308
|
-
const number = Number(val);
|
|
5309
|
-
return Number.isNaN(number) ? fallback : number;
|
|
5310
|
-
};
|
|
5311
|
-
const booleanParser = (val, { fallback = val } = {}) => {
|
|
5312
|
-
if (val === "true") return true;
|
|
5313
|
-
if (val === "false") return false;
|
|
5314
|
-
return fallback;
|
|
5315
|
-
};
|
|
5316
3864
|
|
|
3865
|
+
async function pathExists(path2) {
|
|
3866
|
+
try {
|
|
3867
|
+
await stat(path2);
|
|
3868
|
+
return true;
|
|
3869
|
+
} catch (error) {
|
|
3870
|
+
return false;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
5317
3873
|
function buildExampleArgs(args) {
|
|
5318
3874
|
const parts = [];
|
|
5319
3875
|
const positionalKeys = Object.keys(args || {}).filter((k) => args?.[k]?.type === "positional");
|
|
@@ -5376,7 +3932,6 @@ function defineCommand(options) {
|
|
|
5376
3932
|
onCmdExit,
|
|
5377
3933
|
onLauncherInit,
|
|
5378
3934
|
onLauncherExit,
|
|
5379
|
-
router: options.router,
|
|
5380
3935
|
// Backward-compatible aliases
|
|
5381
3936
|
setup: onCmdInit,
|
|
5382
3937
|
cleanup: onCmdExit
|
|
@@ -5410,7 +3965,7 @@ async function getDefaultCliNameAndVersion() {
|
|
|
5410
3965
|
}
|
|
5411
3966
|
async function findRecursiveFileBasedCommands(baseDir, currentPath = []) {
|
|
5412
3967
|
const results = [];
|
|
5413
|
-
const items = await
|
|
3968
|
+
const items = await readdir(path.join(baseDir, ...currentPath), {
|
|
5414
3969
|
withFileTypes: true
|
|
5415
3970
|
});
|
|
5416
3971
|
for (const dirent of items) {
|
|
@@ -5418,7 +3973,7 @@ async function findRecursiveFileBasedCommands(baseDir, currentPath = []) {
|
|
|
5418
3973
|
const newPath = [...currentPath, dirent.name];
|
|
5419
3974
|
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
5420
3975
|
const fpath = path.join(baseDir, ...newPath, fname);
|
|
5421
|
-
if (await
|
|
3976
|
+
if (await pathExists(fpath)) {
|
|
5422
3977
|
try {
|
|
5423
3978
|
const imported = await import(path.resolve(fpath));
|
|
5424
3979
|
if (imported.default && !imported.default.meta?.hidden) {
|
|
@@ -5676,84 +4231,6 @@ function createCli(options, legacyParserOptions) {
|
|
|
5676
4231
|
};
|
|
5677
4232
|
}
|
|
5678
4233
|
const execute = async (_ctx) => {
|
|
5679
|
-
if (options && typeof options === "object" && "rpc" in options && options.rpc) {
|
|
5680
|
-
const rpcOptions = options.rpc;
|
|
5681
|
-
const rpcRunParams = options.rpcRunParams || {};
|
|
5682
|
-
debugLog("RPC integration detected, creating RPC CLI...");
|
|
5683
|
-
try {
|
|
5684
|
-
require("tsx/cjs");
|
|
5685
|
-
await import('tsx/esm');
|
|
5686
|
-
debugLog("tsx loaded successfully for TypeScript support");
|
|
5687
|
-
} catch {
|
|
5688
|
-
debugLog("tsx not available, continuing without TypeScript support");
|
|
5689
|
-
}
|
|
5690
|
-
const getRouterMeta = (router) => {
|
|
5691
|
-
if ("_def" in router && router._def && "meta" in router._def) {
|
|
5692
|
-
return router._def.meta;
|
|
5693
|
-
}
|
|
5694
|
-
return;
|
|
5695
|
-
};
|
|
5696
|
-
const routerMeta = getRouterMeta(rpcOptions.router);
|
|
5697
|
-
const rpcCli = createRpcCli({
|
|
5698
|
-
router: rpcOptions.router,
|
|
5699
|
-
name: globalCliMeta.name || routerMeta?.name,
|
|
5700
|
-
version: globalCliMeta.version || routerMeta?.version,
|
|
5701
|
-
description: globalCliMeta.description || routerMeta?.description,
|
|
5702
|
-
usage: rpcOptions.usage,
|
|
5703
|
-
context: rpcOptions.context,
|
|
5704
|
-
trpcServer: rpcOptions.trpcServer,
|
|
5705
|
-
"@valibot/to-json-schema": rpcOptions["@valibot/to-json-schema"],
|
|
5706
|
-
effect: rpcOptions.effect
|
|
5707
|
-
});
|
|
5708
|
-
debugLog("RPC CLI created, running with argv:", rpcRunParams.argv || process$1.argv.slice(2));
|
|
5709
|
-
await rpcCli.run({
|
|
5710
|
-
argv: rpcRunParams.argv || process$1.argv.slice(2),
|
|
5711
|
-
logger: rpcRunParams.logger || {
|
|
5712
|
-
info: console.log,
|
|
5713
|
-
error: console.error
|
|
5714
|
-
},
|
|
5715
|
-
completion: rpcRunParams.completion,
|
|
5716
|
-
prompts: rpcRunParams.prompts,
|
|
5717
|
-
formatError: rpcRunParams.formatError,
|
|
5718
|
-
process: rpcRunParams.process
|
|
5719
|
-
});
|
|
5720
|
-
return;
|
|
5721
|
-
}
|
|
5722
|
-
if (command.router) {
|
|
5723
|
-
debugLog("Router detected in command, automatically enabling RPC mode...");
|
|
5724
|
-
try {
|
|
5725
|
-
require("tsx/cjs");
|
|
5726
|
-
await import('tsx/esm');
|
|
5727
|
-
debugLog("tsx loaded successfully for TypeScript support");
|
|
5728
|
-
} catch {
|
|
5729
|
-
debugLog("tsx not available, continuing without TypeScript support");
|
|
5730
|
-
}
|
|
5731
|
-
const getRouterMeta = (router) => {
|
|
5732
|
-
if ("_def" in router && router._def && "meta" in router._def) {
|
|
5733
|
-
return router._def.meta;
|
|
5734
|
-
}
|
|
5735
|
-
return;
|
|
5736
|
-
};
|
|
5737
|
-
const routerMeta = getRouterMeta(command.router);
|
|
5738
|
-
const rpcCli = createRpcCli({
|
|
5739
|
-
router: command.router,
|
|
5740
|
-
name: globalCliMeta.name || command.meta?.name || routerMeta?.name,
|
|
5741
|
-
version: globalCliMeta.version || command.meta?.version || routerMeta?.version,
|
|
5742
|
-
description: globalCliMeta.description || command.meta?.description || routerMeta?.description
|
|
5743
|
-
});
|
|
5744
|
-
debugLog("RPC CLI created from command router, running with argv:", process$1.argv.slice(2));
|
|
5745
|
-
await rpcCli.run({
|
|
5746
|
-
argv: process$1.argv.slice(2),
|
|
5747
|
-
logger: {
|
|
5748
|
-
info: console.log,
|
|
5749
|
-
error: console.error
|
|
5750
|
-
},
|
|
5751
|
-
process: {
|
|
5752
|
-
exit: process$1.exit
|
|
5753
|
-
}
|
|
5754
|
-
});
|
|
5755
|
-
return;
|
|
5756
|
-
}
|
|
5757
4234
|
if (typeof command.onLauncherInit === "function") {
|
|
5758
4235
|
try {
|
|
5759
4236
|
await command.onLauncherInit();
|
|
@@ -5767,7 +4244,7 @@ function createCli(options, legacyParserOptions) {
|
|
|
5767
4244
|
if (!parserOptions.fileBased && !command.commands) {
|
|
5768
4245
|
const mainEntry = process$1.argv[1] ? path.dirname(path.resolve(process$1.argv[1])) : process$1.cwd();
|
|
5769
4246
|
const defaultCmdsRoot = path.join(mainEntry, "src", "app");
|
|
5770
|
-
const exists = await
|
|
4247
|
+
const exists = await pathExists(defaultCmdsRoot);
|
|
5771
4248
|
const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
|
|
5772
4249
|
parserOptions.fileBased = {
|
|
5773
4250
|
enable: true,
|
|
@@ -5776,10 +4253,10 @@ function createCli(options, legacyParserOptions) {
|
|
|
5776
4253
|
}
|
|
5777
4254
|
const rawArgv = process$1.argv.slice(2);
|
|
5778
4255
|
const autoExit = parserOptions.autoExit !== false;
|
|
5779
|
-
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)) {
|
|
5780
4257
|
relinka(
|
|
5781
4258
|
"error",
|
|
5782
|
-
"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."
|
|
5783
4260
|
);
|
|
5784
4261
|
process$1.exit(1);
|
|
5785
4262
|
}
|
|
@@ -5961,7 +4438,7 @@ async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, par
|
|
|
5961
4438
|
if (args.length === 0 || args[0] && isFlag(args[0])) {
|
|
5962
4439
|
const possibleFiles2 = [path.join(baseDir, "cmd.js"), path.join(baseDir, "cmd.ts")];
|
|
5963
4440
|
for (const file of possibleFiles2) {
|
|
5964
|
-
if (await
|
|
4441
|
+
if (await pathExists(file)) {
|
|
5965
4442
|
return { importPath: file, leftoverArgv: args };
|
|
5966
4443
|
}
|
|
5967
4444
|
}
|
|
@@ -5973,12 +4450,12 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
5973
4450
|
);
|
|
5974
4451
|
}
|
|
5975
4452
|
const nextDir = path.join(baseDir, args[0] || "");
|
|
5976
|
-
if (await
|
|
4453
|
+
if (await pathExists(nextDir) && (await stat(nextDir)).isDirectory()) {
|
|
5977
4454
|
return resolveCmdPath(nextDir, args.slice(1));
|
|
5978
4455
|
}
|
|
5979
4456
|
const possibleFiles = [path.join(baseDir, "cmd.js"), path.join(baseDir, "cmd.ts")];
|
|
5980
4457
|
for (const file of possibleFiles) {
|
|
5981
|
-
if (await
|
|
4458
|
+
if (await pathExists(file)) {
|
|
5982
4459
|
return { importPath: file, leftoverArgv: args };
|
|
5983
4460
|
}
|
|
5984
4461
|
}
|
|
@@ -5990,7 +4467,7 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
5990
4467
|
);
|
|
5991
4468
|
}
|
|
5992
4469
|
const startDir = path.join(fileCmdOpts.cmdsRootPath, subName);
|
|
5993
|
-
if (!await
|
|
4470
|
+
if (!await pathExists(startDir) || !(await stat(startDir)).isDirectory()) {
|
|
5994
4471
|
const attempted = [subName, ...argv].join(" ");
|
|
5995
4472
|
const expectedPath = path.relative(
|
|
5996
4473
|
process$1.cwd(),
|
|
@@ -6113,7 +4590,7 @@ async function runCommandWithArgs(command, argv, parserOptions, globalCliMeta, r
|
|
|
6113
4590
|
if (command.run) {
|
|
6114
4591
|
await command.run(ctx);
|
|
6115
4592
|
} else {
|
|
6116
|
-
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;
|
|
6117
4594
|
const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
|
|
6118
4595
|
if (isDispatcher && noSubcommandArgInCurrentCall) {
|
|
6119
4596
|
relinka("warn", "Please specify a command");
|
|
@@ -6250,110 +4727,6 @@ function normalizeArgv(argv) {
|
|
|
6250
4727
|
}
|
|
6251
4728
|
return normalized;
|
|
6252
4729
|
}
|
|
6253
|
-
async function runCmdWithSubcommands(command, argv = [], parserOptions = {}) {
|
|
6254
|
-
const normalizedArgv = normalizeArgv(argv);
|
|
6255
|
-
let currentCommand = command;
|
|
6256
|
-
let currentArgv = normalizedArgv;
|
|
6257
|
-
while (currentCommand.commands && currentArgv.length > 0 && currentArgv[0] && !isFlag(currentArgv[0])) {
|
|
6258
|
-
const [maybeSub, ...restArgv] = currentArgv;
|
|
6259
|
-
let subSpec;
|
|
6260
|
-
for (const [key, spec] of Object.entries(currentCommand.commands)) {
|
|
6261
|
-
if (key === maybeSub) {
|
|
6262
|
-
subSpec = spec;
|
|
6263
|
-
break;
|
|
6264
|
-
}
|
|
6265
|
-
try {
|
|
6266
|
-
const cmd = await loadSubCommand(spec);
|
|
6267
|
-
if (cmd.meta?.aliases?.includes(maybeSub)) {
|
|
6268
|
-
subSpec = spec;
|
|
6269
|
-
break;
|
|
6270
|
-
}
|
|
6271
|
-
} catch (err) {
|
|
6272
|
-
debugLog(`Error checking alias for command ${key}:`, err);
|
|
6273
|
-
}
|
|
6274
|
-
}
|
|
6275
|
-
if (!subSpec) break;
|
|
6276
|
-
const loaded = await loadSubCommand(subSpec);
|
|
6277
|
-
currentCommand = loaded;
|
|
6278
|
-
currentArgv = restArgv;
|
|
6279
|
-
}
|
|
6280
|
-
return await runCommandWithArgs(currentCommand, currentArgv, {
|
|
6281
|
-
...parserOptions,
|
|
6282
|
-
autoExit: false
|
|
6283
|
-
// Don't exit process in programmatic usage
|
|
6284
|
-
});
|
|
6285
|
-
}
|
|
6286
|
-
async function runCmd(command, argv = [], parserOptions = {}) {
|
|
6287
|
-
const normalizedArgv = normalizeArgv(argv);
|
|
6288
|
-
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
6289
|
-
(k) => command.args?.[k]?.type === "boolean"
|
|
6290
|
-
);
|
|
6291
|
-
const defaultMap = {};
|
|
6292
|
-
for (const [argKey, def] of Object.entries(command.args || {})) {
|
|
6293
|
-
if (def.type === "boolean") {
|
|
6294
|
-
defaultMap[argKey] = def.default !== void 0 ? def.default : false;
|
|
6295
|
-
} else if (def.default !== void 0) {
|
|
6296
|
-
defaultMap[argKey] = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
|
|
6297
|
-
}
|
|
6298
|
-
}
|
|
6299
|
-
const mergedParserOptions = {
|
|
6300
|
-
...parserOptions,
|
|
6301
|
-
boolean: [...parserOptions.boolean || [], ...booleanKeys],
|
|
6302
|
-
defaults: { ...defaultMap, ...parserOptions.defaults || {} }
|
|
6303
|
-
};
|
|
6304
|
-
const parsed = reliArgParser(normalizedArgv, mergedParserOptions);
|
|
6305
|
-
debugLog("Parsed arguments (runCmd):", parsed);
|
|
6306
|
-
const finalArgs = {};
|
|
6307
|
-
const positionalKeys = Object.keys(command.args || {}).filter(
|
|
6308
|
-
(k) => command.args?.[k]?.type === "positional"
|
|
6309
|
-
);
|
|
6310
|
-
const leftoverPositionals = [...parsed._ || []];
|
|
6311
|
-
for (let i = 0; i < positionalKeys.length; i++) {
|
|
6312
|
-
const key = positionalKeys[i];
|
|
6313
|
-
if (!key || !command.args) continue;
|
|
6314
|
-
const def = command.args[key];
|
|
6315
|
-
const val = leftoverPositionals[i];
|
|
6316
|
-
finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
|
|
6317
|
-
}
|
|
6318
|
-
const otherKeys = Object.keys(command.args || {}).filter(
|
|
6319
|
-
(k) => command.args?.[k]?.type !== "positional"
|
|
6320
|
-
);
|
|
6321
|
-
for (const key of otherKeys) {
|
|
6322
|
-
const def = command.args?.[key];
|
|
6323
|
-
if (!def) continue;
|
|
6324
|
-
let rawVal = parsed[key];
|
|
6325
|
-
if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
|
|
6326
|
-
rawVal = [rawVal];
|
|
6327
|
-
}
|
|
6328
|
-
const casted = rawVal !== void 0 ? castArgValue(def, rawVal, key) : def.default;
|
|
6329
|
-
const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
|
|
6330
|
-
if (casted == null && def.required) {
|
|
6331
|
-
throw new Error(`Missing required argument: --${key}`);
|
|
6332
|
-
}
|
|
6333
|
-
if (argUsed && def.dependencies?.length) {
|
|
6334
|
-
const missingDeps = def.dependencies.filter((d) => {
|
|
6335
|
-
const depVal = parsed[d] ?? defaultMap[d];
|
|
6336
|
-
return !depVal;
|
|
6337
|
-
});
|
|
6338
|
-
if (missingDeps.length) {
|
|
6339
|
-
const depsList = missingDeps.map((d) => `--${d}`).join(", ");
|
|
6340
|
-
throw new Error(
|
|
6341
|
-
`Argument --${key} can only be used when ${depsList} ${missingDeps.length === 1 ? "is" : "are"} set`
|
|
6342
|
-
);
|
|
6343
|
-
}
|
|
6344
|
-
}
|
|
6345
|
-
finalArgs[key] = def.type === "boolean" ? Boolean(casted) : casted;
|
|
6346
|
-
}
|
|
6347
|
-
const ctx = {
|
|
6348
|
-
args: finalArgs,
|
|
6349
|
-
raw: argv
|
|
6350
|
-
};
|
|
6351
|
-
if (typeof command.run === "function") {
|
|
6352
|
-
await command.run(ctx);
|
|
6353
|
-
} else {
|
|
6354
|
-
throw new Error("Command has no run() handler.");
|
|
6355
|
-
}
|
|
6356
|
-
}
|
|
6357
4730
|
function getParsedContext(command, argv, parserOptions) {
|
|
6358
4731
|
const normalizedArgv = normalizeArgv(argv);
|
|
6359
4732
|
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
@@ -6409,7 +4782,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
|
6409
4782
|
let leftover = [...argv];
|
|
6410
4783
|
while (leftover.length > 0 && leftover[0] && !isFlag(leftover[0])) {
|
|
6411
4784
|
const nextDir = path.join(currentDir, leftover[0]);
|
|
6412
|
-
if (await
|
|
4785
|
+
if (await pathExists(nextDir) && (await stat(nextDir)).isDirectory()) {
|
|
6413
4786
|
currentDir = nextDir;
|
|
6414
4787
|
pathSegments.push(leftover[0]);
|
|
6415
4788
|
leftover = leftover.slice(1);
|
|
@@ -6419,7 +4792,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
|
6419
4792
|
}
|
|
6420
4793
|
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
6421
4794
|
const fpath = path.join(currentDir, fname);
|
|
6422
|
-
if (await
|
|
4795
|
+
if (await pathExists(fpath)) {
|
|
6423
4796
|
const imported = await import(path.resolve(fpath));
|
|
6424
4797
|
if (imported.default) {
|
|
6425
4798
|
return {
|
|
@@ -6461,65 +4834,6 @@ function levenshteinDistance(a, b) {
|
|
|
6461
4834
|
return matrix[b.length][a.length];
|
|
6462
4835
|
}
|
|
6463
4836
|
|
|
6464
|
-
function argsToStringArray(args) {
|
|
6465
|
-
const result = [];
|
|
6466
|
-
for (const [key, value] of Object.entries(args)) {
|
|
6467
|
-
if (value === void 0 || value === null) continue;
|
|
6468
|
-
if (typeof value === "boolean") {
|
|
6469
|
-
result.push(`--${key}=${value}`);
|
|
6470
|
-
} else if (Array.isArray(value)) {
|
|
6471
|
-
result.push(`--${key}=${value.join(",")}`);
|
|
6472
|
-
} else {
|
|
6473
|
-
result.push(`--${key}=${String(value)}`);
|
|
6474
|
-
}
|
|
6475
|
-
}
|
|
6476
|
-
return result;
|
|
6477
|
-
}
|
|
6478
|
-
async function createCallCmd() {
|
|
6479
|
-
return async function callCmd(cmdName, args) {
|
|
6480
|
-
try {
|
|
6481
|
-
const command = await loadCommand(cmdName);
|
|
6482
|
-
const stringArgs = args ? argsToStringArray(args) : [];
|
|
6483
|
-
await runCmd(command, stringArgs);
|
|
6484
|
-
} catch (error) {
|
|
6485
|
-
console.error(`Error running command '${String(cmdName)}':`, error);
|
|
6486
|
-
throw error;
|
|
6487
|
-
}
|
|
6488
|
-
};
|
|
6489
|
-
}
|
|
6490
|
-
async function createGetTypedCmd() {
|
|
6491
|
-
return async function getTypedCmd(cmdName) {
|
|
6492
|
-
const command = await loadCommand(cmdName);
|
|
6493
|
-
return {
|
|
6494
|
-
command,
|
|
6495
|
-
run: async (args) => {
|
|
6496
|
-
const stringArgs = args ? argsToStringArray(args) : [];
|
|
6497
|
-
await runCmd(command, stringArgs);
|
|
6498
|
-
}
|
|
6499
|
-
};
|
|
6500
|
-
};
|
|
6501
|
-
}
|
|
6502
|
-
async function callCmdImpl(cmdName, args) {
|
|
6503
|
-
try {
|
|
6504
|
-
const command = await loadCommand(cmdName);
|
|
6505
|
-
const stringArgs = args ? argsToStringArray(args) : [];
|
|
6506
|
-
await runCmd(command, stringArgs);
|
|
6507
|
-
} catch (error) {
|
|
6508
|
-
console.error(`Error running command '${String(cmdName)}':`, error);
|
|
6509
|
-
throw error;
|
|
6510
|
-
}
|
|
6511
|
-
}
|
|
6512
|
-
async function getTypedCmdImpl(cmdName) {
|
|
6513
|
-
const command = await loadCommand(cmdName);
|
|
6514
|
-
return {
|
|
6515
|
-
command,
|
|
6516
|
-
run: async (args) => {
|
|
6517
|
-
const stringArgs = args ? argsToStringArray(args) : [];
|
|
6518
|
-
await runCmd(command, stringArgs);
|
|
6519
|
-
}
|
|
6520
|
-
};
|
|
6521
|
-
}
|
|
6522
|
-
|
|
6523
4837
|
const runMain = createCli;
|
|
6524
4838
|
|
|
6525
4839
|
const log = relinka;
|
|
@@ -8462,4 +6776,4 @@ function normalizeName(name) {
|
|
|
8462
6776
|
return lastSegment.replace(/[^a-zA-Z0-9-]/g, "");
|
|
8463
6777
|
}
|
|
8464
6778
|
|
|
8465
|
-
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 };
|