@kaynooo/cli-pkg 0.7.1 → 0.8.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 +11 -4
- package/dist/cli.js +682 -450
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,18 @@ var __esm = (fn, res, err) => () => {
|
|
|
26
26
|
return res;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
// ../kit/src/advisory.ts
|
|
30
|
+
function severityRank(severity) {
|
|
31
|
+
return SEVERITIES.indexOf(severity);
|
|
32
|
+
}
|
|
33
|
+
function isIgnored(advisory, ignore) {
|
|
34
|
+
return ignore.includes(advisory.ghsa ?? "") || ignore.includes(String(advisory.id));
|
|
35
|
+
}
|
|
36
|
+
var SEVERITIES;
|
|
37
|
+
var init_advisory = __esm(() => {
|
|
38
|
+
SEVERITIES = ["low", "moderate", "high", "critical"];
|
|
39
|
+
});
|
|
40
|
+
|
|
29
41
|
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-mtetydvc.js
|
|
30
42
|
function x(s) {
|
|
31
43
|
let r = s.startsWith("#") ? s.slice(1).toLowerCase() : s.toLowerCase();
|
|
@@ -293,30 +305,30 @@ var init_colors = __esm(() => {
|
|
|
293
305
|
});
|
|
294
306
|
|
|
295
307
|
// ../kit/src/style.ts
|
|
296
|
-
import
|
|
297
|
-
function takesControlCodes(stream, env =
|
|
308
|
+
import process2 from "process";
|
|
309
|
+
function takesControlCodes(stream, env = process2.env) {
|
|
298
310
|
return stream.isTTY === true && env.NO_COLOR === undefined && env.NODE_DISABLE_COLORS === undefined && env.TERM !== "dumb";
|
|
299
311
|
}
|
|
300
|
-
function paint(stream, env =
|
|
312
|
+
function paint(stream, env = process2.env) {
|
|
301
313
|
return le({ stream: { isTTY: takesControlCodes(stream, env) }, env });
|
|
302
314
|
}
|
|
303
|
-
function marked(mark, text, stream, detail, env =
|
|
315
|
+
function marked(mark, text, stream, detail, env = process2.env) {
|
|
304
316
|
const colors = paint(stream, env);
|
|
305
317
|
const { symbol, word, paint: tint } = MARKS[mark];
|
|
306
318
|
const head = takesControlCodes(stream, env) ? tint(colors)(symbol) : word;
|
|
307
319
|
return `${head} ${text}${detail === undefined ? "" : ` ${colors.dim(detail)}`}`;
|
|
308
320
|
}
|
|
309
321
|
function ok(text, detail) {
|
|
310
|
-
console.log(marked("ok", text,
|
|
322
|
+
console.log(marked("ok", text, process2.stdout, detail));
|
|
311
323
|
}
|
|
312
324
|
function note(text, detail) {
|
|
313
|
-
console.log(marked("note", text,
|
|
325
|
+
console.log(marked("note", text, process2.stdout, detail));
|
|
314
326
|
}
|
|
315
327
|
function warn(text, detail) {
|
|
316
|
-
console.error(marked("warn", text,
|
|
328
|
+
console.error(marked("warn", text, process2.stderr, detail));
|
|
317
329
|
}
|
|
318
330
|
function problem(text, detail) {
|
|
319
|
-
console.error(marked("problem", text,
|
|
331
|
+
console.error(marked("problem", text, process2.stderr, detail));
|
|
320
332
|
}
|
|
321
333
|
var MARKS, STATUSES, STATUS_OF;
|
|
322
334
|
var init_style = __esm(() => {
|
|
@@ -338,7 +350,7 @@ var init_style = __esm(() => {
|
|
|
338
350
|
});
|
|
339
351
|
|
|
340
352
|
// ../kit/src/format.ts
|
|
341
|
-
import
|
|
353
|
+
import process3 from "process";
|
|
342
354
|
function formatSeconds(total) {
|
|
343
355
|
let rest = Math.max(0, Math.round(total));
|
|
344
356
|
const amounts = UNITS.map(([unit, size]) => {
|
|
@@ -383,7 +395,7 @@ function table(rows, { cellWidth, header = false, align = [], fit } = {}) {
|
|
|
383
395
|
widths[index] = Math.max(widths[index] ?? 0, textWidth(cell));
|
|
384
396
|
}
|
|
385
397
|
const shown = fit === undefined ? cells : narrow(cells, widths, fit);
|
|
386
|
-
const colors = paint(
|
|
398
|
+
const colors = paint(process3.stdout);
|
|
387
399
|
const lines = shown.map((row) => row.map((cell, index) => {
|
|
388
400
|
const width = widths[index] ?? 0;
|
|
389
401
|
const gap = " ".repeat(Math.max(0, width - textWidth(cell)));
|
|
@@ -422,21 +434,27 @@ var init_format = __esm(() => {
|
|
|
422
434
|
});
|
|
423
435
|
|
|
424
436
|
// ../kit/src/help.ts
|
|
425
|
-
import
|
|
426
|
-
function usageLine(usage, colors = paint(
|
|
437
|
+
import process4 from "process";
|
|
438
|
+
function usageLine(usage, colors = paint(process4.stdout)) {
|
|
427
439
|
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
428
440
|
}
|
|
429
|
-
function helpText(usage, options, colors = paint(
|
|
430
|
-
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
|
|
441
|
+
function helpText(usage, options, colors = paint(process4.stdout), { examples = [], replaces, exits = [] } = {}) {
|
|
442
|
+
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exitRows(exits, colors), ...exampleRows(examples, colors)].join(`
|
|
431
443
|
`);
|
|
432
444
|
}
|
|
433
|
-
function
|
|
445
|
+
function exitRows(exits, colors = paint(process4.stdout)) {
|
|
446
|
+
if (exits.length === 0)
|
|
447
|
+
return [];
|
|
448
|
+
const width = Math.max(...exits.map(([code]) => String(code).length));
|
|
449
|
+
return ["", colors.bold("Exits:"), ...exits.map(([code, meaning]) => ` ${colors.cyan(String(code).padEnd(width))} ${meaning}`)];
|
|
450
|
+
}
|
|
451
|
+
function replacesRows(replaces, colors = paint(process4.stdout)) {
|
|
434
452
|
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
435
453
|
}
|
|
436
|
-
function wantsHelpJson(env =
|
|
454
|
+
function wantsHelpJson(env = process4.env) {
|
|
437
455
|
return env.KIT_HELP === "json";
|
|
438
456
|
}
|
|
439
|
-
function description(usage, { examples = [], replaces } = {}) {
|
|
457
|
+
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
440
458
|
const lines = usage.replace(USAGE_PREFIX, "").split(`
|
|
441
459
|
`);
|
|
442
460
|
const first = lines[0];
|
|
@@ -447,15 +465,17 @@ function description(usage, { examples = [], replaces } = {}) {
|
|
|
447
465
|
synopsis: colon === -1 ? first : first.slice(0, colon),
|
|
448
466
|
summary: colon === -1 ? fallback : first.slice(colon + 2),
|
|
449
467
|
...replaces === undefined ? {} : { replaces },
|
|
450
|
-
examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
|
|
468
|
+
examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] }),
|
|
469
|
+
...exits === undefined ? {} : { exits: exits.map(([code, meaning]) => ({ code, meaning })) },
|
|
470
|
+
...options === undefined ? {} : { options: Object.entries(options).map(([name, { short, description }]) => ({ name, ...short === undefined ? {} : { short }, ...description === undefined ? {} : { description } })) }
|
|
451
471
|
};
|
|
452
472
|
}
|
|
453
|
-
function exampleRows(examples, colors = paint(
|
|
473
|
+
function exampleRows(examples, colors = paint(process4.stdout)) {
|
|
454
474
|
if (examples.length === 0)
|
|
455
475
|
return [];
|
|
456
476
|
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
457
477
|
}
|
|
458
|
-
function optionRows(options, colors = paint(
|
|
478
|
+
function optionRows(options, colors = paint(process4.stdout)) {
|
|
459
479
|
const rows = Object.entries(options).map(([name, option]) => {
|
|
460
480
|
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
461
481
|
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
@@ -498,6 +518,8 @@ var init_text = __esm(() => {
|
|
|
498
518
|
});
|
|
499
519
|
|
|
500
520
|
// ../kit/src/input.ts
|
|
521
|
+
import { fstatSync } from "fs";
|
|
522
|
+
import process5 from "process";
|
|
501
523
|
function wholeNumber(value, name, fallback, min = 1) {
|
|
502
524
|
if (value === undefined)
|
|
503
525
|
return fallback;
|
|
@@ -515,6 +537,21 @@ function duration(value, name, fallback, unit = "s") {
|
|
|
515
537
|
badUsage(`--${name} takes a duration such as 30s, 5m, 1h or 7d, not ${value}`);
|
|
516
538
|
return ms;
|
|
517
539
|
}
|
|
540
|
+
function isStdinPiped() {
|
|
541
|
+
const stat = fstatSync(0);
|
|
542
|
+
return stat.isFIFO() || stat.isFile();
|
|
543
|
+
}
|
|
544
|
+
async function readInput(path, { noStdin = "nothing is piped on stdin" } = {}) {
|
|
545
|
+
if (path === "-") {
|
|
546
|
+
if (process5.stdin.isTTY)
|
|
547
|
+
fail(noStdin);
|
|
548
|
+
return Bun.stdin.text();
|
|
549
|
+
}
|
|
550
|
+
const file = Bun.file(path);
|
|
551
|
+
if (!await file.exists())
|
|
552
|
+
fail(`no file ${path}`);
|
|
553
|
+
return file.text();
|
|
554
|
+
}
|
|
518
555
|
var WHOLE, DURATION, UNIT_MS;
|
|
519
556
|
var init_input = __esm(() => {
|
|
520
557
|
init_args();
|
|
@@ -524,7 +561,7 @@ var init_input = __esm(() => {
|
|
|
524
561
|
});
|
|
525
562
|
|
|
526
563
|
// ../kit/src/args.ts
|
|
527
|
-
import
|
|
564
|
+
import process6 from "process";
|
|
528
565
|
import { parseArgs } from "util";
|
|
529
566
|
function jsonOption(holds) {
|
|
530
567
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
@@ -546,7 +583,7 @@ class Completing {
|
|
|
546
583
|
this.candidates = candidates;
|
|
547
584
|
}
|
|
548
585
|
}
|
|
549
|
-
function applyOutput(color, plain, env =
|
|
586
|
+
function applyOutput(color, plain, env = process6.env) {
|
|
550
587
|
const when = plain === true ? "never" : color ?? "auto";
|
|
551
588
|
if (when === "auto")
|
|
552
589
|
return;
|
|
@@ -569,7 +606,7 @@ function parse(args, usage, options, settings = {}) {
|
|
|
569
606
|
const { own, rest } = settings.trailing === true ? splitTrailing(args, all, settings.positionals?.length ?? 0) : splitRest(args, settings.rest === true);
|
|
570
607
|
let parsed;
|
|
571
608
|
try {
|
|
572
|
-
parsed = parseArgs({ args: joinDashValues(withBare(own, all), all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
|
|
609
|
+
parsed = parseArgs({ args: joinDashValues(withBare(withAliases(own, all), all), all), options: all, allowPositionals: true, allowNegative: settings.allowNegative === true, strict: true });
|
|
573
610
|
} catch (error) {
|
|
574
611
|
const message = parseError(error);
|
|
575
612
|
throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
|
|
@@ -577,7 +614,7 @@ function parse(args, usage, options, settings = {}) {
|
|
|
577
614
|
const values = parsed.values;
|
|
578
615
|
applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
|
|
579
616
|
if (values.help === true) {
|
|
580
|
-
console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage, listing, undefined, settings));
|
|
617
|
+
console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings, listing)) : helpText(usage, listing, undefined, settings));
|
|
581
618
|
throw new HelpShown;
|
|
582
619
|
}
|
|
583
620
|
checkChoices(parsed.values, all);
|
|
@@ -619,6 +656,18 @@ function listed(options, allowNegative) {
|
|
|
619
656
|
return [...option.description === undefined ? [] : [[name, option]], [`no-${name}`, { type: "boolean", description: option.negative }]];
|
|
620
657
|
}));
|
|
621
658
|
}
|
|
659
|
+
function withAliases(args, options) {
|
|
660
|
+
const named = new Map(Object.entries(options).flatMap(([name, { aliases = [] }]) => aliases.map((alias) => [`--${alias}`, `--${name}`])));
|
|
661
|
+
if (named.size === 0)
|
|
662
|
+
return args;
|
|
663
|
+
const separator = args.indexOf("--");
|
|
664
|
+
const own = separator === -1 ? args : args.slice(0, separator);
|
|
665
|
+
return [...own.map((arg) => {
|
|
666
|
+
const at = arg.indexOf("=");
|
|
667
|
+
const current = named.get(at === -1 ? arg : arg.slice(0, at));
|
|
668
|
+
return current === undefined ? arg : `${current}${at === -1 ? "" : arg.slice(at)}`;
|
|
669
|
+
}), ...separator === -1 ? [] : args.slice(separator)];
|
|
670
|
+
}
|
|
622
671
|
function withBare(args, options) {
|
|
623
672
|
const bare = new Map(Object.entries(options).flatMap(([name, { short, optional }]) => optional === undefined ? [] : [[`--${name}`, optional], ...short === undefined ? [] : [[`-${short}`, optional]]]));
|
|
624
673
|
if (bare.size === 0)
|
|
@@ -745,7 +794,7 @@ var init_chart = __esm(() => {
|
|
|
745
794
|
|
|
746
795
|
// ../kit/src/process.ts
|
|
747
796
|
import { constants } from "os";
|
|
748
|
-
import
|
|
797
|
+
import process7 from "process";
|
|
749
798
|
function exitCodeOf(code, signal) {
|
|
750
799
|
if (code !== null)
|
|
751
800
|
return code;
|
|
@@ -765,7 +814,7 @@ function holdSignals(cleanup) {
|
|
|
765
814
|
},
|
|
766
815
|
release: () => {
|
|
767
816
|
for (const signal of SIGNALS)
|
|
768
|
-
|
|
817
|
+
process7.off(signal, onSignal);
|
|
769
818
|
}
|
|
770
819
|
};
|
|
771
820
|
function onSignal(signal) {
|
|
@@ -778,10 +827,10 @@ function holdSignals(cleanup) {
|
|
|
778
827
|
return;
|
|
779
828
|
held.release();
|
|
780
829
|
cleanup(signal);
|
|
781
|
-
|
|
830
|
+
process7.kill(process7.pid, signal);
|
|
782
831
|
}
|
|
783
832
|
for (const signal of SIGNALS)
|
|
784
|
-
|
|
833
|
+
process7.on(signal, onSignal);
|
|
785
834
|
return held;
|
|
786
835
|
}
|
|
787
836
|
async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal, maxBytes = Infinity, onChunk, onStart } = {}) {
|
|
@@ -795,7 +844,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
|
|
|
795
844
|
return;
|
|
796
845
|
try {
|
|
797
846
|
if (grouped)
|
|
798
|
-
|
|
847
|
+
process7.kill(-proc.pid, killing);
|
|
799
848
|
else
|
|
800
849
|
proc.kill(killing);
|
|
801
850
|
} catch {}
|
|
@@ -868,8 +917,8 @@ var init_process = __esm(() => {
|
|
|
868
917
|
});
|
|
869
918
|
|
|
870
919
|
// ../kit/src/progress.ts
|
|
871
|
-
import
|
|
872
|
-
function liveRegion(render, stream =
|
|
920
|
+
import process8 from "process";
|
|
921
|
+
function liveRegion(render, stream = process8.stderr, env = process8.env) {
|
|
873
922
|
if (!takesControlCodes(stream, env))
|
|
874
923
|
return { redraw: () => {
|
|
875
924
|
return;
|
|
@@ -910,11 +959,11 @@ function liveRegion(render, stream = process6.stderr, env = process6.env) {
|
|
|
910
959
|
clear();
|
|
911
960
|
restore();
|
|
912
961
|
release();
|
|
913
|
-
|
|
962
|
+
process8.off("exit", onExit);
|
|
914
963
|
signals.release();
|
|
915
964
|
}
|
|
916
965
|
timer.unref();
|
|
917
|
-
|
|
966
|
+
process8.on("exit", onExit);
|
|
918
967
|
return {
|
|
919
968
|
redraw: draw,
|
|
920
969
|
print: (text) => {
|
|
@@ -953,14 +1002,14 @@ function cutToWidth(line, width) {
|
|
|
953
1002
|
return `${kept}${RESET_STYLE}${linked ? CLOSE_LINK : ""}`;
|
|
954
1003
|
}
|
|
955
1004
|
function swallowInput() {
|
|
956
|
-
const input =
|
|
1005
|
+
const input = process8.stdin;
|
|
957
1006
|
if (!input.isTTY)
|
|
958
1007
|
return () => {
|
|
959
1008
|
return;
|
|
960
1009
|
};
|
|
961
1010
|
const onData = (data) => {
|
|
962
1011
|
if (data.includes(CTRL_C))
|
|
963
|
-
|
|
1012
|
+
process8.kill(process8.pid, "SIGINT");
|
|
964
1013
|
};
|
|
965
1014
|
input.setRawMode(true);
|
|
966
1015
|
input.on("data", onData);
|
|
@@ -976,7 +1025,7 @@ function swallowInput() {
|
|
|
976
1025
|
};
|
|
977
1026
|
}
|
|
978
1027
|
function interceptOutput(clear) {
|
|
979
|
-
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [
|
|
1028
|
+
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [process8.stdout, "write"], [process8.stderr, "write"]];
|
|
980
1029
|
const wrapped = targets.map(([target, name]) => {
|
|
981
1030
|
const original = Reflect.get(target, name);
|
|
982
1031
|
const wrapper = (...args) => {
|
|
@@ -1030,18 +1079,18 @@ var init_logs = __esm(() => {
|
|
|
1030
1079
|
import { appendFileSync, mkdirSync } from "fs";
|
|
1031
1080
|
import { homedir } from "os";
|
|
1032
1081
|
import { dirname, isAbsolute, join } from "path";
|
|
1033
|
-
import
|
|
1082
|
+
import process9 from "process";
|
|
1034
1083
|
function noteUsageError(message) {
|
|
1035
1084
|
usageError = message;
|
|
1036
1085
|
}
|
|
1037
|
-
function stateHome(env =
|
|
1086
|
+
function stateHome(env = process9.env) {
|
|
1038
1087
|
const dir = env.XDG_STATE_HOME;
|
|
1039
1088
|
return dir !== undefined && isAbsolute(dir) ? dir : join(homedir(), ".local", "state");
|
|
1040
1089
|
}
|
|
1041
|
-
function usagePath(env =
|
|
1090
|
+
function usagePath(env = process9.env) {
|
|
1042
1091
|
return join(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
1043
1092
|
}
|
|
1044
|
-
function usageRecorded(env =
|
|
1093
|
+
function usageRecorded(env = process9.env) {
|
|
1045
1094
|
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
1046
1095
|
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
1047
1096
|
}
|
|
@@ -1055,7 +1104,7 @@ function usageEntry(bin, command, argv, code, now = new Date) {
|
|
|
1055
1104
|
usageError = undefined;
|
|
1056
1105
|
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
1057
1106
|
}
|
|
1058
|
-
function recordUsage(entry, env =
|
|
1107
|
+
function recordUsage(entry, env = process9.env) {
|
|
1059
1108
|
if (!usageRecorded(env))
|
|
1060
1109
|
return;
|
|
1061
1110
|
try {
|
|
@@ -1073,7 +1122,9 @@ var init_usage = __esm(() => {
|
|
|
1073
1122
|
});
|
|
1074
1123
|
|
|
1075
1124
|
// ../kit/src/cli.ts
|
|
1076
|
-
import
|
|
1125
|
+
import { readFileSync, realpathSync } from "fs";
|
|
1126
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
1127
|
+
import process10 from "process";
|
|
1077
1128
|
async function commandRows(all, colors) {
|
|
1078
1129
|
const commands = shown(all);
|
|
1079
1130
|
const width = Math.max(0, ...Object.keys(commands).map((name) => name.length));
|
|
@@ -1148,8 +1199,8 @@ async function help2({ path, header, summary: lazySummary, commands, defaultComm
|
|
|
1148
1199
|
`);
|
|
1149
1200
|
}
|
|
1150
1201
|
function printError(prefix, message, hint, cause) {
|
|
1151
|
-
const colors = paint(
|
|
1152
|
-
const styled = takesControlCodes(
|
|
1202
|
+
const colors = paint(process10.stderr);
|
|
1203
|
+
const styled = takesControlCodes(process10.stderr);
|
|
1153
1204
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
1154
1205
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
1155
1206
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -1192,11 +1243,11 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
1192
1243
|
}
|
|
1193
1244
|
}
|
|
1194
1245
|
if (name === undefined && level.path.length > 1) {
|
|
1195
|
-
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1246
|
+
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stderr));
|
|
1196
1247
|
return 2;
|
|
1197
1248
|
}
|
|
1198
1249
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
1199
|
-
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]),
|
|
1250
|
+
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stdout));
|
|
1200
1251
|
return 0;
|
|
1201
1252
|
}
|
|
1202
1253
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -1310,10 +1361,22 @@ async function printCandidates(found) {
|
|
|
1310
1361
|
console.log(line);
|
|
1311
1362
|
return 0;
|
|
1312
1363
|
}
|
|
1313
|
-
|
|
1364
|
+
function packageVersion(entry = Bun.main) {
|
|
1365
|
+
for (let dir = dirname2(realpathSync(entry));; dir = dirname2(dir)) {
|
|
1366
|
+
try {
|
|
1367
|
+
const { version } = JSON.parse(readFileSync(join2(dir, "package.json"), "utf8"));
|
|
1368
|
+
if (typeof version === "string")
|
|
1369
|
+
return version;
|
|
1370
|
+
} catch {}
|
|
1371
|
+
if (dirname2(dir) === dir)
|
|
1372
|
+
return "0.0.0";
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
async function runCli(cli, argv = process10.argv.slice(2)) {
|
|
1376
|
+
const version = cli.version ?? packageVersion();
|
|
1314
1377
|
if (argv[0] === COMPLETE)
|
|
1315
1378
|
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
1316
|
-
const code = await dispatch({ path: [cli.name], header: (colors, about) => `${colors.bold(cli.name)} ${colors.dim(
|
|
1379
|
+
const code = await dispatch({ path: [cli.name], header: (colors, about) => `${colors.bold(cli.name)} ${colors.dim(version)} ${about}`, summary: cli.about, ...scopeOf(cli.commands, cli.extraCommands, cli.aliases), defaultCommand: cli.defaultCommand, runBare: cli.runBare === true, examples: cli.examples, replaces: cli.replaces }, argv, { version, redact: cli.redact });
|
|
1317
1380
|
if (cli.usage !== false) {
|
|
1318
1381
|
try {
|
|
1319
1382
|
recordUsage(usageEntry(cli.name, commandPath(scopeOf(cli.commands, cli.extraCommands, cli.aliases), argv), argv, code));
|
|
@@ -1348,7 +1411,6 @@ var init_cli = __esm(() => {
|
|
|
1348
1411
|
};
|
|
1349
1412
|
TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
|
|
1350
1413
|
});
|
|
1351
|
-
|
|
1352
1414
|
// ../kit/src/config.ts
|
|
1353
1415
|
var init_config = __esm(() => {
|
|
1354
1416
|
init_args();
|
|
@@ -1399,8 +1461,33 @@ var init_sessions = __esm(() => {
|
|
|
1399
1461
|
ACCOUNT_DIRS = new Glob("*/sessions");
|
|
1400
1462
|
});
|
|
1401
1463
|
|
|
1464
|
+
// ../kit/src/size.ts
|
|
1465
|
+
var init_size = () => {};
|
|
1466
|
+
|
|
1467
|
+
// ../kit/src/user-config.ts
|
|
1468
|
+
import { existsSync } from "fs";
|
|
1469
|
+
import { homedir as homedir2 } from "os";
|
|
1470
|
+
import { join as join3 } from "path";
|
|
1471
|
+
import process11 from "process";
|
|
1472
|
+
function configBase(where = {}) {
|
|
1473
|
+
const xdg = where.xdg ?? (where.home === undefined ? process11.env.XDG_CONFIG_HOME : undefined);
|
|
1474
|
+
return xdg !== undefined && xdg !== "" ? xdg : join3(where.home ?? homedir2(), ".config");
|
|
1475
|
+
}
|
|
1476
|
+
function userConfigPath(bin, where = {}) {
|
|
1477
|
+
return join3(configBase(where), "kaynooo-cli", `${bin}.json`);
|
|
1478
|
+
}
|
|
1479
|
+
function userConfigReadPath(bin, legacy = [], where = {}) {
|
|
1480
|
+
const current = userConfigPath(bin, where);
|
|
1481
|
+
if (existsSync(current))
|
|
1482
|
+
return current;
|
|
1483
|
+
const base = configBase(where);
|
|
1484
|
+
return legacy.map((parts) => join3(base, ...parts)).find((path) => existsSync(path)) ?? current;
|
|
1485
|
+
}
|
|
1486
|
+
var init_user_config = () => {};
|
|
1487
|
+
|
|
1402
1488
|
// ../kit/src/index.ts
|
|
1403
1489
|
var init_src = __esm(() => {
|
|
1490
|
+
init_advisory();
|
|
1404
1491
|
init_args();
|
|
1405
1492
|
init_chart();
|
|
1406
1493
|
init_ci();
|
|
@@ -1413,216 +1500,12 @@ var init_src = __esm(() => {
|
|
|
1413
1500
|
init_process();
|
|
1414
1501
|
init_secrets();
|
|
1415
1502
|
init_sessions();
|
|
1503
|
+
init_size();
|
|
1416
1504
|
init_style();
|
|
1417
1505
|
init_text();
|
|
1418
1506
|
init_tool();
|
|
1419
1507
|
init_usage();
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
// src/registry.ts
|
|
1423
|
-
function isPublic(registry) {
|
|
1424
|
-
return registry.url.replace(TRAILING_SLASHES, "") === PUBLIC_REGISTRY;
|
|
1425
|
-
}
|
|
1426
|
-
function unreachable(message) {
|
|
1427
|
-
return fail(`could not check: ${message}`, 2);
|
|
1428
|
-
}
|
|
1429
|
-
function requestInit(token) {
|
|
1430
|
-
return { headers: { accept: "application/json", ...token === undefined ? {} : { authorization: `Bearer ${token}` } }, signal: AbortSignal.timeout(REQUEST_TIMEOUT) };
|
|
1431
|
-
}
|
|
1432
|
-
async function get(fetcher, url, token) {
|
|
1433
|
-
try {
|
|
1434
|
-
return await fetcher(url, requestInit(token));
|
|
1435
|
-
} catch (error) {
|
|
1436
|
-
return unreachable(`cannot reach ${new URL(url).host}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
function isValidName(name) {
|
|
1440
|
-
return PACKAGE_NAME.test(name) && name.length <= 214;
|
|
1441
|
-
}
|
|
1442
|
-
async function fetchPackument(name, registry, fetcher = fetch) {
|
|
1443
|
-
if (!isValidName(name))
|
|
1444
|
-
fail(`${name} is not a valid npm package name`);
|
|
1445
|
-
const response = await get(fetcher, `${registry.url.replace(TRAILING_SLASHES, "")}/${encodeURIComponent(name).replace("%40", "@").replace("%2F", "%2f")}`, registry.token);
|
|
1446
|
-
if (response.status === 404)
|
|
1447
|
-
return;
|
|
1448
|
-
if (!response.ok)
|
|
1449
|
-
unreachable(`${new URL(registry.url).host} answered ${response.status} for ${name}`);
|
|
1450
|
-
let packument;
|
|
1451
|
-
try {
|
|
1452
|
-
packument = await response.json();
|
|
1453
|
-
} catch {
|
|
1454
|
-
return unreachable(`${new URL(registry.url).host} answered ${name} with something that is not JSON`);
|
|
1455
|
-
}
|
|
1456
|
-
if (packument?.name !== name)
|
|
1457
|
-
unreachable(`${new URL(registry.url).host} answered ${name} with the metadata of ${String(packument?.name)}`);
|
|
1458
|
-
return packument;
|
|
1459
|
-
}
|
|
1460
|
-
async function fetchDownloads(name, fetcher = fetch) {
|
|
1461
|
-
const response = await get(fetcher, `${DOWNLOADS_API}/${encodeURIComponent(name)}`);
|
|
1462
|
-
if (!response.ok)
|
|
1463
|
-
return;
|
|
1464
|
-
try {
|
|
1465
|
-
return (await response.json()).downloads;
|
|
1466
|
-
} catch {
|
|
1467
|
-
return;
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
var PUBLIC_REGISTRY = "https://registry.npmjs.org", DOWNLOADS_API = "https://api.npmjs.org/downloads/point/last-week", TRAILING_SLASHES, REQUEST_TIMEOUT = 1e4, PACKAGE_NAME;
|
|
1471
|
-
var init_registry = __esm(() => {
|
|
1472
|
-
init_src();
|
|
1473
|
-
TRAILING_SLASHES = /\/+$/;
|
|
1474
|
-
PACKAGE_NAME = /^(?:@[\w~-][\w.~-]*\/)?[\w~-][\w.~-]*$/;
|
|
1475
|
-
});
|
|
1476
|
-
|
|
1477
|
-
// src/config.ts
|
|
1478
|
-
import { homedir as homedir2 } from "os";
|
|
1479
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
1480
|
-
import process10 from "process";
|
|
1481
|
-
function expand2(value, env) {
|
|
1482
|
-
let missing = false;
|
|
1483
|
-
const expanded = value.replace(ENV_REFERENCE, (_, braced, bare) => {
|
|
1484
|
-
const found = env[braced ?? bare ?? ""];
|
|
1485
|
-
missing ||= found === undefined;
|
|
1486
|
-
return found ?? "";
|
|
1487
|
-
});
|
|
1488
|
-
return missing ? undefined : expanded;
|
|
1489
|
-
}
|
|
1490
|
-
function literal(value) {
|
|
1491
|
-
return expand2(value, {}) === value ? value : undefined;
|
|
1492
|
-
}
|
|
1493
|
-
function parseNpmrc(text, env) {
|
|
1494
|
-
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
1495
|
-
for (const line of text.split(`
|
|
1496
|
-
`)) {
|
|
1497
|
-
const at = line.indexOf("=");
|
|
1498
|
-
if (at === -1 || COMMENT.test(line))
|
|
1499
|
-
continue;
|
|
1500
|
-
const key = line.slice(0, at).trim();
|
|
1501
|
-
const scope = SCOPE_REGISTRY.exec(key)?.[1];
|
|
1502
|
-
const tokenFor = AUTH_TOKEN.exec(key)?.[1];
|
|
1503
|
-
const raw = line.slice(at + 1).trim().replace(QUOTES, "$2");
|
|
1504
|
-
const value = tokenFor === undefined ? literal(raw) : expand2(raw, env);
|
|
1505
|
-
if (value === undefined || value === "")
|
|
1506
|
-
continue;
|
|
1507
|
-
if (scope !== undefined)
|
|
1508
|
-
config.scopes[scope] = value;
|
|
1509
|
-
else if (tokenFor !== undefined)
|
|
1510
|
-
config.tokens[tokenFor] = value;
|
|
1511
|
-
else if (key === "registry")
|
|
1512
|
-
config.registry = value;
|
|
1513
|
-
}
|
|
1514
|
-
return config;
|
|
1515
|
-
}
|
|
1516
|
-
function bunEntry(entry, env) {
|
|
1517
|
-
const url = typeof entry === "string" ? entry : entry.url;
|
|
1518
|
-
const token = typeof entry === "string" || entry.token === undefined ? undefined : expand2(entry.token, env);
|
|
1519
|
-
return { ...url === undefined || literal(url) === undefined ? {} : { url }, ...token === undefined ? {} : { token } };
|
|
1520
|
-
}
|
|
1521
|
-
function parseBunfig(text, env) {
|
|
1522
|
-
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
1523
|
-
const install = Bun.TOML.parse(text).install;
|
|
1524
|
-
if (install?.registry !== undefined) {
|
|
1525
|
-
const { url, token } = bunEntry(install.registry, env);
|
|
1526
|
-
if (url !== undefined)
|
|
1527
|
-
config.registry = url;
|
|
1528
|
-
if (url !== undefined && token !== undefined)
|
|
1529
|
-
config.tokens[url.replace(PROTOCOL, "")] = token;
|
|
1530
|
-
}
|
|
1531
|
-
for (const [scope, entry] of Object.entries(install?.scopes ?? {})) {
|
|
1532
|
-
const { url, token } = bunEntry(entry, env);
|
|
1533
|
-
if (url !== undefined)
|
|
1534
|
-
config.scopes[scope.startsWith("@") ? scope : `@${scope}`] = url;
|
|
1535
|
-
if (token !== undefined)
|
|
1536
|
-
config.scopeTokens[scope.startsWith("@") ? scope : `@${scope}`] = token;
|
|
1537
|
-
}
|
|
1538
|
-
return config;
|
|
1539
|
-
}
|
|
1540
|
-
function tokenFor(config, url) {
|
|
1541
|
-
const address = `${url.replace(PROTOCOL, "").replace(TRAILING_SLASHES2, "")}/`;
|
|
1542
|
-
const best = Object.keys(config.tokens).filter((key) => address.startsWith(`${key.replace(TRAILING_SLASHES2, "")}/`)).sort((a, b) => b.length - a.length)[0];
|
|
1543
|
-
return best === undefined ? undefined : config.tokens[best];
|
|
1544
|
-
}
|
|
1545
|
-
function mayCarryToken(url) {
|
|
1546
|
-
const { protocol, hostname } = new URL(url);
|
|
1547
|
-
return protocol === "https:" || LOCAL_HOSTS.has(hostname);
|
|
1548
|
-
}
|
|
1549
|
-
function registryFor(name, configs) {
|
|
1550
|
-
const scope = name.startsWith("@") ? name.slice(0, name.indexOf("/")) : undefined;
|
|
1551
|
-
const scoped = scope === undefined ? undefined : configs.find((config) => config.scopes[scope] !== undefined);
|
|
1552
|
-
const url = (scope === undefined ? undefined : scoped?.scopes[scope]) ?? configs.find((config) => config.registry !== undefined)?.registry;
|
|
1553
|
-
if (url === undefined)
|
|
1554
|
-
return { url: PUBLIC_REGISTRY };
|
|
1555
|
-
const token = (scope === undefined ? undefined : scoped?.scopeTokens[scope]) ?? configs.map((other) => tokenFor(other, url)).find((found) => found !== undefined);
|
|
1556
|
-
return { url, token: mayCarryToken(url) ? token : undefined };
|
|
1557
|
-
}
|
|
1558
|
-
function readable(path, parse) {
|
|
1559
|
-
try {
|
|
1560
|
-
return parse();
|
|
1561
|
-
} catch (error) {
|
|
1562
|
-
return unreachable(`${path} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
async function readIfThere(path) {
|
|
1566
|
-
const file = Bun.file(path);
|
|
1567
|
-
return await file.exists() ? file.text() : undefined;
|
|
1568
|
-
}
|
|
1569
|
-
async function loadConfigs(cwd = process10.cwd(), env = process10.env, home = homedir2()) {
|
|
1570
|
-
const directories = [];
|
|
1571
|
-
for (let dir = cwd;!directories.includes(dir); dir = dirname2(dir))
|
|
1572
|
-
directories.push(dir);
|
|
1573
|
-
if (!directories.includes(home))
|
|
1574
|
-
directories.push(home);
|
|
1575
|
-
const configs = [];
|
|
1576
|
-
for (const dir of directories) {
|
|
1577
|
-
const bunfig = await readIfThere(join2(dir, "bunfig.toml"));
|
|
1578
|
-
const npmrc = await readIfThere(join2(dir, ".npmrc"));
|
|
1579
|
-
if (bunfig !== undefined)
|
|
1580
|
-
configs.push(readable(join2(dir, "bunfig.toml"), () => parseBunfig(bunfig, env)));
|
|
1581
|
-
if (npmrc !== undefined)
|
|
1582
|
-
configs.push(parseNpmrc(npmrc, env));
|
|
1583
|
-
}
|
|
1584
|
-
return configs;
|
|
1585
|
-
}
|
|
1586
|
-
function isSeverity(value) {
|
|
1587
|
-
return SEVERITIES.includes(value);
|
|
1588
|
-
}
|
|
1589
|
-
function parseSettings(text) {
|
|
1590
|
-
const raw = Bun.JSONC.parse(text);
|
|
1591
|
-
const settings = {};
|
|
1592
|
-
if (Array.isArray(raw?.licenses) && raw.licenses.every((each) => typeof each === "string"))
|
|
1593
|
-
settings.licenses = raw.licenses;
|
|
1594
|
-
if (isSeverity(raw?.blockSeverity))
|
|
1595
|
-
settings.blockSeverity = raw.blockSeverity;
|
|
1596
|
-
return settings;
|
|
1597
|
-
}
|
|
1598
|
-
async function loadSettings(cwd = process10.cwd(), home = homedir2()) {
|
|
1599
|
-
const files = [];
|
|
1600
|
-
for (let dir = cwd;!files.includes(join2(dir, SETTINGS_FILE)); dir = dirname2(dir))
|
|
1601
|
-
files.push(join2(dir, SETTINGS_FILE));
|
|
1602
|
-
files.push(join2(home, ".config", "pkg", "config.json"));
|
|
1603
|
-
const settings = {};
|
|
1604
|
-
for (const file of files) {
|
|
1605
|
-
const text = await readIfThere(file);
|
|
1606
|
-
if (text === undefined)
|
|
1607
|
-
continue;
|
|
1608
|
-
const found = readable(file, () => parseSettings(text));
|
|
1609
|
-
settings.licenses ??= found.licenses;
|
|
1610
|
-
settings.blockSeverity ??= found.blockSeverity;
|
|
1611
|
-
}
|
|
1612
|
-
return settings;
|
|
1613
|
-
}
|
|
1614
|
-
var ENV_REFERENCE, COMMENT, SCOPE_REGISTRY, AUTH_TOKEN, PROTOCOL, TRAILING_SLASHES2, LOCAL_HOSTS, QUOTES, SEVERITIES, DEFAULT_BLOCK_SEVERITY = "high", SETTINGS_FILE = ".pkgrc.json";
|
|
1615
|
-
var init_config2 = __esm(() => {
|
|
1616
|
-
init_registry();
|
|
1617
|
-
ENV_REFERENCE = /\$\{(\w+)\}|\$(\w+)/g;
|
|
1618
|
-
COMMENT = /^\s*[#;]/;
|
|
1619
|
-
SCOPE_REGISTRY = /^(@[^:]+):registry$/;
|
|
1620
|
-
AUTH_TOKEN = /^(\/\/.+?):_authToken$/;
|
|
1621
|
-
PROTOCOL = /^\w+:/;
|
|
1622
|
-
TRAILING_SLASHES2 = /\/+$/;
|
|
1623
|
-
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1624
|
-
QUOTES = /^(["'])(.*)\1$/;
|
|
1625
|
-
SEVERITIES = ["low", "moderate", "high", "critical"];
|
|
1508
|
+
init_user_config();
|
|
1626
1509
|
});
|
|
1627
1510
|
|
|
1628
1511
|
// src/semver.ts
|
|
@@ -1667,15 +1550,12 @@ var init_semver = __esm(() => {
|
|
|
1667
1550
|
});
|
|
1668
1551
|
|
|
1669
1552
|
// src/advisories.ts
|
|
1670
|
-
function severityRank(severity) {
|
|
1671
|
-
return SEVERITIES.indexOf(severity);
|
|
1672
|
-
}
|
|
1673
1553
|
function fixedVersion(vulnerable, version) {
|
|
1674
1554
|
const range = vulnerable.split("||").map((each) => each.trim()).find((each) => inRange(version, each));
|
|
1675
1555
|
return range === undefined ? undefined : UPPER_BOUND.exec(range)?.[1];
|
|
1676
1556
|
}
|
|
1677
1557
|
async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
1678
|
-
const url = `${registry.url.replace(
|
|
1558
|
+
const url = `${registry.url.replace(TRAILING_SLASHES, "")}${BULK_PATH}`;
|
|
1679
1559
|
const host = new URL(registry.url).host;
|
|
1680
1560
|
let response;
|
|
1681
1561
|
try {
|
|
@@ -1683,7 +1563,7 @@ async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
|
1683
1563
|
method: "POST",
|
|
1684
1564
|
headers: { accept: "application/json", "content-type": "application/json", ...registry.token === undefined ? {} : { authorization: `Bearer ${registry.token}` } },
|
|
1685
1565
|
body: JSON.stringify(versions),
|
|
1686
|
-
signal: AbortSignal.timeout(
|
|
1566
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT)
|
|
1687
1567
|
});
|
|
1688
1568
|
} catch (error) {
|
|
1689
1569
|
return { found: {}, unavailable: `cannot reach ${host} for advisories: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -1717,13 +1597,13 @@ function advisoriesFor(advisories, version) {
|
|
|
1717
1597
|
return (advisories ?? []).filter((each) => inRange(version, each.vulnerable)).map((each) => ({ ...each, fixed: fixedVersion(each.vulnerable, version) }));
|
|
1718
1598
|
}
|
|
1719
1599
|
function filterAdvisories(advisories, level, ignore = []) {
|
|
1720
|
-
return advisories.filter((each) => severityRank(each.severity) >= severityRank(level) && !
|
|
1600
|
+
return advisories.filter((each) => severityRank(each.severity) >= severityRank(level) && !isIgnored(each, ignore));
|
|
1721
1601
|
}
|
|
1722
|
-
var BULK_PATH = "/-/npm/v1/security/advisories/bulk",
|
|
1602
|
+
var BULK_PATH = "/-/npm/v1/security/advisories/bulk", TRAILING_SLASHES, REQUEST_TIMEOUT = 1e4, GHSA, UPPER_BOUND, NO_ENDPOINT;
|
|
1723
1603
|
var init_advisories = __esm(() => {
|
|
1724
|
-
|
|
1604
|
+
init_src();
|
|
1725
1605
|
init_semver();
|
|
1726
|
-
|
|
1606
|
+
TRAILING_SLASHES = /\/+$/;
|
|
1727
1607
|
GHSA = /GHSA-[\w-]+$/;
|
|
1728
1608
|
UPPER_BOUND = /(?:^|\s)<([\w.+-]+)/;
|
|
1729
1609
|
NO_ENDPOINT = new Set([404, 405, 501]);
|
|
@@ -2289,17 +2169,72 @@ var init_nearmiss = __esm(() => {
|
|
|
2289
2169
|
SEPARATORS = /[-_.]/g;
|
|
2290
2170
|
});
|
|
2291
2171
|
|
|
2292
|
-
// src/
|
|
2293
|
-
function
|
|
2294
|
-
|
|
2295
|
-
return at === -1 ? { name: text } : { name: text.slice(0, at), request: text.slice(at + 1) };
|
|
2172
|
+
// src/registry.ts
|
|
2173
|
+
function isPublic(registry) {
|
|
2174
|
+
return registry.url.replace(TRAILING_SLASHES2, "") === PUBLIC_REGISTRY;
|
|
2296
2175
|
}
|
|
2297
|
-
function
|
|
2298
|
-
return
|
|
2176
|
+
function unreachable(message) {
|
|
2177
|
+
return fail(`could not check: ${message}`, 2);
|
|
2299
2178
|
}
|
|
2300
|
-
function
|
|
2301
|
-
|
|
2302
|
-
|
|
2179
|
+
function requestInit(token) {
|
|
2180
|
+
return { headers: { accept: "application/json", ...token === undefined ? {} : { authorization: `Bearer ${token}` } }, signal: AbortSignal.timeout(REQUEST_TIMEOUT2) };
|
|
2181
|
+
}
|
|
2182
|
+
async function get(fetcher, url, token) {
|
|
2183
|
+
try {
|
|
2184
|
+
return await fetcher(url, requestInit(token));
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
return unreachable(`cannot reach ${new URL(url).host}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function isValidName(name) {
|
|
2190
|
+
return PACKAGE_NAME.test(name) && name.length <= 214;
|
|
2191
|
+
}
|
|
2192
|
+
async function fetchPackument(name, registry, fetcher = fetch) {
|
|
2193
|
+
if (!isValidName(name))
|
|
2194
|
+
fail(`${name} is not a valid npm package name`);
|
|
2195
|
+
const response = await get(fetcher, `${registry.url.replace(TRAILING_SLASHES2, "")}/${encodeURIComponent(name).replace("%40", "@").replace("%2F", "%2f")}`, registry.token);
|
|
2196
|
+
if (response.status === 404)
|
|
2197
|
+
return;
|
|
2198
|
+
if (!response.ok)
|
|
2199
|
+
unreachable(`${new URL(registry.url).host} answered ${response.status} for ${name}`);
|
|
2200
|
+
let packument;
|
|
2201
|
+
try {
|
|
2202
|
+
packument = await response.json();
|
|
2203
|
+
} catch {
|
|
2204
|
+
return unreachable(`${new URL(registry.url).host} answered ${name} with something that is not JSON`);
|
|
2205
|
+
}
|
|
2206
|
+
if (packument?.name !== name)
|
|
2207
|
+
unreachable(`${new URL(registry.url).host} answered ${name} with the metadata of ${String(packument?.name)}`);
|
|
2208
|
+
return packument;
|
|
2209
|
+
}
|
|
2210
|
+
async function fetchDownloads(name, fetcher = fetch) {
|
|
2211
|
+
const response = await get(fetcher, `${DOWNLOADS_API}/${encodeURIComponent(name)}`);
|
|
2212
|
+
if (!response.ok)
|
|
2213
|
+
return;
|
|
2214
|
+
try {
|
|
2215
|
+
return (await response.json()).downloads;
|
|
2216
|
+
} catch {
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
var PUBLIC_REGISTRY = "https://registry.npmjs.org", DOWNLOADS_API = "https://api.npmjs.org/downloads/point/last-week", TRAILING_SLASHES2, REQUEST_TIMEOUT2 = 1e4, PACKAGE_NAME;
|
|
2221
|
+
var init_registry = __esm(() => {
|
|
2222
|
+
init_src();
|
|
2223
|
+
TRAILING_SLASHES2 = /\/+$/;
|
|
2224
|
+
PACKAGE_NAME = /^(?:@[\w~-][\w.~-]*\/)?[\w~-][\w.~-]*$/;
|
|
2225
|
+
});
|
|
2226
|
+
|
|
2227
|
+
// src/analyze.ts
|
|
2228
|
+
function parseSpec(text) {
|
|
2229
|
+
const at = text.search(VERSION_SEPARATOR);
|
|
2230
|
+
return at === -1 ? { name: text } : { name: text.slice(0, at), request: text.slice(at + 1) };
|
|
2231
|
+
}
|
|
2232
|
+
function isStable(version) {
|
|
2233
|
+
return !version.includes("-");
|
|
2234
|
+
}
|
|
2235
|
+
function resolve(packument, request) {
|
|
2236
|
+
const tags = packument["dist-tags"] ?? {};
|
|
2237
|
+
const versions = Object.keys(packument.versions ?? {});
|
|
2303
2238
|
const wanted = request === undefined || request === "" ? "latest" : request;
|
|
2304
2239
|
if (tags[wanted] !== undefined)
|
|
2305
2240
|
return tags[wanted];
|
|
@@ -2408,6 +2343,310 @@ var init_analyze = __esm(() => {
|
|
|
2408
2343
|
VERSION_SEPARATOR = /(?<=.)@/;
|
|
2409
2344
|
});
|
|
2410
2345
|
|
|
2346
|
+
// src/config.ts
|
|
2347
|
+
import { homedir as homedir3 } from "os";
|
|
2348
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
2349
|
+
import process13 from "process";
|
|
2350
|
+
function expand2(value, env) {
|
|
2351
|
+
let missing = false;
|
|
2352
|
+
const expanded = value.replace(ENV_REFERENCE, (_, braced, bare) => {
|
|
2353
|
+
const found = env[braced ?? bare ?? ""];
|
|
2354
|
+
missing ||= found === undefined;
|
|
2355
|
+
return found ?? "";
|
|
2356
|
+
});
|
|
2357
|
+
return missing ? undefined : expanded;
|
|
2358
|
+
}
|
|
2359
|
+
function literal(value) {
|
|
2360
|
+
return expand2(value, {}) === value ? value : undefined;
|
|
2361
|
+
}
|
|
2362
|
+
function parseNpmrc(text, env) {
|
|
2363
|
+
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
2364
|
+
for (const line of text.split(`
|
|
2365
|
+
`)) {
|
|
2366
|
+
const at = line.indexOf("=");
|
|
2367
|
+
if (at === -1 || COMMENT.test(line))
|
|
2368
|
+
continue;
|
|
2369
|
+
const key = line.slice(0, at).trim();
|
|
2370
|
+
const scope = SCOPE_REGISTRY.exec(key)?.[1];
|
|
2371
|
+
const tokenFor = AUTH_TOKEN.exec(key)?.[1];
|
|
2372
|
+
const raw = line.slice(at + 1).trim().replace(QUOTES, "$2");
|
|
2373
|
+
const value = tokenFor === undefined ? literal(raw) : expand2(raw, env);
|
|
2374
|
+
if (value === undefined || value === "")
|
|
2375
|
+
continue;
|
|
2376
|
+
if (scope !== undefined)
|
|
2377
|
+
config.scopes[scope] = value;
|
|
2378
|
+
else if (tokenFor !== undefined)
|
|
2379
|
+
config.tokens[tokenFor] = value;
|
|
2380
|
+
else if (key === "registry")
|
|
2381
|
+
config.registry = value;
|
|
2382
|
+
}
|
|
2383
|
+
return config;
|
|
2384
|
+
}
|
|
2385
|
+
function bunEntry(entry, env) {
|
|
2386
|
+
const url = typeof entry === "string" ? entry : entry.url;
|
|
2387
|
+
const token = typeof entry === "string" || entry.token === undefined ? undefined : expand2(entry.token, env);
|
|
2388
|
+
return { ...url === undefined || literal(url) === undefined ? {} : { url }, ...token === undefined ? {} : { token } };
|
|
2389
|
+
}
|
|
2390
|
+
function parseBunfig(text, env) {
|
|
2391
|
+
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
2392
|
+
const install = Bun.TOML.parse(text).install;
|
|
2393
|
+
if (install?.registry !== undefined) {
|
|
2394
|
+
const { url, token } = bunEntry(install.registry, env);
|
|
2395
|
+
if (url !== undefined)
|
|
2396
|
+
config.registry = url;
|
|
2397
|
+
if (url !== undefined && token !== undefined)
|
|
2398
|
+
config.tokens[url.replace(PROTOCOL, "")] = token;
|
|
2399
|
+
}
|
|
2400
|
+
for (const [scope, entry] of Object.entries(install?.scopes ?? {})) {
|
|
2401
|
+
const { url, token } = bunEntry(entry, env);
|
|
2402
|
+
if (url !== undefined)
|
|
2403
|
+
config.scopes[scope.startsWith("@") ? scope : `@${scope}`] = url;
|
|
2404
|
+
if (token !== undefined)
|
|
2405
|
+
config.scopeTokens[scope.startsWith("@") ? scope : `@${scope}`] = token;
|
|
2406
|
+
}
|
|
2407
|
+
return config;
|
|
2408
|
+
}
|
|
2409
|
+
function tokenFor(config, url) {
|
|
2410
|
+
const address = `${url.replace(PROTOCOL, "").replace(TRAILING_SLASHES3, "")}/`;
|
|
2411
|
+
const best = Object.keys(config.tokens).filter((key) => address.startsWith(`${key.replace(TRAILING_SLASHES3, "")}/`)).sort((a, b) => b.length - a.length)[0];
|
|
2412
|
+
return best === undefined ? undefined : config.tokens[best];
|
|
2413
|
+
}
|
|
2414
|
+
function mayCarryToken(url) {
|
|
2415
|
+
const { protocol, hostname } = new URL(url);
|
|
2416
|
+
return protocol === "https:" || LOCAL_HOSTS.has(hostname);
|
|
2417
|
+
}
|
|
2418
|
+
function registryFor(name, configs) {
|
|
2419
|
+
const scope = name.startsWith("@") ? name.slice(0, name.indexOf("/")) : undefined;
|
|
2420
|
+
const scoped = scope === undefined ? undefined : configs.find((config) => config.scopes[scope] !== undefined);
|
|
2421
|
+
const url = (scope === undefined ? undefined : scoped?.scopes[scope]) ?? configs.find((config) => config.registry !== undefined)?.registry;
|
|
2422
|
+
if (url === undefined)
|
|
2423
|
+
return { url: PUBLIC_REGISTRY };
|
|
2424
|
+
const token = (scope === undefined ? undefined : scoped?.scopeTokens[scope]) ?? configs.map((other) => tokenFor(other, url)).find((found) => found !== undefined);
|
|
2425
|
+
return { url, token: mayCarryToken(url) ? token : undefined };
|
|
2426
|
+
}
|
|
2427
|
+
function readable(path, parse) {
|
|
2428
|
+
try {
|
|
2429
|
+
return parse();
|
|
2430
|
+
} catch (error) {
|
|
2431
|
+
return unreachable(`${path} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
async function readIfThere(path) {
|
|
2435
|
+
const file = Bun.file(path);
|
|
2436
|
+
return await file.exists() ? file.text() : undefined;
|
|
2437
|
+
}
|
|
2438
|
+
async function loadConfigs(cwd = process13.cwd(), env = process13.env, home = homedir3()) {
|
|
2439
|
+
const directories = [];
|
|
2440
|
+
for (let dir = cwd;!directories.includes(dir); dir = dirname3(dir))
|
|
2441
|
+
directories.push(dir);
|
|
2442
|
+
if (!directories.includes(home))
|
|
2443
|
+
directories.push(home);
|
|
2444
|
+
const configs = [];
|
|
2445
|
+
for (const dir of directories) {
|
|
2446
|
+
const bunfig = await readIfThere(join4(dir, "bunfig.toml"));
|
|
2447
|
+
const npmrc = await readIfThere(join4(dir, ".npmrc"));
|
|
2448
|
+
if (bunfig !== undefined)
|
|
2449
|
+
configs.push(readable(join4(dir, "bunfig.toml"), () => parseBunfig(bunfig, env)));
|
|
2450
|
+
if (npmrc !== undefined)
|
|
2451
|
+
configs.push(parseNpmrc(npmrc, env));
|
|
2452
|
+
}
|
|
2453
|
+
return configs;
|
|
2454
|
+
}
|
|
2455
|
+
function isSeverity(value) {
|
|
2456
|
+
return SEVERITIES.includes(value);
|
|
2457
|
+
}
|
|
2458
|
+
function parseSettings(text) {
|
|
2459
|
+
const raw = Bun.JSONC.parse(text);
|
|
2460
|
+
const settings = {};
|
|
2461
|
+
if (Array.isArray(raw?.licenses) && raw.licenses.every((each) => typeof each === "string"))
|
|
2462
|
+
settings.licenses = raw.licenses;
|
|
2463
|
+
if (isSeverity(raw?.blockSeverity))
|
|
2464
|
+
settings.blockSeverity = raw.blockSeverity;
|
|
2465
|
+
return settings;
|
|
2466
|
+
}
|
|
2467
|
+
async function loadSettings(cwd = process13.cwd(), home) {
|
|
2468
|
+
const files = [];
|
|
2469
|
+
for (let dir = cwd;!files.includes(join4(dir, SETTINGS_FILE)); dir = dirname3(dir))
|
|
2470
|
+
files.push(join4(dir, SETTINGS_FILE));
|
|
2471
|
+
files.push(userConfigReadPath("pkg", [["pkg", "config.json"]], { home }));
|
|
2472
|
+
const settings = {};
|
|
2473
|
+
for (const file of files) {
|
|
2474
|
+
const text = await readIfThere(file);
|
|
2475
|
+
if (text === undefined)
|
|
2476
|
+
continue;
|
|
2477
|
+
const found = readable(file, () => parseSettings(text));
|
|
2478
|
+
settings.licenses ??= found.licenses;
|
|
2479
|
+
settings.blockSeverity ??= found.blockSeverity;
|
|
2480
|
+
}
|
|
2481
|
+
return settings;
|
|
2482
|
+
}
|
|
2483
|
+
var ENV_REFERENCE, COMMENT, SCOPE_REGISTRY, AUTH_TOKEN, PROTOCOL, TRAILING_SLASHES3, LOCAL_HOSTS, QUOTES, DEFAULT_BLOCK_SEVERITY = "high", SETTINGS_FILE = ".pkgrc.json";
|
|
2484
|
+
var init_config2 = __esm(() => {
|
|
2485
|
+
init_src();
|
|
2486
|
+
init_registry();
|
|
2487
|
+
ENV_REFERENCE = /\$\{(\w+)\}|\$(\w+)/g;
|
|
2488
|
+
COMMENT = /^\s*[#;]/;
|
|
2489
|
+
SCOPE_REGISTRY = /^(@[^:]+):registry$/;
|
|
2490
|
+
AUTH_TOKEN = /^(\/\/.+?):_authToken$/;
|
|
2491
|
+
PROTOCOL = /^\w+:/;
|
|
2492
|
+
TRAILING_SLASHES3 = /\/+$/;
|
|
2493
|
+
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
2494
|
+
QUOTES = /^(["'])(.*)\1$/;
|
|
2495
|
+
});
|
|
2496
|
+
|
|
2497
|
+
// ../kit/src/shell.ts
|
|
2498
|
+
function wrapper(short = "", long = [], operands = 0, runsString = false) {
|
|
2499
|
+
return { short, long, operands, runsString };
|
|
2500
|
+
}
|
|
2501
|
+
var SEPARATORS2, PLAIN_BREAKERS, GLOB_CHARS, COMMENT_PREFIXES, DOUBLE_QUOTED_ESCAPES, KEYWORDS, SHELLS, SCANNED_PROGRAMS, COMMAND_STRING_PROGRAMS, POWERSHELL, SHELL_VALUE_OPTIONS, FISH_VALUE_OPTIONS, PRINTERS, FIND_EXEC, WRAPPERS;
|
|
2502
|
+
var init_shell = __esm(() => {
|
|
2503
|
+
SEPARATORS2 = new Set([`
|
|
2504
|
+
`, ";", "|"]);
|
|
2505
|
+
PLAIN_BREAKERS = new Set(["<", ">", "(", ")", "&", "|"]);
|
|
2506
|
+
GLOB_CHARS = new Set(["*", "?", "["]);
|
|
2507
|
+
COMMENT_PREFIXES = new Set([";", "&", "|", "(", ")"]);
|
|
2508
|
+
DOUBLE_QUOTED_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
2509
|
+
KEYWORDS = new Set(["then", "do", "else", "if", "elif", "while", "until", "!", "{", "}"]);
|
|
2510
|
+
SHELLS = new Set(["sh", "bash", "zsh", "dash", "ash", "ksh", "fish", "csh", "tcsh", "nu", "xonsh", "elvish", "pwsh", "powershell"]);
|
|
2511
|
+
SCANNED_PROGRAMS = new Set(["su", "runuser", "flock"]);
|
|
2512
|
+
COMMAND_STRING_PROGRAMS = new Set([...SHELLS, ...SCANNED_PROGRAMS]);
|
|
2513
|
+
POWERSHELL = new Set(["pwsh", "powershell"]);
|
|
2514
|
+
SHELL_VALUE_OPTIONS = new Set(["-o", "-O", "--rcfile", "--init-file"]);
|
|
2515
|
+
FISH_VALUE_OPTIONS = new Set(["-C", "--init-command"]);
|
|
2516
|
+
PRINTERS = new Set(["echo", "printf"]);
|
|
2517
|
+
FIND_EXEC = new Set(["-exec", "-execdir", "-ok", "-okdir"]);
|
|
2518
|
+
WRAPPERS = new Map([
|
|
2519
|
+
["command", wrapper()],
|
|
2520
|
+
["builtin", wrapper()],
|
|
2521
|
+
["nohup", wrapper()],
|
|
2522
|
+
["setsid", wrapper()],
|
|
2523
|
+
["busybox", wrapper()],
|
|
2524
|
+
["exec", wrapper("a")],
|
|
2525
|
+
["time", wrapper("fo", ["--format", "--output"])],
|
|
2526
|
+
["env", wrapper("uCS", ["--unset", "--chdir", "--split-string", "--argv0"])],
|
|
2527
|
+
["sudo", wrapper("ughpCTrtUDR", ["--user", "--group", "--host", "--prompt", "--close-from", "--command-timeout", "--role", "--type", "--other-user", "--chdir", "--chroot"])],
|
|
2528
|
+
["doas", wrapper("uC")],
|
|
2529
|
+
["timeout", wrapper("sk", ["--signal", "--kill-after"], 1)],
|
|
2530
|
+
["nice", wrapper("n", ["--adjustment"])],
|
|
2531
|
+
["ionice", wrapper("cnpPu", ["--class", "--classdata", "--pid", "--pgid", "--uid"])],
|
|
2532
|
+
["stdbuf", wrapper("ioe", ["--input", "--output", "--error"])],
|
|
2533
|
+
["chroot", wrapper("", ["--userspec", "--groups"], 1)],
|
|
2534
|
+
["watch", wrapper("n", ["--interval"], 0, true)],
|
|
2535
|
+
["flock", wrapper("wE", ["--timeout", "--conflict-exit-code"], 1)],
|
|
2536
|
+
["parallel", wrapper("jnNSaIPlLdTsC", ["--jobs", "--max-args", "--max-replace-args", "--sshlogin", "--arg-file", "--delimiter", "--colsep"], 0, true)],
|
|
2537
|
+
["unbuffer", wrapper()],
|
|
2538
|
+
["systemd-run", wrapper("puEMH", ["--property", "--unit", "--description", "--slice", "--setenv", "--machine", "--host", "--uid", "--gid", "--working-directory", "--nice", "--service-type"])],
|
|
2539
|
+
["xargs", wrapper("IndsEaPL", ["--max-args", "--max-procs", "--max-chars", "--delimiter", "--arg-file", "--eof", "--max-lines", "--process-slot-var"])]
|
|
2540
|
+
]);
|
|
2541
|
+
});
|
|
2542
|
+
|
|
2543
|
+
// src/pin.ts
|
|
2544
|
+
function actions(byAction) {
|
|
2545
|
+
return new Map(Object.entries(byAction).flatMap(([action, names]) => names.map((name) => [name, action])));
|
|
2546
|
+
}
|
|
2547
|
+
var LOCKFILES, ACTIONS, OPTION_FLAGS, DIR_FLAGS, VALUE_FLAGS;
|
|
2548
|
+
var init_pin = __esm(() => {
|
|
2549
|
+
init_shell();
|
|
2550
|
+
LOCKFILES = [
|
|
2551
|
+
["bun.lock", "bun"],
|
|
2552
|
+
["bun.lockb", "bun"],
|
|
2553
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
2554
|
+
["yarn.lock", "yarn"],
|
|
2555
|
+
["package-lock.json", "npm"]
|
|
2556
|
+
];
|
|
2557
|
+
ACTIONS = {
|
|
2558
|
+
bun: actions({ install: ["install", "i"], add: ["add", "a"], remove: ["remove", "rm"], update: ["update"] }),
|
|
2559
|
+
pnpm: actions({ install: ["install", "i"], add: ["add"], remove: ["remove", "rm"], update: ["update", "up"] }),
|
|
2560
|
+
yarn: new Map([...actions({ install: ["", "install"], add: ["add"], remove: ["remove"], update: ["upgrade"] }), ["upgrade-interactive", null], ["import", null]]),
|
|
2561
|
+
npm: actions({
|
|
2562
|
+
install: ["install", "i", "in", "ins", "inst", "insta", "instal", "isnt", "isnta", "isntal", "isntall"],
|
|
2563
|
+
add: ["add"],
|
|
2564
|
+
frozen: ["ci", "clean-install", "ic", "install-clean", "isntall-clean"],
|
|
2565
|
+
remove: ["uninstall", "unlink", "remove", "rm", "r", "un"],
|
|
2566
|
+
update: ["update", "u", "up", "upgrade", "udpate"]
|
|
2567
|
+
})
|
|
2568
|
+
};
|
|
2569
|
+
OPTION_FLAGS = new Map([
|
|
2570
|
+
["-D", "dev"],
|
|
2571
|
+
["--save-dev", "dev"],
|
|
2572
|
+
["--dev", "dev"],
|
|
2573
|
+
["-E", "exact"],
|
|
2574
|
+
["--save-exact", "exact"],
|
|
2575
|
+
["--exact", "exact"]
|
|
2576
|
+
]);
|
|
2577
|
+
DIR_FLAGS = new Set(["--cwd", "-C", "--dir", "--prefix"]);
|
|
2578
|
+
VALUE_FLAGS = new Set([...DIR_FLAGS, "--filter", "-F"]);
|
|
2579
|
+
});
|
|
2580
|
+
|
|
2581
|
+
// src/consumers.ts
|
|
2582
|
+
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
2583
|
+
import { dirname as dirname4, join as join5, relative } from "path";
|
|
2584
|
+
function packageFiles(dir, depth, found) {
|
|
2585
|
+
let entries;
|
|
2586
|
+
try {
|
|
2587
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
2588
|
+
} catch {
|
|
2589
|
+
return found;
|
|
2590
|
+
}
|
|
2591
|
+
for (const entry of entries) {
|
|
2592
|
+
if (entry.isFile() && entry.name === "package.json")
|
|
2593
|
+
found.push(join5(dir, entry.name));
|
|
2594
|
+
else if (entry.isDirectory() && depth < MAX_DEPTH && !entry.name.startsWith(".") && !SKIPPED.has(entry.name))
|
|
2595
|
+
packageFiles(join5(dir, entry.name), depth + 1, found);
|
|
2596
|
+
}
|
|
2597
|
+
return found;
|
|
2598
|
+
}
|
|
2599
|
+
function managerFor(dir, root) {
|
|
2600
|
+
for (let at = dir;; at = dirname4(at)) {
|
|
2601
|
+
const lockfile = LOCKFILES.find(([file]) => existsSync2(join5(at, file)));
|
|
2602
|
+
if (lockfile !== undefined)
|
|
2603
|
+
return lockfile[1];
|
|
2604
|
+
if (at === root || at === dirname4(at))
|
|
2605
|
+
return "bun";
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
function findConsumers(name, root) {
|
|
2609
|
+
const consumers = [];
|
|
2610
|
+
for (const path of packageFiles(root, 0, []).sort()) {
|
|
2611
|
+
let manifest;
|
|
2612
|
+
try {
|
|
2613
|
+
manifest = JSON.parse(readFileSync2(path, "utf8"));
|
|
2614
|
+
} catch {
|
|
2615
|
+
continue;
|
|
2616
|
+
}
|
|
2617
|
+
const kind = KINDS.find((each) => typeof manifest[each]?.[name] === "string");
|
|
2618
|
+
const spec = kind === undefined ? undefined : manifest[kind]?.[name];
|
|
2619
|
+
if (kind !== undefined && spec !== undefined)
|
|
2620
|
+
consumers.push({ dir: relative(root, dirname4(path)) || ".", path, kind, spec, manager: managerFor(dirname4(path), root) });
|
|
2621
|
+
}
|
|
2622
|
+
return consumers;
|
|
2623
|
+
}
|
|
2624
|
+
function isLocal(consumer) {
|
|
2625
|
+
return LOCAL_SPEC.test(consumer.spec);
|
|
2626
|
+
}
|
|
2627
|
+
function addCommand(consumer, name, version) {
|
|
2628
|
+
return ["bun", "add", ...KIND_FLAGS[consumer.kind], "--exact", "--no-cache", `${name}@${version}`];
|
|
2629
|
+
}
|
|
2630
|
+
function registryDependencies(text) {
|
|
2631
|
+
let manifest;
|
|
2632
|
+
try {
|
|
2633
|
+
manifest = JSON.parse(text);
|
|
2634
|
+
} catch {
|
|
2635
|
+
return fail("the package.json is not valid JSON");
|
|
2636
|
+
}
|
|
2637
|
+
return REGISTRY_KINDS.flatMap((kind) => Object.entries(manifest?.[kind] ?? {}).flatMap(([name, spec]) => typeof spec === "string" && !LOCAL_SPEC.test(spec) ? [{ name, kind, spec }] : []));
|
|
2638
|
+
}
|
|
2639
|
+
var KINDS, SKIPPED, MAX_DEPTH = 5, LOCAL_SPEC, KIND_FLAGS, REGISTRY_KINDS;
|
|
2640
|
+
var init_consumers = __esm(() => {
|
|
2641
|
+
init_src();
|
|
2642
|
+
init_pin();
|
|
2643
|
+
KINDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
2644
|
+
SKIPPED = new Set(["node_modules", "dist", "build", "vendor", "target", "coverage"]);
|
|
2645
|
+
LOCAL_SPEC = /[:/]/;
|
|
2646
|
+
KIND_FLAGS = { dependencies: [], devDependencies: ["--dev"], optionalDependencies: ["--optional"], peerDependencies: ["--peer"] };
|
|
2647
|
+
REGISTRY_KINDS = KINDS.filter((kind) => kind !== "peerDependencies");
|
|
2648
|
+
});
|
|
2649
|
+
|
|
2411
2650
|
// src/commands/check.ts
|
|
2412
2651
|
var exports_check = {};
|
|
2413
2652
|
__export(exports_check, {
|
|
@@ -2457,13 +2696,20 @@ function render(report, now = Date.now()) {
|
|
|
2457
2696
|
].join(`
|
|
2458
2697
|
`);
|
|
2459
2698
|
}
|
|
2699
|
+
async function wanted(positionals, from) {
|
|
2700
|
+
const names = positionals.filter((each) => each !== "-");
|
|
2701
|
+
const fromFile = from === undefined ? [] : registryDependencies(await readInput(from)).map(({ name, spec }) => `${name}@${spec}`);
|
|
2702
|
+
const fromStdin = positionals.includes("-") || names.length === 0 && fromFile.length === 0 && isStdinPiped() ? (await readInput("-")).split(WORDS).filter((each) => each !== "") : [];
|
|
2703
|
+
return [...new Set([...names, ...fromFile, ...fromStdin])];
|
|
2704
|
+
}
|
|
2460
2705
|
async function check(args) {
|
|
2461
|
-
const parsed = parse(args, usage2, options);
|
|
2462
|
-
const { values
|
|
2706
|
+
const parsed = parse(args, usage2, options, { exits: EXITS });
|
|
2707
|
+
const { values } = parsed;
|
|
2708
|
+
const positionals = await wanted(parsed.positionals, values.from);
|
|
2463
2709
|
if (positionals.length === 0)
|
|
2464
|
-
fail(`a package name is needed
|
|
2710
|
+
fail(values.from === undefined ? `a package name is needed
|
|
2465
2711
|
|
|
2466
|
-
${usage2}`);
|
|
2712
|
+
${usage2}` : `${values.from} has no registry dependency to check`);
|
|
2467
2713
|
const context = { configs: await loadConfigs(), settings: await loadSettings(), minAgeDays: wholeNumber(values["min-age"], "min-age", DEFAULT_MIN_AGE_DAYS, 0) };
|
|
2468
2714
|
const reports = await Promise.all(positionals.map(async (text) => checkPackage(text, context)));
|
|
2469
2715
|
if (values.json === true)
|
|
@@ -2474,23 +2720,27 @@ ${usage2}`);
|
|
|
2474
2720
|
`));
|
|
2475
2721
|
return reports.some((report) => report.blocked) ? 1 : 0;
|
|
2476
2722
|
}
|
|
2477
|
-
var usage2 = `pkg [check] <name>[@version]...
|
|
2723
|
+
var usage2 = `pkg [check] <name>[@version]... | --from <package.json> | -
|
|
2478
2724
|
|
|
2479
2725
|
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.
|
|
2480
2726
|
|
|
2481
|
-
|
|
2727
|
+
Names come from the arguments, from the dependencies of a package.json with --from (each checked as \`name@range\`, so it resolves what an install would; dev and optional ones included, peer ranges and local or remote sources left out), or from stdin, separated by spaces or lines, when \`-\` is given or nothing else is and stdin is piped.
|
|
2482
2728
|
|
|
2483
|
-
|
|
2729
|
+
A \`.pkgrc.json\` (or ~/.config/kaynooo-cli/pkg.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.`, EXITS, options, WORDS;
|
|
2484
2730
|
var init_check = __esm(() => {
|
|
2485
2731
|
init_src();
|
|
2486
2732
|
init_advisories();
|
|
2487
2733
|
init_analyze();
|
|
2488
2734
|
init_config2();
|
|
2735
|
+
init_consumers();
|
|
2489
2736
|
init_registry();
|
|
2737
|
+
EXITS = [[0, "every package passes"], [1, "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, "it could not check (the registry unreachable, slow or answering badly, a broken .pkgrc.json, bunfig.toml or .npmrc) or a usage error"]];
|
|
2490
2738
|
options = {
|
|
2491
2739
|
json: jsonOption(),
|
|
2492
|
-
"min-age": { type: "string", description: `days a version must be old (${DEFAULT_MIN_AGE_DAYS})` }
|
|
2740
|
+
"min-age": { type: "string", description: `days a version must be old (${DEFAULT_MIN_AGE_DAYS})` },
|
|
2741
|
+
from: { type: "string", description: "check the dependencies of this package.json" }
|
|
2493
2742
|
};
|
|
2743
|
+
WORDS = /\s+/;
|
|
2494
2744
|
});
|
|
2495
2745
|
|
|
2496
2746
|
// src/lockfile.ts
|
|
@@ -2516,6 +2766,42 @@ function parseBunLock(text) {
|
|
|
2516
2766
|
}
|
|
2517
2767
|
return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name) || Bun.semver.order(a.version, b.version));
|
|
2518
2768
|
}
|
|
2769
|
+
function parentKey(key) {
|
|
2770
|
+
const parts = key.split("/");
|
|
2771
|
+
const drop = parts.length > 1 && parts.at(-2)?.startsWith("@") ? 2 : 1;
|
|
2772
|
+
return parts.length > drop ? parts.slice(0, -drop).join("/") : undefined;
|
|
2773
|
+
}
|
|
2774
|
+
function productionPackages(text) {
|
|
2775
|
+
const lock = Bun.JSONC.parse(text);
|
|
2776
|
+
const packages = lock?.packages ?? {};
|
|
2777
|
+
const reached = new Set;
|
|
2778
|
+
const visited = new Set;
|
|
2779
|
+
const pending = [];
|
|
2780
|
+
for (const workspace of Object.values(lock?.workspaces ?? {})) {
|
|
2781
|
+
for (const name of Object.keys({ ...workspace.dependencies, ...workspace.optionalDependencies }))
|
|
2782
|
+
pending.push({ name, from: undefined });
|
|
2783
|
+
}
|
|
2784
|
+
while (pending.length > 0) {
|
|
2785
|
+
const { name, from } = pending.pop();
|
|
2786
|
+
let scope = from;
|
|
2787
|
+
let key = scope === undefined ? name : `${scope}/${name}`;
|
|
2788
|
+
while (!(key in packages) && scope !== undefined) {
|
|
2789
|
+
scope = parentKey(scope);
|
|
2790
|
+
key = scope === undefined ? name : `${scope}/${name}`;
|
|
2791
|
+
}
|
|
2792
|
+
const entry = packages[key];
|
|
2793
|
+
if (entry === undefined || visited.has(key))
|
|
2794
|
+
continue;
|
|
2795
|
+
visited.add(key);
|
|
2796
|
+
const locked = typeof entry[0] === "string" ? split(entry[0]) : undefined;
|
|
2797
|
+
if (locked !== undefined)
|
|
2798
|
+
reached.add(`${locked.name}@${locked.version}`);
|
|
2799
|
+
const info = entry[2] ?? {};
|
|
2800
|
+
for (const dependency of Object.keys({ ...info.dependencies, ...info.optionalDependencies }))
|
|
2801
|
+
pending.push({ name: dependency, from: key });
|
|
2802
|
+
}
|
|
2803
|
+
return reached;
|
|
2804
|
+
}
|
|
2519
2805
|
var NOT_REGISTRY, VERSION_SEPARATOR2, NPM_ALIAS = "npm:";
|
|
2520
2806
|
var init_lockfile = __esm(() => {
|
|
2521
2807
|
NOT_REGISTRY = /^(?:workspace|link|file|github|git|http|https):|^[\w.-]+\/[\w.-]+$/;
|
|
@@ -2527,8 +2813,8 @@ var exports_audit = {};
|
|
|
2527
2813
|
__export(exports_audit, {
|
|
2528
2814
|
audit: () => audit
|
|
2529
2815
|
});
|
|
2530
|
-
import { join as
|
|
2531
|
-
import
|
|
2816
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
2817
|
+
import process14 from "process";
|
|
2532
2818
|
function hasFinding(audited) {
|
|
2533
2819
|
return audited.blocked || audited.warnings.length > 0 || audited.advisories.length > 0;
|
|
2534
2820
|
}
|
|
@@ -2583,15 +2869,17 @@ function renderAudit(findings, total) {
|
|
|
2583
2869
|
`);
|
|
2584
2870
|
}
|
|
2585
2871
|
async function audit(args) {
|
|
2586
|
-
const { values, positionals: [asked] } = parse(args, usage3, options2, { positionals: ["[dir]"] });
|
|
2587
|
-
const level = values
|
|
2872
|
+
const { values, positionals: [asked] } = parse(args, usage3, options2, { positionals: ["[dir]"], exits: EXITS2 });
|
|
2873
|
+
const level = values.level ?? "moderate";
|
|
2588
2874
|
if (!isSeverity(level))
|
|
2589
|
-
fail(`--
|
|
2590
|
-
const dir = resolve2(asked ??
|
|
2591
|
-
const lock = Bun.file(
|
|
2875
|
+
fail(`--level takes ${SEVERITIES.join(", ")}, not ${level}`);
|
|
2876
|
+
const dir = resolve2(asked ?? process14.cwd());
|
|
2877
|
+
const lock = Bun.file(join6(dir, "bun.lock"));
|
|
2592
2878
|
if (!await lock.exists())
|
|
2593
2879
|
fail(`no bun.lock in ${dir}`);
|
|
2594
|
-
const
|
|
2880
|
+
const text = await lock.text();
|
|
2881
|
+
const production = values.prod === true ? productionPackages(text) : undefined;
|
|
2882
|
+
const packages = parseBunLock(text).filter(({ name, version }) => production?.has(`${name}@${version}`) ?? true);
|
|
2595
2883
|
const context = {
|
|
2596
2884
|
configs: await loadConfigs(dir),
|
|
2597
2885
|
settings: await loadSettings(dir),
|
|
@@ -2615,8 +2903,7 @@ var usage3 = `pkg audit [dir]
|
|
|
2615
2903
|
|
|
2616
2904
|
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.
|
|
2617
2905
|
Findings are grouped per package, each registry package looked up once per run.
|
|
2618
|
-
|
|
2619
|
-
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;
|
|
2906
|
+
Reach for it to vet one repository in depth; \`audit\` sweeps many repositories for advisories only, and shares --level, --prod and --ignore.`, EXITS2, options2, BATCH = 8;
|
|
2620
2907
|
var init_audit = __esm(() => {
|
|
2621
2908
|
init_src();
|
|
2622
2909
|
init_advisories();
|
|
@@ -2624,146 +2911,95 @@ var init_audit = __esm(() => {
|
|
|
2624
2911
|
init_config2();
|
|
2625
2912
|
init_lockfile();
|
|
2626
2913
|
init_registry();
|
|
2914
|
+
EXITS2 = [[0, "nothing blocks"], [1, "a package is missing, too fresh or outside the licence allowlist, or an advisory reaches --level"], [2, "the registry could not be reached or answered badly (a warning says which, and nothing is reported as clean), a usage error or no bun.lock"]];
|
|
2627
2915
|
options2 = {
|
|
2628
2916
|
json: jsonOption("[{name, version, license, blocked, warnings, advisories}] for the packages with a finding"),
|
|
2629
2917
|
"min-age": { type: "string", description: `days a version must be old (${DEFAULT_MIN_AGE_DAYS})` },
|
|
2630
|
-
|
|
2918
|
+
level: { type: "string", description: "lowest advisory severity listed and failing: low, moderate, high, critical (moderate)" },
|
|
2919
|
+
prod: { type: "boolean", description: "only the packages a production dependency or an optional one of a workspace reaches" },
|
|
2631
2920
|
ignore: { type: "string", multiple: true, description: "an advisory skipped by GHSA or numeric id, repeatable" }
|
|
2632
2921
|
};
|
|
2633
2922
|
});
|
|
2634
2923
|
|
|
2635
|
-
//
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
var SEPARATORS2, PLAIN_BREAKERS, GLOB_CHARS, COMMENT_PREFIXES, DOUBLE_QUOTED_ESCAPES, KEYWORDS, SHELLS, COMMAND_STRING_PROGRAMS, SHELL_VALUE_OPTIONS, PRINTERS, FIND_EXEC, WRAPPERS;
|
|
2640
|
-
var init_shell = __esm(() => {
|
|
2641
|
-
SEPARATORS2 = new Set([`
|
|
2642
|
-
`, ";", "|"]);
|
|
2643
|
-
PLAIN_BREAKERS = new Set(["<", ">", "(", ")", "&", "|"]);
|
|
2644
|
-
GLOB_CHARS = new Set(["*", "?", "["]);
|
|
2645
|
-
COMMENT_PREFIXES = new Set([";", "&", "|", "(", ")"]);
|
|
2646
|
-
DOUBLE_QUOTED_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
2647
|
-
KEYWORDS = new Set(["then", "do", "else", "if", "elif", "while", "until", "!", "{", "}"]);
|
|
2648
|
-
SHELLS = new Set(["sh", "bash", "zsh", "dash", "ash", "ksh"]);
|
|
2649
|
-
COMMAND_STRING_PROGRAMS = new Set([...SHELLS, "su", "runuser"]);
|
|
2650
|
-
SHELL_VALUE_OPTIONS = new Set(["-o", "-O", "--rcfile", "--init-file"]);
|
|
2651
|
-
PRINTERS = new Set(["echo", "printf"]);
|
|
2652
|
-
FIND_EXEC = new Set(["-exec", "-execdir", "-ok", "-okdir"]);
|
|
2653
|
-
WRAPPERS = new Map([
|
|
2654
|
-
["command", wrapper()],
|
|
2655
|
-
["builtin", wrapper()],
|
|
2656
|
-
["nohup", wrapper()],
|
|
2657
|
-
["setsid", wrapper()],
|
|
2658
|
-
["busybox", wrapper()],
|
|
2659
|
-
["exec", wrapper("a")],
|
|
2660
|
-
["time", wrapper("fo", ["--format", "--output"])],
|
|
2661
|
-
["env", wrapper("uCS", ["--unset", "--chdir", "--split-string", "--argv0"])],
|
|
2662
|
-
["sudo", wrapper("ughpCTrtUDR", ["--user", "--group", "--host", "--prompt", "--close-from", "--command-timeout", "--role", "--type", "--other-user", "--chdir", "--chroot"])],
|
|
2663
|
-
["doas", wrapper("uC")],
|
|
2664
|
-
["timeout", wrapper("sk", ["--signal", "--kill-after"], 1)],
|
|
2665
|
-
["nice", wrapper("n", ["--adjustment"])],
|
|
2666
|
-
["ionice", wrapper("cnpPu", ["--class", "--classdata", "--pid", "--pgid", "--uid"])],
|
|
2667
|
-
["stdbuf", wrapper("ioe", ["--input", "--output", "--error"])],
|
|
2668
|
-
["chroot", wrapper("", ["--userspec", "--groups"], 1)],
|
|
2669
|
-
["xargs", wrapper("IndsEaPL", ["--max-args", "--max-procs", "--max-chars", "--delimiter", "--arg-file", "--eof", "--max-lines", "--process-slot-var"])]
|
|
2670
|
-
]);
|
|
2924
|
+
// src/commands/outdated.ts
|
|
2925
|
+
var exports_outdated = {};
|
|
2926
|
+
__export(exports_outdated, {
|
|
2927
|
+
outdatedCommand: () => outdatedCommand
|
|
2671
2928
|
});
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
function
|
|
2675
|
-
|
|
2929
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2930
|
+
import { join as join7, resolve as resolve3 } from "path";
|
|
2931
|
+
function currentOf(name, spec, locked) {
|
|
2932
|
+
const pinned = locked.filter((each) => each.name === name && Bun.semver.satisfies(each.version, spec)).map((each) => each.version).sort(Bun.semver.order).at(-1);
|
|
2933
|
+
const written = FIRST_VERSION.exec(spec)?.[0];
|
|
2934
|
+
return pinned ?? (written === undefined ? undefined : [...written.split("."), "0", "0"].slice(0, 3).join("."));
|
|
2935
|
+
}
|
|
2936
|
+
function changeOf(current, next) {
|
|
2937
|
+
const [from, to] = [current, next].map((version) => version.split(DOT).map(Number));
|
|
2938
|
+
if (from?.[0] !== to?.[0])
|
|
2939
|
+
return "major";
|
|
2940
|
+
return from?.[1] === to?.[1] ? "patch" : "minor";
|
|
2941
|
+
}
|
|
2942
|
+
async function outdated(manifest, context) {
|
|
2943
|
+
const configs = await loadConfigs();
|
|
2944
|
+
const dependencies = registryDependencies(manifest);
|
|
2945
|
+
const rows = [];
|
|
2946
|
+
for (let start = 0;start < dependencies.length; start += BATCH2) {
|
|
2947
|
+
const looked = await Promise.all(dependencies.slice(start, start + BATCH2).map(async ({ name, kind, spec }) => {
|
|
2948
|
+
const registry = registryFor(name, configs);
|
|
2949
|
+
const packument = await fetchPackument(name, registry, context.fetcher);
|
|
2950
|
+
if (packument === undefined) {
|
|
2951
|
+
warn(`${name} is not on ${new URL(registry.url).host}`);
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
const { safe, latest } = analyze({ spec: { name }, packument, registry: new URL(registry.url).host, now: context.now, minAgeDays: context.minAgeDays });
|
|
2955
|
+
const current = currentOf(name, spec, context.locked);
|
|
2956
|
+
if (safe === undefined || current === undefined || Bun.semver.order(safe.version, current) <= 0)
|
|
2957
|
+
return;
|
|
2958
|
+
const row = { name, kind, spec, current, safe: safe.version, change: changeOf(current, safe.version), published: safe.published };
|
|
2959
|
+
return latest !== undefined && latest.version !== safe.version && Bun.semver.order(latest.version, safe.version) > 0 ? { ...row, latest: latest.version } : row;
|
|
2960
|
+
}));
|
|
2961
|
+
rows.push(...looked.filter((row) => row !== undefined));
|
|
2962
|
+
}
|
|
2963
|
+
return rows.sort((a, b) => a.name.localeCompare(b.name));
|
|
2964
|
+
}
|
|
2965
|
+
async function outdatedCommand(args) {
|
|
2966
|
+
const { values, positionals: [dir = "."] } = parse(args, usage4, options3, { positionals: ["[dir]"], exits: EXITS3 });
|
|
2967
|
+
const folder = resolve3(dir);
|
|
2968
|
+
const manifest = Bun.file(join7(folder, "package.json"));
|
|
2969
|
+
if (!await manifest.exists())
|
|
2970
|
+
fail(`no package.json in ${folder}`);
|
|
2971
|
+
const lockPath = join7(folder, "bun.lock");
|
|
2972
|
+
const locked = existsSync3(lockPath) ? parseBunLock(await Bun.file(lockPath).text()) : [];
|
|
2973
|
+
const rows = await outdated(await manifest.text(), { minAgeDays: wholeNumber(values["min-age"], "min-age", DEFAULT_MIN_AGE_DAYS, 0), locked });
|
|
2974
|
+
const { shown, footer } = capped(rows, limitOf(values, OUTDATED_LIMIT));
|
|
2975
|
+
if (values.json === true)
|
|
2976
|
+
printJson(shown);
|
|
2977
|
+
else if (shown.length === 0)
|
|
2978
|
+
console.log("nothing outdated: every dependency is on its safe version");
|
|
2979
|
+
else
|
|
2980
|
+
console.log([table([["PACKAGE", "KIND", "CURRENT", "SAFE", "CHANGE", "PUBLISHED", "LATEST"], ...shown.map((each) => [each.name, each.kind, each.current, each.safe, each.change, each.published === undefined ? "-" : formatAge(each.published), each.latest ?? ""])], { header: true }), ...footer === undefined ? [] : [footer]].join(`
|
|
2981
|
+
`));
|
|
2982
|
+
return 0;
|
|
2676
2983
|
}
|
|
2677
|
-
var
|
|
2678
|
-
var init_pin = __esm(() => {
|
|
2679
|
-
init_shell();
|
|
2680
|
-
LOCKFILES = [
|
|
2681
|
-
["bun.lock", "bun"],
|
|
2682
|
-
["bun.lockb", "bun"],
|
|
2683
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
2684
|
-
["yarn.lock", "yarn"],
|
|
2685
|
-
["package-lock.json", "npm"]
|
|
2686
|
-
];
|
|
2687
|
-
ACTIONS = {
|
|
2688
|
-
bun: actions({ install: ["install", "i"], add: ["add", "a"], remove: ["remove", "rm"], update: ["update"] }),
|
|
2689
|
-
pnpm: actions({ install: ["install", "i"], add: ["add"], remove: ["remove", "rm"], update: ["update", "up"] }),
|
|
2690
|
-
yarn: new Map([...actions({ install: ["", "install"], add: ["add"], remove: ["remove"], update: ["upgrade"] }), ["upgrade-interactive", null], ["import", null]]),
|
|
2691
|
-
npm: actions({
|
|
2692
|
-
install: ["install", "i", "in", "ins", "inst", "insta", "instal", "isnt", "isnta", "isntal", "isntall"],
|
|
2693
|
-
add: ["add"],
|
|
2694
|
-
frozen: ["ci", "clean-install", "ic", "install-clean", "isntall-clean"],
|
|
2695
|
-
remove: ["uninstall", "unlink", "remove", "rm", "r", "un"],
|
|
2696
|
-
update: ["update", "u", "up", "upgrade", "udpate"]
|
|
2697
|
-
})
|
|
2698
|
-
};
|
|
2699
|
-
OPTION_FLAGS = new Map([
|
|
2700
|
-
["-D", "dev"],
|
|
2701
|
-
["--save-dev", "dev"],
|
|
2702
|
-
["--dev", "dev"],
|
|
2703
|
-
["-E", "exact"],
|
|
2704
|
-
["--save-exact", "exact"],
|
|
2705
|
-
["--exact", "exact"]
|
|
2706
|
-
]);
|
|
2707
|
-
DIR_FLAGS = new Set(["--cwd", "-C", "--dir", "--prefix"]);
|
|
2708
|
-
VALUE_FLAGS = new Set([...DIR_FLAGS, "--filter", "-F"]);
|
|
2709
|
-
});
|
|
2984
|
+
var usage4 = `pkg outdated [dir]
|
|
2710
2985
|
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
}
|
|
2729
|
-
function managerFor(dir, root) {
|
|
2730
|
-
for (let at = dir;; at = dirname3(at)) {
|
|
2731
|
-
const lockfile = LOCKFILES.find(([file]) => existsSync(join4(at, file)));
|
|
2732
|
-
if (lockfile !== undefined)
|
|
2733
|
-
return lockfile[1];
|
|
2734
|
-
if (at === root || at === dirname3(at))
|
|
2735
|
-
return "bun";
|
|
2736
|
-
}
|
|
2737
|
-
}
|
|
2738
|
-
function findConsumers(name, root) {
|
|
2739
|
-
const consumers = [];
|
|
2740
|
-
for (const path of packageFiles(root, 0, []).sort()) {
|
|
2741
|
-
let manifest;
|
|
2742
|
-
try {
|
|
2743
|
-
manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
2744
|
-
} catch {
|
|
2745
|
-
continue;
|
|
2746
|
-
}
|
|
2747
|
-
const kind = KINDS.find((each) => typeof manifest[each]?.[name] === "string");
|
|
2748
|
-
const spec = kind === undefined ? undefined : manifest[kind]?.[name];
|
|
2749
|
-
if (kind !== undefined && spec !== undefined)
|
|
2750
|
-
consumers.push({ dir: relative(root, dirname3(path)) || ".", path, kind, spec, manager: managerFor(dirname3(path), root) });
|
|
2751
|
-
}
|
|
2752
|
-
return consumers;
|
|
2753
|
-
}
|
|
2754
|
-
function isLocal(consumer) {
|
|
2755
|
-
return LOCAL_SPEC.test(consumer.spec);
|
|
2756
|
-
}
|
|
2757
|
-
function addCommand(consumer, name, version) {
|
|
2758
|
-
return ["bun", "add", ...KIND_FLAGS[consumer.kind], "--exact", "--no-cache", `${name}@${version}`];
|
|
2759
|
-
}
|
|
2760
|
-
var KINDS, SKIPPED, MAX_DEPTH = 5, LOCAL_SPEC, KIND_FLAGS;
|
|
2761
|
-
var init_consumers = __esm(() => {
|
|
2762
|
-
init_pin();
|
|
2763
|
-
KINDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
2764
|
-
SKIPPED = new Set(["node_modules", "dist", "build", "vendor", "target", "coverage"]);
|
|
2765
|
-
LOCAL_SPEC = /[:/]/;
|
|
2766
|
-
KIND_FLAGS = { dependencies: [], devDependencies: ["--dev"], optionalDependencies: ["--optional"], peerDependencies: ["--peer"] };
|
|
2986
|
+
Lists the dependencies of the package.json in the folder (the current one by default, registry versions only) that have a newer version safe to take: the highest stable one at least --min-age days old, the \`safe\` of \`pkg check\`. The version in use is the highest one the folder's bun.lock pins that the range allows, else the exact version written, else the first version in the range. A dependency whose newest version is still too fresh shows it under \`latest\`.
|
|
2987
|
+
It reads only the registry's metadata, no advisories, and changes nothing: \`bun add --exact name@version\` adopts a row.`, EXITS3, OUTDATED_LIMIT = 50, BATCH2 = 8, FIRST_VERSION, DOT, options3;
|
|
2988
|
+
var init_outdated = __esm(() => {
|
|
2989
|
+
init_src();
|
|
2990
|
+
init_analyze();
|
|
2991
|
+
init_config2();
|
|
2992
|
+
init_consumers();
|
|
2993
|
+
init_lockfile();
|
|
2994
|
+
init_registry();
|
|
2995
|
+
EXITS3 = [[0, "it listed what is outdated, nothing included"], [2, "the registry could not be reached or answered badly, no package.json, or a usage error"]];
|
|
2996
|
+
FIRST_VERSION = /\d+(?:\.\d+){0,2}(?:-[\w.-]+)?/;
|
|
2997
|
+
DOT = /[.-]/;
|
|
2998
|
+
options3 = {
|
|
2999
|
+
"min-age": { type: "string", description: `days a version must be old (${DEFAULT_MIN_AGE_DAYS})` },
|
|
3000
|
+
...limitOptions(OUTDATED_LIMIT),
|
|
3001
|
+
json: jsonOption("[{name, kind, spec, current, safe, change, published, latest?}]")
|
|
3002
|
+
};
|
|
2767
3003
|
});
|
|
2768
3004
|
|
|
2769
3005
|
// src/commands/bump.ts
|
|
@@ -2772,9 +3008,9 @@ __export(exports_bump, {
|
|
|
2772
3008
|
ROOT_OPTION: () => ROOT_OPTION,
|
|
2773
3009
|
bump: () => bump
|
|
2774
3010
|
});
|
|
2775
|
-
import { existsSync as
|
|
2776
|
-
import { homedir as
|
|
2777
|
-
import { dirname as
|
|
3011
|
+
import { existsSync as existsSync4 } from "fs";
|
|
3012
|
+
import { homedir as homedir4 } from "os";
|
|
3013
|
+
import { dirname as dirname5, join as join8, relative as relative2 } from "path";
|
|
2778
3014
|
async function lookup(name, registry, fetcher) {
|
|
2779
3015
|
try {
|
|
2780
3016
|
return { packument: await fetchPackument(name, registry, fetcher) };
|
|
@@ -2792,7 +3028,7 @@ async function servedVersion(name, version, settings) {
|
|
|
2792
3028
|
const registry = registryFor(name, settings.configs);
|
|
2793
3029
|
const host = new URL(registry.url).host;
|
|
2794
3030
|
const started = Date.now();
|
|
2795
|
-
const region = liveRegion((spinner) => [`${spinner} waiting for ${host} to serve ${name}@${version} ${formatElapsed(Date.now() - started)}`]);
|
|
3031
|
+
const region = liveRegion((spinner) => [`${spinner} waiting for ${host} to serve ${name}@${version ?? "latest"} ${formatElapsed(Date.now() - started)}`]);
|
|
2796
3032
|
let lastError = "";
|
|
2797
3033
|
try {
|
|
2798
3034
|
for (;; ) {
|
|
@@ -2811,7 +3047,7 @@ async function servedVersion(name, version, settings) {
|
|
|
2811
3047
|
return version;
|
|
2812
3048
|
}
|
|
2813
3049
|
if (Date.now() - started >= settings.timeout)
|
|
2814
|
-
fail(`${host} does not serve ${name}@${version} after ${formatDuration(settings.timeout)}${lastError === "" ? "" : `, last error: ${lastError}`}`);
|
|
3050
|
+
fail(`${host} does not serve ${name}@${version ?? "latest"} after ${formatDuration(settings.timeout)}${lastError === "" ? "" : `, last error: ${lastError}`}`);
|
|
2815
3051
|
region.redraw();
|
|
2816
3052
|
await Bun.sleep(settings.poll ?? POLL);
|
|
2817
3053
|
}
|
|
@@ -2834,11 +3070,11 @@ async function vet(name, version, settings) {
|
|
|
2834
3070
|
return false;
|
|
2835
3071
|
}
|
|
2836
3072
|
function lockfileOf(dir, root) {
|
|
2837
|
-
for (let at = dir;; at =
|
|
2838
|
-
const found = ["bun.lock", "bun.lockb"].find((file) =>
|
|
3073
|
+
for (let at = dir;; at = dirname5(at)) {
|
|
3074
|
+
const found = ["bun.lock", "bun.lockb"].find((file) => existsSync4(join8(at, file)));
|
|
2839
3075
|
if (found !== undefined)
|
|
2840
|
-
return relative2(dir,
|
|
2841
|
-
if (at === root || at ===
|
|
3076
|
+
return relative2(dir, join8(at, found));
|
|
3077
|
+
if (at === root || at === dirname5(at))
|
|
2842
3078
|
return;
|
|
2843
3079
|
}
|
|
2844
3080
|
}
|
|
@@ -2872,7 +3108,7 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2872
3108
|
note(`${local} non-registry dependenc${local === 1 ? "y" : "ies"} (workspace:, file:, git, URL, alias, catalog:)`, "left as they are");
|
|
2873
3109
|
for (const consumer of consumers) {
|
|
2874
3110
|
const argv = addCommand(consumer, name, version);
|
|
2875
|
-
const where =
|
|
3111
|
+
const where = join8(settings.root, consumer.dir);
|
|
2876
3112
|
if (consumer.kind === "peerDependencies") {
|
|
2877
3113
|
skipped.push(consumer.dir);
|
|
2878
3114
|
note(consumer.dir, `peer range ${consumer.spec}, left as it is`);
|
|
@@ -2915,9 +3151,9 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2915
3151
|
return isClean;
|
|
2916
3152
|
}
|
|
2917
3153
|
async function bump(args) {
|
|
2918
|
-
const { values, positionals: [name, asked] } = parse(args,
|
|
3154
|
+
const { values, positionals: [name, asked] } = parse(args, usage5, options4, { positionals: ["<name>", "[version]"] });
|
|
2919
3155
|
const settings = {
|
|
2920
|
-
root: values.root ??
|
|
3156
|
+
root: values.root ?? join8(homedir4(), "Workspace"),
|
|
2921
3157
|
configs: await loadConfigs(),
|
|
2922
3158
|
timeout: duration(values.timeout, "timeout", 10 * 60000),
|
|
2923
3159
|
isDryRun: values["dry-run"] === true,
|
|
@@ -2931,14 +3167,14 @@ async function bump(args) {
|
|
|
2931
3167
|
return 1;
|
|
2932
3168
|
return await bumpConsumers(name, version, settings) ? 0 : 1;
|
|
2933
3169
|
}
|
|
2934
|
-
var
|
|
3170
|
+
var usage5 = `pkg bump <name> [version]
|
|
2935
3171
|
|
|
2936
3172
|
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.
|
|
2937
3173
|
A version the vetting blocks is refused before any folder is touched, unless --force is given.
|
|
2938
3174
|
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.
|
|
2939
3175
|
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.
|
|
2940
3176
|
|
|
2941
|
-
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,
|
|
3177
|
+
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, options4, POLL = 5000;
|
|
2942
3178
|
var init_bump = __esm(() => {
|
|
2943
3179
|
init_src();
|
|
2944
3180
|
init_progress();
|
|
@@ -2948,7 +3184,7 @@ var init_bump = __esm(() => {
|
|
|
2948
3184
|
init_semver();
|
|
2949
3185
|
init_check();
|
|
2950
3186
|
ROOT_OPTION = { type: "string", description: "the folder holding the repositories (~/Workspace)" };
|
|
2951
|
-
|
|
3187
|
+
options4 = {
|
|
2952
3188
|
root: ROOT_OPTION,
|
|
2953
3189
|
timeout: { type: "string", short: "t", description: "how long to wait for the registry (10m): 30s, 5m, 1h" },
|
|
2954
3190
|
"all-consumers": { type: "boolean", description: "after each install run the folder's check and commit it through gc when it passes" },
|
|
@@ -2963,11 +3199,11 @@ var exports_consumers = {};
|
|
|
2963
3199
|
__export(exports_consumers, {
|
|
2964
3200
|
consumers: () => consumers
|
|
2965
3201
|
});
|
|
2966
|
-
import { homedir as
|
|
2967
|
-
import { join as
|
|
3202
|
+
import { homedir as homedir5 } from "os";
|
|
3203
|
+
import { join as join9 } from "path";
|
|
2968
3204
|
function consumers(args) {
|
|
2969
|
-
const { values, positionals: [name] } = parse(args,
|
|
2970
|
-
const root = values.root ??
|
|
3205
|
+
const { values, positionals: [name] } = parse(args, usage6, options5, { positionals: ["<name>"] });
|
|
3206
|
+
const root = values.root ?? join9(homedir5(), "Workspace");
|
|
2971
3207
|
const { shown, footer } = capped(findConsumers(name, root), limitOf(values, CONSUMERS_LIMIT));
|
|
2972
3208
|
if (values.json === true)
|
|
2973
3209
|
printJson(shown);
|
|
@@ -2978,16 +3214,16 @@ function consumers(args) {
|
|
|
2978
3214
|
`));
|
|
2979
3215
|
return 0;
|
|
2980
3216
|
}
|
|
2981
|
-
var
|
|
3217
|
+
var usage6 = `pkg consumers <name>
|
|
2982
3218
|
|
|
2983
3219
|
Lists the folders under --root whose package.json depends on the package: the folder, the kind of dependency, the version it asks for and the manager its lockfile pins, 30 at most with the count of the rest after them (--limit <n>, --full for all; --json is never cut unless --limit is given).
|
|
2984
3220
|
|
|
2985
|
-
Exits 0 when it listed them, 2 on a usage error.`, CONSUMERS_LIMIT = 30,
|
|
3221
|
+
Exits 0 when it listed them, 2 on a usage error.`, CONSUMERS_LIMIT = 30, options5;
|
|
2986
3222
|
var init_consumers2 = __esm(() => {
|
|
2987
3223
|
init_src();
|
|
2988
3224
|
init_consumers();
|
|
2989
3225
|
init_bump();
|
|
2990
|
-
|
|
3226
|
+
options5 = {
|
|
2991
3227
|
root: ROOT_OPTION,
|
|
2992
3228
|
...limitOptions(CONSUMERS_LIMIT),
|
|
2993
3229
|
json: jsonOption("[{dir, path, kind, spec, manager}]")
|
|
@@ -2996,14 +3232,9 @@ var init_consumers2 = __esm(() => {
|
|
|
2996
3232
|
|
|
2997
3233
|
// src/cli.ts
|
|
2998
3234
|
init_src();
|
|
2999
|
-
import
|
|
3000
|
-
|
|
3001
|
-
var version = "0.7.1";
|
|
3002
|
-
|
|
3003
|
-
// src/cli.ts
|
|
3004
|
-
process12.exitCode = await runCli({
|
|
3235
|
+
import process15 from "process";
|
|
3236
|
+
process15.exitCode = await runCli({
|
|
3005
3237
|
name: "pkg",
|
|
3006
|
-
version,
|
|
3007
3238
|
about: "checks npm packages before they are added, and moves a lib's consumers onto a new release",
|
|
3008
3239
|
replaces: "bun add on trust, and a bun info and sleep loop then a bun add per consumer",
|
|
3009
3240
|
examples: [["pkg zod", "the name, the newest version two weeks old, its licence and scripts"], ["pkg bump @kaynooo/cli-kit --dry-run", "the consumers a release would move"]],
|
|
@@ -3011,6 +3242,7 @@ process12.exitCode = await runCli({
|
|
|
3011
3242
|
commands: {
|
|
3012
3243
|
check: { summary: "check packages before they are added (`pkg <name>` alone runs it)", run: async (args) => (await Promise.resolve().then(() => (init_check(), exports_check))).check(args) },
|
|
3013
3244
|
audit: { summary: "check every package a bun.lock pins, with its known advisories", run: async (args) => (await Promise.resolve().then(() => (init_audit(), exports_audit))).audit(args) },
|
|
3245
|
+
outdated: { summary: "list the dependencies of this folder that have a newer version safe to take", run: async (args) => (await Promise.resolve().then(() => (init_outdated(), exports_outdated))).outdatedCommand(args) },
|
|
3014
3246
|
bump: { summary: "wait for a release on the registry, then bun add it in every consumer", run: async (args) => (await Promise.resolve().then(() => (init_bump(), exports_bump))).bump(args) },
|
|
3015
3247
|
consumers: { summary: "list the folders depending on a package, with the version each asks for", run: async (args) => (await Promise.resolve().then(() => (init_consumers2(), exports_consumers))).consumers(args) }
|
|
3016
3248
|
}
|