@penvhq/launcher 0.14.0 → 0.16.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/dist/bin.cjs +243 -30
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-WA5LM767.js → chunk-HQTTS5BH.js} +250 -35
- package/dist/chunk-HQTTS5BH.js.map +1 -0
- package/dist/index.cjs +249 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -15
- package/dist/index.d.ts +35 -15
- package/dist/index.js +7 -5
- package/package.json +3 -3
- package/dist/chunk-WA5LM767.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -366,6 +366,26 @@ var DeclarationNotSelfContainedError = class extends import_core.PenvError {
|
|
|
366
366
|
);
|
|
367
367
|
}
|
|
368
368
|
};
|
|
369
|
+
var DeclarationReservedFieldError = class extends import_core.PenvError {
|
|
370
|
+
name = "DeclarationReservedFieldError";
|
|
371
|
+
constructor(name, file, field2) {
|
|
372
|
+
super(
|
|
373
|
+
"PENV_DECLARATION_RESERVED_FIELD",
|
|
374
|
+
`The declaration ${name} ships at \`${file}\` declares \`${field2}\`, which penv owns on every environment entry`,
|
|
375
|
+
`Report it to ${name}. penv reserves ${import_core.RESERVED_ENTRY_FIELDS.map((reserved) => `\`${reserved}\``).join(", ")} inside an \`environments\` entry, so a provider names its own fields in its own vocabulary \u2014 \`project\`, \`path\` \u2014 and leaves those four to penv.`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
var DeclarationShapeUnreadableError = class extends import_core.PenvError {
|
|
380
|
+
name = "DeclarationShapeUnreadableError";
|
|
381
|
+
constructor(name, file, member) {
|
|
382
|
+
super(
|
|
383
|
+
"PENV_DECLARATION_SHAPE_UNREADABLE",
|
|
384
|
+
member === void 0 ? `The declaration ${name} ships at \`${file}\` has a \`ProviderConfigMap\` member penv cannot read` : `The declaration ${name} ships at \`${file}\` writes \`${member}\` as something other than an entry shape`,
|
|
385
|
+
`Report it to ${name}. Each \`ProviderConfigMap\` member is written as its own object literal \u2014 \`"@acme/provider-x": { readonly path: string }\` \u2014 so penv can check it names none of ${import_core.RESERVED_ENTRY_FIELDS.map((reserved) => `\`${reserved}\``).join(", ")}, which it owns on every environment entry.`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
369
389
|
var EnginePinUnreleasedError = class extends import_core.PenvError {
|
|
370
390
|
name = "EnginePinUnreleasedError";
|
|
371
391
|
constructor() {
|
|
@@ -422,7 +442,7 @@ var UpgradeUnattendedError = class extends import_core.PenvError {
|
|
|
422
442
|
super(
|
|
423
443
|
"PENV_UPGRADE_UNATTENDED",
|
|
424
444
|
`Upgrading rewrites ${import_core.MANIFEST_PATH} and package.json, and this run has nobody to decide that`,
|
|
425
|
-
`Run \`${UPGRADE_COMMAND}
|
|
445
|
+
`Run \`${UPGRADE_COMMAND} ${YES_FLAG}\` to take what \`latest\` points at, or \`${UPGRADE_COMMAND} <version> ${YES_FLAG}\` to name one. In CI, run \`${INSTALL_COMMAND}\`: it installs what the committed manifest already pins.`
|
|
426
446
|
);
|
|
427
447
|
}
|
|
428
448
|
};
|
|
@@ -607,7 +627,7 @@ function readKey(source, index) {
|
|
|
607
627
|
const match = /^[A-Za-z_$][A-Za-z0-9_$]*/.exec(source.slice(index));
|
|
608
628
|
return match === null ? void 0 : { key: match[0], end: index + match[0].length };
|
|
609
629
|
}
|
|
610
|
-
function
|
|
630
|
+
function providerSlotIn(source, open, close) {
|
|
611
631
|
let i = skipTrivia(source, open + 1);
|
|
612
632
|
while (i < close - 1) {
|
|
613
633
|
const key = readKey(source, i);
|
|
@@ -623,7 +643,7 @@ function typeSlotIn(source, open, close) {
|
|
|
623
643
|
let valueEnd;
|
|
624
644
|
if (QUOTES.has(ch)) {
|
|
625
645
|
valueEnd = skipString(source, valueStart);
|
|
626
|
-
if (key.key === "
|
|
646
|
+
if (key.key === "provider" && ch !== "`") {
|
|
627
647
|
return {
|
|
628
648
|
start: valueStart,
|
|
629
649
|
end: valueEnd,
|
|
@@ -646,8 +666,33 @@ function typeSlotIn(source, open, close) {
|
|
|
646
666
|
}
|
|
647
667
|
return void 0;
|
|
648
668
|
}
|
|
649
|
-
function
|
|
650
|
-
|
|
669
|
+
function blankComments(source) {
|
|
670
|
+
let out = "";
|
|
671
|
+
let i = 0;
|
|
672
|
+
while (i < source.length) {
|
|
673
|
+
const ch = source.charAt(i);
|
|
674
|
+
if (QUOTES.has(ch)) {
|
|
675
|
+
const end = skipString(source, i);
|
|
676
|
+
out += source.slice(i, end);
|
|
677
|
+
i = end;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (ch === "/" && (source.charAt(i + 1) === "/" || source.charAt(i + 1) === "*")) {
|
|
681
|
+
const line = source.charAt(i + 1) === "/";
|
|
682
|
+
const found = line ? source.indexOf("\n", i) : source.indexOf("*/", i + 2);
|
|
683
|
+
const end = found === -1 ? source.length : line ? found : found + 2;
|
|
684
|
+
out += source.slice(i, end).replace(/[^\n]/g, " ");
|
|
685
|
+
i = end;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
out += ch;
|
|
689
|
+
i += 1;
|
|
690
|
+
}
|
|
691
|
+
return out;
|
|
692
|
+
}
|
|
693
|
+
function scan(raw) {
|
|
694
|
+
const source = blankComments(raw);
|
|
695
|
+
const found = /(?:^|[\s{,;])environments\s*:\s*\{/.exec(source);
|
|
651
696
|
if (found === null) {
|
|
652
697
|
return void 0;
|
|
653
698
|
}
|
|
@@ -668,31 +713,42 @@ function scan(source) {
|
|
|
668
713
|
return void 0;
|
|
669
714
|
}
|
|
670
715
|
const entryOpen = skipTrivia(source, colon + 1);
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
716
|
+
const ch = source.charAt(entryOpen);
|
|
717
|
+
let entryEnd;
|
|
718
|
+
let slot;
|
|
719
|
+
if (ch === "{") {
|
|
720
|
+
entryEnd = matchBrace(source, entryOpen);
|
|
721
|
+
if (entryEnd === -1) {
|
|
722
|
+
return void 0;
|
|
723
|
+
}
|
|
724
|
+
slot = providerSlotIn(source, entryOpen, entryEnd);
|
|
725
|
+
} else if (QUOTES.has(ch)) {
|
|
726
|
+
entryEnd = skipString(source, entryOpen);
|
|
727
|
+
slot = ch === "`" ? void 0 : {
|
|
728
|
+
start: entryOpen,
|
|
729
|
+
end: entryEnd,
|
|
730
|
+
value: source.slice(entryOpen + 1, entryEnd - 1)
|
|
731
|
+
};
|
|
732
|
+
} else {
|
|
676
733
|
return void 0;
|
|
677
734
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
i = skipTrivia(source, entryClose);
|
|
735
|
+
entries.push({ environment: key.key, provider: slot?.value, slot });
|
|
736
|
+
i = skipTrivia(source, entryEnd);
|
|
681
737
|
if (source.charAt(i) === ",") {
|
|
682
738
|
i = skipTrivia(source, i + 1);
|
|
683
739
|
}
|
|
684
740
|
}
|
|
685
741
|
return entries;
|
|
686
742
|
}
|
|
687
|
-
function
|
|
688
|
-
return scan(source)?.map(({ environment,
|
|
743
|
+
function readEnvironmentProviders(source) {
|
|
744
|
+
return scan(source)?.map(({ environment, provider }) => ({ environment, provider }));
|
|
689
745
|
}
|
|
690
|
-
function
|
|
746
|
+
function setEnvironmentProvider(source, environment, provider) {
|
|
691
747
|
const entry = scan(source)?.find((candidate) => candidate.environment === environment);
|
|
692
748
|
if (entry?.slot === void 0) {
|
|
693
749
|
return void 0;
|
|
694
750
|
}
|
|
695
|
-
return `${source.slice(0, entry.slot.start)}${JSON.stringify(
|
|
751
|
+
return `${source.slice(0, entry.slot.start)}${JSON.stringify(provider)}${source.slice(entry.slot.end)}`;
|
|
696
752
|
}
|
|
697
753
|
|
|
698
754
|
// src/declaration.ts
|
|
@@ -737,7 +793,7 @@ function openShape(name) {
|
|
|
737
793
|
|
|
738
794
|
declare module "${AUGMENTATION_TARGET}" {
|
|
739
795
|
interface ProviderConfigMap {
|
|
740
|
-
${JSON.stringify(name)}: ProviderConfig & { readonly
|
|
796
|
+
${JSON.stringify(name)}: ProviderConfig & { readonly provider: ${JSON.stringify(name)} };
|
|
741
797
|
}
|
|
742
798
|
}
|
|
743
799
|
`;
|
|
@@ -755,12 +811,166 @@ function assertSelfContained(name, file, source) {
|
|
|
755
811
|
}
|
|
756
812
|
}
|
|
757
813
|
}
|
|
814
|
+
function endOfString(source, index) {
|
|
815
|
+
const quote = source.charAt(index);
|
|
816
|
+
let i = index + 1;
|
|
817
|
+
while (i < source.length) {
|
|
818
|
+
const ch = source.charAt(i);
|
|
819
|
+
if (ch === "\\") {
|
|
820
|
+
i += 2;
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
if (ch === quote) {
|
|
824
|
+
return i + 1;
|
|
825
|
+
}
|
|
826
|
+
i += 1;
|
|
827
|
+
}
|
|
828
|
+
return source.length;
|
|
829
|
+
}
|
|
830
|
+
function withoutComments(source) {
|
|
831
|
+
let out = "";
|
|
832
|
+
let i = 0;
|
|
833
|
+
while (i < source.length) {
|
|
834
|
+
const ch = source.charAt(i);
|
|
835
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
836
|
+
const end = endOfString(source, i);
|
|
837
|
+
out += source.slice(i, end);
|
|
838
|
+
i = end;
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
if (ch === "/" && (source.charAt(i + 1) === "/" || source.charAt(i + 1) === "*")) {
|
|
842
|
+
const line = source.charAt(i + 1) === "/";
|
|
843
|
+
const end = line ? source.indexOf("\n", i) : source.indexOf("*/", i + 2);
|
|
844
|
+
i = end === -1 ? source.length : line ? end : end + 2;
|
|
845
|
+
out += " ";
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
out += ch;
|
|
849
|
+
i += 1;
|
|
850
|
+
}
|
|
851
|
+
return out;
|
|
852
|
+
}
|
|
853
|
+
var RESERVED_FIELDS = [...import_core3.RESERVED_ENTRY_FIELDS].sort((a, b) => b.length - a.length);
|
|
854
|
+
var RESERVED_MEMBER = new RegExp(
|
|
855
|
+
`(?:^|[\\s;{,])(?:readonly\\s+)?(["']?)(${RESERVED_FIELDS.join("|")})\\1\\s*\\??\\s*:`
|
|
856
|
+
);
|
|
857
|
+
function endOfBrace(code, open) {
|
|
858
|
+
let depth = 0;
|
|
859
|
+
let i = open;
|
|
860
|
+
while (i < code.length) {
|
|
861
|
+
const ch = code.charAt(i);
|
|
862
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
863
|
+
i = endOfString(code, i);
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (ch === "{" || ch === "[" || ch === "(") {
|
|
867
|
+
depth += 1;
|
|
868
|
+
} else if (ch === "}" || ch === "]" || ch === ")") {
|
|
869
|
+
depth -= 1;
|
|
870
|
+
if (depth === 0) {
|
|
871
|
+
return i + 1;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
i += 1;
|
|
875
|
+
}
|
|
876
|
+
return -1;
|
|
877
|
+
}
|
|
878
|
+
function ownMembers(body) {
|
|
879
|
+
let members = "";
|
|
880
|
+
let depth = 0;
|
|
881
|
+
let i = 0;
|
|
882
|
+
while (i < body.length) {
|
|
883
|
+
const ch = body.charAt(i);
|
|
884
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
885
|
+
const end = endOfString(body, i);
|
|
886
|
+
if (depth === 0) {
|
|
887
|
+
members += body.slice(i, end);
|
|
888
|
+
}
|
|
889
|
+
i = end;
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (ch === "{" || ch === "[" || ch === "(") {
|
|
893
|
+
depth += 1;
|
|
894
|
+
} else if (ch === "}" || ch === "]" || ch === ")") {
|
|
895
|
+
depth -= 1;
|
|
896
|
+
} else if (depth === 0) {
|
|
897
|
+
members += ch;
|
|
898
|
+
i += 1;
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
if (depth <= 1) {
|
|
902
|
+
members += " ";
|
|
903
|
+
}
|
|
904
|
+
i += 1;
|
|
905
|
+
}
|
|
906
|
+
return members;
|
|
907
|
+
}
|
|
908
|
+
var MEMBER_NAME = /^(?:readonly\s+)?(?:(["'])([^"']*)\1|([A-Za-z_$][\w$]*))\s*\??\s*:/;
|
|
909
|
+
function mapMembers(source) {
|
|
910
|
+
const code = withoutComments(source);
|
|
911
|
+
const map = /interface\s+ProviderConfigMap\s*\{/.exec(code);
|
|
912
|
+
if (map === null) {
|
|
913
|
+
return [];
|
|
914
|
+
}
|
|
915
|
+
const open = map.index + map[0].length - 1;
|
|
916
|
+
const close = endOfBrace(code, open);
|
|
917
|
+
if (close === -1) {
|
|
918
|
+
return { unreadable: void 0 };
|
|
919
|
+
}
|
|
920
|
+
const members = [];
|
|
921
|
+
let i = open + 1;
|
|
922
|
+
for (; ; ) {
|
|
923
|
+
while (/\s|;|,/.test(code.charAt(i))) {
|
|
924
|
+
i += 1;
|
|
925
|
+
}
|
|
926
|
+
if (i >= close - 1) {
|
|
927
|
+
return members;
|
|
928
|
+
}
|
|
929
|
+
const name = MEMBER_NAME.exec(code.slice(i, close - 1));
|
|
930
|
+
if (name === null) {
|
|
931
|
+
return { unreadable: void 0 };
|
|
932
|
+
}
|
|
933
|
+
let value = i + name[0].length;
|
|
934
|
+
while (/\s/.test(code.charAt(value))) {
|
|
935
|
+
value += 1;
|
|
936
|
+
}
|
|
937
|
+
const declared = name[2] ?? name[3] ?? "";
|
|
938
|
+
if (code.charAt(value) !== "{") {
|
|
939
|
+
return { unreadable: declared };
|
|
940
|
+
}
|
|
941
|
+
const end = endOfBrace(code, value);
|
|
942
|
+
if (end === -1) {
|
|
943
|
+
return { unreadable: declared };
|
|
944
|
+
}
|
|
945
|
+
members.push({ name: declared, body: code.slice(value + 1, end - 1) });
|
|
946
|
+
i = end;
|
|
947
|
+
while (/\s/.test(code.charAt(i))) {
|
|
948
|
+
i += 1;
|
|
949
|
+
}
|
|
950
|
+
if (i < close - 1 && code.charAt(i) !== ";" && code.charAt(i) !== ",") {
|
|
951
|
+
return { unreadable: declared };
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
function assertEntryShapesAreReadable(name, file, source) {
|
|
956
|
+
const members = mapMembers(source);
|
|
957
|
+
if (!Array.isArray(members)) {
|
|
958
|
+
throw new DeclarationShapeUnreadableError(name, file, members.unreadable);
|
|
959
|
+
}
|
|
960
|
+
for (const member of members) {
|
|
961
|
+
const field2 = RESERVED_MEMBER.exec(ownMembers(member.body))?.[2];
|
|
962
|
+
if (field2 !== void 0) {
|
|
963
|
+
throw new DeclarationReservedFieldError(name, file, field2);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
758
967
|
function renderDeclaration(subject, shipped) {
|
|
759
968
|
if (shipped === void 0) {
|
|
760
969
|
return `${header(subject)}
|
|
761
970
|
${openShape(subject.name)}`;
|
|
762
971
|
}
|
|
763
972
|
assertSelfContained(subject.name, shipped.file, shipped.source);
|
|
973
|
+
assertEntryShapesAreReadable(subject.name, shipped.file, shipped.source);
|
|
764
974
|
const body = shipped.source.replace(/^/, "").trimEnd();
|
|
765
975
|
return `${header(subject)}
|
|
766
976
|
${body}
|
|
@@ -1257,30 +1467,33 @@ function chooseEnvironments(answer, offered) {
|
|
|
1257
1467
|
function quoted(environments) {
|
|
1258
1468
|
return environments.map((environment) => `\`${environment}\``).join(", ");
|
|
1259
1469
|
}
|
|
1470
|
+
function blindAdvice(name) {
|
|
1471
|
+
const spec = JSON.stringify(name);
|
|
1472
|
+
return `Point an environment at ${name} in penv.config.ts: \`production: ${spec}\`, or \`production: { provider: ${spec} }\` plus the provider's own fields and a \`keySource\`.`;
|
|
1473
|
+
}
|
|
1260
1474
|
function configAdvice(name, pointing, unpointed) {
|
|
1261
|
-
const add2 = `Add \`type: ${JSON.stringify(name)}\``;
|
|
1262
1475
|
if (pointing.length === 0) {
|
|
1263
|
-
return
|
|
1476
|
+
return blindAdvice(name);
|
|
1264
1477
|
}
|
|
1265
|
-
return `${quoted(pointing)} already ${pointing.length === 1 ? "points" : "point"} at ${name}.
|
|
1478
|
+
return `${quoted(pointing)} already ${pointing.length === 1 ? "points" : "point"} at ${name}. Point ${quoted(unpointed)} at it in penv.config.ts if ${unpointed.length === 1 ? "it" : "they"} should too.`;
|
|
1266
1479
|
}
|
|
1267
1480
|
async function offerConfigEdit(options, name, ask) {
|
|
1268
1481
|
const { io: io2, root } = options;
|
|
1269
1482
|
const configFile = (0, import_core6.findConfigFile)(root);
|
|
1270
|
-
const blind =
|
|
1483
|
+
const blind = blindAdvice(name);
|
|
1271
1484
|
if (configFile === void 0) {
|
|
1272
1485
|
io2.out(blind);
|
|
1273
1486
|
return;
|
|
1274
1487
|
}
|
|
1275
1488
|
const shown = (0, import_node_path5.relative)(root, configFile).split(import_node_path5.sep).join("/");
|
|
1276
1489
|
let current = (0, import_node_fs5.readFileSync)(configFile, "utf8");
|
|
1277
|
-
const entries =
|
|
1490
|
+
const entries = readEnvironmentProviders(current);
|
|
1278
1491
|
if (entries === void 0 || entries.length === 0) {
|
|
1279
1492
|
io2.out(blind);
|
|
1280
1493
|
return;
|
|
1281
1494
|
}
|
|
1282
|
-
const pointing = entries.filter((entry) => entry.
|
|
1283
|
-
const offered = entries.filter((entry) => entry.
|
|
1495
|
+
const pointing = entries.filter((entry) => entry.provider === name).map((entry) => entry.environment);
|
|
1496
|
+
const offered = entries.filter((entry) => entry.provider !== name).map((entry) => entry.environment);
|
|
1284
1497
|
if (offered.length === 0) {
|
|
1285
1498
|
return;
|
|
1286
1499
|
}
|
|
@@ -1299,9 +1512,9 @@ async function offerConfigEdit(options, name, ask) {
|
|
|
1299
1512
|
return;
|
|
1300
1513
|
}
|
|
1301
1514
|
for (const environment of chosen) {
|
|
1302
|
-
const next =
|
|
1515
|
+
const next = setEnvironmentProvider(current, environment, name);
|
|
1303
1516
|
if (next === void 0) {
|
|
1304
|
-
io2.out(`Add \`
|
|
1517
|
+
io2.out(`Add \`provider: ${JSON.stringify(name)}\` to \`${environment}\` in ${shown}.`);
|
|
1305
1518
|
continue;
|
|
1306
1519
|
}
|
|
1307
1520
|
current = next;
|
|
@@ -1519,8 +1732,8 @@ var DEV_PIN_INTEGRITY = "sha512-development-build-not-a-published-release";
|
|
|
1519
1732
|
var DEV_PIN_VERSION = "0.0.0-dev";
|
|
1520
1733
|
var BUNDLED_ENGINE_PIN = {
|
|
1521
1734
|
package: import_core8.ENGINE_PACKAGE,
|
|
1522
|
-
version: "0.
|
|
1523
|
-
integrity: "sha512-
|
|
1735
|
+
version: "0.16.0",
|
|
1736
|
+
integrity: "sha512-DSA07wrSown70tU/9ix9yozJihsQjHFPN3/iXLiH6sS6LYT+/PWBFmVI6C2tH/qaUL2GGh4mgRHL8LGM749C8Q=="
|
|
1524
1737
|
};
|
|
1525
1738
|
function assertReleasePin(pin) {
|
|
1526
1739
|
if (pin.integrity === DEV_PIN_INTEGRITY || pin.version === DEV_PIN_VERSION) {
|
|
@@ -1618,7 +1831,7 @@ async function upgrade(options) {
|
|
|
1618
1831
|
if (options.noDownload === true) {
|
|
1619
1832
|
throw new UpgradeNoDownloadError();
|
|
1620
1833
|
}
|
|
1621
|
-
if ((options.ci === true || !io2.interactive) && !
|
|
1834
|
+
if ((options.ci === true || !io2.interactive) && !request.yes) {
|
|
1622
1835
|
throw new UpgradeUnattendedError();
|
|
1623
1836
|
}
|
|
1624
1837
|
const release = await fetchRelease({
|