@kaynooo/pkg-tools 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/dist/cli.js +664 -304
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -418,6 +418,29 @@ var init_format = __esm(() => {
|
|
|
418
418
|
ESCAPE = String.fromCharCode(27);
|
|
419
419
|
});
|
|
420
420
|
|
|
421
|
+
// ../kit/src/text.ts
|
|
422
|
+
function distance(a, b) {
|
|
423
|
+
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
424
|
+
for (const [i, left] of [...a].entries()) {
|
|
425
|
+
const current = [i + 1];
|
|
426
|
+
for (const [j, right] of [...b].entries())
|
|
427
|
+
current.push(Math.min((previous[j + 1] ?? 0) + 1, (current[j] ?? 0) + 1, (previous[j] ?? 0) + (left === right ? 0 : 1)));
|
|
428
|
+
previous = current;
|
|
429
|
+
}
|
|
430
|
+
return previous[b.length] ?? 0;
|
|
431
|
+
}
|
|
432
|
+
function closest(name, names) {
|
|
433
|
+
const started = names.find((known) => known.startsWith(name));
|
|
434
|
+
if (started !== undefined)
|
|
435
|
+
return started;
|
|
436
|
+
const [best] = names.map((known) => ({ known, far: distance(name, known) })).sort((a, b) => a.far - b.far);
|
|
437
|
+
return best !== undefined && best.far <= (name.length < 4 ? 1 : 2) ? best.known : undefined;
|
|
438
|
+
}
|
|
439
|
+
var ANSI;
|
|
440
|
+
var init_text = __esm(() => {
|
|
441
|
+
ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
|
|
442
|
+
});
|
|
443
|
+
|
|
421
444
|
// ../kit/src/args.ts
|
|
422
445
|
import process3 from "process";
|
|
423
446
|
import { parseArgs } from "util";
|
|
@@ -473,10 +496,10 @@ function optionRows(options, colors = paint(process3.stdout)) {
|
|
|
473
496
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
474
497
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
475
498
|
const value = option.type === "string" ? ` ${colors.dim("<value>")}` : "";
|
|
476
|
-
return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? " <value>".length : 0), description: option.description };
|
|
499
|
+
return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? " <value>".length : 0), description: option.description ?? "" };
|
|
477
500
|
});
|
|
478
501
|
const width = Math.max(0, ...rows.map((row) => row.width));
|
|
479
|
-
return rows.map((row) => ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
|
|
502
|
+
return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
|
|
480
503
|
}
|
|
481
504
|
function applyOutput(color, plain, env = process3.env) {
|
|
482
505
|
const when = plain === true ? "never" : color ?? "auto";
|
|
@@ -504,7 +527,8 @@ function parse(args, usage, options, settings = {}) {
|
|
|
504
527
|
try {
|
|
505
528
|
parsed = parseArgs({ args: joinDashValues(own, all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
|
|
506
529
|
} catch (error) {
|
|
507
|
-
|
|
530
|
+
const message = parseError(error);
|
|
531
|
+
throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
|
|
508
532
|
}
|
|
509
533
|
const values = parsed.values;
|
|
510
534
|
applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
|
|
@@ -547,12 +571,27 @@ function parseError(error) {
|
|
|
547
571
|
const message = upTo(error instanceof Error ? error.message : String(error), ". ");
|
|
548
572
|
return `${message.charAt(0).toLowerCase()}${message.slice(1)}`;
|
|
549
573
|
}
|
|
574
|
+
function nearestOption(message, options, allowNegative) {
|
|
575
|
+
const typed = UNKNOWN_OPTION.exec(message)?.[1];
|
|
576
|
+
if (typed === undefined)
|
|
577
|
+
return;
|
|
578
|
+
const word = typed.replace(DASHES, "");
|
|
579
|
+
if (word.length < 2 && !typed.startsWith("--"))
|
|
580
|
+
return;
|
|
581
|
+
const known = Object.entries(options).flatMap(([name, option]) => [
|
|
582
|
+
...option.short === undefined ? [] : [`-${option.short}`],
|
|
583
|
+
`--${name}`,
|
|
584
|
+
...allowNegative && option.type === "boolean" ? [`--no-${name}`] : []
|
|
585
|
+
]);
|
|
586
|
+
const meant = closest(word, known.map((flag) => flag.replace(DASHES, "")));
|
|
587
|
+
return meant === undefined ? undefined : `did you mean ${known.find((flag) => flag.replace(DASHES, "") === meant)}?`;
|
|
588
|
+
}
|
|
550
589
|
function wholeNumber(value, name, fallback, min = 1) {
|
|
551
590
|
if (value === undefined)
|
|
552
591
|
return fallback;
|
|
553
592
|
const number = Number(value);
|
|
554
|
-
if (!Number.
|
|
555
|
-
badUsage(`--${name} takes a whole number from ${min}, not ${value}`);
|
|
593
|
+
if (!WHOLE.test(value) || !Number.isSafeInteger(number) || number < min)
|
|
594
|
+
badUsage(`${name.startsWith("<") ? name : `--${name}`} takes a whole number from ${min}, not ${value}`);
|
|
556
595
|
return number;
|
|
557
596
|
}
|
|
558
597
|
function duration(value, name, fallback, unit = "s") {
|
|
@@ -564,10 +603,11 @@ function duration(value, name, fallback, unit = "s") {
|
|
|
564
603
|
badUsage(`--${name} takes a duration such as 30s, 5m or 1h, not ${value}`);
|
|
565
604
|
return ms;
|
|
566
605
|
}
|
|
567
|
-
var Exit, UsageError, HelpShown, completion, OPTIONAL, USAGE_PREFIX, FULL_STOP, OUTPUT_OPTIONS, DURATION, UNIT_MS;
|
|
606
|
+
var Exit, UsageError, HelpShown, completion, OPTIONAL, USAGE_PREFIX, FULL_STOP, DASHES, OUTPUT_OPTIONS, UNKNOWN_OPTION, WHOLE, DURATION, UNIT_MS;
|
|
568
607
|
var init_args = __esm(() => {
|
|
569
608
|
init_format();
|
|
570
609
|
init_style();
|
|
610
|
+
init_text();
|
|
571
611
|
Exit = class Exit extends Error {
|
|
572
612
|
code;
|
|
573
613
|
hint;
|
|
@@ -578,8 +618,8 @@ var init_args = __esm(() => {
|
|
|
578
618
|
}
|
|
579
619
|
};
|
|
580
620
|
UsageError = class UsageError extends Exit {
|
|
581
|
-
constructor(message) {
|
|
582
|
-
super(message, 2);
|
|
621
|
+
constructor(message, hint) {
|
|
622
|
+
super(message, 2, hint);
|
|
583
623
|
}
|
|
584
624
|
};
|
|
585
625
|
HelpShown = class HelpShown extends Exit {
|
|
@@ -591,10 +631,13 @@ var init_args = __esm(() => {
|
|
|
591
631
|
OPTIONAL = /\[[^\]]+\]/g;
|
|
592
632
|
USAGE_PREFIX = /^usage:\s*/i;
|
|
593
633
|
FULL_STOP = /\.$/;
|
|
634
|
+
DASHES = /^-+/;
|
|
594
635
|
OUTPUT_OPTIONS = {
|
|
595
636
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
596
637
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
597
638
|
};
|
|
639
|
+
UNKNOWN_OPTION = /^unknown option '(-[^']+)'/;
|
|
640
|
+
WHOLE = /^\d+$/;
|
|
598
641
|
DURATION = /^(\d+(?:\.\d+)?)(ms|[smh])?$/;
|
|
599
642
|
UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000 };
|
|
600
643
|
});
|
|
@@ -605,31 +648,265 @@ var init_chart = __esm(() => {
|
|
|
605
648
|
init_style();
|
|
606
649
|
});
|
|
607
650
|
|
|
608
|
-
// ../kit/src/
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
651
|
+
// ../kit/src/process.ts
|
|
652
|
+
import { constants } from "os";
|
|
653
|
+
import process4 from "process";
|
|
654
|
+
function exitCodeOf(code, signal) {
|
|
655
|
+
if (code !== null)
|
|
656
|
+
return code;
|
|
657
|
+
if (typeof signal === "number")
|
|
658
|
+
return 128 + signal;
|
|
659
|
+
return signal === null ? 129 : 128 + constants.signals[signal];
|
|
660
|
+
}
|
|
661
|
+
function holdSignals(cleanup) {
|
|
662
|
+
let received;
|
|
663
|
+
let child;
|
|
664
|
+
const held = {
|
|
665
|
+
get signal() {
|
|
666
|
+
return received;
|
|
667
|
+
},
|
|
668
|
+
forward: (to) => {
|
|
669
|
+
child = to;
|
|
670
|
+
},
|
|
671
|
+
release: () => {
|
|
672
|
+
for (const signal of SIGNALS)
|
|
673
|
+
process4.off(signal, onSignal);
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
function onSignal(signal) {
|
|
677
|
+
received = signal;
|
|
678
|
+
if (child !== undefined) {
|
|
679
|
+
child.kill(signal);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (cleanup === undefined)
|
|
683
|
+
return;
|
|
684
|
+
held.release();
|
|
685
|
+
cleanup(signal);
|
|
686
|
+
process4.kill(process4.pid, signal);
|
|
616
687
|
}
|
|
617
|
-
|
|
688
|
+
for (const signal of SIGNALS)
|
|
689
|
+
process4.on(signal, onSignal);
|
|
690
|
+
return held;
|
|
618
691
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
692
|
+
async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal, maxBytes = Infinity, onChunk, onStart } = {}) {
|
|
693
|
+
const chunks = [];
|
|
694
|
+
const grouped = timeoutMs !== undefined || signal !== undefined || onStart !== undefined || onChunk !== undefined;
|
|
695
|
+
const proc = Bun.spawn(argv, { ...cwd === undefined ? {} : { cwd }, ...env === undefined ? {} : { env }, stdin, stdout: "pipe", stderr: "pipe", ...grouped ? { detached: true } : {} });
|
|
696
|
+
const state = { kept: 0, truncated: false, timedOut: false, failure: undefined, done: false };
|
|
697
|
+
const timers = [];
|
|
698
|
+
const killGroup = (killing) => {
|
|
699
|
+
if (state.done)
|
|
700
|
+
return;
|
|
701
|
+
try {
|
|
702
|
+
if (grouped)
|
|
703
|
+
process4.kill(-proc.pid, killing);
|
|
704
|
+
else
|
|
705
|
+
proc.kill(killing);
|
|
706
|
+
} catch {}
|
|
707
|
+
};
|
|
708
|
+
const stop = () => {
|
|
709
|
+
killGroup("SIGTERM");
|
|
710
|
+
timers.push(setTimeout(killGroup, KILL_GRACE_MS, "SIGKILL"));
|
|
711
|
+
};
|
|
712
|
+
const onAbort = () => stop();
|
|
713
|
+
if (timeoutMs !== undefined) {
|
|
714
|
+
timers.push(setTimeout(() => {
|
|
715
|
+
state.timedOut = true;
|
|
716
|
+
stop();
|
|
717
|
+
}, timeoutMs));
|
|
718
|
+
}
|
|
719
|
+
if (signal?.aborted === true)
|
|
720
|
+
onAbort();
|
|
721
|
+
else
|
|
722
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
723
|
+
onStart?.({ kill: (killing) => killGroup(killing) });
|
|
724
|
+
const drain = async (stream, name) => {
|
|
725
|
+
for await (const data of stream) {
|
|
726
|
+
if (state.failure !== undefined)
|
|
727
|
+
continue;
|
|
728
|
+
try {
|
|
729
|
+
onChunk?.({ stream: name, data });
|
|
730
|
+
} catch (error) {
|
|
731
|
+
state.failure = error;
|
|
732
|
+
stop();
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
if (state.kept + data.length > maxBytes) {
|
|
736
|
+
state.truncated = true;
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
state.kept += data.length;
|
|
740
|
+
chunks.push({ stream: name, data });
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
try {
|
|
744
|
+
await Promise.all([drain(proc.stdout, "stdout"), drain(proc.stderr, "stderr")]);
|
|
745
|
+
await proc.exited;
|
|
746
|
+
} finally {
|
|
747
|
+
state.done = true;
|
|
748
|
+
for (const timer of timers)
|
|
749
|
+
clearTimeout(timer);
|
|
750
|
+
signal?.removeEventListener("abort", onAbort);
|
|
751
|
+
}
|
|
752
|
+
if (state.failure !== undefined)
|
|
753
|
+
throw state.failure;
|
|
754
|
+
const joined = () => Buffer.concat(chunks.map(({ data }) => data));
|
|
755
|
+
let output;
|
|
756
|
+
let text;
|
|
757
|
+
return {
|
|
758
|
+
code: exitCodeOf(proc.exitCode, proc.signalCode),
|
|
759
|
+
chunks,
|
|
760
|
+
timedOut: state.timedOut,
|
|
761
|
+
truncated: state.truncated,
|
|
762
|
+
get output() {
|
|
763
|
+
return output ??= joined();
|
|
764
|
+
},
|
|
765
|
+
get text() {
|
|
766
|
+
return text ??= (output ??= joined()).toString();
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
var KILL_GRACE_MS = 2000, SIGNALS;
|
|
771
|
+
var init_process = __esm(() => {
|
|
772
|
+
SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// ../kit/src/progress.ts
|
|
776
|
+
import process5 from "process";
|
|
777
|
+
function liveRegion(render, stream = process5.stderr, env = process5.env) {
|
|
778
|
+
if (!takesControlCodes(stream, env))
|
|
779
|
+
return { redraw: () => {
|
|
780
|
+
return;
|
|
781
|
+
}, print: (text) => void stream.write(`${text}
|
|
782
|
+
`), stop: () => {
|
|
783
|
+
return;
|
|
784
|
+
} };
|
|
785
|
+
const write = stream.write.bind(stream);
|
|
786
|
+
let frame = 0;
|
|
787
|
+
let drawn = 0;
|
|
788
|
+
const clear = () => {
|
|
789
|
+
if (drawn > 0)
|
|
790
|
+
write(`${CLEAR_LINE}${LINE_UP.repeat(drawn - 1)}`);
|
|
791
|
+
drawn = 0;
|
|
792
|
+
};
|
|
793
|
+
const draw = () => {
|
|
794
|
+
const width = (stream.columns === undefined || stream.columns === 0 ? 80 : stream.columns) - 1;
|
|
795
|
+
const height = stream.rows === undefined || stream.rows === 0 ? 24 : stream.rows;
|
|
796
|
+
const lines = render(FRAMES[frame++ % FRAMES.length]).slice(0, Math.max(1, height - 1)).map((line) => cutToWidth(line, width));
|
|
797
|
+
if (lines.length === 0) {
|
|
798
|
+
clear();
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
write(`${drawn > 0 ? `${CLEAR_LINE}${LINE_UP.repeat(drawn - 1)}` : CLEAR_LINE}${lines.join(`
|
|
802
|
+
`)}`);
|
|
803
|
+
drawn = lines.length;
|
|
804
|
+
};
|
|
805
|
+
const timer = setInterval(draw, FRAME_MS);
|
|
806
|
+
const restore = interceptOutput(clear);
|
|
807
|
+
const onExit = () => clear();
|
|
808
|
+
const signals = holdSignals(stop);
|
|
809
|
+
function stop() {
|
|
810
|
+
clearInterval(timer);
|
|
811
|
+
clear();
|
|
812
|
+
restore();
|
|
813
|
+
process5.off("exit", onExit);
|
|
814
|
+
signals.release();
|
|
815
|
+
}
|
|
816
|
+
timer.unref();
|
|
817
|
+
process5.on("exit", onExit);
|
|
818
|
+
return {
|
|
819
|
+
redraw: draw,
|
|
820
|
+
print: (text) => {
|
|
821
|
+
clear();
|
|
822
|
+
write(`${text}
|
|
823
|
+
`);
|
|
824
|
+
draw();
|
|
825
|
+
},
|
|
826
|
+
stop
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
function cutToWidth(line, width) {
|
|
830
|
+
if (Bun.stringWidth(line) <= width)
|
|
831
|
+
return line;
|
|
832
|
+
let room = width;
|
|
833
|
+
let kept = "";
|
|
834
|
+
let index = 0;
|
|
835
|
+
let linked = false;
|
|
836
|
+
while (index < line.length) {
|
|
837
|
+
ESCAPE_CODE.lastIndex = index;
|
|
838
|
+
const escape = ESCAPE_CODE.exec(line);
|
|
839
|
+
if (escape !== null) {
|
|
840
|
+
kept += escape[0];
|
|
841
|
+
linked ||= escape[0].startsWith(`${ESC}]`);
|
|
842
|
+
index = ESCAPE_CODE.lastIndex;
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
const char = String.fromCodePoint(line.codePointAt(index));
|
|
846
|
+
const columns = Bun.stringWidth(char);
|
|
847
|
+
if (columns > room)
|
|
848
|
+
break;
|
|
849
|
+
kept += char;
|
|
850
|
+
room -= columns;
|
|
851
|
+
index += char.length;
|
|
852
|
+
}
|
|
853
|
+
return `${kept}${RESET_STYLE}${linked ? CLOSE_LINK : ""}`;
|
|
854
|
+
}
|
|
855
|
+
function interceptOutput(clear) {
|
|
856
|
+
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [process5.stdout, "write"], [process5.stderr, "write"]];
|
|
857
|
+
const wrapped = targets.map(([target, name]) => {
|
|
858
|
+
const original = Reflect.get(target, name);
|
|
859
|
+
const wrapper = (...args) => {
|
|
860
|
+
clear();
|
|
861
|
+
return original.apply(target, args);
|
|
862
|
+
};
|
|
863
|
+
Reflect.set(target, name, wrapper);
|
|
864
|
+
return { target, name, original, wrapper };
|
|
865
|
+
});
|
|
866
|
+
return () => {
|
|
867
|
+
for (const { target, name, original, wrapper } of wrapped) {
|
|
868
|
+
if (Reflect.get(target, name) === wrapper)
|
|
869
|
+
Reflect.set(target, name, original);
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
var FRAMES, FRAME_MS = 80, CLEAR_LINE = "\r\x1B[2K", LINE_UP = "\x1B[1A\x1B[2K", ESC, ESCAPE_CODE, RESET_STYLE, CLOSE_LINK, CONSOLE_METHODS;
|
|
874
|
+
var init_progress = __esm(() => {
|
|
875
|
+
init_format();
|
|
876
|
+
init_process();
|
|
877
|
+
init_style();
|
|
878
|
+
FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
879
|
+
ESC = String.fromCharCode(27);
|
|
880
|
+
ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]|\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\))`, "y");
|
|
881
|
+
RESET_STYLE = `${ESC}[0m`;
|
|
882
|
+
CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
883
|
+
CONSOLE_METHODS = ["log", "info", "warn", "error", "debug", "dir", "dirxml", "table", "trace", "group", "groupCollapsed", "count", "timeEnd", "timeLog", "assert"];
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
// ../kit/src/tool.ts
|
|
887
|
+
var init_tool = __esm(() => {
|
|
888
|
+
init_format();
|
|
889
|
+
init_process();
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
// ../kit/src/ci.ts
|
|
893
|
+
var init_ci = __esm(() => {
|
|
894
|
+
init_args();
|
|
895
|
+
init_format();
|
|
896
|
+
init_progress();
|
|
897
|
+
init_tool();
|
|
622
898
|
});
|
|
623
899
|
|
|
624
900
|
// ../kit/src/cli.ts
|
|
625
|
-
import
|
|
626
|
-
function commandRows(commands, colors) {
|
|
901
|
+
import process6 from "process";
|
|
902
|
+
async function commandRows(commands, colors) {
|
|
627
903
|
const width = Math.max(...Object.keys(commands).map((name) => name.length));
|
|
628
904
|
const groups = new Map([["Commands:", []]]);
|
|
629
|
-
|
|
905
|
+
const summaries = await Promise.all(Object.values(commands).map(async ({ summary }) => resolveSummary(summary)));
|
|
906
|
+
for (const [index, [name, { group }]] of Object.entries(commands).entries()) {
|
|
630
907
|
const heading = group === undefined ? "Commands:" : `${group}:`;
|
|
631
908
|
const rows = groups.get(heading) ?? [];
|
|
632
|
-
rows.push(` ${colors.cyan(name.padEnd(width))} ${colors.dim(
|
|
909
|
+
rows.push(` ${colors.cyan(name.padEnd(width))} ${colors.dim(summaries[index])}`);
|
|
633
910
|
groups.set(heading, rows);
|
|
634
911
|
}
|
|
635
912
|
return [...groups].filter(([, rows]) => rows.length > 0).flatMap(([heading, rows], index) => [...index === 0 ? [] : [""], colors.bold(heading), ...rows]);
|
|
@@ -649,28 +926,38 @@ function takeOutputFlags(argv) {
|
|
|
649
926
|
}
|
|
650
927
|
return argv.slice(index);
|
|
651
928
|
}
|
|
652
|
-
function
|
|
653
|
-
|
|
654
|
-
if (started !== undefined)
|
|
655
|
-
return started;
|
|
656
|
-
const [best] = names.map((known) => ({ known, far: distance(name, known) })).sort((a, b) => a.far - b.far);
|
|
657
|
-
return best !== undefined && best.far <= (name.length < 4 ? 1 : 2) ? best.known : undefined;
|
|
929
|
+
async function resolveSummary(summary) {
|
|
930
|
+
return typeof summary === "string" ? summary : summary();
|
|
658
931
|
}
|
|
659
|
-
|
|
932
|
+
function scopeOf(commands, extra, aliases) {
|
|
933
|
+
return { commands: typeof commands === "function" ? {} : commands, lazy: [...typeof commands === "function" ? [commands] : [], ...extra === undefined ? [] : [extra]], aliases };
|
|
934
|
+
}
|
|
935
|
+
async function expand(scope, words) {
|
|
936
|
+
if (scope.lazy.length === 0)
|
|
937
|
+
return scope;
|
|
938
|
+
const commands = { ...scope.commands };
|
|
939
|
+
for (const added of await Promise.all(scope.lazy.map(async (lazy) => lazy(words)))) {
|
|
940
|
+
for (const [name, command] of Object.entries(added))
|
|
941
|
+
commands[name] ??= command;
|
|
942
|
+
}
|
|
943
|
+
return { ...scope, commands, lazy: [] };
|
|
944
|
+
}
|
|
945
|
+
async function help({ path, header, summary: lazySummary, commands, defaultCommand, examples, replaces }, stream) {
|
|
660
946
|
const colors = paint(stream);
|
|
661
947
|
const prefix = path.join(" ");
|
|
948
|
+
const summary = await resolveSummary(lazySummary);
|
|
662
949
|
if (wantsHelpJson())
|
|
663
950
|
return JSON.stringify(description(`${prefix} <command> [options]: ${summary}`, { examples, replaces }));
|
|
664
951
|
const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
|
|
665
952
|
const options = fallback !== undefined && "run" in fallback ? await optionsOf(fallback.run) : undefined;
|
|
666
953
|
const own = Object.entries(options ?? {}).filter(([name]) => !(name in TOP_OPTIONS));
|
|
667
954
|
return [
|
|
668
|
-
header(colors),
|
|
955
|
+
header(colors, summary),
|
|
669
956
|
"",
|
|
670
957
|
usageLine(`${prefix} ${defaultCommand === undefined ? colors.cyan("<command>") : `[${colors.cyan("<command>")}]`} [options]`, colors),
|
|
671
958
|
...replacesRows(replaces, colors),
|
|
672
959
|
"",
|
|
673
|
-
...commandRows(commands, colors),
|
|
960
|
+
...await commandRows(commands, colors),
|
|
674
961
|
...own.length === 0 ? [] : ["", `${colors.bold(`Options of ${defaultCommand}:`)} ${colors.dim("the command run when none is named")}`, ...optionRows(Object.fromEntries(own), colors)],
|
|
675
962
|
"",
|
|
676
963
|
colors.bold("Options:"),
|
|
@@ -682,8 +969,8 @@ async function help({ path, header, summary, commands, defaultCommand, examples,
|
|
|
682
969
|
`);
|
|
683
970
|
}
|
|
684
971
|
function printError(prefix, message, hint, cause) {
|
|
685
|
-
const colors = paint(
|
|
686
|
-
const styled = takesControlCodes(
|
|
972
|
+
const colors = paint(process6.stderr);
|
|
973
|
+
const styled = takesControlCodes(process6.stderr);
|
|
687
974
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
688
975
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
689
976
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -716,11 +1003,11 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
716
1003
|
}
|
|
717
1004
|
const [name, ...args] = argv;
|
|
718
1005
|
if (name === undefined && level.path.length > 1) {
|
|
719
|
-
console.error(await help(level,
|
|
1006
|
+
console.error(await help(await expand(level, [...level.path.slice(1), ...argv]), process6.stderr));
|
|
720
1007
|
return 2;
|
|
721
1008
|
}
|
|
722
1009
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
723
|
-
console.log(await help(level,
|
|
1010
|
+
console.log(await help(await expand(level, [...level.path.slice(1), ...argv]), process6.stdout));
|
|
724
1011
|
return 0;
|
|
725
1012
|
}
|
|
726
1013
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -729,6 +1016,10 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
729
1016
|
}
|
|
730
1017
|
let command = level.commands[level.aliases?.[name] ?? name];
|
|
731
1018
|
let rest = args;
|
|
1019
|
+
if (command === undefined && level.lazy.length > 0) {
|
|
1020
|
+
level = await expand(level, [...level.path.slice(1), ...argv]);
|
|
1021
|
+
command = level.commands[level.aliases?.[name] ?? name];
|
|
1022
|
+
}
|
|
732
1023
|
if (command === undefined && level.defaultCommand !== undefined) {
|
|
733
1024
|
command = level.commands[level.defaultCommand];
|
|
734
1025
|
rest = argv;
|
|
@@ -740,7 +1031,7 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
740
1031
|
}
|
|
741
1032
|
if ("commands" in command) {
|
|
742
1033
|
const { summary } = command;
|
|
743
|
-
return dispatch({ path: [...level.path, name], header: (colors) => `${colors.bold(`${prefix} ${name}`)} ${
|
|
1034
|
+
return dispatch({ path: [...level.path, name], header: (colors, text) => `${colors.bold(`${prefix} ${name}`)} ${text}`, summary, ...scopeOf(command.commands, command.extraCommands, command.aliases), defaultCommand: undefined, examples: command.examples, replaces: undefined }, rest, { version, redact });
|
|
744
1035
|
}
|
|
745
1036
|
try {
|
|
746
1037
|
return await command.run(rest);
|
|
@@ -763,28 +1054,34 @@ async function optionsOf(run) {
|
|
|
763
1054
|
async function leafCandidates(run, words) {
|
|
764
1055
|
if (!(words.at(-1) ?? "").startsWith("-"))
|
|
765
1056
|
return [FILES];
|
|
766
|
-
return Object.entries(await optionsOf(run)).map(([name, option]) => `--${name} ${option.description}`);
|
|
1057
|
+
return Object.entries(await optionsOf(run)).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
|
|
767
1058
|
}
|
|
768
|
-
async function candidates(
|
|
1059
|
+
async function candidates(scope, defaultCommand, words, before = []) {
|
|
769
1060
|
const [word = "", ...rest] = words;
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
1061
|
+
const listing = rest.length === 0 && !word.startsWith("-");
|
|
1062
|
+
let { commands, aliases } = scope;
|
|
1063
|
+
let command = commands[aliases?.[word] ?? word];
|
|
1064
|
+
if (listing || command === undefined) {
|
|
1065
|
+
({ commands, aliases } = await expand(scope, [...before, ...words]));
|
|
1066
|
+
command = commands[aliases?.[word] ?? word];
|
|
1067
|
+
}
|
|
1068
|
+
if (listing)
|
|
1069
|
+
return Promise.all(Object.entries(commands).map(async ([name, { summary }]) => `${name} ${await resolveSummary(summary)}`));
|
|
773
1070
|
if (command === undefined) {
|
|
774
1071
|
const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
|
|
775
1072
|
return fallback !== undefined && "run" in fallback ? leafCandidates(fallback.run, words) : [];
|
|
776
1073
|
}
|
|
777
|
-
return "commands" in command ? candidates(command.commands, command.aliases, undefined, rest) : leafCandidates(command.run, rest);
|
|
1074
|
+
return "commands" in command ? candidates(scopeOf(command.commands, command.extraCommands, command.aliases), undefined, rest, [...before, word]) : leafCandidates(command.run, rest);
|
|
778
1075
|
}
|
|
779
1076
|
async function printCandidates(found) {
|
|
780
1077
|
for (const line of await found)
|
|
781
1078
|
console.log(line);
|
|
782
1079
|
return 0;
|
|
783
1080
|
}
|
|
784
|
-
async function runCli(cli, argv =
|
|
1081
|
+
async function runCli(cli, argv = process6.argv.slice(2)) {
|
|
785
1082
|
if (argv[0] === COMPLETE)
|
|
786
|
-
return printCandidates(candidates(cli.commands, cli.aliases, cli.defaultCommand, argv.slice(1)));
|
|
787
|
-
return dispatch({ path: [cli.name], header: (colors) => `${colors.bold(cli.name)} ${colors.dim(cli.version)} ${
|
|
1083
|
+
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
1084
|
+
return dispatch({ path: [cli.name], header: (colors, about) => `${colors.bold(cli.name)} ${colors.dim(cli.version)} ${about}`, summary: cli.about, ...scopeOf(cli.commands, cli.extraCommands, cli.aliases), defaultCommand: cli.defaultCommand, examples: cli.examples, replaces: cli.replaces }, argv, { version: cli.version, redact: cli.redact });
|
|
788
1085
|
}
|
|
789
1086
|
var LEVEL_OPTIONS, TOP_OPTIONS, COMPLETE = "__complete", FILES = "__files__";
|
|
790
1087
|
var init_cli = __esm(() => {
|
|
@@ -803,6 +1100,12 @@ var init_config = __esm(() => {
|
|
|
803
1100
|
init_args();
|
|
804
1101
|
});
|
|
805
1102
|
|
|
1103
|
+
// ../kit/src/git.ts
|
|
1104
|
+
var init_git = __esm(() => {
|
|
1105
|
+
init_args();
|
|
1106
|
+
init_tool();
|
|
1107
|
+
});
|
|
1108
|
+
|
|
806
1109
|
// ../kit/src/limit.ts
|
|
807
1110
|
function limitOptions(fallback) {
|
|
808
1111
|
return {
|
|
@@ -828,114 +1131,96 @@ var init_limit = __esm(() => {
|
|
|
828
1131
|
init_args();
|
|
829
1132
|
});
|
|
830
1133
|
|
|
831
|
-
// ../kit/src/
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
if (typeof signal === "number")
|
|
842
|
-
return 128 + signal;
|
|
843
|
-
return signal === null ? 129 : 128 + constants.signals[signal];
|
|
844
|
-
}
|
|
845
|
-
function holdSignals(cleanup) {
|
|
846
|
-
let received;
|
|
847
|
-
let child;
|
|
848
|
-
const held = {
|
|
849
|
-
get signal() {
|
|
850
|
-
return received;
|
|
851
|
-
},
|
|
852
|
-
forward: (to) => {
|
|
853
|
-
child = to;
|
|
854
|
-
},
|
|
855
|
-
release: () => {
|
|
856
|
-
for (const signal of SIGNALS)
|
|
857
|
-
process5.off(signal, onSignal);
|
|
858
|
-
}
|
|
859
|
-
};
|
|
860
|
-
function onSignal(signal) {
|
|
861
|
-
received = signal;
|
|
862
|
-
if (child !== undefined) {
|
|
863
|
-
child.kill(signal);
|
|
864
|
-
return;
|
|
865
|
-
}
|
|
866
|
-
if (cleanup === undefined)
|
|
867
|
-
return;
|
|
868
|
-
held.release();
|
|
869
|
-
cleanup(signal);
|
|
870
|
-
process5.kill(process5.pid, signal);
|
|
871
|
-
}
|
|
872
|
-
for (const signal of SIGNALS)
|
|
873
|
-
process5.on(signal, onSignal);
|
|
874
|
-
return held;
|
|
875
|
-
}
|
|
876
|
-
async function runCommand(argv, { cwd, env, stdin = "ignore" } = {}) {
|
|
877
|
-
const chunks = [];
|
|
878
|
-
const proc = Bun.spawn(argv, { ...cwd === undefined ? {} : { cwd }, ...env === undefined ? {} : { env }, stdin, stdout: "pipe", stderr: "pipe" });
|
|
879
|
-
await Promise.all([collect(proc.stdout, "stdout", chunks), collect(proc.stderr, "stderr", chunks)]);
|
|
880
|
-
await proc.exited;
|
|
881
|
-
const output = Buffer.concat(chunks.map(({ data }) => data));
|
|
882
|
-
return { code: exitCodeOf(proc.exitCode, proc.signalCode), chunks, output, text: output.toString() };
|
|
883
|
-
}
|
|
884
|
-
var SIGNALS;
|
|
885
|
-
var init_process = __esm(() => {
|
|
886
|
-
SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
1134
|
+
// ../kit/src/logs.ts
|
|
1135
|
+
var DAY_MS;
|
|
1136
|
+
var init_logs = __esm(() => {
|
|
1137
|
+
DAY_MS = 24 * 60 * 60 * 1000;
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
// ../kit/src/secrets.ts
|
|
1141
|
+
var SECRET_WORDS;
|
|
1142
|
+
var init_secrets = __esm(() => {
|
|
1143
|
+
SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
887
1144
|
});
|
|
888
1145
|
|
|
889
1146
|
// ../kit/src/index.ts
|
|
890
1147
|
var init_src = __esm(() => {
|
|
891
1148
|
init_args();
|
|
892
1149
|
init_chart();
|
|
1150
|
+
init_ci();
|
|
893
1151
|
init_cli();
|
|
894
1152
|
init_config();
|
|
895
1153
|
init_format();
|
|
1154
|
+
init_git();
|
|
896
1155
|
init_limit();
|
|
1156
|
+
init_logs();
|
|
897
1157
|
init_process();
|
|
1158
|
+
init_secrets();
|
|
898
1159
|
init_style();
|
|
899
1160
|
init_text();
|
|
1161
|
+
init_tool();
|
|
900
1162
|
});
|
|
901
1163
|
|
|
902
1164
|
// src/registry.ts
|
|
903
1165
|
function isPublic(registry) {
|
|
904
1166
|
return registry.url.replace(TRAILING_SLASHES, "") === PUBLIC_REGISTRY;
|
|
905
1167
|
}
|
|
1168
|
+
function unreachable(message) {
|
|
1169
|
+
return fail(`could not check: ${message}`, 2);
|
|
1170
|
+
}
|
|
1171
|
+
function requestInit(token) {
|
|
1172
|
+
return { headers: { accept: "application/json", ...token === undefined ? {} : { authorization: `Bearer ${token}` } }, signal: AbortSignal.timeout(REQUEST_TIMEOUT) };
|
|
1173
|
+
}
|
|
906
1174
|
async function get(fetcher, url, token) {
|
|
907
1175
|
try {
|
|
908
|
-
return await fetcher(url,
|
|
1176
|
+
return await fetcher(url, requestInit(token));
|
|
909
1177
|
} catch (error) {
|
|
910
|
-
return
|
|
1178
|
+
return unreachable(`cannot reach ${new URL(url).host}: ${error instanceof Error ? error.message : String(error)}`);
|
|
911
1179
|
}
|
|
912
1180
|
}
|
|
1181
|
+
function isValidName(name) {
|
|
1182
|
+
return PACKAGE_NAME.test(name) && name.length <= 214;
|
|
1183
|
+
}
|
|
913
1184
|
async function fetchPackument(name, registry, fetcher = fetch) {
|
|
914
|
-
|
|
1185
|
+
if (!isValidName(name))
|
|
1186
|
+
fail(`${name} is not a valid npm package name`);
|
|
1187
|
+
const response = await get(fetcher, `${registry.url.replace(TRAILING_SLASHES, "")}/${encodeURIComponent(name).replace("%40", "@").replace("%2F", "%2f")}`, registry.token);
|
|
915
1188
|
if (response.status === 404)
|
|
916
1189
|
return;
|
|
917
1190
|
if (!response.ok)
|
|
918
|
-
|
|
919
|
-
|
|
1191
|
+
unreachable(`${new URL(registry.url).host} answered ${response.status} for ${name}`);
|
|
1192
|
+
let packument;
|
|
1193
|
+
try {
|
|
1194
|
+
packument = await response.json();
|
|
1195
|
+
} catch {
|
|
1196
|
+
return unreachable(`${new URL(registry.url).host} answered ${name} with something that is not JSON`);
|
|
1197
|
+
}
|
|
1198
|
+
if (packument?.name !== name)
|
|
1199
|
+
unreachable(`${new URL(registry.url).host} answered ${name} with the metadata of ${String(packument?.name)}`);
|
|
1200
|
+
return packument;
|
|
920
1201
|
}
|
|
921
1202
|
async function fetchDownloads(name, fetcher = fetch) {
|
|
922
|
-
const response = await get(fetcher, `${DOWNLOADS_API}/${name}`);
|
|
1203
|
+
const response = await get(fetcher, `${DOWNLOADS_API}/${encodeURIComponent(name)}`);
|
|
923
1204
|
if (!response.ok)
|
|
924
1205
|
return;
|
|
925
|
-
|
|
926
|
-
|
|
1206
|
+
try {
|
|
1207
|
+
return (await response.json()).downloads;
|
|
1208
|
+
} catch {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
927
1211
|
}
|
|
928
|
-
var PUBLIC_REGISTRY = "https://registry.npmjs.org", DOWNLOADS_API = "https://api.npmjs.org/downloads/point/last-week", TRAILING_SLASHES;
|
|
1212
|
+
var PUBLIC_REGISTRY = "https://registry.npmjs.org", DOWNLOADS_API = "https://api.npmjs.org/downloads/point/last-week", TRAILING_SLASHES, REQUEST_TIMEOUT = 1e4, PACKAGE_NAME;
|
|
929
1213
|
var init_registry = __esm(() => {
|
|
930
1214
|
init_src();
|
|
931
1215
|
TRAILING_SLASHES = /\/+$/;
|
|
1216
|
+
PACKAGE_NAME = /^(?:@[\w~-][\w.~-]*\/)?[\w~-][\w.~-]*$/;
|
|
932
1217
|
});
|
|
933
1218
|
|
|
934
1219
|
// src/config.ts
|
|
935
1220
|
import { homedir } from "os";
|
|
936
1221
|
import { dirname, join } from "path";
|
|
937
|
-
import
|
|
938
|
-
function
|
|
1222
|
+
import process8 from "process";
|
|
1223
|
+
function expand2(value, env) {
|
|
939
1224
|
let missing = false;
|
|
940
1225
|
const expanded = value.replace(ENV_REFERENCE, (_, braced, bare) => {
|
|
941
1226
|
const found = env[braced ?? bare ?? ""];
|
|
@@ -944,6 +1229,9 @@ function expand(value, env) {
|
|
|
944
1229
|
});
|
|
945
1230
|
return missing ? undefined : expanded;
|
|
946
1231
|
}
|
|
1232
|
+
function literal(value) {
|
|
1233
|
+
return expand2(value, {}) === value ? value : undefined;
|
|
1234
|
+
}
|
|
947
1235
|
function parseNpmrc(text, env) {
|
|
948
1236
|
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
949
1237
|
for (const line of text.split(`
|
|
@@ -952,11 +1240,12 @@ function parseNpmrc(text, env) {
|
|
|
952
1240
|
if (at === -1 || COMMENT.test(line))
|
|
953
1241
|
continue;
|
|
954
1242
|
const key = line.slice(0, at).trim();
|
|
955
|
-
const value = expand(line.slice(at + 1).trim().replace(QUOTES, "$2"), env);
|
|
956
|
-
if (value === undefined || value === "")
|
|
957
|
-
continue;
|
|
958
1243
|
const scope = SCOPE_REGISTRY.exec(key)?.[1];
|
|
959
1244
|
const tokenFor = AUTH_TOKEN.exec(key)?.[1];
|
|
1245
|
+
const raw = line.slice(at + 1).trim().replace(QUOTES, "$2");
|
|
1246
|
+
const value = tokenFor === undefined ? literal(raw) : expand2(raw, env);
|
|
1247
|
+
if (value === undefined || value === "")
|
|
1248
|
+
continue;
|
|
960
1249
|
if (scope !== undefined)
|
|
961
1250
|
config.scopes[scope] = value;
|
|
962
1251
|
else if (tokenFor !== undefined)
|
|
@@ -968,8 +1257,8 @@ function parseNpmrc(text, env) {
|
|
|
968
1257
|
}
|
|
969
1258
|
function bunEntry(entry, env) {
|
|
970
1259
|
const url = typeof entry === "string" ? entry : entry.url;
|
|
971
|
-
const token = typeof entry === "string" || entry.token === undefined ? undefined :
|
|
972
|
-
return { ...url === undefined ? {} : { url
|
|
1260
|
+
const token = typeof entry === "string" || entry.token === undefined ? undefined : expand2(entry.token, env);
|
|
1261
|
+
return { ...url === undefined || literal(url) === undefined ? {} : { url }, ...token === undefined ? {} : { token } };
|
|
973
1262
|
}
|
|
974
1263
|
function parseBunfig(text, env) {
|
|
975
1264
|
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
@@ -991,26 +1280,35 @@ function parseBunfig(text, env) {
|
|
|
991
1280
|
return config;
|
|
992
1281
|
}
|
|
993
1282
|
function tokenFor(config, url) {
|
|
994
|
-
const address = url.replace(PROTOCOL, "")
|
|
995
|
-
const best = Object.keys(config.tokens).filter((key) => address.startsWith(key)).sort((a, b) => b.length - a.length)[0];
|
|
1283
|
+
const address = `${url.replace(PROTOCOL, "").replace(TRAILING_SLASHES2, "")}/`;
|
|
1284
|
+
const best = Object.keys(config.tokens).filter((key) => address.startsWith(`${key.replace(TRAILING_SLASHES2, "")}/`)).sort((a, b) => b.length - a.length)[0];
|
|
996
1285
|
return best === undefined ? undefined : config.tokens[best];
|
|
997
1286
|
}
|
|
1287
|
+
function mayCarryToken(url) {
|
|
1288
|
+
const { protocol, hostname } = new URL(url);
|
|
1289
|
+
return protocol === "https:" || LOCAL_HOSTS.has(hostname);
|
|
1290
|
+
}
|
|
998
1291
|
function registryFor(name, configs) {
|
|
999
1292
|
const scope = name.startsWith("@") ? name.slice(0, name.indexOf("/")) : undefined;
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1293
|
+
const scoped = scope === undefined ? undefined : configs.find((config) => config.scopes[scope] !== undefined);
|
|
1294
|
+
const url = (scope === undefined ? undefined : scoped?.scopes[scope]) ?? configs.find((config) => config.registry !== undefined)?.registry;
|
|
1295
|
+
if (url === undefined)
|
|
1296
|
+
return { url: PUBLIC_REGISTRY };
|
|
1297
|
+
const token = (scope === undefined ? undefined : scoped?.scopeTokens[scope]) ?? configs.map((other) => tokenFor(other, url)).find((found) => found !== undefined);
|
|
1298
|
+
return { url, token: mayCarryToken(url) ? token : undefined };
|
|
1299
|
+
}
|
|
1300
|
+
function readable(path, parse) {
|
|
1301
|
+
try {
|
|
1302
|
+
return parse();
|
|
1303
|
+
} catch (error) {
|
|
1304
|
+
return unreachable(`${path} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
1006
1305
|
}
|
|
1007
|
-
return { url: PUBLIC_REGISTRY };
|
|
1008
1306
|
}
|
|
1009
1307
|
async function readIfThere(path) {
|
|
1010
1308
|
const file = Bun.file(path);
|
|
1011
1309
|
return await file.exists() ? file.text() : undefined;
|
|
1012
1310
|
}
|
|
1013
|
-
async function loadConfigs(cwd =
|
|
1311
|
+
async function loadConfigs(cwd = process8.cwd(), env = process8.env, home = homedir()) {
|
|
1014
1312
|
const directories = [];
|
|
1015
1313
|
for (let dir = cwd;!directories.includes(dir); dir = dirname(dir))
|
|
1016
1314
|
directories.push(dir);
|
|
@@ -1021,7 +1319,7 @@ async function loadConfigs(cwd = process7.cwd(), env = process7.env, home = home
|
|
|
1021
1319
|
const bunfig = await readIfThere(join(dir, "bunfig.toml"));
|
|
1022
1320
|
const npmrc = await readIfThere(join(dir, ".npmrc"));
|
|
1023
1321
|
if (bunfig !== undefined)
|
|
1024
|
-
configs.push(parseBunfig(bunfig, env));
|
|
1322
|
+
configs.push(readable(join(dir, "bunfig.toml"), () => parseBunfig(bunfig, env)));
|
|
1025
1323
|
if (npmrc !== undefined)
|
|
1026
1324
|
configs.push(parseNpmrc(npmrc, env));
|
|
1027
1325
|
}
|
|
@@ -1039,7 +1337,7 @@ function parseSettings(text) {
|
|
|
1039
1337
|
settings.blockSeverity = raw.blockSeverity;
|
|
1040
1338
|
return settings;
|
|
1041
1339
|
}
|
|
1042
|
-
async function loadSettings(cwd =
|
|
1340
|
+
async function loadSettings(cwd = process8.cwd(), home = homedir()) {
|
|
1043
1341
|
const files = [];
|
|
1044
1342
|
for (let dir = cwd;!files.includes(join(dir, SETTINGS_FILE)); dir = dirname(dir))
|
|
1045
1343
|
files.push(join(dir, SETTINGS_FILE));
|
|
@@ -1049,13 +1347,13 @@ async function loadSettings(cwd = process7.cwd(), home = homedir()) {
|
|
|
1049
1347
|
const text = await readIfThere(file);
|
|
1050
1348
|
if (text === undefined)
|
|
1051
1349
|
continue;
|
|
1052
|
-
const found = parseSettings(text);
|
|
1350
|
+
const found = readable(file, () => parseSettings(text));
|
|
1053
1351
|
settings.licenses ??= found.licenses;
|
|
1054
1352
|
settings.blockSeverity ??= found.blockSeverity;
|
|
1055
1353
|
}
|
|
1056
1354
|
return settings;
|
|
1057
1355
|
}
|
|
1058
|
-
var ENV_REFERENCE, COMMENT, SCOPE_REGISTRY, AUTH_TOKEN, PROTOCOL, QUOTES, SEVERITIES, SETTINGS_FILE = ".pkgrc.json";
|
|
1356
|
+
var ENV_REFERENCE, COMMENT, SCOPE_REGISTRY, AUTH_TOKEN, PROTOCOL, TRAILING_SLASHES2, LOCAL_HOSTS, QUOTES, SEVERITIES, DEFAULT_BLOCK_SEVERITY = "high", SETTINGS_FILE = ".pkgrc.json";
|
|
1059
1357
|
var init_config2 = __esm(() => {
|
|
1060
1358
|
init_registry();
|
|
1061
1359
|
ENV_REFERENCE = /\$\{(\w+)\}|\$(\w+)/g;
|
|
@@ -1063,35 +1361,89 @@ var init_config2 = __esm(() => {
|
|
|
1063
1361
|
SCOPE_REGISTRY = /^(@[^:]+):registry$/;
|
|
1064
1362
|
AUTH_TOKEN = /^(\/\/.+?):_authToken$/;
|
|
1065
1363
|
PROTOCOL = /^\w+:/;
|
|
1364
|
+
TRAILING_SLASHES2 = /\/+$/;
|
|
1365
|
+
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1066
1366
|
QUOTES = /^(["'])(.*)\1$/;
|
|
1067
1367
|
SEVERITIES = ["low", "moderate", "high", "critical"];
|
|
1068
1368
|
});
|
|
1069
1369
|
|
|
1370
|
+
// src/semver.ts
|
|
1371
|
+
function isRange(text) {
|
|
1372
|
+
if (text.trim() === "")
|
|
1373
|
+
return true;
|
|
1374
|
+
return text.split(OR).every((alternative) => {
|
|
1375
|
+
const words = alternative.trim().split(WHITESPACE);
|
|
1376
|
+
return words.every((word, index) => word === "-" ? index > 0 && index < words.length - 1 : COMPARATOR.test(word));
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
function compare(version, word) {
|
|
1380
|
+
const bound = BOUND.exec(word);
|
|
1381
|
+
if (bound === null)
|
|
1382
|
+
return;
|
|
1383
|
+
const order = Bun.semver.order(version, bound[2] ?? "");
|
|
1384
|
+
const operator = bound[1] ?? "=";
|
|
1385
|
+
if (operator === "<")
|
|
1386
|
+
return order < 0;
|
|
1387
|
+
if (operator === "<=")
|
|
1388
|
+
return order <= 0;
|
|
1389
|
+
if (operator === ">")
|
|
1390
|
+
return order > 0;
|
|
1391
|
+
return operator === ">=" ? order >= 0 : order === 0;
|
|
1392
|
+
}
|
|
1393
|
+
function inRange(version, range) {
|
|
1394
|
+
if (Bun.semver.satisfies(version, range))
|
|
1395
|
+
return true;
|
|
1396
|
+
if (!PRERELEASE.test(version))
|
|
1397
|
+
return false;
|
|
1398
|
+
return range.split(OR).some((alternative) => alternative.trim().split(WHITESPACE).every((word) => compare(version, word) ?? Bun.semver.satisfies(version, word)));
|
|
1399
|
+
}
|
|
1400
|
+
var OR, WHITESPACE, PRERELEASE, PART, COMPARATOR, BOUND, EXACT_VERSION;
|
|
1401
|
+
var init_semver = __esm(() => {
|
|
1402
|
+
OR = /\s*\|\|\s*/;
|
|
1403
|
+
WHITESPACE = /\s+/;
|
|
1404
|
+
PRERELEASE = /-/;
|
|
1405
|
+
PART = String.raw`(?:\d+|[xX*])`;
|
|
1406
|
+
COMPARATOR = new RegExp(String.raw`^(?:[<>]=?|=|\^|~>?)?v?${PART}(?:\.${PART}){0,2}(?:-[\w.-]+)?(?:\+[\w.-]+)?$`);
|
|
1407
|
+
BOUND = /^(<=|>=|[<>=])?v?(\d+\.\d+\.\d+(?:-[\w.-]+)?)$/;
|
|
1408
|
+
EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1070
1411
|
// src/advisories.ts
|
|
1071
1412
|
function severityRank(severity) {
|
|
1072
1413
|
return SEVERITIES.indexOf(severity);
|
|
1073
1414
|
}
|
|
1074
1415
|
function fixedVersion(vulnerable, version) {
|
|
1075
|
-
const range = vulnerable.split("||").map((each) => each.trim()).find((each) =>
|
|
1416
|
+
const range = vulnerable.split("||").map((each) => each.trim()).find((each) => inRange(version, each));
|
|
1076
1417
|
return range === undefined ? undefined : UPPER_BOUND.exec(range)?.[1];
|
|
1077
1418
|
}
|
|
1078
1419
|
async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
1079
|
-
const url = `${registry.url.replace(
|
|
1420
|
+
const url = `${registry.url.replace(TRAILING_SLASHES3, "")}${BULK_PATH}`;
|
|
1421
|
+
const host = new URL(registry.url).host;
|
|
1080
1422
|
let response;
|
|
1081
1423
|
try {
|
|
1082
1424
|
response = await fetcher(url, {
|
|
1083
1425
|
method: "POST",
|
|
1084
1426
|
headers: { accept: "application/json", "content-type": "application/json", ...registry.token === undefined ? {} : { authorization: `Bearer ${registry.token}` } },
|
|
1085
|
-
body: JSON.stringify(versions)
|
|
1427
|
+
body: JSON.stringify(versions),
|
|
1428
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT2)
|
|
1086
1429
|
});
|
|
1087
|
-
} catch {
|
|
1088
|
-
return {};
|
|
1430
|
+
} catch (error) {
|
|
1431
|
+
return { found: {}, unavailable: `cannot reach ${host} for advisories: ${error instanceof Error ? error.message : String(error)}` };
|
|
1089
1432
|
}
|
|
1433
|
+
if (NO_ENDPOINT.has(response.status))
|
|
1434
|
+
return { found: {}, isUnsupported: true, unavailable: `${host} has no advisory endpoint` };
|
|
1090
1435
|
if (!response.ok)
|
|
1091
|
-
return {};
|
|
1092
|
-
|
|
1436
|
+
return { found: {}, unavailable: `${host} answered ${response.status} for advisories` };
|
|
1437
|
+
let body;
|
|
1438
|
+
try {
|
|
1439
|
+
body = await response.json();
|
|
1440
|
+
} catch {
|
|
1441
|
+
return { found: {}, unavailable: `${host} answered advisories with something that is not JSON` };
|
|
1442
|
+
}
|
|
1093
1443
|
const found = {};
|
|
1094
1444
|
for (const [name, raws] of Object.entries(body)) {
|
|
1445
|
+
if (!Array.isArray(raws))
|
|
1446
|
+
continue;
|
|
1095
1447
|
found[name] = raws.filter((raw) => SEVERITIES.includes(raw.severity)).map((raw) => ({
|
|
1096
1448
|
id: raw.id,
|
|
1097
1449
|
ghsa: GHSA.exec(raw.url)?.[0],
|
|
@@ -1101,20 +1453,22 @@ async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
|
1101
1453
|
vulnerable: raw.vulnerable_versions
|
|
1102
1454
|
}));
|
|
1103
1455
|
}
|
|
1104
|
-
return found;
|
|
1456
|
+
return { found };
|
|
1105
1457
|
}
|
|
1106
1458
|
function advisoriesFor(advisories, version) {
|
|
1107
|
-
return (advisories ?? []).filter((each) =>
|
|
1459
|
+
return (advisories ?? []).filter((each) => inRange(version, each.vulnerable)).map((each) => ({ ...each, fixed: fixedVersion(each.vulnerable, version) }));
|
|
1108
1460
|
}
|
|
1109
1461
|
function filterAdvisories(advisories, level, ignore = []) {
|
|
1110
1462
|
return advisories.filter((each) => severityRank(each.severity) >= severityRank(level) && !ignore.includes(each.ghsa ?? "") && !ignore.includes(String(each.id)));
|
|
1111
1463
|
}
|
|
1112
|
-
var BULK_PATH = "/-/npm/v1/security/advisories/bulk",
|
|
1464
|
+
var BULK_PATH = "/-/npm/v1/security/advisories/bulk", TRAILING_SLASHES3, REQUEST_TIMEOUT2 = 1e4, GHSA, UPPER_BOUND, NO_ENDPOINT;
|
|
1113
1465
|
var init_advisories = __esm(() => {
|
|
1114
1466
|
init_config2();
|
|
1115
|
-
|
|
1467
|
+
init_semver();
|
|
1468
|
+
TRAILING_SLASHES3 = /\/+$/;
|
|
1116
1469
|
GHSA = /GHSA-[\w-]+$/;
|
|
1117
1470
|
UPPER_BOUND = /(?:^|\s)<([\w.+-]+)/;
|
|
1471
|
+
NO_ENDPOINT = new Set([404, 405, 501]);
|
|
1118
1472
|
});
|
|
1119
1473
|
|
|
1120
1474
|
// src/licenses.ts
|
|
@@ -1641,20 +1995,23 @@ var init_popular = __esm(() => {
|
|
|
1641
1995
|
function baseName(name) {
|
|
1642
1996
|
return name.slice(name.indexOf("/") + 1);
|
|
1643
1997
|
}
|
|
1644
|
-
function
|
|
1998
|
+
function scopeOf2(name) {
|
|
1645
1999
|
return name.startsWith("@") ? name.slice(0, name.indexOf("/")) : "";
|
|
1646
2000
|
}
|
|
1647
2001
|
function squash(name) {
|
|
1648
2002
|
return name.toLowerCase().replace(SEPARATORS, "");
|
|
1649
2003
|
}
|
|
1650
2004
|
function resemblance(name, popular) {
|
|
1651
|
-
if (
|
|
2005
|
+
if (scopeOf2(name) !== scopeOf2(popular) && baseName(name) === baseName(popular) && baseName(name).length >= MIN_LENGTH)
|
|
1652
2006
|
return `${popular} under another scope`;
|
|
1653
2007
|
if (squash(name) === squash(popular))
|
|
1654
2008
|
return `${popular} spelled with other separators or case`;
|
|
2009
|
+
const shortest = Math.min(name.length, popular.length);
|
|
2010
|
+
const allowed = shortest >= MIN_LENGTH * 2 ? 2 : 1;
|
|
2011
|
+
if (shortest < MIN_LENGTH || Math.abs(name.length - popular.length) > allowed)
|
|
2012
|
+
return;
|
|
1655
2013
|
const edits = distance(name, popular);
|
|
1656
|
-
|
|
1657
|
-
return Math.min(name.length, popular.length) >= MIN_LENGTH && edits <= allowed ? `${popular}, ${edits} ${edits === 1 ? "edit" : "edits"} away` : undefined;
|
|
2014
|
+
return edits <= allowed ? `${popular}, ${edits} ${edits === 1 ? "edit" : "edits"} away` : undefined;
|
|
1658
2015
|
}
|
|
1659
2016
|
function nearMisses(name, popular = popular_default) {
|
|
1660
2017
|
if (popular.includes(name))
|
|
@@ -1690,6 +2047,8 @@ function resolve(packument, request) {
|
|
|
1690
2047
|
return tags[wanted];
|
|
1691
2048
|
if (versions.includes(wanted))
|
|
1692
2049
|
return wanted;
|
|
2050
|
+
if (!isRange(wanted))
|
|
2051
|
+
return;
|
|
1693
2052
|
return versions.filter((version) => Bun.semver.satisfies(version, wanted)).sort(Bun.semver.order).at(-1);
|
|
1694
2053
|
}
|
|
1695
2054
|
function licenseOf(license) {
|
|
@@ -1740,7 +2099,9 @@ function analyze(input) {
|
|
|
1740
2099
|
}
|
|
1741
2100
|
const age = ageDays(report.published, now);
|
|
1742
2101
|
if (age === undefined) {
|
|
1743
|
-
|
|
2102
|
+
const isBlocking = minAgeDays > 0 && registry === PUBLIC_HOST;
|
|
2103
|
+
report.blocked ||= isBlocking;
|
|
2104
|
+
report.warnings.push(`${registry} gives no publish date for ${version}, its age cannot be checked${isBlocking ? " and it is refused" : ""}`);
|
|
1744
2105
|
} else if (age < minAgeDays) {
|
|
1745
2106
|
report.blocked = true;
|
|
1746
2107
|
report.warnings.push(`${version} was published ${age < 1 ? "less than a day" : `${Math.floor(age)} day${Math.floor(age) === 1 ? "" : "s"}`} ago, under ${minAgeDays} days${report.safe === undefined ? ", and no older stable version exists" : `, use ${spec.name}@${report.safe.version}`}`);
|
|
@@ -1769,11 +2130,14 @@ function analyze(input) {
|
|
|
1769
2130
|
}
|
|
1770
2131
|
return report;
|
|
1771
2132
|
}
|
|
1772
|
-
var DEFAULT_MIN_AGE_DAYS = 14, DAY = 86400000, INSTALL_SCRIPTS, GIT_PREFIX, VERSION_SEPARATOR;
|
|
2133
|
+
var DEFAULT_MIN_AGE_DAYS = 14, DAY = 86400000, PUBLIC_HOST, INSTALL_SCRIPTS, GIT_PREFIX, VERSION_SEPARATOR;
|
|
1773
2134
|
var init_analyze = __esm(() => {
|
|
1774
2135
|
init_advisories();
|
|
1775
2136
|
init_licenses();
|
|
1776
2137
|
init_nearmiss();
|
|
2138
|
+
init_registry();
|
|
2139
|
+
init_semver();
|
|
2140
|
+
PUBLIC_HOST = new URL(PUBLIC_REGISTRY).host;
|
|
1777
2141
|
INSTALL_SCRIPTS = ["preinstall", "install", "postinstall"];
|
|
1778
2142
|
GIT_PREFIX = /^git\+/;
|
|
1779
2143
|
VERSION_SEPARATOR = /(?<=.)@/;
|
|
@@ -1782,7 +2146,8 @@ var init_analyze = __esm(() => {
|
|
|
1782
2146
|
// src/commands/check.ts
|
|
1783
2147
|
var exports_check = {};
|
|
1784
2148
|
__export(exports_check, {
|
|
1785
|
-
check: () => check
|
|
2149
|
+
check: () => check,
|
|
2150
|
+
checkPackage: () => checkPackage
|
|
1786
2151
|
});
|
|
1787
2152
|
async function checkPackage(text, context) {
|
|
1788
2153
|
const spec = parseSpec(text);
|
|
@@ -1791,11 +2156,16 @@ async function checkPackage(text, context) {
|
|
|
1791
2156
|
const downloads = packument !== undefined && isPublic(registry) ? await fetchDownloads(spec.name, context.fetcher) : undefined;
|
|
1792
2157
|
const input = { spec, packument, downloads, registry: new URL(registry.url).host, now: context.now, minAgeDays: context.minAgeDays, licenses: context.settings?.licenses };
|
|
1793
2158
|
const report = analyze(input);
|
|
1794
|
-
const
|
|
1795
|
-
if (
|
|
2159
|
+
const blockSeverity = context.settings?.blockSeverity ?? DEFAULT_BLOCK_SEVERITY;
|
|
2160
|
+
if (report.version === undefined)
|
|
1796
2161
|
return report;
|
|
1797
|
-
const found = await fetchAdvisories({ [spec.name]: [report.version] }, registry, context.fetcher);
|
|
1798
|
-
|
|
2162
|
+
const { found, unavailable, isUnsupported } = await fetchAdvisories({ [spec.name]: [report.version] }, registry, context.fetcher);
|
|
2163
|
+
if (unavailable !== undefined && isUnsupported !== true)
|
|
2164
|
+
return unreachable(unavailable);
|
|
2165
|
+
const checked = analyze({ ...input, blockSeverity, advisories: advisoriesFor(found[spec.name], report.version) });
|
|
2166
|
+
if (unavailable !== undefined)
|
|
2167
|
+
checked.warnings.push(`${unavailable}, so its known advisories are not checked`);
|
|
2168
|
+
return checked;
|
|
1799
2169
|
}
|
|
1800
2170
|
function when(release, now) {
|
|
1801
2171
|
return release?.published === undefined ? "" : `, published ${formatAge(release.published, now)} (${release.published.slice(0, 10)})`;
|
|
@@ -1842,9 +2212,9 @@ var usage = `pkg [check] <name>[@version]...
|
|
|
1842
2212
|
|
|
1843
2213
|
Checks npm packages before they are added: whether the name exists, the latest and the newest version at least two weeks old, weekly downloads, licence, repository, install scripts and a near miss of a popular name.
|
|
1844
2214
|
|
|
1845
|
-
A \`.pkgrc.json\` (or ~/.config/pkg/config.json) with \`licenses\` (SPDX ids) refuses a licence outside the list or a missing one, and \`blockSeverity\` (low, moderate, high, critical) refuses a version with an advisory at that level or above.
|
|
2215
|
+
A \`.pkgrc.json\` (or ~/.config/pkg/config.json) with \`licenses\` (SPDX ids) refuses a licence outside the list or a missing one, and \`blockSeverity\` (low, moderate, high, critical; high when unset) refuses a version with an advisory at that level or above.
|
|
1846
2216
|
|
|
1847
|
-
Exits 0 when every package passes, 1 when one is missing, the version asked for is under the minimum age, its licence is outside the allowlist or an advisory reaches the threshold, 2 on a usage error.`, options;
|
|
2217
|
+
Exits 0 when every package passes, 1 when one is blocked (missing, the version asked for is under the minimum age or has no date, its licence is outside the allowlist or an advisory reaches the threshold), 2 when it could not check (the registry unreachable, slow or answering badly, a broken .pkgrc.json, bunfig.toml or .npmrc) or on a usage error.`, options;
|
|
1848
2218
|
var init_check = __esm(() => {
|
|
1849
2219
|
init_src();
|
|
1850
2220
|
init_advisories();
|
|
@@ -1858,6 +2228,15 @@ var init_check = __esm(() => {
|
|
|
1858
2228
|
});
|
|
1859
2229
|
|
|
1860
2230
|
// src/lockfile.ts
|
|
2231
|
+
function split(resolution) {
|
|
2232
|
+
const at = resolution.search(VERSION_SEPARATOR2);
|
|
2233
|
+
if (at === -1)
|
|
2234
|
+
return;
|
|
2235
|
+
const target = resolution.slice(at + 1);
|
|
2236
|
+
if (target.startsWith(NPM_ALIAS))
|
|
2237
|
+
return split(target.slice(NPM_ALIAS.length));
|
|
2238
|
+
return NOT_REGISTRY.test(target) ? undefined : { name: resolution.slice(0, at), version: target };
|
|
2239
|
+
}
|
|
1861
2240
|
function parseBunLock(text) {
|
|
1862
2241
|
const lock = Bun.JSONC.parse(text);
|
|
1863
2242
|
const seen = new Map;
|
|
@@ -1865,17 +2244,15 @@ function parseBunLock(text) {
|
|
|
1865
2244
|
const resolution = entry[0];
|
|
1866
2245
|
if (typeof resolution !== "string")
|
|
1867
2246
|
continue;
|
|
1868
|
-
const
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
if (at !== -1 && !NOT_REGISTRY.test(version))
|
|
1872
|
-
seen.set(`${name}@${version}`, { name, version });
|
|
2247
|
+
const locked = split(resolution);
|
|
2248
|
+
if (locked !== undefined)
|
|
2249
|
+
seen.set(`${locked.name}@${locked.version}`, locked);
|
|
1873
2250
|
}
|
|
1874
2251
|
return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name) || Bun.semver.order(a.version, b.version));
|
|
1875
2252
|
}
|
|
1876
|
-
var NOT_REGISTRY, VERSION_SEPARATOR2;
|
|
2253
|
+
var NOT_REGISTRY, VERSION_SEPARATOR2, NPM_ALIAS = "npm:";
|
|
1877
2254
|
var init_lockfile = __esm(() => {
|
|
1878
|
-
NOT_REGISTRY = /^(?:workspace|link|file|github|git|http|https
|
|
2255
|
+
NOT_REGISTRY = /^(?:workspace|link|file|github|git|http|https):|^[\w.-]+\/[\w.-]+$/;
|
|
1879
2256
|
VERSION_SEPARATOR2 = /(?<=.)@/;
|
|
1880
2257
|
});
|
|
1881
2258
|
|
|
@@ -1885,7 +2262,7 @@ __export(exports_audit, {
|
|
|
1885
2262
|
audit: () => audit
|
|
1886
2263
|
});
|
|
1887
2264
|
import { join as join2, resolve as resolve2 } from "path";
|
|
1888
|
-
import
|
|
2265
|
+
import process9 from "process";
|
|
1889
2266
|
function hasFinding(audited) {
|
|
1890
2267
|
return audited.blocked || audited.warnings.length > 0 || audited.advisories.length > 0;
|
|
1891
2268
|
}
|
|
@@ -1905,8 +2282,13 @@ async function auditPackages(packages, context) {
|
|
|
1905
2282
|
registries.set(registry.url, group);
|
|
1906
2283
|
}
|
|
1907
2284
|
const advisories = {};
|
|
1908
|
-
|
|
1909
|
-
|
|
2285
|
+
const unavailable = [];
|
|
2286
|
+
for (const { registry, versions } of registries.values()) {
|
|
2287
|
+
const fetched = await fetchAdvisories(versions, registry, context.fetcher);
|
|
2288
|
+
Object.assign(advisories, fetched.found);
|
|
2289
|
+
if (fetched.unavailable !== undefined)
|
|
2290
|
+
unavailable.push(fetched.unavailable);
|
|
2291
|
+
}
|
|
1910
2292
|
const audited = [];
|
|
1911
2293
|
for (let start = 0;start < packages.length; start += BATCH) {
|
|
1912
2294
|
audited.push(...await Promise.all(packages.slice(start, start + BATCH).map(async ({ name, version }) => {
|
|
@@ -1916,7 +2298,7 @@ async function auditPackages(packages, context) {
|
|
|
1916
2298
|
return { name, version, license: report.license, blocked: report.blocked || found.length > 0, warnings: report.warnings, advisories: found };
|
|
1917
2299
|
})));
|
|
1918
2300
|
}
|
|
1919
|
-
return audited;
|
|
2301
|
+
return { audited, unavailable };
|
|
1920
2302
|
}
|
|
1921
2303
|
function renderAudit(findings, total) {
|
|
1922
2304
|
const blocks = findings.map(({ name, version, warnings, advisories }) => [
|
|
@@ -1934,7 +2316,7 @@ async function audit(args) {
|
|
|
1934
2316
|
const level = values["audit-level"] ?? "low";
|
|
1935
2317
|
if (!isSeverity(level))
|
|
1936
2318
|
fail(`--audit-level takes ${SEVERITIES.join(", ")}, not ${level}`);
|
|
1937
|
-
const dir = resolve2(asked ??
|
|
2319
|
+
const dir = resolve2(asked ?? process9.cwd());
|
|
1938
2320
|
const lock = Bun.file(join2(dir, "bun.lock"));
|
|
1939
2321
|
if (!await lock.exists())
|
|
1940
2322
|
fail(`no bun.lock in ${dir}`);
|
|
@@ -1946,19 +2328,24 @@ async function audit(args) {
|
|
|
1946
2328
|
level,
|
|
1947
2329
|
ignore: values.ignore ?? []
|
|
1948
2330
|
};
|
|
1949
|
-
const
|
|
2331
|
+
const { audited, unavailable } = await auditPackages(packages, context);
|
|
2332
|
+
const findings = audited.filter(hasFinding);
|
|
1950
2333
|
if (values.json === true)
|
|
1951
2334
|
printJson(findings);
|
|
1952
2335
|
else
|
|
1953
2336
|
console.log(renderAudit(findings, packages.length));
|
|
1954
|
-
|
|
2337
|
+
for (const reason of unavailable)
|
|
2338
|
+
warn(`${reason}, so its advisories are not checked`);
|
|
2339
|
+
if (findings.some((each) => each.blocked))
|
|
2340
|
+
return 1;
|
|
2341
|
+
return unavailable.length > 0 ? 2 : 0;
|
|
1955
2342
|
}
|
|
1956
2343
|
var usage2 = `pkg audit [dir]
|
|
1957
2344
|
|
|
1958
2345
|
Reads the bun.lock in the folder (the current one by default) and runs on every registry package it pins the checks \`pkg check\` runs before an add: age, install scripts, a deprecated version, a near miss of a popular name, and the licence allowlist of the pkg config. It also lists the known advisories of each version, with the GHSA, the severity and the fixed version, from the registry's bulk advisory endpoint, the one \`bun audit\` reads.
|
|
1959
2346
|
Findings are grouped per package, each registry package looked up once per run.
|
|
1960
2347
|
|
|
1961
|
-
Exits 0 when nothing blocks, 1 when a package is missing, too fresh or outside the licence allowlist, or an advisory reaches --audit-level, 2 on a usage error or without a bun.lock.`, options2, BATCH = 8;
|
|
2348
|
+
Exits 0 when nothing blocks, 1 when a package is missing, too fresh or outside the licence allowlist, or an advisory reaches --audit-level, 2 when the registry could not be reached or answered badly (a warning says which, and nothing is reported as clean), on a usage error or without a bun.lock.`, options2, BATCH = 8;
|
|
1962
2349
|
var init_audit = __esm(() => {
|
|
1963
2350
|
init_src();
|
|
1964
2351
|
init_advisories();
|
|
@@ -1974,125 +2361,42 @@ var init_audit = __esm(() => {
|
|
|
1974
2361
|
};
|
|
1975
2362
|
});
|
|
1976
2363
|
|
|
1977
|
-
// ../kit/src/progress.ts
|
|
1978
|
-
import process9 from "process";
|
|
1979
|
-
function liveRegion(render, stream = process9.stderr, env = process9.env) {
|
|
1980
|
-
if (!takesControlCodes(stream, env))
|
|
1981
|
-
return { redraw: () => {
|
|
1982
|
-
return;
|
|
1983
|
-
}, print: (text) => void stream.write(`${text}
|
|
1984
|
-
`), stop: () => {
|
|
1985
|
-
return;
|
|
1986
|
-
} };
|
|
1987
|
-
const write = stream.write.bind(stream);
|
|
1988
|
-
let frame = 0;
|
|
1989
|
-
let drawn = 0;
|
|
1990
|
-
const clear = () => {
|
|
1991
|
-
if (drawn > 0)
|
|
1992
|
-
write(`${CLEAR_LINE}${LINE_UP.repeat(drawn - 1)}`);
|
|
1993
|
-
drawn = 0;
|
|
1994
|
-
};
|
|
1995
|
-
const draw = () => {
|
|
1996
|
-
const width = (stream.columns === undefined || stream.columns === 0 ? 80 : stream.columns) - 1;
|
|
1997
|
-
const height = stream.rows === undefined || stream.rows === 0 ? 24 : stream.rows;
|
|
1998
|
-
const lines = render(FRAMES[frame++ % FRAMES.length]).slice(0, Math.max(1, height - 1)).map((line) => cutToWidth(line, width));
|
|
1999
|
-
if (lines.length === 0) {
|
|
2000
|
-
clear();
|
|
2001
|
-
return;
|
|
2002
|
-
}
|
|
2003
|
-
write(`${drawn > 0 ? `${CLEAR_LINE}${LINE_UP.repeat(drawn - 1)}` : CLEAR_LINE}${lines.join(`
|
|
2004
|
-
`)}`);
|
|
2005
|
-
drawn = lines.length;
|
|
2006
|
-
};
|
|
2007
|
-
const timer = setInterval(draw, FRAME_MS);
|
|
2008
|
-
const restore = interceptOutput(clear);
|
|
2009
|
-
const onExit = () => clear();
|
|
2010
|
-
const signals = holdSignals(stop);
|
|
2011
|
-
function stop() {
|
|
2012
|
-
clearInterval(timer);
|
|
2013
|
-
clear();
|
|
2014
|
-
restore();
|
|
2015
|
-
process9.off("exit", onExit);
|
|
2016
|
-
signals.release();
|
|
2017
|
-
}
|
|
2018
|
-
timer.unref();
|
|
2019
|
-
process9.on("exit", onExit);
|
|
2020
|
-
return {
|
|
2021
|
-
redraw: draw,
|
|
2022
|
-
print: (text) => {
|
|
2023
|
-
clear();
|
|
2024
|
-
write(`${text}
|
|
2025
|
-
`);
|
|
2026
|
-
draw();
|
|
2027
|
-
},
|
|
2028
|
-
stop
|
|
2029
|
-
};
|
|
2030
|
-
}
|
|
2031
|
-
function cutToWidth(line, width) {
|
|
2032
|
-
if (Bun.stringWidth(line) <= width)
|
|
2033
|
-
return line;
|
|
2034
|
-
let room = width;
|
|
2035
|
-
let kept = "";
|
|
2036
|
-
let index = 0;
|
|
2037
|
-
let linked = false;
|
|
2038
|
-
while (index < line.length) {
|
|
2039
|
-
ESCAPE_CODE.lastIndex = index;
|
|
2040
|
-
const escape = ESCAPE_CODE.exec(line);
|
|
2041
|
-
if (escape !== null) {
|
|
2042
|
-
kept += escape[0];
|
|
2043
|
-
linked ||= escape[0].startsWith(`${ESC}]`);
|
|
2044
|
-
index = ESCAPE_CODE.lastIndex;
|
|
2045
|
-
continue;
|
|
2046
|
-
}
|
|
2047
|
-
const char = String.fromCodePoint(line.codePointAt(index));
|
|
2048
|
-
const columns = Bun.stringWidth(char);
|
|
2049
|
-
if (columns > room)
|
|
2050
|
-
break;
|
|
2051
|
-
kept += char;
|
|
2052
|
-
room -= columns;
|
|
2053
|
-
index += char.length;
|
|
2054
|
-
}
|
|
2055
|
-
return `${kept}${RESET_STYLE}${linked ? CLOSE_LINK : ""}`;
|
|
2056
|
-
}
|
|
2057
|
-
function interceptOutput(clear) {
|
|
2058
|
-
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [process9.stdout, "write"], [process9.stderr, "write"]];
|
|
2059
|
-
const wrapped = targets.map(([target, name]) => {
|
|
2060
|
-
const original = Reflect.get(target, name);
|
|
2061
|
-
const wrapper = (...args) => {
|
|
2062
|
-
clear();
|
|
2063
|
-
return original.apply(target, args);
|
|
2064
|
-
};
|
|
2065
|
-
Reflect.set(target, name, wrapper);
|
|
2066
|
-
return { target, name, original, wrapper };
|
|
2067
|
-
});
|
|
2068
|
-
return () => {
|
|
2069
|
-
for (const { target, name, original, wrapper } of wrapped) {
|
|
2070
|
-
if (Reflect.get(target, name) === wrapper)
|
|
2071
|
-
Reflect.set(target, name, original);
|
|
2072
|
-
}
|
|
2073
|
-
};
|
|
2074
|
-
}
|
|
2075
|
-
var FRAMES, FRAME_MS = 80, CLEAR_LINE = "\r\x1B[2K", LINE_UP = "\x1B[1A\x1B[2K", ESC, ESCAPE_CODE, RESET_STYLE, CLOSE_LINK, CONSOLE_METHODS;
|
|
2076
|
-
var init_progress = __esm(() => {
|
|
2077
|
-
init_format();
|
|
2078
|
-
init_process();
|
|
2079
|
-
init_style();
|
|
2080
|
-
FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
2081
|
-
ESC = String.fromCharCode(27);
|
|
2082
|
-
ESCAPE_CODE = new RegExp(`${ESC}(?:\\[[\\x30-\\x3F]*[\\x20-\\x2F]*[\\x40-\\x7E]|\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\))`, "y");
|
|
2083
|
-
RESET_STYLE = `${ESC}[0m`;
|
|
2084
|
-
CLOSE_LINK = `${ESC}]8;;${ESC}\\`;
|
|
2085
|
-
CONSOLE_METHODS = ["log", "info", "warn", "error", "debug", "dir", "dirxml", "table", "trace", "group", "groupCollapsed", "count", "timeEnd", "timeLog", "assert"];
|
|
2086
|
-
});
|
|
2087
|
-
|
|
2088
2364
|
// ../kit/src/shell.ts
|
|
2089
|
-
|
|
2365
|
+
function wrapper(short = "", long = [], operands = 0) {
|
|
2366
|
+
return { short, long, operands };
|
|
2367
|
+
}
|
|
2368
|
+
var SEPARATORS2, PLAIN_BREAKERS, GLOB_CHARS, COMMENT_PREFIXES, DOUBLE_QUOTED_ESCAPES, KEYWORDS, SHELLS, COMMAND_STRING_PROGRAMS, SHELL_VALUE_OPTIONS, PRINTERS, FIND_EXEC, WRAPPERS;
|
|
2090
2369
|
var init_shell = __esm(() => {
|
|
2091
2370
|
SEPARATORS2 = new Set([`
|
|
2092
2371
|
`, ";", "|"]);
|
|
2093
2372
|
PLAIN_BREAKERS = new Set(["<", ">", "(", ")", "&", "|"]);
|
|
2373
|
+
GLOB_CHARS = new Set(["*", "?", "["]);
|
|
2374
|
+
COMMENT_PREFIXES = new Set([";", "&", "|", "(", ")"]);
|
|
2094
2375
|
DOUBLE_QUOTED_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
2095
|
-
|
|
2376
|
+
KEYWORDS = new Set(["then", "do", "else", "if", "elif", "while", "until", "!", "{", "}"]);
|
|
2377
|
+
SHELLS = new Set(["sh", "bash", "zsh", "dash", "ash", "ksh"]);
|
|
2378
|
+
COMMAND_STRING_PROGRAMS = new Set([...SHELLS, "su", "runuser"]);
|
|
2379
|
+
SHELL_VALUE_OPTIONS = new Set(["-o", "-O", "--rcfile", "--init-file"]);
|
|
2380
|
+
PRINTERS = new Set(["echo", "printf"]);
|
|
2381
|
+
FIND_EXEC = new Set(["-exec", "-execdir", "-ok", "-okdir"]);
|
|
2382
|
+
WRAPPERS = new Map([
|
|
2383
|
+
["command", wrapper()],
|
|
2384
|
+
["builtin", wrapper()],
|
|
2385
|
+
["nohup", wrapper()],
|
|
2386
|
+
["setsid", wrapper()],
|
|
2387
|
+
["busybox", wrapper()],
|
|
2388
|
+
["exec", wrapper("a")],
|
|
2389
|
+
["time", wrapper("fo", ["--format", "--output"])],
|
|
2390
|
+
["env", wrapper("uCS", ["--unset", "--chdir", "--split-string", "--argv0"])],
|
|
2391
|
+
["sudo", wrapper("ughpCTrtUDR", ["--user", "--group", "--host", "--prompt", "--close-from", "--command-timeout", "--role", "--type", "--other-user", "--chdir", "--chroot"])],
|
|
2392
|
+
["doas", wrapper("uC")],
|
|
2393
|
+
["timeout", wrapper("sk", ["--signal", "--kill-after"], 1)],
|
|
2394
|
+
["nice", wrapper("n", ["--adjustment"])],
|
|
2395
|
+
["ionice", wrapper("cnpPu", ["--class", "--classdata", "--pid", "--pgid", "--uid"])],
|
|
2396
|
+
["stdbuf", wrapper("ioe", ["--input", "--output", "--error"])],
|
|
2397
|
+
["chroot", wrapper("", ["--userspec", "--groups"], 1)],
|
|
2398
|
+
["xargs", wrapper("IndsEaPL", ["--max-args", "--max-procs", "--max-chars", "--delimiter", "--arg-file", "--eof", "--max-lines", "--process-slot-var"])]
|
|
2399
|
+
]);
|
|
2096
2400
|
});
|
|
2097
2401
|
|
|
2098
2402
|
// src/pin.ts
|
|
@@ -2187,7 +2491,7 @@ var init_consumers = __esm(() => {
|
|
|
2187
2491
|
init_pin();
|
|
2188
2492
|
KINDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
2189
2493
|
SKIPPED = new Set(["node_modules", "dist", "build", "vendor", "target", "coverage"]);
|
|
2190
|
-
LOCAL_SPEC =
|
|
2494
|
+
LOCAL_SPEC = /[:/]/;
|
|
2191
2495
|
KIND_FLAGS = { dependencies: [], devDependencies: ["--dev"], optionalDependencies: ["--optional"], peerDependencies: ["--peer"] };
|
|
2192
2496
|
});
|
|
2193
2497
|
|
|
@@ -2200,23 +2504,43 @@ __export(exports_bump, {
|
|
|
2200
2504
|
import { existsSync as existsSync2 } from "fs";
|
|
2201
2505
|
import { homedir as homedir2 } from "os";
|
|
2202
2506
|
import { dirname as dirname3, join as join4, relative as relative2 } from "path";
|
|
2507
|
+
async function lookup(name, registry, fetcher) {
|
|
2508
|
+
try {
|
|
2509
|
+
return { packument: await fetchPackument(name, registry, fetcher) };
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
if (error instanceof Exit && error.code === 2)
|
|
2512
|
+
return { error: error.message };
|
|
2513
|
+
throw error;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2203
2516
|
async function servedVersion(name, version, settings) {
|
|
2517
|
+
if (!isValidName(name))
|
|
2518
|
+
fail(`${name} is not a valid npm package name`);
|
|
2519
|
+
if (version !== undefined && !EXACT_VERSION.test(version))
|
|
2520
|
+
fail(`bump takes an exact version, not ${version}: leave it out for the latest`);
|
|
2204
2521
|
const registry = registryFor(name, settings.configs);
|
|
2205
2522
|
const host = new URL(registry.url).host;
|
|
2206
2523
|
const started = Date.now();
|
|
2207
2524
|
const region = liveRegion((spinner) => [`${spinner} waiting for ${host} to serve ${name}@${version} ${formatDuration(Date.now() - started)}`]);
|
|
2525
|
+
let lastError = "";
|
|
2208
2526
|
try {
|
|
2209
2527
|
for (;; ) {
|
|
2210
|
-
const
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2528
|
+
const looked = await lookup(name, registry, settings.fetcher);
|
|
2529
|
+
if ("error" in looked) {
|
|
2530
|
+
lastError = looked.error;
|
|
2531
|
+
} else {
|
|
2532
|
+
const latest = looked.packument?.["dist-tags"]?.latest;
|
|
2533
|
+
if (looked.packument === undefined)
|
|
2534
|
+
fail(`${host} has no ${name}`, 1);
|
|
2535
|
+
if (version === undefined && latest === undefined)
|
|
2536
|
+
fail(`${host} has no ${name}`, 1);
|
|
2537
|
+
if (version === undefined && latest !== undefined)
|
|
2538
|
+
return latest;
|
|
2539
|
+
if (version !== undefined && looked.packument.versions?.[version] !== undefined)
|
|
2540
|
+
return version;
|
|
2541
|
+
}
|
|
2218
2542
|
if (Date.now() - started >= settings.timeout)
|
|
2219
|
-
fail(`${host} does not serve ${name}@${version} after ${formatDuration(settings.timeout)}`);
|
|
2543
|
+
fail(`${host} does not serve ${name}@${version} after ${formatDuration(settings.timeout)}${lastError === "" ? "" : `, last error: ${lastError}`}`);
|
|
2220
2544
|
region.redraw();
|
|
2221
2545
|
await Bun.sleep(settings.poll ?? POLL);
|
|
2222
2546
|
}
|
|
@@ -2224,6 +2548,20 @@ async function servedVersion(name, version, settings) {
|
|
|
2224
2548
|
region.stop();
|
|
2225
2549
|
}
|
|
2226
2550
|
}
|
|
2551
|
+
async function vet(name, version, settings) {
|
|
2552
|
+
if (settings.isForced === true)
|
|
2553
|
+
return true;
|
|
2554
|
+
const report = await checkPackage(`${name}@${version}`, { configs: settings.configs, fetcher: settings.fetcher, minAgeDays: settings.minAgeDays ?? 0, settings: settings.pkgSettings });
|
|
2555
|
+
if (!report.blocked) {
|
|
2556
|
+
for (const warning of report.warnings)
|
|
2557
|
+
warn(`${name}@${version}`, warning);
|
|
2558
|
+
return true;
|
|
2559
|
+
}
|
|
2560
|
+
for (const warning of report.warnings)
|
|
2561
|
+
problem(`${name}@${version} is refused`, warning);
|
|
2562
|
+
problem(`${name}@${version} is refused`, "no consumer was touched, --force bumps it anyway");
|
|
2563
|
+
return false;
|
|
2564
|
+
}
|
|
2227
2565
|
function lockfileOf(dir, root) {
|
|
2228
2566
|
for (let at = dir;; at = dirname3(at)) {
|
|
2229
2567
|
const found = ["bun.lock", "bun.lockb"].find((file) => existsSync2(join4(at, file)));
|
|
@@ -2233,6 +2571,11 @@ function lockfileOf(dir, root) {
|
|
|
2233
2571
|
return;
|
|
2234
2572
|
}
|
|
2235
2573
|
}
|
|
2574
|
+
async function hasUncommittedChanges(where, root, run) {
|
|
2575
|
+
const lockfile = lockfileOf(where, root);
|
|
2576
|
+
const status = await run(["git", "status", "--porcelain", "--", "package.json", ...lockfile === undefined ? [] : [lockfile]], where);
|
|
2577
|
+
return status.code === 0 && status.text.trim() !== "";
|
|
2578
|
+
}
|
|
2236
2579
|
async function checkAndCommit(name, version, where, root, run) {
|
|
2237
2580
|
const checked = await run(["check"], where);
|
|
2238
2581
|
if (checked.code !== 0)
|
|
@@ -2255,11 +2598,14 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2255
2598
|
if (found.length === 0)
|
|
2256
2599
|
note(`nothing under ${settings.root} depends on ${name}`);
|
|
2257
2600
|
if (local > 0)
|
|
2258
|
-
note(`${local}
|
|
2601
|
+
note(`${local} non-registry dependenc${local === 1 ? "y" : "ies"} (workspace:, file:, git, URL, alias, catalog:)`, "left as they are");
|
|
2259
2602
|
for (const consumer of consumers) {
|
|
2260
2603
|
const argv = addCommand(consumer, name, version);
|
|
2261
2604
|
const where = join4(settings.root, consumer.dir);
|
|
2262
|
-
if (consumer.
|
|
2605
|
+
if (consumer.kind === "peerDependencies") {
|
|
2606
|
+
skipped.push(consumer.dir);
|
|
2607
|
+
note(consumer.dir, `peer range ${consumer.spec}, left as it is`);
|
|
2608
|
+
} else if (consumer.spec === version) {
|
|
2263
2609
|
skipped.push(consumer.dir);
|
|
2264
2610
|
note(consumer.dir, `already on ${version}`);
|
|
2265
2611
|
} else if (consumer.manager !== "bun") {
|
|
@@ -2267,6 +2613,10 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2267
2613
|
warn(consumer.dir, `${consumer.spec}, its lockfile pins ${consumer.manager}: put ${version} in by hand`);
|
|
2268
2614
|
} else if (settings.isDryRun === true) {
|
|
2269
2615
|
note(consumer.dir, `would run ${[argv.join(" "), ...settings.isAll === true ? ["check", `gc 'chore(deps): bump ${name} to ${version}'`] : []].join(", then ")}`);
|
|
2616
|
+
} else if (settings.isAll === true && await hasUncommittedChanges(where, settings.root, run)) {
|
|
2617
|
+
isClean = false;
|
|
2618
|
+
failing.push(consumer.dir);
|
|
2619
|
+
problem(consumer.dir, "package.json or its lockfile has uncommitted changes, left alone so that gc does not commit them");
|
|
2270
2620
|
} else {
|
|
2271
2621
|
const ran = await run(argv, where);
|
|
2272
2622
|
if (ran.code !== 0) {
|
|
@@ -2300,30 +2650,40 @@ async function bump(args) {
|
|
|
2300
2650
|
configs: await loadConfigs(),
|
|
2301
2651
|
timeout: duration(values.timeout, "timeout", 10 * 60000),
|
|
2302
2652
|
isDryRun: values["dry-run"] === true,
|
|
2303
|
-
isAll: values["all-consumers"] === true
|
|
2653
|
+
isAll: values["all-consumers"] === true,
|
|
2654
|
+
isForced: values.force === true,
|
|
2655
|
+
pkgSettings: await loadSettings(),
|
|
2656
|
+
minAgeDays: wholeNumber(values["min-age"], "min-age", 0, 0)
|
|
2304
2657
|
};
|
|
2305
2658
|
const version = await servedVersion(name, asked, settings);
|
|
2659
|
+
if (!await vet(name, version, settings))
|
|
2660
|
+
return 1;
|
|
2306
2661
|
return await bumpConsumers(name, version, settings) ? 0 : 1;
|
|
2307
2662
|
}
|
|
2308
2663
|
var usage3 = `pkg bump <name> [version]
|
|
2309
2664
|
|
|
2310
|
-
Waits until the registry serves the version (the latest when none is given), then runs \`bun add --exact --no-cache\` in each folder under --root whose package.json depends on the package, the kind of dependency kept, a line per folder.
|
|
2311
|
-
A
|
|
2312
|
-
|
|
2665
|
+
Waits until the registry serves the version (the latest when none is given, an exact version otherwise), vets it as \`pkg check\` does (advisories, licence allowlist, and a minimum age only when --min-age asks for one), then runs \`bun add --exact --no-cache\` in each folder under --root whose package.json depends on the package, the kind of dependency kept, a line per folder.
|
|
2666
|
+
A version the vetting blocks is refused before any folder is touched, unless --force is given.
|
|
2667
|
+
A dependency that is not a registry version (workspace:, link:, file:, git, a URL, an npm: alias, catalog:), a peer range, a folder already on the version and one whose lockfile pins another manager are left as they are, each said so.
|
|
2668
|
+
With --all-consumers a folder whose package.json or lockfile already has uncommitted changes is left alone, and each folder whose install went through then runs its own \`check\` (the check bin) and is committed with \`gc 'chore(deps): bump <name> to <version>' -- package.json <lockfile>\` only when that passes; a failing one is left uncommitted and listed in the summary with the skipped ones, and nothing is ever pushed.
|
|
2313
2669
|
|
|
2314
|
-
Exits 0 when every install ran or was left as it is (with --all-consumers, and every check passed and every commit landed), 1 when an install, a check or a commit fails or the registry has no such package, 2 when the version never shows within the timeout or on a usage error.`, ROOT_OPTION, options3, POLL = 5000;
|
|
2670
|
+
Exits 0 when every install ran or was left as it is (with --all-consumers, and every check passed and every commit landed), 1 when the vetting refuses the version, an install, a check or a commit fails or the registry has no such package, 2 when the version never shows within the timeout (a registry that cannot be reached is retried until then) or on a usage error.`, ROOT_OPTION, options3, POLL = 5000;
|
|
2315
2671
|
var init_bump = __esm(() => {
|
|
2316
2672
|
init_src();
|
|
2317
2673
|
init_progress();
|
|
2318
2674
|
init_config2();
|
|
2319
2675
|
init_consumers();
|
|
2320
2676
|
init_registry();
|
|
2677
|
+
init_semver();
|
|
2678
|
+
init_check();
|
|
2321
2679
|
ROOT_OPTION = { type: "string", description: "the folder holding the repositories (~/Workspace)" };
|
|
2322
2680
|
options3 = {
|
|
2323
2681
|
root: ROOT_OPTION,
|
|
2324
2682
|
timeout: { type: "string", short: "t", description: "how long to wait for the registry (10m): 30s, 5m, 1h" },
|
|
2325
2683
|
"all-consumers": { type: "boolean", description: "after each install run the folder's check and commit it through gc when it passes" },
|
|
2326
|
-
"dry-run": { type: "boolean", description: "print what would run, changing nothing" }
|
|
2684
|
+
"dry-run": { type: "boolean", description: "print what would run, changing nothing" },
|
|
2685
|
+
force: { type: "boolean", description: "bump even when the version is blocked by the vetting" },
|
|
2686
|
+
"min-age": { type: "string", description: "days a version must be old (0: a bump adopts a release on purpose, often one just made)" }
|
|
2327
2687
|
};
|
|
2328
2688
|
});
|
|
2329
2689
|
|
|
@@ -2367,7 +2727,7 @@ var init_consumers2 = __esm(() => {
|
|
|
2367
2727
|
init_src();
|
|
2368
2728
|
import process10 from "process";
|
|
2369
2729
|
// package.json
|
|
2370
|
-
var version = "0.
|
|
2730
|
+
var version = "0.5.0";
|
|
2371
2731
|
|
|
2372
2732
|
// src/cli.ts
|
|
2373
2733
|
process10.exitCode = await runCli({
|