@kaynooo/cli-pkg 0.7.0 → 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 +1036 -586
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -26,7 +26,19 @@ var __esm = (fn, res, err) => () => {
|
|
|
26
26
|
return res;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
//
|
|
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
|
+
|
|
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();
|
|
32
44
|
if (!/^[a-f0-9]+$/.test(r))
|
|
@@ -245,7 +257,7 @@ class e {
|
|
|
245
257
|
var m = (s) => s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4, p = (s) => s <= 0.0031308 ? 12.92 * s : 1.055 * s ** 0.4166666666666667 - 0.055, i = (s, r) => Math.round(s * 10 ** r) / 10 ** r;
|
|
246
258
|
var init_chunk_mtetydvc = () => {};
|
|
247
259
|
|
|
248
|
-
// ../../node_modules/.bun/@kaynooo+utils@2.31.
|
|
260
|
+
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/chunk-y1msbssb.js
|
|
249
261
|
function h(i, n = globalThis.process?.env ?? {}) {
|
|
250
262
|
if (n.FORCE_COLOR !== undefined)
|
|
251
263
|
return b.has(n.FORCE_COLOR);
|
|
@@ -287,36 +299,36 @@ var init_chunk_y1msbssb = __esm(() => {
|
|
|
287
299
|
t = le();
|
|
288
300
|
});
|
|
289
301
|
|
|
290
|
-
// ../../node_modules/.bun/@kaynooo+utils@2.31.
|
|
302
|
+
// ../../node_modules/.bun/@kaynooo+utils@2.31.2+d0769e28dc4dad16/node_modules/@kaynooo/utils/dist/tools/colors.js
|
|
291
303
|
var init_colors = __esm(() => {
|
|
292
304
|
init_chunk_y1msbssb();
|
|
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)));
|
|
@@ -421,6 +433,67 @@ var init_format = __esm(() => {
|
|
|
421
433
|
ESCAPE = String.fromCharCode(27);
|
|
422
434
|
});
|
|
423
435
|
|
|
436
|
+
// ../kit/src/help.ts
|
|
437
|
+
import process4 from "process";
|
|
438
|
+
function usageLine(usage, colors = paint(process4.stdout)) {
|
|
439
|
+
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
440
|
+
}
|
|
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(`
|
|
443
|
+
`);
|
|
444
|
+
}
|
|
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)) {
|
|
452
|
+
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
453
|
+
}
|
|
454
|
+
function wantsHelpJson(env = process4.env) {
|
|
455
|
+
return env.KIT_HELP === "json";
|
|
456
|
+
}
|
|
457
|
+
function description(usage, { examples = [], replaces, exits } = {}, options) {
|
|
458
|
+
const lines = usage.replace(USAGE_PREFIX, "").split(`
|
|
459
|
+
`);
|
|
460
|
+
const first = lines[0];
|
|
461
|
+
const colon = first.indexOf(": ");
|
|
462
|
+
const prose = lines[lines.indexOf("") + 1] ?? "";
|
|
463
|
+
const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
|
|
464
|
+
return {
|
|
465
|
+
synopsis: colon === -1 ? first : first.slice(0, colon),
|
|
466
|
+
summary: colon === -1 ? fallback : first.slice(colon + 2),
|
|
467
|
+
...replaces === undefined ? {} : { replaces },
|
|
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 } })) }
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function exampleRows(examples, colors = paint(process4.stdout)) {
|
|
474
|
+
if (examples.length === 0)
|
|
475
|
+
return [];
|
|
476
|
+
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
477
|
+
}
|
|
478
|
+
function optionRows(options, colors = paint(process4.stdout)) {
|
|
479
|
+
const rows = Object.entries(options).map(([name, option]) => {
|
|
480
|
+
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
481
|
+
const named = option.choices === undefined ? "<value>" : `<${option.choices.join("|")}>`;
|
|
482
|
+
const placeholder = option.optional === undefined ? named : `[${named}]`;
|
|
483
|
+
const value = option.type === "string" ? ` ${colors.dim(placeholder)}` : "";
|
|
484
|
+
return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? placeholder.length + 1 : 0), description: option.description ?? "" };
|
|
485
|
+
});
|
|
486
|
+
const width = Math.max(0, ...rows.map((row) => row.width));
|
|
487
|
+
return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
|
|
488
|
+
}
|
|
489
|
+
var OPTIONAL, USAGE_PREFIX, FULL_STOP;
|
|
490
|
+
var init_help = __esm(() => {
|
|
491
|
+
init_style();
|
|
492
|
+
OPTIONAL = /\[[^\]]+\]/g;
|
|
493
|
+
USAGE_PREFIX = /^usage:\s*/i;
|
|
494
|
+
FULL_STOP = /\.$/;
|
|
495
|
+
});
|
|
496
|
+
|
|
424
497
|
// ../kit/src/text.ts
|
|
425
498
|
function distance(a, b) {
|
|
426
499
|
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
@@ -444,8 +517,51 @@ var init_text = __esm(() => {
|
|
|
444
517
|
ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
|
|
445
518
|
});
|
|
446
519
|
|
|
520
|
+
// ../kit/src/input.ts
|
|
521
|
+
import { fstatSync } from "fs";
|
|
522
|
+
import process5 from "process";
|
|
523
|
+
function wholeNumber(value, name, fallback, min = 1) {
|
|
524
|
+
if (value === undefined)
|
|
525
|
+
return fallback;
|
|
526
|
+
const number = Number(value);
|
|
527
|
+
if (!WHOLE.test(value) || !Number.isSafeInteger(number) || number < min)
|
|
528
|
+
badUsage(`${name.startsWith("<") ? name : `--${name}`} takes a whole number from ${min}, not ${value}`);
|
|
529
|
+
return number;
|
|
530
|
+
}
|
|
531
|
+
function duration(value, name, fallback, unit = "s") {
|
|
532
|
+
if (value === undefined)
|
|
533
|
+
return fallback;
|
|
534
|
+
const match = DURATION.exec(value.trim());
|
|
535
|
+
const ms = match === null ? 0 : Number(match[1]) * UNIT_MS[match[2] ?? unit];
|
|
536
|
+
if (ms < 1)
|
|
537
|
+
badUsage(`--${name} takes a duration such as 30s, 5m, 1h or 7d, not ${value}`);
|
|
538
|
+
return ms;
|
|
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
|
+
}
|
|
555
|
+
var WHOLE, DURATION, UNIT_MS;
|
|
556
|
+
var init_input = __esm(() => {
|
|
557
|
+
init_args();
|
|
558
|
+
WHOLE = /^\d+$/;
|
|
559
|
+
DURATION = /^(\d+(?:\.\d+)?)(ms|[smhd])?$/;
|
|
560
|
+
UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
|
|
561
|
+
});
|
|
562
|
+
|
|
447
563
|
// ../kit/src/args.ts
|
|
448
|
-
import
|
|
564
|
+
import process6 from "process";
|
|
449
565
|
import { parseArgs } from "util";
|
|
450
566
|
function jsonOption(holds) {
|
|
451
567
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
@@ -459,52 +575,15 @@ function badUsage(message) {
|
|
|
459
575
|
|
|
460
576
|
class Completing {
|
|
461
577
|
options;
|
|
462
|
-
|
|
578
|
+
positionals;
|
|
579
|
+
candidates;
|
|
580
|
+
constructor(options, positionals = [], candidates = {}) {
|
|
463
581
|
this.options = options;
|
|
582
|
+
this.positionals = positionals;
|
|
583
|
+
this.candidates = candidates;
|
|
464
584
|
}
|
|
465
585
|
}
|
|
466
|
-
function
|
|
467
|
-
return `${colors.bold("Usage:")} ${usage.replace(USAGE_PREFIX, "").replaceAll(OPTIONAL, (part) => colors.dim(part))}`;
|
|
468
|
-
}
|
|
469
|
-
function helpText(usage, options, colors = paint(process3.stdout), { examples = [], replaces } = {}) {
|
|
470
|
-
return [usageLine(usage, colors), ...replacesRows(replaces, colors), "", colors.bold("Options:"), ...optionRows(options, colors), ...exampleRows(examples, colors)].join(`
|
|
471
|
-
`);
|
|
472
|
-
}
|
|
473
|
-
function replacesRows(replaces, colors = paint(process3.stdout)) {
|
|
474
|
-
return replaces === undefined ? [] : ["", `${colors.bold("Instead of:")} ${replaces}`];
|
|
475
|
-
}
|
|
476
|
-
function wantsHelpJson(env = process3.env) {
|
|
477
|
-
return env.KIT_HELP === "json";
|
|
478
|
-
}
|
|
479
|
-
function description(usage, { examples = [], replaces } = {}) {
|
|
480
|
-
const lines = usage.replace(USAGE_PREFIX, "").split(`
|
|
481
|
-
`);
|
|
482
|
-
const first = lines[0];
|
|
483
|
-
const colon = first.indexOf(": ");
|
|
484
|
-
const prose = lines[lines.indexOf("") + 1] ?? "";
|
|
485
|
-
const fallback = lines.includes("") ? `${prose.charAt(0).toLowerCase()}${prose.slice(1)}`.replace(FULL_STOP, "") : "";
|
|
486
|
-
return {
|
|
487
|
-
synopsis: colon === -1 ? first : first.slice(0, colon),
|
|
488
|
-
summary: colon === -1 ? fallback : first.slice(colon + 2),
|
|
489
|
-
...replaces === undefined ? {} : { replaces },
|
|
490
|
-
examples: examples.map((example) => typeof example === "string" ? { line: example } : { line: example[0], note: example[1] })
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
function exampleRows(examples, colors = paint(process3.stdout)) {
|
|
494
|
-
if (examples.length === 0)
|
|
495
|
-
return [];
|
|
496
|
-
return ["", colors.bold("Examples:"), ...examples.map((example) => typeof example === "string" ? ` ${example}` : ` ${example[0]} ${colors.dim(`# ${example[1]}`)}`)];
|
|
497
|
-
}
|
|
498
|
-
function optionRows(options, colors = paint(process3.stdout)) {
|
|
499
|
-
const rows = Object.entries(options).map(([name, option]) => {
|
|
500
|
-
const short = option.short === undefined ? " " : `${colors.cyan(`-${option.short}`)}, `;
|
|
501
|
-
const value = option.type === "string" ? ` ${colors.dim("<value>")}` : "";
|
|
502
|
-
return { flag: `${short}${colors.cyan(`--${name}`)}${value}`, width: `-x, --${name}`.length + (option.type === "string" ? " <value>".length : 0), description: option.description ?? "" };
|
|
503
|
-
});
|
|
504
|
-
const width = Math.max(0, ...rows.map((row) => row.width));
|
|
505
|
-
return rows.map((row) => row.description === "" ? ` ${row.flag}` : ` ${row.flag}${" ".repeat(width - row.width)} ${colors.dim(row.description)}`);
|
|
506
|
-
}
|
|
507
|
-
function applyOutput(color, plain, env = process3.env) {
|
|
586
|
+
function applyOutput(color, plain, env = process6.env) {
|
|
508
587
|
const when = plain === true ? "never" : color ?? "auto";
|
|
509
588
|
if (when === "auto")
|
|
510
589
|
return;
|
|
@@ -521,14 +600,13 @@ function applyOutput(color, plain, env = process3.env) {
|
|
|
521
600
|
function parse(args, usage, options, settings = {}) {
|
|
522
601
|
const output = Object.fromEntries(Object.entries(OUTPUT_OPTIONS).filter(([name]) => !(name in options)));
|
|
523
602
|
const all = { ...options, ...output, help: { type: "boolean", short: "h", description: "show this help" } };
|
|
603
|
+
const listing = listed(all, settings.allowNegative === true);
|
|
524
604
|
if (completion.active)
|
|
525
|
-
throw new Completing(
|
|
526
|
-
const
|
|
527
|
-
const own = separator === -1 ? args : args.slice(0, separator);
|
|
528
|
-
const rest = separator === -1 ? undefined : args.slice(separator + 1);
|
|
605
|
+
throw new Completing(listing, settings.positionals, settings.candidates);
|
|
606
|
+
const { own, rest } = settings.trailing === true ? splitTrailing(args, all, settings.positionals?.length ?? 0) : splitRest(args, settings.rest === true);
|
|
529
607
|
let parsed;
|
|
530
608
|
try {
|
|
531
|
-
parsed = parseArgs({ args: joinDashValues(own, 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 });
|
|
532
610
|
} catch (error) {
|
|
533
611
|
const message = parseError(error);
|
|
534
612
|
throw new UsageError(message, nearestOption(message, all, settings.allowNegative === true));
|
|
@@ -536,12 +614,96 @@ function parse(args, usage, options, settings = {}) {
|
|
|
536
614
|
const values = parsed.values;
|
|
537
615
|
applyOutput("color" in output ? values.color : undefined, "plain" in output ? values.plain : undefined);
|
|
538
616
|
if (values.help === true) {
|
|
539
|
-
console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings)) : helpText(usage,
|
|
617
|
+
console.log(wantsHelpJson() ? JSON.stringify(description(usage, settings, listing)) : helpText(usage, listing, undefined, settings));
|
|
540
618
|
throw new HelpShown;
|
|
541
619
|
}
|
|
620
|
+
checkChoices(parsed.values, all);
|
|
621
|
+
checkConflicts(parsed.values, all);
|
|
542
622
|
if (settings.positionals !== undefined)
|
|
543
623
|
checkPositionals(parsed.positionals, settings.positionals);
|
|
544
|
-
return { ...parsed, positionals: parsed.positionals, rest };
|
|
624
|
+
return { ...parsed, values: parsed.values, positionals: parsed.positionals, rest };
|
|
625
|
+
}
|
|
626
|
+
function splitRest(args, passes) {
|
|
627
|
+
const separator = passes ? args.indexOf("--") : -1;
|
|
628
|
+
return { own: separator === -1 ? args : args.slice(0, separator), rest: separator === -1 ? undefined : args.slice(separator + 1) };
|
|
629
|
+
}
|
|
630
|
+
function splitTrailing(args, options, count) {
|
|
631
|
+
const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
|
|
632
|
+
let seen = 0;
|
|
633
|
+
if (count === 0)
|
|
634
|
+
return { own: args, rest: undefined };
|
|
635
|
+
for (let at = 0;at < args.length; at++) {
|
|
636
|
+
const word = args[at];
|
|
637
|
+
if (word === "--")
|
|
638
|
+
break;
|
|
639
|
+
if (word.startsWith("-")) {
|
|
640
|
+
if (takesValue(word))
|
|
641
|
+
at++;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
seen++;
|
|
645
|
+
if (seen === count)
|
|
646
|
+
return { own: args.slice(0, at + 1), rest: args.slice(at + 1) };
|
|
647
|
+
}
|
|
648
|
+
return { own: args, rest: undefined };
|
|
649
|
+
}
|
|
650
|
+
function listed(options, allowNegative) {
|
|
651
|
+
if (!allowNegative)
|
|
652
|
+
return options;
|
|
653
|
+
return Object.fromEntries(Object.entries(options).flatMap(([name, option]) => {
|
|
654
|
+
if (option.type !== "boolean" || option.negative === undefined)
|
|
655
|
+
return [[name, option]];
|
|
656
|
+
return [...option.description === undefined ? [] : [[name, option]], [`no-${name}`, { type: "boolean", description: option.negative }]];
|
|
657
|
+
}));
|
|
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
|
+
}
|
|
671
|
+
function withBare(args, options) {
|
|
672
|
+
const bare = new Map(Object.entries(options).flatMap(([name, { short, optional }]) => optional === undefined ? [] : [[`--${name}`, optional], ...short === undefined ? [] : [[`-${short}`, optional]]]));
|
|
673
|
+
if (bare.size === 0)
|
|
674
|
+
return args;
|
|
675
|
+
const separator = args.indexOf("--");
|
|
676
|
+
const own = separator === -1 ? args : args.slice(0, separator);
|
|
677
|
+
return [...own.flatMap((arg, index) => {
|
|
678
|
+
const optional = bare.get(arg);
|
|
679
|
+
const next = own[index + 1];
|
|
680
|
+
const value = next !== undefined && (optional?.accepts === undefined ? !next.startsWith("-") : optional.accepts.test(next));
|
|
681
|
+
return optional === undefined || value ? [arg] : [arg, optional.bare];
|
|
682
|
+
}), ...separator === -1 ? [] : args.slice(separator)];
|
|
683
|
+
}
|
|
684
|
+
function checkConflicts(values, options) {
|
|
685
|
+
const given = (name) => values[name] !== undefined && values[name] !== false;
|
|
686
|
+
for (const [name, { conflicts = [] }] of Object.entries(options)) {
|
|
687
|
+
const other = given(name) ? conflicts.find(given) : undefined;
|
|
688
|
+
if (other !== undefined)
|
|
689
|
+
badUsage(`--${name} cannot be used with --${other}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
function checkChoices(values, options) {
|
|
693
|
+
for (const [name, option] of Object.entries(options)) {
|
|
694
|
+
if (option.choices === undefined)
|
|
695
|
+
continue;
|
|
696
|
+
const given = values[name];
|
|
697
|
+
for (const value of Array.isArray(given) ? given : [given]) {
|
|
698
|
+
if (typeof value === "string")
|
|
699
|
+
oneOf(value, name, option.choices);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function oneOf(value, name, choices) {
|
|
704
|
+
if (!choices.includes(value))
|
|
705
|
+
badUsage(`${name.startsWith("<") ? name : `--${name}`} takes one of ${choices.join(", ")}, not ${value}`);
|
|
706
|
+
return value;
|
|
545
707
|
}
|
|
546
708
|
function checkPositionals(given, names) {
|
|
547
709
|
const variadic = names.at(-1)?.replace("]", "").endsWith("...") === true;
|
|
@@ -589,28 +751,14 @@ function nearestOption(message, options, allowNegative) {
|
|
|
589
751
|
const meant = closest(word, known.map((flag) => flag.replace(DASHES, "")));
|
|
590
752
|
return meant === undefined ? undefined : `did you mean ${known.find((flag) => flag.replace(DASHES, "") === meant)}?`;
|
|
591
753
|
}
|
|
592
|
-
|
|
593
|
-
if (value === undefined)
|
|
594
|
-
return fallback;
|
|
595
|
-
const number = Number(value);
|
|
596
|
-
if (!WHOLE.test(value) || !Number.isSafeInteger(number) || number < min)
|
|
597
|
-
badUsage(`${name.startsWith("<") ? name : `--${name}`} takes a whole number from ${min}, not ${value}`);
|
|
598
|
-
return number;
|
|
599
|
-
}
|
|
600
|
-
function duration(value, name, fallback, unit = "s") {
|
|
601
|
-
if (value === undefined)
|
|
602
|
-
return fallback;
|
|
603
|
-
const match = DURATION.exec(value.trim());
|
|
604
|
-
const ms = match === null ? 0 : Number(match[1]) * UNIT_MS[match[2] ?? unit];
|
|
605
|
-
if (ms < 1)
|
|
606
|
-
badUsage(`--${name} takes a duration such as 30s, 5m, 1h or 7d, not ${value}`);
|
|
607
|
-
return ms;
|
|
608
|
-
}
|
|
609
|
-
var Exit, UsageError, HelpShown, completion, OPTIONAL, USAGE_PREFIX, FULL_STOP, DASHES, OUTPUT_OPTIONS, UNKNOWN_OPTION, WHOLE, DURATION, UNIT_MS;
|
|
754
|
+
var DASHES, Exit, UsageError, HelpShown, completion, OUTPUT_OPTIONS, UNKNOWN_OPTION;
|
|
610
755
|
var init_args = __esm(() => {
|
|
611
756
|
init_format();
|
|
612
|
-
|
|
757
|
+
init_help();
|
|
613
758
|
init_text();
|
|
759
|
+
init_help();
|
|
760
|
+
init_input();
|
|
761
|
+
DASHES = /^-+/;
|
|
614
762
|
Exit = class Exit extends Error {
|
|
615
763
|
code;
|
|
616
764
|
hint;
|
|
@@ -631,18 +779,11 @@ var init_args = __esm(() => {
|
|
|
631
779
|
}
|
|
632
780
|
};
|
|
633
781
|
completion = { active: false };
|
|
634
|
-
OPTIONAL = /\[[^\]]+\]/g;
|
|
635
|
-
USAGE_PREFIX = /^usage:\s*/i;
|
|
636
|
-
FULL_STOP = /\.$/;
|
|
637
|
-
DASHES = /^-+/;
|
|
638
782
|
OUTPUT_OPTIONS = {
|
|
639
783
|
color: { type: "string", description: "auto (on a terminal alone), always or never" },
|
|
640
784
|
plain: { type: "boolean", description: "plain text, no colour or spinner: --color never" }
|
|
641
785
|
};
|
|
642
786
|
UNKNOWN_OPTION = /^unknown option '(-[^']+)'/;
|
|
643
|
-
WHOLE = /^\d+$/;
|
|
644
|
-
DURATION = /^(\d+(?:\.\d+)?)(ms|[smhd])?$/;
|
|
645
|
-
UNIT_MS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000 };
|
|
646
787
|
});
|
|
647
788
|
|
|
648
789
|
// ../kit/src/chart.ts
|
|
@@ -653,7 +794,7 @@ var init_chart = __esm(() => {
|
|
|
653
794
|
|
|
654
795
|
// ../kit/src/process.ts
|
|
655
796
|
import { constants } from "os";
|
|
656
|
-
import
|
|
797
|
+
import process7 from "process";
|
|
657
798
|
function exitCodeOf(code, signal) {
|
|
658
799
|
if (code !== null)
|
|
659
800
|
return code;
|
|
@@ -673,7 +814,7 @@ function holdSignals(cleanup) {
|
|
|
673
814
|
},
|
|
674
815
|
release: () => {
|
|
675
816
|
for (const signal of SIGNALS)
|
|
676
|
-
|
|
817
|
+
process7.off(signal, onSignal);
|
|
677
818
|
}
|
|
678
819
|
};
|
|
679
820
|
function onSignal(signal) {
|
|
@@ -686,10 +827,10 @@ function holdSignals(cleanup) {
|
|
|
686
827
|
return;
|
|
687
828
|
held.release();
|
|
688
829
|
cleanup(signal);
|
|
689
|
-
|
|
830
|
+
process7.kill(process7.pid, signal);
|
|
690
831
|
}
|
|
691
832
|
for (const signal of SIGNALS)
|
|
692
|
-
|
|
833
|
+
process7.on(signal, onSignal);
|
|
693
834
|
return held;
|
|
694
835
|
}
|
|
695
836
|
async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal, maxBytes = Infinity, onChunk, onStart } = {}) {
|
|
@@ -703,7 +844,7 @@ async function runCommand(argv, { cwd, env, stdin = "ignore", timeoutMs, signal,
|
|
|
703
844
|
return;
|
|
704
845
|
try {
|
|
705
846
|
if (grouped)
|
|
706
|
-
|
|
847
|
+
process7.kill(-proc.pid, killing);
|
|
707
848
|
else
|
|
708
849
|
proc.kill(killing);
|
|
709
850
|
} catch {}
|
|
@@ -776,8 +917,8 @@ var init_process = __esm(() => {
|
|
|
776
917
|
});
|
|
777
918
|
|
|
778
919
|
// ../kit/src/progress.ts
|
|
779
|
-
import
|
|
780
|
-
function liveRegion(render, stream =
|
|
920
|
+
import process8 from "process";
|
|
921
|
+
function liveRegion(render, stream = process8.stderr, env = process8.env) {
|
|
781
922
|
if (!takesControlCodes(stream, env))
|
|
782
923
|
return { redraw: () => {
|
|
783
924
|
return;
|
|
@@ -818,11 +959,11 @@ function liveRegion(render, stream = process5.stderr, env = process5.env) {
|
|
|
818
959
|
clear();
|
|
819
960
|
restore();
|
|
820
961
|
release();
|
|
821
|
-
|
|
962
|
+
process8.off("exit", onExit);
|
|
822
963
|
signals.release();
|
|
823
964
|
}
|
|
824
965
|
timer.unref();
|
|
825
|
-
|
|
966
|
+
process8.on("exit", onExit);
|
|
826
967
|
return {
|
|
827
968
|
redraw: draw,
|
|
828
969
|
print: (text) => {
|
|
@@ -861,14 +1002,14 @@ function cutToWidth(line, width) {
|
|
|
861
1002
|
return `${kept}${RESET_STYLE}${linked ? CLOSE_LINK : ""}`;
|
|
862
1003
|
}
|
|
863
1004
|
function swallowInput() {
|
|
864
|
-
const input =
|
|
1005
|
+
const input = process8.stdin;
|
|
865
1006
|
if (!input.isTTY)
|
|
866
1007
|
return () => {
|
|
867
1008
|
return;
|
|
868
1009
|
};
|
|
869
1010
|
const onData = (data) => {
|
|
870
1011
|
if (data.includes(CTRL_C))
|
|
871
|
-
|
|
1012
|
+
process8.kill(process8.pid, "SIGINT");
|
|
872
1013
|
};
|
|
873
1014
|
input.setRawMode(true);
|
|
874
1015
|
input.on("data", onData);
|
|
@@ -884,7 +1025,7 @@ function swallowInput() {
|
|
|
884
1025
|
};
|
|
885
1026
|
}
|
|
886
1027
|
function interceptOutput(clear) {
|
|
887
|
-
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [
|
|
1028
|
+
const targets = [...CONSOLE_METHODS.map((name) => [console, name]), [process8.stdout, "write"], [process8.stderr, "write"]];
|
|
888
1029
|
const wrapped = targets.map(([target, name]) => {
|
|
889
1030
|
const original = Reflect.get(target, name);
|
|
890
1031
|
const wrapper = (...args) => {
|
|
@@ -928,10 +1069,65 @@ var init_ci = __esm(() => {
|
|
|
928
1069
|
init_tool();
|
|
929
1070
|
});
|
|
930
1071
|
|
|
1072
|
+
// ../kit/src/logs.ts
|
|
1073
|
+
var DAY_MS, CLI_FOLDER = "kaynooo-cli";
|
|
1074
|
+
var init_logs = __esm(() => {
|
|
1075
|
+
DAY_MS = 24 * 60 * 60 * 1000;
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
// ../kit/src/usage.ts
|
|
1079
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
1080
|
+
import { homedir } from "os";
|
|
1081
|
+
import { dirname, isAbsolute, join } from "path";
|
|
1082
|
+
import process9 from "process";
|
|
1083
|
+
function noteUsageError(message) {
|
|
1084
|
+
usageError = message;
|
|
1085
|
+
}
|
|
1086
|
+
function stateHome(env = process9.env) {
|
|
1087
|
+
const dir = env.XDG_STATE_HOME;
|
|
1088
|
+
return dir !== undefined && isAbsolute(dir) ? dir : join(homedir(), ".local", "state");
|
|
1089
|
+
}
|
|
1090
|
+
function usagePath(env = process9.env) {
|
|
1091
|
+
return join(stateHome(env), CLI_FOLDER, "usage.jsonl");
|
|
1092
|
+
}
|
|
1093
|
+
function usageRecorded(env = process9.env) {
|
|
1094
|
+
const off = env.KAYNOOO_CLI_NO_USAGE;
|
|
1095
|
+
return env.NODE_ENV !== "test" && (off === undefined || off === "" || off === "0");
|
|
1096
|
+
}
|
|
1097
|
+
function flagNames(argv) {
|
|
1098
|
+
const end = argv.indexOf("--");
|
|
1099
|
+
const names = (end === -1 ? argv : argv.slice(0, end)).filter((word) => word.startsWith("-") && word !== "-").map((word) => word.includes("=") ? word.slice(0, word.indexOf("=")) : word);
|
|
1100
|
+
return [...new Set(names)].filter((name) => name.length <= LONGEST_NAME && FLAG_NAME.test(name));
|
|
1101
|
+
}
|
|
1102
|
+
function usageEntry(bin, command, argv, code, now = new Date) {
|
|
1103
|
+
const unknown = code === 2 && usageError !== undefined ? UNKNOWN_OPTION2.exec(usageError)?.[1] : undefined;
|
|
1104
|
+
usageError = undefined;
|
|
1105
|
+
return { at: now.toISOString(), bin, ...command === undefined ? {} : { command }, flags: flagNames(argv), code, ...unknown === undefined ? {} : { unknown } };
|
|
1106
|
+
}
|
|
1107
|
+
function recordUsage(entry, env = process9.env) {
|
|
1108
|
+
if (!usageRecorded(env))
|
|
1109
|
+
return;
|
|
1110
|
+
try {
|
|
1111
|
+
const path = usagePath(env);
|
|
1112
|
+
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
1113
|
+
appendFileSync(path, `${JSON.stringify(entry)}
|
|
1114
|
+
`, { mode: 384 });
|
|
1115
|
+
} catch {}
|
|
1116
|
+
}
|
|
1117
|
+
var UNKNOWN_OPTION2, FLAG_NAME, LONGEST_NAME = 40, usageError;
|
|
1118
|
+
var init_usage = __esm(() => {
|
|
1119
|
+
init_logs();
|
|
1120
|
+
UNKNOWN_OPTION2 = /unknown option '(--[a-z][a-z0-9-]*)[=']/;
|
|
1121
|
+
FLAG_NAME = /^(?:--[a-z][a-z0-9-]*|-[a-zA-Z])$/;
|
|
1122
|
+
});
|
|
1123
|
+
|
|
931
1124
|
// ../kit/src/cli.ts
|
|
932
|
-
import
|
|
933
|
-
|
|
934
|
-
|
|
1125
|
+
import { readFileSync, realpathSync } from "fs";
|
|
1126
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
1127
|
+
import process10 from "process";
|
|
1128
|
+
async function commandRows(all, colors) {
|
|
1129
|
+
const commands = shown(all);
|
|
1130
|
+
const width = Math.max(0, ...Object.keys(commands).map((name) => name.length));
|
|
935
1131
|
const groups = new Map([["Commands:", []]]);
|
|
936
1132
|
const summaries = await Promise.all(Object.values(commands).map(async ({ summary }) => resolveSummary(summary)));
|
|
937
1133
|
for (const [index, [name, { group }]] of Object.entries(commands).entries()) {
|
|
@@ -942,6 +1138,9 @@ async function commandRows(commands, colors) {
|
|
|
942
1138
|
}
|
|
943
1139
|
return [...groups].filter(([, rows]) => rows.length > 0).flatMap(([heading, rows], index) => [...index === 0 ? [] : [""], colors.bold(heading), ...rows]);
|
|
944
1140
|
}
|
|
1141
|
+
function shown(commands) {
|
|
1142
|
+
return Object.fromEntries(Object.entries(commands).filter(([, { hidden }]) => hidden !== true));
|
|
1143
|
+
}
|
|
945
1144
|
function takeOutputFlags(argv) {
|
|
946
1145
|
let index = 0;
|
|
947
1146
|
for (;index < argv.length; index++) {
|
|
@@ -973,7 +1172,7 @@ async function expand(scope, words) {
|
|
|
973
1172
|
}
|
|
974
1173
|
return { ...scope, commands, lazy: [] };
|
|
975
1174
|
}
|
|
976
|
-
async function
|
|
1175
|
+
async function help2({ path, header, summary: lazySummary, commands, defaultCommand, examples, replaces }, stream) {
|
|
977
1176
|
const colors = paint(stream);
|
|
978
1177
|
const prefix = path.join(" ");
|
|
979
1178
|
const summary = await resolveSummary(lazySummary);
|
|
@@ -1000,8 +1199,8 @@ async function help({ path, header, summary: lazySummary, commands, defaultComma
|
|
|
1000
1199
|
`);
|
|
1001
1200
|
}
|
|
1002
1201
|
function printError(prefix, message, hint, cause) {
|
|
1003
|
-
const colors = paint(
|
|
1004
|
-
const styled = takesControlCodes(
|
|
1202
|
+
const colors = paint(process10.stderr);
|
|
1203
|
+
const styled = takesControlCodes(process10.stderr);
|
|
1005
1204
|
const head = styled ? `${colors.red.bold("error")} ${colors.dim(`${prefix}:`)}` : `error: ${prefix}:`;
|
|
1006
1205
|
const under = (label, text, tint) => text === undefined ? "" : `
|
|
1007
1206
|
${styled ? tint(label) : `${label}:`} ${text}`;
|
|
@@ -1020,6 +1219,8 @@ function reportThrown(prefix, error, redact = (text) => text, json = false) {
|
|
|
1020
1219
|
const help = error instanceof UsageError ? `run ${prefix} --help for its options` : undefined;
|
|
1021
1220
|
const named = error instanceof Error && !(error instanceof Exit) && error.name !== "Error" ? `${error.name}: ${error.message}` : undefined;
|
|
1022
1221
|
const cause = error instanceof Error && error.cause instanceof Error ? redact(error.cause.message) : undefined;
|
|
1222
|
+
if (error instanceof UsageError)
|
|
1223
|
+
noteUsageError(error.message);
|
|
1023
1224
|
const report = json ? printJsonError : (message, hint, causeText) => printError(prefix, message, hint, causeText);
|
|
1024
1225
|
report(redact(named ?? (error instanceof Error ? error.message : String(error))), error instanceof Exit ? error.hint ?? help : undefined, cause);
|
|
1025
1226
|
return error instanceof Exit ? error.code : 1;
|
|
@@ -1033,12 +1234,20 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
1033
1234
|
return reportThrown(prefix, error);
|
|
1034
1235
|
}
|
|
1035
1236
|
const [name, ...args] = argv;
|
|
1237
|
+
const fallback = level.defaultCommand === undefined ? undefined : level.commands[level.defaultCommand];
|
|
1238
|
+
if (name === undefined && level.runBare && fallback !== undefined && "run" in fallback) {
|
|
1239
|
+
try {
|
|
1240
|
+
return await fallback.run([]);
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
return reportThrown(`${prefix} ${level.defaultCommand}`, error, redact, false);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1036
1245
|
if (name === undefined && level.path.length > 1) {
|
|
1037
|
-
console.error(await
|
|
1246
|
+
console.error(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stderr));
|
|
1038
1247
|
return 2;
|
|
1039
1248
|
}
|
|
1040
1249
|
if (name === undefined || name === "help" || name === "--help" || name === "-h") {
|
|
1041
|
-
console.log(await
|
|
1250
|
+
console.log(await help2(await expand(level, [...level.path.slice(1), ...argv]), process10.stdout));
|
|
1042
1251
|
return 0;
|
|
1043
1252
|
}
|
|
1044
1253
|
if (level.path.length === 1 && (name === "--version" || name === "-v")) {
|
|
@@ -1047,6 +1256,7 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
1047
1256
|
}
|
|
1048
1257
|
let command = level.commands[level.aliases?.[name] ?? name];
|
|
1049
1258
|
let rest = args;
|
|
1259
|
+
let ran = name;
|
|
1050
1260
|
if (command === undefined && level.lazy.length > 0) {
|
|
1051
1261
|
level = await expand(level, [...level.path.slice(1), ...argv]);
|
|
1052
1262
|
command = level.commands[level.aliases?.[name] ?? name];
|
|
@@ -1054,38 +1264,75 @@ async function dispatch(level, typed, { version, redact }) {
|
|
|
1054
1264
|
if (command === undefined && level.defaultCommand !== undefined) {
|
|
1055
1265
|
command = level.commands[level.defaultCommand];
|
|
1056
1266
|
rest = argv;
|
|
1267
|
+
ran = level.defaultCommand;
|
|
1057
1268
|
}
|
|
1058
1269
|
if (command === undefined) {
|
|
1059
|
-
const meant = closest(name, Object.keys(level.commands));
|
|
1270
|
+
const meant = closest(name, Object.keys(shown(level.commands)));
|
|
1060
1271
|
printError(prefix, `no command ${name}`, meant === undefined ? `run ${prefix} --help for its commands` : `did you mean ${meant}?`);
|
|
1061
1272
|
return 2;
|
|
1062
1273
|
}
|
|
1063
1274
|
if ("commands" in command) {
|
|
1064
1275
|
const { summary } = command;
|
|
1065
|
-
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 });
|
|
1276
|
+
return dispatch({ path: [...level.path, name], header: (colors, text) => `${colors.bold(`${prefix} ${name}`)} ${text}`, summary, ...scopeOf(command.commands, command.extraCommands, command.aliases), defaultCommand: undefined, runBare: false, examples: command.examples, replaces: undefined }, rest, { version, redact });
|
|
1066
1277
|
}
|
|
1067
1278
|
try {
|
|
1068
1279
|
return await command.run(rest);
|
|
1069
1280
|
} catch (error) {
|
|
1070
|
-
return reportThrown(`${prefix} ${
|
|
1281
|
+
return reportThrown(`${prefix} ${ran}`, error, redact, wantsJson(rest));
|
|
1071
1282
|
}
|
|
1072
1283
|
}
|
|
1073
|
-
async function
|
|
1284
|
+
async function completingOf(run) {
|
|
1074
1285
|
completion.active = true;
|
|
1075
1286
|
try {
|
|
1076
1287
|
await run([]);
|
|
1077
1288
|
} catch (error) {
|
|
1078
1289
|
if (error instanceof Completing)
|
|
1079
|
-
return error
|
|
1290
|
+
return error;
|
|
1080
1291
|
} finally {
|
|
1081
1292
|
completion.active = false;
|
|
1082
1293
|
}
|
|
1083
|
-
return {};
|
|
1294
|
+
return new Completing({});
|
|
1295
|
+
}
|
|
1296
|
+
async function optionsOf(run) {
|
|
1297
|
+
return (await completingOf(run)).options;
|
|
1298
|
+
}
|
|
1299
|
+
function candidateLine(candidate) {
|
|
1300
|
+
return typeof candidate === "string" ? candidate : candidate.join("\t");
|
|
1301
|
+
}
|
|
1302
|
+
function positionalBeingTyped(before, { options, positionals }) {
|
|
1303
|
+
const takesValue = (word) => !word.includes("=") && Object.entries(options).some(([name, { short, type }]) => type === "string" && (word === `--${name}` || word === `-${short}`));
|
|
1304
|
+
let index = 0;
|
|
1305
|
+
let at = 0;
|
|
1306
|
+
while (at < before.length) {
|
|
1307
|
+
const word = before[at];
|
|
1308
|
+
if (word === "--") {
|
|
1309
|
+
index += before.length - at - 1;
|
|
1310
|
+
break;
|
|
1311
|
+
}
|
|
1312
|
+
if (!word.startsWith("-"))
|
|
1313
|
+
index++;
|
|
1314
|
+
else if (takesValue(word))
|
|
1315
|
+
at++;
|
|
1316
|
+
at++;
|
|
1317
|
+
}
|
|
1318
|
+
const last = positionals.at(-1);
|
|
1319
|
+
if (index < positionals.length)
|
|
1320
|
+
return positionals[index];
|
|
1321
|
+
return last?.replace("]", "").endsWith("...") === true ? last : undefined;
|
|
1084
1322
|
}
|
|
1085
1323
|
async function leafCandidates(run, words) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1324
|
+
const completing = await completingOf(run);
|
|
1325
|
+
if ((words.at(-1) ?? "").startsWith("-"))
|
|
1326
|
+
return Object.entries(completing.options).map(([name, option]) => option.description === undefined ? `--${name}` : `--${name} ${option.description}`);
|
|
1327
|
+
const flag = words.at(-2);
|
|
1328
|
+
const option = flag?.startsWith("-") === true ? Object.entries(completing.options).find(([name, { short }]) => flag === `--${name}` || flag === `-${short}`)?.[1] : undefined;
|
|
1329
|
+
if (option?.type === "string") {
|
|
1330
|
+
const values = option.choices === undefined ? await option.candidates?.() : option.choices;
|
|
1331
|
+
return values === undefined ? [FILES] : values.map(candidateLine);
|
|
1332
|
+
}
|
|
1333
|
+
const name = positionalBeingTyped(words.slice(0, -1), completing);
|
|
1334
|
+
const values = name === undefined ? undefined : await completing.candidates[name]?.();
|
|
1335
|
+
return values === undefined ? [FILES] : values.map(candidateLine);
|
|
1089
1336
|
}
|
|
1090
1337
|
async function candidates(scope, defaultCommand, words, before = []) {
|
|
1091
1338
|
const [word = "", ...rest] = words;
|
|
@@ -1096,8 +1343,13 @@ async function candidates(scope, defaultCommand, words, before = []) {
|
|
|
1096
1343
|
({ commands, aliases } = await expand(scope, [...before, ...words]));
|
|
1097
1344
|
command = commands[aliases?.[word] ?? word];
|
|
1098
1345
|
}
|
|
1099
|
-
if (listing)
|
|
1100
|
-
|
|
1346
|
+
if (listing) {
|
|
1347
|
+
const own = await Promise.all(Object.entries(shown(commands)).map(async ([name, { summary }]) => `${name} ${await resolveSummary(summary)}`));
|
|
1348
|
+
const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
|
|
1349
|
+
const values = fallback !== undefined && "run" in fallback ? await leafCandidates(fallback.run, [word]) : [];
|
|
1350
|
+
const valueOf = (line) => line.slice(0, line.includes("\t") ? line.indexOf("\t") : undefined);
|
|
1351
|
+
return [...own, ...values.filter((line) => line !== FILES && !(valueOf(line) in commands))];
|
|
1352
|
+
}
|
|
1101
1353
|
if (command === undefined) {
|
|
1102
1354
|
const fallback = defaultCommand === undefined ? undefined : commands[defaultCommand];
|
|
1103
1355
|
return fallback !== undefined && "run" in fallback ? leafCandidates(fallback.run, words) : [];
|
|
@@ -1109,23 +1361,56 @@ async function printCandidates(found) {
|
|
|
1109
1361
|
console.log(line);
|
|
1110
1362
|
return 0;
|
|
1111
1363
|
}
|
|
1112
|
-
|
|
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();
|
|
1113
1377
|
if (argv[0] === COMPLETE)
|
|
1114
1378
|
return printCandidates(candidates(scopeOf(cli.commands, cli.extraCommands, cli.aliases), cli.defaultCommand, argv.slice(1)));
|
|
1115
|
-
|
|
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 });
|
|
1380
|
+
if (cli.usage !== false) {
|
|
1381
|
+
try {
|
|
1382
|
+
recordUsage(usageEntry(cli.name, commandPath(scopeOf(cli.commands, cli.extraCommands, cli.aliases), argv), argv, code));
|
|
1383
|
+
} catch {}
|
|
1384
|
+
}
|
|
1385
|
+
return code;
|
|
1386
|
+
}
|
|
1387
|
+
function commandPath(scope, argv) {
|
|
1388
|
+
const path = [];
|
|
1389
|
+
let level = scope;
|
|
1390
|
+
for (const word of argv.filter((each) => !each.startsWith("-"))) {
|
|
1391
|
+
const name = level.aliases !== undefined && Object.hasOwn(level.aliases, word) ? level.aliases[word] ?? word : word;
|
|
1392
|
+
const command = Object.hasOwn(level.commands, name) ? level.commands[name] : undefined;
|
|
1393
|
+
if (command === undefined)
|
|
1394
|
+
break;
|
|
1395
|
+
path.push(word);
|
|
1396
|
+
if (!("commands" in command))
|
|
1397
|
+
break;
|
|
1398
|
+
level = scopeOf(command.commands, command.extraCommands, command.aliases);
|
|
1399
|
+
}
|
|
1400
|
+
return path.length === 0 ? undefined : path.join(" ");
|
|
1116
1401
|
}
|
|
1117
1402
|
var LEVEL_OPTIONS, TOP_OPTIONS, COMPLETE = "__complete", FILES = "__files__";
|
|
1118
1403
|
var init_cli = __esm(() => {
|
|
1119
1404
|
init_args();
|
|
1120
1405
|
init_style();
|
|
1121
1406
|
init_text();
|
|
1407
|
+
init_usage();
|
|
1122
1408
|
LEVEL_OPTIONS = {
|
|
1123
1409
|
...OUTPUT_OPTIONS,
|
|
1124
1410
|
help: { type: "boolean", short: "h", description: "show this help" }
|
|
1125
1411
|
};
|
|
1126
1412
|
TOP_OPTIONS = { ...LEVEL_OPTIONS, version: { type: "boolean", short: "v", description: "print the version" } };
|
|
1127
1413
|
});
|
|
1128
|
-
|
|
1129
1414
|
// ../kit/src/config.ts
|
|
1130
1415
|
var init_config = __esm(() => {
|
|
1131
1416
|
init_args();
|
|
@@ -1140,7 +1425,7 @@ var init_git = __esm(() => {
|
|
|
1140
1425
|
// ../kit/src/limit.ts
|
|
1141
1426
|
function limitOptions(fallback) {
|
|
1142
1427
|
return {
|
|
1143
|
-
limit: { type: "string", description: `show at most this many rows, the rest counted (${fallback})` },
|
|
1428
|
+
limit: { type: "string", short: "n", description: `show at most this many rows, the rest counted (${fallback})` },
|
|
1144
1429
|
full: { type: "boolean", description: "show every row" }
|
|
1145
1430
|
};
|
|
1146
1431
|
}
|
|
@@ -1162,12 +1447,6 @@ var init_limit = __esm(() => {
|
|
|
1162
1447
|
init_args();
|
|
1163
1448
|
});
|
|
1164
1449
|
|
|
1165
|
-
// ../kit/src/logs.ts
|
|
1166
|
-
var DAY_MS;
|
|
1167
|
-
var init_logs = __esm(() => {
|
|
1168
|
-
DAY_MS = 24 * 60 * 60 * 1000;
|
|
1169
|
-
});
|
|
1170
|
-
|
|
1171
1450
|
// ../kit/src/secrets.ts
|
|
1172
1451
|
var SECRET_WORDS;
|
|
1173
1452
|
var init_secrets = __esm(() => {
|
|
@@ -1182,8 +1461,33 @@ var init_sessions = __esm(() => {
|
|
|
1182
1461
|
ACCOUNT_DIRS = new Glob("*/sessions");
|
|
1183
1462
|
});
|
|
1184
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
|
+
|
|
1185
1488
|
// ../kit/src/index.ts
|
|
1186
1489
|
var init_src = __esm(() => {
|
|
1490
|
+
init_advisory();
|
|
1187
1491
|
init_args();
|
|
1188
1492
|
init_chart();
|
|
1189
1493
|
init_ci();
|
|
@@ -1196,276 +1500,70 @@ var init_src = __esm(() => {
|
|
|
1196
1500
|
init_process();
|
|
1197
1501
|
init_secrets();
|
|
1198
1502
|
init_sessions();
|
|
1503
|
+
init_size();
|
|
1199
1504
|
init_style();
|
|
1200
1505
|
init_text();
|
|
1201
1506
|
init_tool();
|
|
1507
|
+
init_usage();
|
|
1508
|
+
init_user_config();
|
|
1202
1509
|
});
|
|
1203
1510
|
|
|
1204
|
-
// src/
|
|
1205
|
-
function
|
|
1206
|
-
|
|
1511
|
+
// src/semver.ts
|
|
1512
|
+
function isRange(text) {
|
|
1513
|
+
if (text.trim() === "")
|
|
1514
|
+
return true;
|
|
1515
|
+
return text.split(OR).every((alternative) => {
|
|
1516
|
+
const words = alternative.trim().split(WHITESPACE);
|
|
1517
|
+
return words.every((word, index) => word === "-" ? index > 0 && index < words.length - 1 : COMPARATOR.test(word));
|
|
1518
|
+
});
|
|
1207
1519
|
}
|
|
1208
|
-
function
|
|
1209
|
-
|
|
1520
|
+
function compare(version, word) {
|
|
1521
|
+
const bound = BOUND.exec(word);
|
|
1522
|
+
if (bound === null)
|
|
1523
|
+
return;
|
|
1524
|
+
const order = Bun.semver.order(version, bound[2] ?? "");
|
|
1525
|
+
const operator = bound[1] ?? "=";
|
|
1526
|
+
if (operator === "<")
|
|
1527
|
+
return order < 0;
|
|
1528
|
+
if (operator === "<=")
|
|
1529
|
+
return order <= 0;
|
|
1530
|
+
if (operator === ">")
|
|
1531
|
+
return order > 0;
|
|
1532
|
+
return operator === ">=" ? order >= 0 : order === 0;
|
|
1210
1533
|
}
|
|
1211
|
-
function
|
|
1212
|
-
|
|
1534
|
+
function inRange(version, range) {
|
|
1535
|
+
if (Bun.semver.satisfies(version, range))
|
|
1536
|
+
return true;
|
|
1537
|
+
if (!PRERELEASE.test(version))
|
|
1538
|
+
return false;
|
|
1539
|
+
return range.split(OR).some((alternative) => alternative.trim().split(WHITESPACE).every((word) => compare(version, word) ?? Bun.semver.satisfies(version, word)));
|
|
1213
1540
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
packument = await response.json();
|
|
1235
|
-
} catch {
|
|
1236
|
-
return unreachable(`${new URL(registry.url).host} answered ${name} with something that is not JSON`);
|
|
1237
|
-
}
|
|
1238
|
-
if (packument?.name !== name)
|
|
1239
|
-
unreachable(`${new URL(registry.url).host} answered ${name} with the metadata of ${String(packument?.name)}`);
|
|
1240
|
-
return packument;
|
|
1241
|
-
}
|
|
1242
|
-
async function fetchDownloads(name, fetcher = fetch) {
|
|
1243
|
-
const response = await get(fetcher, `${DOWNLOADS_API}/${encodeURIComponent(name)}`);
|
|
1244
|
-
if (!response.ok)
|
|
1245
|
-
return;
|
|
1246
|
-
try {
|
|
1247
|
-
return (await response.json()).downloads;
|
|
1248
|
-
} catch {
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
var PUBLIC_REGISTRY = "https://registry.npmjs.org", DOWNLOADS_API = "https://api.npmjs.org/downloads/point/last-week", TRAILING_SLASHES, REQUEST_TIMEOUT = 1e4, PACKAGE_NAME;
|
|
1253
|
-
var init_registry = __esm(() => {
|
|
1254
|
-
init_src();
|
|
1255
|
-
TRAILING_SLASHES = /\/+$/;
|
|
1256
|
-
PACKAGE_NAME = /^(?:@[\w~-][\w.~-]*\/)?[\w~-][\w.~-]*$/;
|
|
1257
|
-
});
|
|
1258
|
-
|
|
1259
|
-
// src/config.ts
|
|
1260
|
-
import { homedir } from "os";
|
|
1261
|
-
import { dirname, join } from "path";
|
|
1262
|
-
import process8 from "process";
|
|
1263
|
-
function expand2(value, env) {
|
|
1264
|
-
let missing = false;
|
|
1265
|
-
const expanded = value.replace(ENV_REFERENCE, (_, braced, bare) => {
|
|
1266
|
-
const found = env[braced ?? bare ?? ""];
|
|
1267
|
-
missing ||= found === undefined;
|
|
1268
|
-
return found ?? "";
|
|
1269
|
-
});
|
|
1270
|
-
return missing ? undefined : expanded;
|
|
1271
|
-
}
|
|
1272
|
-
function literal(value) {
|
|
1273
|
-
return expand2(value, {}) === value ? value : undefined;
|
|
1274
|
-
}
|
|
1275
|
-
function parseNpmrc(text, env) {
|
|
1276
|
-
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
1277
|
-
for (const line of text.split(`
|
|
1278
|
-
`)) {
|
|
1279
|
-
const at = line.indexOf("=");
|
|
1280
|
-
if (at === -1 || COMMENT.test(line))
|
|
1281
|
-
continue;
|
|
1282
|
-
const key = line.slice(0, at).trim();
|
|
1283
|
-
const scope = SCOPE_REGISTRY.exec(key)?.[1];
|
|
1284
|
-
const tokenFor = AUTH_TOKEN.exec(key)?.[1];
|
|
1285
|
-
const raw = line.slice(at + 1).trim().replace(QUOTES, "$2");
|
|
1286
|
-
const value = tokenFor === undefined ? literal(raw) : expand2(raw, env);
|
|
1287
|
-
if (value === undefined || value === "")
|
|
1288
|
-
continue;
|
|
1289
|
-
if (scope !== undefined)
|
|
1290
|
-
config.scopes[scope] = value;
|
|
1291
|
-
else if (tokenFor !== undefined)
|
|
1292
|
-
config.tokens[tokenFor] = value;
|
|
1293
|
-
else if (key === "registry")
|
|
1294
|
-
config.registry = value;
|
|
1295
|
-
}
|
|
1296
|
-
return config;
|
|
1297
|
-
}
|
|
1298
|
-
function bunEntry(entry, env) {
|
|
1299
|
-
const url = typeof entry === "string" ? entry : entry.url;
|
|
1300
|
-
const token = typeof entry === "string" || entry.token === undefined ? undefined : expand2(entry.token, env);
|
|
1301
|
-
return { ...url === undefined || literal(url) === undefined ? {} : { url }, ...token === undefined ? {} : { token } };
|
|
1302
|
-
}
|
|
1303
|
-
function parseBunfig(text, env) {
|
|
1304
|
-
const config = { scopes: {}, tokens: {}, scopeTokens: {} };
|
|
1305
|
-
const install = Bun.TOML.parse(text).install;
|
|
1306
|
-
if (install?.registry !== undefined) {
|
|
1307
|
-
const { url, token } = bunEntry(install.registry, env);
|
|
1308
|
-
if (url !== undefined)
|
|
1309
|
-
config.registry = url;
|
|
1310
|
-
if (url !== undefined && token !== undefined)
|
|
1311
|
-
config.tokens[url.replace(PROTOCOL, "")] = token;
|
|
1312
|
-
}
|
|
1313
|
-
for (const [scope, entry] of Object.entries(install?.scopes ?? {})) {
|
|
1314
|
-
const { url, token } = bunEntry(entry, env);
|
|
1315
|
-
if (url !== undefined)
|
|
1316
|
-
config.scopes[scope.startsWith("@") ? scope : `@${scope}`] = url;
|
|
1317
|
-
if (token !== undefined)
|
|
1318
|
-
config.scopeTokens[scope.startsWith("@") ? scope : `@${scope}`] = token;
|
|
1319
|
-
}
|
|
1320
|
-
return config;
|
|
1321
|
-
}
|
|
1322
|
-
function tokenFor(config, url) {
|
|
1323
|
-
const address = `${url.replace(PROTOCOL, "").replace(TRAILING_SLASHES2, "")}/`;
|
|
1324
|
-
const best = Object.keys(config.tokens).filter((key) => address.startsWith(`${key.replace(TRAILING_SLASHES2, "")}/`)).sort((a, b) => b.length - a.length)[0];
|
|
1325
|
-
return best === undefined ? undefined : config.tokens[best];
|
|
1326
|
-
}
|
|
1327
|
-
function mayCarryToken(url) {
|
|
1328
|
-
const { protocol, hostname } = new URL(url);
|
|
1329
|
-
return protocol === "https:" || LOCAL_HOSTS.has(hostname);
|
|
1330
|
-
}
|
|
1331
|
-
function registryFor(name, configs) {
|
|
1332
|
-
const scope = name.startsWith("@") ? name.slice(0, name.indexOf("/")) : undefined;
|
|
1333
|
-
const scoped = scope === undefined ? undefined : configs.find((config) => config.scopes[scope] !== undefined);
|
|
1334
|
-
const url = (scope === undefined ? undefined : scoped?.scopes[scope]) ?? configs.find((config) => config.registry !== undefined)?.registry;
|
|
1335
|
-
if (url === undefined)
|
|
1336
|
-
return { url: PUBLIC_REGISTRY };
|
|
1337
|
-
const token = (scope === undefined ? undefined : scoped?.scopeTokens[scope]) ?? configs.map((other) => tokenFor(other, url)).find((found) => found !== undefined);
|
|
1338
|
-
return { url, token: mayCarryToken(url) ? token : undefined };
|
|
1339
|
-
}
|
|
1340
|
-
function readable(path, parse) {
|
|
1341
|
-
try {
|
|
1342
|
-
return parse();
|
|
1343
|
-
} catch (error) {
|
|
1344
|
-
return unreachable(`${path} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
async function readIfThere(path) {
|
|
1348
|
-
const file = Bun.file(path);
|
|
1349
|
-
return await file.exists() ? file.text() : undefined;
|
|
1350
|
-
}
|
|
1351
|
-
async function loadConfigs(cwd = process8.cwd(), env = process8.env, home = homedir()) {
|
|
1352
|
-
const directories = [];
|
|
1353
|
-
for (let dir = cwd;!directories.includes(dir); dir = dirname(dir))
|
|
1354
|
-
directories.push(dir);
|
|
1355
|
-
if (!directories.includes(home))
|
|
1356
|
-
directories.push(home);
|
|
1357
|
-
const configs = [];
|
|
1358
|
-
for (const dir of directories) {
|
|
1359
|
-
const bunfig = await readIfThere(join(dir, "bunfig.toml"));
|
|
1360
|
-
const npmrc = await readIfThere(join(dir, ".npmrc"));
|
|
1361
|
-
if (bunfig !== undefined)
|
|
1362
|
-
configs.push(readable(join(dir, "bunfig.toml"), () => parseBunfig(bunfig, env)));
|
|
1363
|
-
if (npmrc !== undefined)
|
|
1364
|
-
configs.push(parseNpmrc(npmrc, env));
|
|
1365
|
-
}
|
|
1366
|
-
return configs;
|
|
1367
|
-
}
|
|
1368
|
-
function isSeverity(value) {
|
|
1369
|
-
return SEVERITIES.includes(value);
|
|
1370
|
-
}
|
|
1371
|
-
function parseSettings(text) {
|
|
1372
|
-
const raw = Bun.JSONC.parse(text);
|
|
1373
|
-
const settings = {};
|
|
1374
|
-
if (Array.isArray(raw?.licenses) && raw.licenses.every((each) => typeof each === "string"))
|
|
1375
|
-
settings.licenses = raw.licenses;
|
|
1376
|
-
if (isSeverity(raw?.blockSeverity))
|
|
1377
|
-
settings.blockSeverity = raw.blockSeverity;
|
|
1378
|
-
return settings;
|
|
1379
|
-
}
|
|
1380
|
-
async function loadSettings(cwd = process8.cwd(), home = homedir()) {
|
|
1381
|
-
const files = [];
|
|
1382
|
-
for (let dir = cwd;!files.includes(join(dir, SETTINGS_FILE)); dir = dirname(dir))
|
|
1383
|
-
files.push(join(dir, SETTINGS_FILE));
|
|
1384
|
-
files.push(join(home, ".config", "pkg", "config.json"));
|
|
1385
|
-
const settings = {};
|
|
1386
|
-
for (const file of files) {
|
|
1387
|
-
const text = await readIfThere(file);
|
|
1388
|
-
if (text === undefined)
|
|
1389
|
-
continue;
|
|
1390
|
-
const found = readable(file, () => parseSettings(text));
|
|
1391
|
-
settings.licenses ??= found.licenses;
|
|
1392
|
-
settings.blockSeverity ??= found.blockSeverity;
|
|
1393
|
-
}
|
|
1394
|
-
return settings;
|
|
1395
|
-
}
|
|
1396
|
-
var ENV_REFERENCE, COMMENT, SCOPE_REGISTRY, AUTH_TOKEN, PROTOCOL, TRAILING_SLASHES2, LOCAL_HOSTS, QUOTES, SEVERITIES, DEFAULT_BLOCK_SEVERITY = "high", SETTINGS_FILE = ".pkgrc.json";
|
|
1397
|
-
var init_config2 = __esm(() => {
|
|
1398
|
-
init_registry();
|
|
1399
|
-
ENV_REFERENCE = /\$\{(\w+)\}|\$(\w+)/g;
|
|
1400
|
-
COMMENT = /^\s*[#;]/;
|
|
1401
|
-
SCOPE_REGISTRY = /^(@[^:]+):registry$/;
|
|
1402
|
-
AUTH_TOKEN = /^(\/\/.+?):_authToken$/;
|
|
1403
|
-
PROTOCOL = /^\w+:/;
|
|
1404
|
-
TRAILING_SLASHES2 = /\/+$/;
|
|
1405
|
-
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
1406
|
-
QUOTES = /^(["'])(.*)\1$/;
|
|
1407
|
-
SEVERITIES = ["low", "moderate", "high", "critical"];
|
|
1408
|
-
});
|
|
1409
|
-
|
|
1410
|
-
// src/semver.ts
|
|
1411
|
-
function isRange(text) {
|
|
1412
|
-
if (text.trim() === "")
|
|
1413
|
-
return true;
|
|
1414
|
-
return text.split(OR).every((alternative) => {
|
|
1415
|
-
const words = alternative.trim().split(WHITESPACE);
|
|
1416
|
-
return words.every((word, index) => word === "-" ? index > 0 && index < words.length - 1 : COMPARATOR.test(word));
|
|
1417
|
-
});
|
|
1418
|
-
}
|
|
1419
|
-
function compare(version, word) {
|
|
1420
|
-
const bound = BOUND.exec(word);
|
|
1421
|
-
if (bound === null)
|
|
1422
|
-
return;
|
|
1423
|
-
const order = Bun.semver.order(version, bound[2] ?? "");
|
|
1424
|
-
const operator = bound[1] ?? "=";
|
|
1425
|
-
if (operator === "<")
|
|
1426
|
-
return order < 0;
|
|
1427
|
-
if (operator === "<=")
|
|
1428
|
-
return order <= 0;
|
|
1429
|
-
if (operator === ">")
|
|
1430
|
-
return order > 0;
|
|
1431
|
-
return operator === ">=" ? order >= 0 : order === 0;
|
|
1432
|
-
}
|
|
1433
|
-
function inRange(version, range) {
|
|
1434
|
-
if (Bun.semver.satisfies(version, range))
|
|
1435
|
-
return true;
|
|
1436
|
-
if (!PRERELEASE.test(version))
|
|
1437
|
-
return false;
|
|
1438
|
-
return range.split(OR).some((alternative) => alternative.trim().split(WHITESPACE).every((word) => compare(version, word) ?? Bun.semver.satisfies(version, word)));
|
|
1439
|
-
}
|
|
1440
|
-
var OR, WHITESPACE, PRERELEASE, PART, COMPARATOR, BOUND, EXACT_VERSION;
|
|
1441
|
-
var init_semver = __esm(() => {
|
|
1442
|
-
OR = /\s*\|\|\s*/;
|
|
1443
|
-
WHITESPACE = /\s+/;
|
|
1444
|
-
PRERELEASE = /-/;
|
|
1445
|
-
PART = String.raw`(?:\d+|[xX*])`;
|
|
1446
|
-
COMPARATOR = new RegExp(String.raw`^(?:[<>]=?|=|\^|~>?)?v?${PART}(?:\.${PART}){0,2}(?:-[\w.-]+)?(?:\+[\w.-]+)?$`);
|
|
1447
|
-
BOUND = /^(<=|>=|[<>=])?v?(\d+\.\d+\.\d+(?:-[\w.-]+)?)$/;
|
|
1448
|
-
EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
|
|
1449
|
-
});
|
|
1450
|
-
|
|
1451
|
-
// src/advisories.ts
|
|
1452
|
-
function severityRank(severity) {
|
|
1453
|
-
return SEVERITIES.indexOf(severity);
|
|
1454
|
-
}
|
|
1455
|
-
function fixedVersion(vulnerable, version) {
|
|
1456
|
-
const range = vulnerable.split("||").map((each) => each.trim()).find((each) => inRange(version, each));
|
|
1457
|
-
return range === undefined ? undefined : UPPER_BOUND.exec(range)?.[1];
|
|
1458
|
-
}
|
|
1459
|
-
async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
1460
|
-
const url = `${registry.url.replace(TRAILING_SLASHES3, "")}${BULK_PATH}`;
|
|
1461
|
-
const host = new URL(registry.url).host;
|
|
1462
|
-
let response;
|
|
1541
|
+
var OR, WHITESPACE, PRERELEASE, PART, COMPARATOR, BOUND, EXACT_VERSION;
|
|
1542
|
+
var init_semver = __esm(() => {
|
|
1543
|
+
OR = /\s*\|\|\s*/;
|
|
1544
|
+
WHITESPACE = /\s+/;
|
|
1545
|
+
PRERELEASE = /-/;
|
|
1546
|
+
PART = String.raw`(?:\d+|[xX*])`;
|
|
1547
|
+
COMPARATOR = new RegExp(String.raw`^(?:[<>]=?|=|\^|~>?)?v?${PART}(?:\.${PART}){0,2}(?:-[\w.-]+)?(?:\+[\w.-]+)?$`);
|
|
1548
|
+
BOUND = /^(<=|>=|[<>=])?v?(\d+\.\d+\.\d+(?:-[\w.-]+)?)$/;
|
|
1549
|
+
EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
// src/advisories.ts
|
|
1553
|
+
function fixedVersion(vulnerable, version) {
|
|
1554
|
+
const range = vulnerable.split("||").map((each) => each.trim()).find((each) => inRange(version, each));
|
|
1555
|
+
return range === undefined ? undefined : UPPER_BOUND.exec(range)?.[1];
|
|
1556
|
+
}
|
|
1557
|
+
async function fetchAdvisories(versions, registry, fetcher = fetch) {
|
|
1558
|
+
const url = `${registry.url.replace(TRAILING_SLASHES, "")}${BULK_PATH}`;
|
|
1559
|
+
const host = new URL(registry.url).host;
|
|
1560
|
+
let response;
|
|
1463
1561
|
try {
|
|
1464
1562
|
response = await fetcher(url, {
|
|
1465
1563
|
method: "POST",
|
|
1466
1564
|
headers: { accept: "application/json", "content-type": "application/json", ...registry.token === undefined ? {} : { authorization: `Bearer ${registry.token}` } },
|
|
1467
1565
|
body: JSON.stringify(versions),
|
|
1468
|
-
signal: AbortSignal.timeout(
|
|
1566
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT)
|
|
1469
1567
|
});
|
|
1470
1568
|
} catch (error) {
|
|
1471
1569
|
return { found: {}, unavailable: `cannot reach ${host} for advisories: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -1499,13 +1597,13 @@ function advisoriesFor(advisories, version) {
|
|
|
1499
1597
|
return (advisories ?? []).filter((each) => inRange(version, each.vulnerable)).map((each) => ({ ...each, fixed: fixedVersion(each.vulnerable, version) }));
|
|
1500
1598
|
}
|
|
1501
1599
|
function filterAdvisories(advisories, level, ignore = []) {
|
|
1502
|
-
return advisories.filter((each) => severityRank(each.severity) >= severityRank(level) && !
|
|
1600
|
+
return advisories.filter((each) => severityRank(each.severity) >= severityRank(level) && !isIgnored(each, ignore));
|
|
1503
1601
|
}
|
|
1504
|
-
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;
|
|
1505
1603
|
var init_advisories = __esm(() => {
|
|
1506
|
-
|
|
1604
|
+
init_src();
|
|
1507
1605
|
init_semver();
|
|
1508
|
-
|
|
1606
|
+
TRAILING_SLASHES = /\/+$/;
|
|
1509
1607
|
GHSA = /GHSA-[\w-]+$/;
|
|
1510
1608
|
UPPER_BOUND = /(?:^|\s)<([\w.+-]+)/;
|
|
1511
1609
|
NO_ENDPOINT = new Set([404, 405, 501]);
|
|
@@ -2071,24 +2169,79 @@ var init_nearmiss = __esm(() => {
|
|
|
2071
2169
|
SEPARATORS = /[-_.]/g;
|
|
2072
2170
|
});
|
|
2073
2171
|
|
|
2074
|
-
// src/
|
|
2075
|
-
function
|
|
2076
|
-
|
|
2077
|
-
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;
|
|
2078
2175
|
}
|
|
2079
|
-
function
|
|
2080
|
-
return
|
|
2176
|
+
function unreachable(message) {
|
|
2177
|
+
return fail(`could not check: ${message}`, 2);
|
|
2081
2178
|
}
|
|
2082
|
-
function
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
return
|
|
2088
|
-
|
|
2089
|
-
return
|
|
2090
|
-
|
|
2091
|
-
|
|
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 ?? {});
|
|
2238
|
+
const wanted = request === undefined || request === "" ? "latest" : request;
|
|
2239
|
+
if (tags[wanted] !== undefined)
|
|
2240
|
+
return tags[wanted];
|
|
2241
|
+
if (versions.includes(wanted))
|
|
2242
|
+
return wanted;
|
|
2243
|
+
if (!isRange(wanted))
|
|
2244
|
+
return;
|
|
2092
2245
|
return versions.filter((version) => Bun.semver.satisfies(version, wanted)).sort(Bun.semver.order).at(-1);
|
|
2093
2246
|
}
|
|
2094
2247
|
function licenseOf(license) {
|
|
@@ -2190,6 +2343,310 @@ var init_analyze = __esm(() => {
|
|
|
2190
2343
|
VERSION_SEPARATOR = /(?<=.)@/;
|
|
2191
2344
|
});
|
|
2192
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
|
+
|
|
2193
2650
|
// src/commands/check.ts
|
|
2194
2651
|
var exports_check = {};
|
|
2195
2652
|
__export(exports_check, {
|
|
@@ -2239,13 +2696,20 @@ function render(report, now = Date.now()) {
|
|
|
2239
2696
|
].join(`
|
|
2240
2697
|
`);
|
|
2241
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
|
+
}
|
|
2242
2705
|
async function check(args) {
|
|
2243
|
-
const parsed = parse(args,
|
|
2244
|
-
const { values
|
|
2706
|
+
const parsed = parse(args, usage2, options, { exits: EXITS });
|
|
2707
|
+
const { values } = parsed;
|
|
2708
|
+
const positionals = await wanted(parsed.positionals, values.from);
|
|
2245
2709
|
if (positionals.length === 0)
|
|
2246
|
-
fail(`a package name is needed
|
|
2710
|
+
fail(values.from === undefined ? `a package name is needed
|
|
2247
2711
|
|
|
2248
|
-
${
|
|
2712
|
+
${usage2}` : `${values.from} has no registry dependency to check`);
|
|
2249
2713
|
const context = { configs: await loadConfigs(), settings: await loadSettings(), minAgeDays: wholeNumber(values["min-age"], "min-age", DEFAULT_MIN_AGE_DAYS, 0) };
|
|
2250
2714
|
const reports = await Promise.all(positionals.map(async (text) => checkPackage(text, context)));
|
|
2251
2715
|
if (values.json === true)
|
|
@@ -2256,23 +2720,27 @@ ${usage}`);
|
|
|
2256
2720
|
`));
|
|
2257
2721
|
return reports.some((report) => report.blocked) ? 1 : 0;
|
|
2258
2722
|
}
|
|
2259
|
-
var
|
|
2723
|
+
var usage2 = `pkg [check] <name>[@version]... | --from <package.json> | -
|
|
2260
2724
|
|
|
2261
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.
|
|
2262
2726
|
|
|
2263
|
-
|
|
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.
|
|
2264
2728
|
|
|
2265
|
-
|
|
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;
|
|
2266
2730
|
var init_check = __esm(() => {
|
|
2267
2731
|
init_src();
|
|
2268
2732
|
init_advisories();
|
|
2269
2733
|
init_analyze();
|
|
2270
2734
|
init_config2();
|
|
2735
|
+
init_consumers();
|
|
2271
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"]];
|
|
2272
2738
|
options = {
|
|
2273
2739
|
json: jsonOption(),
|
|
2274
|
-
"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" }
|
|
2275
2742
|
};
|
|
2743
|
+
WORDS = /\s+/;
|
|
2276
2744
|
});
|
|
2277
2745
|
|
|
2278
2746
|
// src/lockfile.ts
|
|
@@ -2298,6 +2766,42 @@ function parseBunLock(text) {
|
|
|
2298
2766
|
}
|
|
2299
2767
|
return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name) || Bun.semver.order(a.version, b.version));
|
|
2300
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
|
+
}
|
|
2301
2805
|
var NOT_REGISTRY, VERSION_SEPARATOR2, NPM_ALIAS = "npm:";
|
|
2302
2806
|
var init_lockfile = __esm(() => {
|
|
2303
2807
|
NOT_REGISTRY = /^(?:workspace|link|file|github|git|http|https):|^[\w.-]+\/[\w.-]+$/;
|
|
@@ -2309,8 +2813,8 @@ var exports_audit = {};
|
|
|
2309
2813
|
__export(exports_audit, {
|
|
2310
2814
|
audit: () => audit
|
|
2311
2815
|
});
|
|
2312
|
-
import { join as
|
|
2313
|
-
import
|
|
2816
|
+
import { join as join6, resolve as resolve2 } from "path";
|
|
2817
|
+
import process14 from "process";
|
|
2314
2818
|
function hasFinding(audited) {
|
|
2315
2819
|
return audited.blocked || audited.warnings.length > 0 || audited.advisories.length > 0;
|
|
2316
2820
|
}
|
|
@@ -2365,15 +2869,17 @@ function renderAudit(findings, total) {
|
|
|
2365
2869
|
`);
|
|
2366
2870
|
}
|
|
2367
2871
|
async function audit(args) {
|
|
2368
|
-
const { values, positionals: [asked] } = parse(args,
|
|
2369
|
-
const level = values
|
|
2872
|
+
const { values, positionals: [asked] } = parse(args, usage3, options2, { positionals: ["[dir]"], exits: EXITS2 });
|
|
2873
|
+
const level = values.level ?? "moderate";
|
|
2370
2874
|
if (!isSeverity(level))
|
|
2371
|
-
fail(`--
|
|
2372
|
-
const dir = resolve2(asked ??
|
|
2373
|
-
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"));
|
|
2374
2878
|
if (!await lock.exists())
|
|
2375
2879
|
fail(`no bun.lock in ${dir}`);
|
|
2376
|
-
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);
|
|
2377
2883
|
const context = {
|
|
2378
2884
|
configs: await loadConfigs(dir),
|
|
2379
2885
|
settings: await loadSettings(dir),
|
|
@@ -2393,12 +2899,11 @@ async function audit(args) {
|
|
|
2393
2899
|
return 1;
|
|
2394
2900
|
return unavailable.length > 0 ? 2 : 0;
|
|
2395
2901
|
}
|
|
2396
|
-
var
|
|
2902
|
+
var usage3 = `pkg audit [dir]
|
|
2397
2903
|
|
|
2398
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.
|
|
2399
2905
|
Findings are grouped per package, each registry package looked up once per run.
|
|
2400
|
-
|
|
2401
|
-
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;
|
|
2402
2907
|
var init_audit = __esm(() => {
|
|
2403
2908
|
init_src();
|
|
2404
2909
|
init_advisories();
|
|
@@ -2406,146 +2911,95 @@ var init_audit = __esm(() => {
|
|
|
2406
2911
|
init_config2();
|
|
2407
2912
|
init_lockfile();
|
|
2408
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"]];
|
|
2409
2915
|
options2 = {
|
|
2410
2916
|
json: jsonOption("[{name, version, license, blocked, warnings, advisories}] for the packages with a finding"),
|
|
2411
2917
|
"min-age": { type: "string", description: `days a version must be old (${DEFAULT_MIN_AGE_DAYS})` },
|
|
2412
|
-
|
|
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" },
|
|
2413
2920
|
ignore: { type: "string", multiple: true, description: "an advisory skipped by GHSA or numeric id, repeatable" }
|
|
2414
2921
|
};
|
|
2415
2922
|
});
|
|
2416
2923
|
|
|
2417
|
-
//
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
var SEPARATORS2, PLAIN_BREAKERS, GLOB_CHARS, COMMENT_PREFIXES, DOUBLE_QUOTED_ESCAPES, KEYWORDS, SHELLS, COMMAND_STRING_PROGRAMS, SHELL_VALUE_OPTIONS, PRINTERS, FIND_EXEC, WRAPPERS;
|
|
2422
|
-
var init_shell = __esm(() => {
|
|
2423
|
-
SEPARATORS2 = new Set([`
|
|
2424
|
-
`, ";", "|"]);
|
|
2425
|
-
PLAIN_BREAKERS = new Set(["<", ">", "(", ")", "&", "|"]);
|
|
2426
|
-
GLOB_CHARS = new Set(["*", "?", "["]);
|
|
2427
|
-
COMMENT_PREFIXES = new Set([";", "&", "|", "(", ")"]);
|
|
2428
|
-
DOUBLE_QUOTED_ESCAPES = new Set(["$", "`", '"', "\\"]);
|
|
2429
|
-
KEYWORDS = new Set(["then", "do", "else", "if", "elif", "while", "until", "!", "{", "}"]);
|
|
2430
|
-
SHELLS = new Set(["sh", "bash", "zsh", "dash", "ash", "ksh"]);
|
|
2431
|
-
COMMAND_STRING_PROGRAMS = new Set([...SHELLS, "su", "runuser"]);
|
|
2432
|
-
SHELL_VALUE_OPTIONS = new Set(["-o", "-O", "--rcfile", "--init-file"]);
|
|
2433
|
-
PRINTERS = new Set(["echo", "printf"]);
|
|
2434
|
-
FIND_EXEC = new Set(["-exec", "-execdir", "-ok", "-okdir"]);
|
|
2435
|
-
WRAPPERS = new Map([
|
|
2436
|
-
["command", wrapper()],
|
|
2437
|
-
["builtin", wrapper()],
|
|
2438
|
-
["nohup", wrapper()],
|
|
2439
|
-
["setsid", wrapper()],
|
|
2440
|
-
["busybox", wrapper()],
|
|
2441
|
-
["exec", wrapper("a")],
|
|
2442
|
-
["time", wrapper("fo", ["--format", "--output"])],
|
|
2443
|
-
["env", wrapper("uCS", ["--unset", "--chdir", "--split-string", "--argv0"])],
|
|
2444
|
-
["sudo", wrapper("ughpCTrtUDR", ["--user", "--group", "--host", "--prompt", "--close-from", "--command-timeout", "--role", "--type", "--other-user", "--chdir", "--chroot"])],
|
|
2445
|
-
["doas", wrapper("uC")],
|
|
2446
|
-
["timeout", wrapper("sk", ["--signal", "--kill-after"], 1)],
|
|
2447
|
-
["nice", wrapper("n", ["--adjustment"])],
|
|
2448
|
-
["ionice", wrapper("cnpPu", ["--class", "--classdata", "--pid", "--pgid", "--uid"])],
|
|
2449
|
-
["stdbuf", wrapper("ioe", ["--input", "--output", "--error"])],
|
|
2450
|
-
["chroot", wrapper("", ["--userspec", "--groups"], 1)],
|
|
2451
|
-
["xargs", wrapper("IndsEaPL", ["--max-args", "--max-procs", "--max-chars", "--delimiter", "--arg-file", "--eof", "--max-lines", "--process-slot-var"])]
|
|
2452
|
-
]);
|
|
2924
|
+
// src/commands/outdated.ts
|
|
2925
|
+
var exports_outdated = {};
|
|
2926
|
+
__export(exports_outdated, {
|
|
2927
|
+
outdatedCommand: () => outdatedCommand
|
|
2453
2928
|
});
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
function
|
|
2457
|
-
|
|
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;
|
|
2458
2983
|
}
|
|
2459
|
-
var
|
|
2460
|
-
var init_pin = __esm(() => {
|
|
2461
|
-
init_shell();
|
|
2462
|
-
LOCKFILES = [
|
|
2463
|
-
["bun.lock", "bun"],
|
|
2464
|
-
["bun.lockb", "bun"],
|
|
2465
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
2466
|
-
["yarn.lock", "yarn"],
|
|
2467
|
-
["package-lock.json", "npm"]
|
|
2468
|
-
];
|
|
2469
|
-
ACTIONS = {
|
|
2470
|
-
bun: actions({ install: ["install", "i"], add: ["add", "a"], remove: ["remove", "rm"], update: ["update"] }),
|
|
2471
|
-
pnpm: actions({ install: ["install", "i"], add: ["add"], remove: ["remove", "rm"], update: ["update", "up"] }),
|
|
2472
|
-
yarn: new Map([...actions({ install: ["", "install"], add: ["add"], remove: ["remove"], update: ["upgrade"] }), ["upgrade-interactive", null], ["import", null]]),
|
|
2473
|
-
npm: actions({
|
|
2474
|
-
install: ["install", "i", "in", "ins", "inst", "insta", "instal", "isnt", "isnta", "isntal", "isntall"],
|
|
2475
|
-
add: ["add"],
|
|
2476
|
-
frozen: ["ci", "clean-install", "ic", "install-clean", "isntall-clean"],
|
|
2477
|
-
remove: ["uninstall", "unlink", "remove", "rm", "r", "un"],
|
|
2478
|
-
update: ["update", "u", "up", "upgrade", "udpate"]
|
|
2479
|
-
})
|
|
2480
|
-
};
|
|
2481
|
-
OPTION_FLAGS = new Map([
|
|
2482
|
-
["-D", "dev"],
|
|
2483
|
-
["--save-dev", "dev"],
|
|
2484
|
-
["--dev", "dev"],
|
|
2485
|
-
["-E", "exact"],
|
|
2486
|
-
["--save-exact", "exact"],
|
|
2487
|
-
["--exact", "exact"]
|
|
2488
|
-
]);
|
|
2489
|
-
DIR_FLAGS = new Set(["--cwd", "-C", "--dir", "--prefix"]);
|
|
2490
|
-
VALUE_FLAGS = new Set([...DIR_FLAGS, "--filter", "-F"]);
|
|
2491
|
-
});
|
|
2984
|
+
var usage4 = `pkg outdated [dir]
|
|
2492
2985
|
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
}
|
|
2511
|
-
function managerFor(dir, root) {
|
|
2512
|
-
for (let at = dir;; at = dirname2(at)) {
|
|
2513
|
-
const lockfile = LOCKFILES.find(([file]) => existsSync(join3(at, file)));
|
|
2514
|
-
if (lockfile !== undefined)
|
|
2515
|
-
return lockfile[1];
|
|
2516
|
-
if (at === root || at === dirname2(at))
|
|
2517
|
-
return "bun";
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
function findConsumers(name, root) {
|
|
2521
|
-
const consumers = [];
|
|
2522
|
-
for (const path of packageFiles(root, 0, []).sort()) {
|
|
2523
|
-
let manifest;
|
|
2524
|
-
try {
|
|
2525
|
-
manifest = JSON.parse(readFileSync(path, "utf8"));
|
|
2526
|
-
} catch {
|
|
2527
|
-
continue;
|
|
2528
|
-
}
|
|
2529
|
-
const kind = KINDS.find((each) => typeof manifest[each]?.[name] === "string");
|
|
2530
|
-
const spec = kind === undefined ? undefined : manifest[kind]?.[name];
|
|
2531
|
-
if (kind !== undefined && spec !== undefined)
|
|
2532
|
-
consumers.push({ dir: relative(root, dirname2(path)) || ".", path, kind, spec, manager: managerFor(dirname2(path), root) });
|
|
2533
|
-
}
|
|
2534
|
-
return consumers;
|
|
2535
|
-
}
|
|
2536
|
-
function isLocal(consumer) {
|
|
2537
|
-
return LOCAL_SPEC.test(consumer.spec);
|
|
2538
|
-
}
|
|
2539
|
-
function addCommand(consumer, name, version) {
|
|
2540
|
-
return ["bun", "add", ...KIND_FLAGS[consumer.kind], "--exact", "--no-cache", `${name}@${version}`];
|
|
2541
|
-
}
|
|
2542
|
-
var KINDS, SKIPPED, MAX_DEPTH = 5, LOCAL_SPEC, KIND_FLAGS;
|
|
2543
|
-
var init_consumers = __esm(() => {
|
|
2544
|
-
init_pin();
|
|
2545
|
-
KINDS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
|
|
2546
|
-
SKIPPED = new Set(["node_modules", "dist", "build", "vendor", "target", "coverage"]);
|
|
2547
|
-
LOCAL_SPEC = /[:/]/;
|
|
2548
|
-
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
|
+
};
|
|
2549
3003
|
});
|
|
2550
3004
|
|
|
2551
3005
|
// src/commands/bump.ts
|
|
@@ -2554,9 +3008,9 @@ __export(exports_bump, {
|
|
|
2554
3008
|
ROOT_OPTION: () => ROOT_OPTION,
|
|
2555
3009
|
bump: () => bump
|
|
2556
3010
|
});
|
|
2557
|
-
import { existsSync as
|
|
2558
|
-
import { homedir as
|
|
2559
|
-
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";
|
|
2560
3014
|
async function lookup(name, registry, fetcher) {
|
|
2561
3015
|
try {
|
|
2562
3016
|
return { packument: await fetchPackument(name, registry, fetcher) };
|
|
@@ -2574,7 +3028,7 @@ async function servedVersion(name, version, settings) {
|
|
|
2574
3028
|
const registry = registryFor(name, settings.configs);
|
|
2575
3029
|
const host = new URL(registry.url).host;
|
|
2576
3030
|
const started = Date.now();
|
|
2577
|
-
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)}`]);
|
|
2578
3032
|
let lastError = "";
|
|
2579
3033
|
try {
|
|
2580
3034
|
for (;; ) {
|
|
@@ -2593,7 +3047,7 @@ async function servedVersion(name, version, settings) {
|
|
|
2593
3047
|
return version;
|
|
2594
3048
|
}
|
|
2595
3049
|
if (Date.now() - started >= settings.timeout)
|
|
2596
|
-
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}`}`);
|
|
2597
3051
|
region.redraw();
|
|
2598
3052
|
await Bun.sleep(settings.poll ?? POLL);
|
|
2599
3053
|
}
|
|
@@ -2616,11 +3070,11 @@ async function vet(name, version, settings) {
|
|
|
2616
3070
|
return false;
|
|
2617
3071
|
}
|
|
2618
3072
|
function lockfileOf(dir, root) {
|
|
2619
|
-
for (let at = dir;; at =
|
|
2620
|
-
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)));
|
|
2621
3075
|
if (found !== undefined)
|
|
2622
|
-
return relative2(dir,
|
|
2623
|
-
if (at === root || at ===
|
|
3076
|
+
return relative2(dir, join8(at, found));
|
|
3077
|
+
if (at === root || at === dirname5(at))
|
|
2624
3078
|
return;
|
|
2625
3079
|
}
|
|
2626
3080
|
}
|
|
@@ -2654,7 +3108,7 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2654
3108
|
note(`${local} non-registry dependenc${local === 1 ? "y" : "ies"} (workspace:, file:, git, URL, alias, catalog:)`, "left as they are");
|
|
2655
3109
|
for (const consumer of consumers) {
|
|
2656
3110
|
const argv = addCommand(consumer, name, version);
|
|
2657
|
-
const where =
|
|
3111
|
+
const where = join8(settings.root, consumer.dir);
|
|
2658
3112
|
if (consumer.kind === "peerDependencies") {
|
|
2659
3113
|
skipped.push(consumer.dir);
|
|
2660
3114
|
note(consumer.dir, `peer range ${consumer.spec}, left as it is`);
|
|
@@ -2697,9 +3151,9 @@ async function bumpConsumers(name, version, settings) {
|
|
|
2697
3151
|
return isClean;
|
|
2698
3152
|
}
|
|
2699
3153
|
async function bump(args) {
|
|
2700
|
-
const { values, positionals: [name, asked] } = parse(args,
|
|
3154
|
+
const { values, positionals: [name, asked] } = parse(args, usage5, options4, { positionals: ["<name>", "[version]"] });
|
|
2701
3155
|
const settings = {
|
|
2702
|
-
root: values.root ??
|
|
3156
|
+
root: values.root ?? join8(homedir4(), "Workspace"),
|
|
2703
3157
|
configs: await loadConfigs(),
|
|
2704
3158
|
timeout: duration(values.timeout, "timeout", 10 * 60000),
|
|
2705
3159
|
isDryRun: values["dry-run"] === true,
|
|
@@ -2713,14 +3167,14 @@ async function bump(args) {
|
|
|
2713
3167
|
return 1;
|
|
2714
3168
|
return await bumpConsumers(name, version, settings) ? 0 : 1;
|
|
2715
3169
|
}
|
|
2716
|
-
var
|
|
3170
|
+
var usage5 = `pkg bump <name> [version]
|
|
2717
3171
|
|
|
2718
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.
|
|
2719
3173
|
A version the vetting blocks is refused before any folder is touched, unless --force is given.
|
|
2720
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.
|
|
2721
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.
|
|
2722
3176
|
|
|
2723
|
-
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;
|
|
2724
3178
|
var init_bump = __esm(() => {
|
|
2725
3179
|
init_src();
|
|
2726
3180
|
init_progress();
|
|
@@ -2730,7 +3184,7 @@ var init_bump = __esm(() => {
|
|
|
2730
3184
|
init_semver();
|
|
2731
3185
|
init_check();
|
|
2732
3186
|
ROOT_OPTION = { type: "string", description: "the folder holding the repositories (~/Workspace)" };
|
|
2733
|
-
|
|
3187
|
+
options4 = {
|
|
2734
3188
|
root: ROOT_OPTION,
|
|
2735
3189
|
timeout: { type: "string", short: "t", description: "how long to wait for the registry (10m): 30s, 5m, 1h" },
|
|
2736
3190
|
"all-consumers": { type: "boolean", description: "after each install run the folder's check and commit it through gc when it passes" },
|
|
@@ -2745,11 +3199,11 @@ var exports_consumers = {};
|
|
|
2745
3199
|
__export(exports_consumers, {
|
|
2746
3200
|
consumers: () => consumers
|
|
2747
3201
|
});
|
|
2748
|
-
import { homedir as
|
|
2749
|
-
import { join as
|
|
3202
|
+
import { homedir as homedir5 } from "os";
|
|
3203
|
+
import { join as join9 } from "path";
|
|
2750
3204
|
function consumers(args) {
|
|
2751
|
-
const { values, positionals: [name] } = parse(args,
|
|
2752
|
-
const root = values.root ??
|
|
3205
|
+
const { values, positionals: [name] } = parse(args, usage6, options5, { positionals: ["<name>"] });
|
|
3206
|
+
const root = values.root ?? join9(homedir5(), "Workspace");
|
|
2753
3207
|
const { shown, footer } = capped(findConsumers(name, root), limitOf(values, CONSUMERS_LIMIT));
|
|
2754
3208
|
if (values.json === true)
|
|
2755
3209
|
printJson(shown);
|
|
@@ -2760,16 +3214,16 @@ function consumers(args) {
|
|
|
2760
3214
|
`));
|
|
2761
3215
|
return 0;
|
|
2762
3216
|
}
|
|
2763
|
-
var
|
|
3217
|
+
var usage6 = `pkg consumers <name>
|
|
2764
3218
|
|
|
2765
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).
|
|
2766
3220
|
|
|
2767
|
-
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;
|
|
2768
3222
|
var init_consumers2 = __esm(() => {
|
|
2769
3223
|
init_src();
|
|
2770
3224
|
init_consumers();
|
|
2771
3225
|
init_bump();
|
|
2772
|
-
|
|
3226
|
+
options5 = {
|
|
2773
3227
|
root: ROOT_OPTION,
|
|
2774
3228
|
...limitOptions(CONSUMERS_LIMIT),
|
|
2775
3229
|
json: jsonOption("[{dir, path, kind, spec, manager}]")
|
|
@@ -2778,14 +3232,9 @@ var init_consumers2 = __esm(() => {
|
|
|
2778
3232
|
|
|
2779
3233
|
// src/cli.ts
|
|
2780
3234
|
init_src();
|
|
2781
|
-
import
|
|
2782
|
-
|
|
2783
|
-
var version = "0.7.0";
|
|
2784
|
-
|
|
2785
|
-
// src/cli.ts
|
|
2786
|
-
process10.exitCode = await runCli({
|
|
3235
|
+
import process15 from "process";
|
|
3236
|
+
process15.exitCode = await runCli({
|
|
2787
3237
|
name: "pkg",
|
|
2788
|
-
version,
|
|
2789
3238
|
about: "checks npm packages before they are added, and moves a lib's consumers onto a new release",
|
|
2790
3239
|
replaces: "bun add on trust, and a bun info and sleep loop then a bun add per consumer",
|
|
2791
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"]],
|
|
@@ -2793,6 +3242,7 @@ process10.exitCode = await runCli({
|
|
|
2793
3242
|
commands: {
|
|
2794
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) },
|
|
2795
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) },
|
|
2796
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) },
|
|
2797
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) }
|
|
2798
3248
|
}
|