@heroiclands/package-build 8.1.0 → 9.0.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/CHANGELOG.md +54 -0
- package/bin/content-build.mjs +44 -118
- package/bin/package-build.mjs +27 -69
- package/bin/report.mjs +1 -2
- package/bundle.mjs +2 -10
- package/config.mjs +31 -106
- package/container.mjs +13 -57
- package/content-config.mjs +45 -164
- package/coverage.mjs +14 -55
- package/deploy.mjs +4 -13
- package/e2e.mjs +16 -55
- package/engine/address-diff.mjs +1 -4
- package/engine/base-compiler.mjs +10 -28
- package/engine/code-fences.mjs +4 -13
- package/engine/compendiums.mjs +13 -37
- package/engine/content-address.mjs +2 -6
- package/engine/content-links.mjs +13 -44
- package/engine/content-lint.mjs +4 -15
- package/engine/content-slug.mjs +2 -6
- package/engine/content-tables.mjs +26 -79
- package/engine/diagnostics.mjs +4 -15
- package/engine/field-reference.mjs +6 -20
- package/engine/field-spec.mjs +1 -3
- package/engine/foreign-catalog.mjs +7 -22
- package/engine/foreign-manifests.mjs +1 -4
- package/engine/frontmatter-lint.mjs +6 -18
- package/engine/frontmatter.mjs +3 -8
- package/engine/generate.mjs +4 -16
- package/engine/helpers.mjs +13 -52
- package/engine/homepage.mjs +4 -15
- package/engine/ids.mjs +3 -12
- package/engine/item-registry.mjs +2 -6
- package/engine/journals.mjs +4 -14
- package/engine/kb-manifest.mjs +5 -17
- package/engine/macros.mjs +2 -10
- package/engine/manifest-emit.mjs +6 -17
- package/engine/map-notes.mjs +19 -69
- package/engine/note-package.mjs +1 -4
- package/engine/pack-config.mjs +17 -38
- package/engine/pack-router.mjs +1 -2
- package/engine/prose-config.mjs +20 -4
- package/engine/prose-lint.mjs +6 -14
- package/engine/region-events.mjs +1 -3
- package/engine/scene-levels.mjs +8 -22
- package/engine/scenes.mjs +13 -47
- package/engine/schema-check.mjs +1 -4
- package/engine/schema-extract.mjs +11 -39
- package/engine/site-build.mjs +12 -37
- package/engine/site-index.mjs +3 -15
- package/engine/web-wikilinks.mjs +4 -13
- package/engine/wikilinks.mjs +115 -167
- package/index.mjs +1 -5
- package/lang.mjs +1 -3
- package/manifest.mjs +10 -37
- package/markdownlint-config.mjs +1 -5
- package/package.json +1 -1
- package/sohl/actors.mjs +10 -40
- package/sohl/being-info.mjs +3 -6
- package/sohl/index.mjs +1 -6
- package/sohl/item-builders.mjs +1 -3
- package/sohl/item-fields.mjs +16 -34
- package/sohl/items.mjs +1 -3
- package/sohl/kb-passes.mjs +29 -39
- package/sohl/skill-base.mjs +7 -23
- package/stage.mjs +3 -13
- package/templates.mjs +4 -15
- package/types/bundle.d.mts +1 -1
- package/types/container.d.mts +2 -2
- package/types/coverage.d.mts +1 -1
- package/types/e2e.d.mts +4 -4
- package/types/engine/generate.d.mts +1 -1
- package/types/engine/helpers.d.mts +1 -1
- package/types/engine/schema-extract.d.mts +1 -1
- package/types/engine/site-index.d.mts +1 -1
- package/types/manifest.d.mts +1 -1
package/container.mjs
CHANGED
|
@@ -155,10 +155,7 @@ export function containerName(packageId, stage, base = null) {
|
|
|
155
155
|
* @returns {number} The host port.
|
|
156
156
|
* @throws {Error} When the stage has no port from any source.
|
|
157
157
|
*/
|
|
158
|
-
export function resolveStagePort(
|
|
159
|
-
stage,
|
|
160
|
-
{ env = process.env, stages = {} } = {},
|
|
161
|
-
) {
|
|
158
|
+
export function resolveStagePort(stage, { env = process.env, stages = {} } = {}) {
|
|
162
159
|
const fromEnv = env[`FOUNDRYVTT_${stage.toUpperCase()}_PORT`]?.trim();
|
|
163
160
|
const port =
|
|
164
161
|
fromEnv ? Number(fromEnv)
|
|
@@ -205,12 +202,7 @@ const EXACT_BUILD = /^\d+\.\d+$/;
|
|
|
205
202
|
*/
|
|
206
203
|
export function resolveFoundryVersion(
|
|
207
204
|
stage,
|
|
208
|
-
{
|
|
209
|
-
env = process.env,
|
|
210
|
-
stages = {},
|
|
211
|
-
compatibilityMinimum = null,
|
|
212
|
-
e2eStage = "test",
|
|
213
|
-
} = {},
|
|
205
|
+
{ env = process.env, stages = {}, compatibilityMinimum = null, e2eStage = "test" } = {},
|
|
214
206
|
) {
|
|
215
207
|
const fromEnv = env[`FOUNDRYVTT_${stage.toUpperCase()}_VERSION`]?.trim();
|
|
216
208
|
if (fromEnv) return fromEnv;
|
|
@@ -267,9 +259,7 @@ export function resolveWorld(stage, { env = process.env, stages = {} } = {}) {
|
|
|
267
259
|
const fromEnv = env[`FOUNDRYVTT_${stage.toUpperCase()}_WORLD`];
|
|
268
260
|
if (fromEnv !== undefined) return fromEnv.trim();
|
|
269
261
|
const declared = stages[stage]?.world;
|
|
270
|
-
return declared === undefined || declared === null ?
|
|
271
|
-
null
|
|
272
|
-
: String(declared);
|
|
262
|
+
return declared === undefined || declared === null ? null : String(declared);
|
|
273
263
|
}
|
|
274
264
|
|
|
275
265
|
/**
|
|
@@ -387,12 +377,7 @@ export function dockerRunArgs({
|
|
|
387
377
|
`${dataRoot}:/data`,
|
|
388
378
|
];
|
|
389
379
|
if (cacheDir) {
|
|
390
|
-
args.push(
|
|
391
|
-
"--volume",
|
|
392
|
-
`${cacheDir}:${CACHE_MOUNT}`,
|
|
393
|
-
"-e",
|
|
394
|
-
`CONTAINER_CACHE=${CACHE_MOUNT}`,
|
|
395
|
-
);
|
|
380
|
+
args.push("--volume", `${cacheDir}:${CACHE_MOUNT}`, "-e", `CONTAINER_CACHE=${CACHE_MOUNT}`);
|
|
396
381
|
}
|
|
397
382
|
for (const [key, value] of passthroughEnv(env)) {
|
|
398
383
|
args.push("-e", `${key}=${value}`);
|
|
@@ -414,10 +399,7 @@ export function dockerRunArgs({
|
|
|
414
399
|
export function runDocker(args) {
|
|
415
400
|
const result = spawnSync("docker", args, { stdio: "inherit" });
|
|
416
401
|
if (result.error) {
|
|
417
|
-
if (
|
|
418
|
-
/** @type {NodeJS.ErrnoException} */ (result.error).code ===
|
|
419
|
-
"ENOENT"
|
|
420
|
-
) {
|
|
402
|
+
if (/** @type {NodeJS.ErrnoException} */ (result.error).code === "ENOENT") {
|
|
421
403
|
throw new Error(
|
|
422
404
|
"docker was not found on PATH. Install Docker and make sure " +
|
|
423
405
|
"the `docker` CLI is available.",
|
|
@@ -464,13 +446,7 @@ export function containerExists(name, runningOnly = false) {
|
|
|
464
446
|
* @returns {string[]} The container names.
|
|
465
447
|
*/
|
|
466
448
|
export function runningFoundryContainers(except = "") {
|
|
467
|
-
return captureDocker([
|
|
468
|
-
"ps",
|
|
469
|
-
"--filter",
|
|
470
|
-
"name=-foundry-",
|
|
471
|
-
"--format",
|
|
472
|
-
"{{.Names}}",
|
|
473
|
-
])
|
|
449
|
+
return captureDocker(["ps", "--filter", "name=-foundry-", "--format", "{{.Names}}"])
|
|
474
450
|
.split("\n")
|
|
475
451
|
.filter((name) => name && name !== except);
|
|
476
452
|
}
|
|
@@ -559,26 +535,18 @@ export function resolveContainer({ stage, config, env = process.env }) {
|
|
|
559
535
|
* @param {(message: string) => void} [opts.log] - Progress reporting.
|
|
560
536
|
* @returns {number} The exit status.
|
|
561
537
|
*/
|
|
562
|
-
export function startContainer(
|
|
563
|
-
container,
|
|
564
|
-
{ dataRoot, env = process.env, log = () => {} },
|
|
565
|
-
) {
|
|
538
|
+
export function startContainer(container, { dataRoot, env = process.env, log = () => {} }) {
|
|
566
539
|
if (containerExists(container.name)) {
|
|
567
540
|
// Nothing is running against this data root — we are about to start it
|
|
568
541
|
// — so any lock present was left by a previous crash.
|
|
569
|
-
if (!containerExists(container.name, true))
|
|
570
|
-
|
|
571
|
-
log(
|
|
572
|
-
`Starting existing container '${container.name}' → ${container.url}`,
|
|
573
|
-
);
|
|
542
|
+
if (!containerExists(container.name, true)) clearStaleLock(dataRoot, log);
|
|
543
|
+
log(`Starting existing container '${container.name}' → ${container.url}`);
|
|
574
544
|
return runDocker(["start", container.name]);
|
|
575
545
|
}
|
|
576
546
|
|
|
577
547
|
clearStaleLock(dataRoot, log);
|
|
578
548
|
if (container.cacheDir && !fs.existsSync(container.cacheDir)) {
|
|
579
|
-
throw new Error(
|
|
580
|
-
`FOUNDRYVTT_CACHE directory does not exist: ${container.cacheDir}.`,
|
|
581
|
-
);
|
|
549
|
+
throw new Error(`FOUNDRYVTT_CACHE directory does not exist: ${container.cacheDir}.`);
|
|
582
550
|
}
|
|
583
551
|
log(
|
|
584
552
|
`Creating container '${container.name}' from ${container.image}\n` +
|
|
@@ -634,13 +602,7 @@ export function removeContainer(name, log = () => {}) {
|
|
|
634
602
|
* @returns {number} The exit status.
|
|
635
603
|
* @throws {Error} On an unknown action, or a stage with no usable data root.
|
|
636
604
|
*/
|
|
637
|
-
export function containerAction({
|
|
638
|
-
action,
|
|
639
|
-
stage,
|
|
640
|
-
config,
|
|
641
|
-
env = process.env,
|
|
642
|
-
log = () => {},
|
|
643
|
-
}) {
|
|
605
|
+
export function containerAction({ action, stage, config, env = process.env, log = () => {} }) {
|
|
644
606
|
if (!CONTAINER_ACTIONS.includes(action)) {
|
|
645
607
|
throw new Error(
|
|
646
608
|
`Invalid container action '${action}'. Valid actions are: ` +
|
|
@@ -677,12 +639,7 @@ export function containerAction({
|
|
|
677
639
|
removeContainer(container.name, log);
|
|
678
640
|
return 0;
|
|
679
641
|
case "status":
|
|
680
|
-
return runDocker([
|
|
681
|
-
"ps",
|
|
682
|
-
"-a",
|
|
683
|
-
"--filter",
|
|
684
|
-
`name=^${container.name}$`,
|
|
685
|
-
]);
|
|
642
|
+
return runDocker(["ps", "-a", "--filter", `name=^${container.name}$`]);
|
|
686
643
|
case "logs":
|
|
687
644
|
return runDocker(["logs", "-f", container.name]);
|
|
688
645
|
default:
|
|
@@ -702,8 +659,7 @@ function requireDataRoot(stage, env) {
|
|
|
702
659
|
const dataRoot = resolveDataRoot(stage, { env });
|
|
703
660
|
if (!fs.existsSync(dataRoot)) {
|
|
704
661
|
throw new Error(
|
|
705
|
-
`Data directory does not exist: ${dataRoot} (from ` +
|
|
706
|
-
`${dataEnvVar(stage)}).`,
|
|
662
|
+
`Data directory does not exist: ${dataRoot} (from ` + `${dataEnvVar(stage)}).`,
|
|
707
663
|
);
|
|
708
664
|
}
|
|
709
665
|
return dataRoot;
|
package/content-config.mjs
CHANGED
|
@@ -608,13 +608,7 @@ const SITE_TREE_KEYS = ["from", "section"];
|
|
|
608
608
|
const SECTION_META_KEYS = ["title", "banner", "description"];
|
|
609
609
|
const DOC_PAGE_KEYS = ["title", "out", "preamble"];
|
|
610
610
|
const RELATIONSHIP_KINDS = ["systems", "requires", "recommends", "conflicts"];
|
|
611
|
-
const RELATIONSHIP_KEYS = [
|
|
612
|
-
"id",
|
|
613
|
-
"type",
|
|
614
|
-
"manifest",
|
|
615
|
-
"compatibility",
|
|
616
|
-
"itemCatalog",
|
|
617
|
-
];
|
|
611
|
+
const RELATIONSHIP_KEYS = ["id", "type", "manifest", "compatibility", "itemCatalog"];
|
|
618
612
|
const ITEM_BUILDER_KEYS = ["system", "img", "fields"];
|
|
619
613
|
const PACK_KEYS = [
|
|
620
614
|
"name",
|
|
@@ -644,9 +638,7 @@ const STATS_KEYS = ["lastModifiedBy"];
|
|
|
644
638
|
*
|
|
645
639
|
* @type {symbol}
|
|
646
640
|
*/
|
|
647
|
-
export const DERIVED_SYSTEM_VERSION = Symbol.for(
|
|
648
|
-
"package-build.derivedSystemVersion",
|
|
649
|
-
);
|
|
641
|
+
export const DERIVED_SYSTEM_VERSION = Symbol.for("package-build.derivedSystemVersion");
|
|
650
642
|
const PUBLISH_KEYS = ["site", "manifests", "address"];
|
|
651
643
|
const MANIFEST_KEYS = ["publish", "consume"];
|
|
652
644
|
const ADDRESS_KEYS = ["prefix", "landing"];
|
|
@@ -672,10 +664,7 @@ function isPlainObject(value) {
|
|
|
672
664
|
* @returns {never}
|
|
673
665
|
*/
|
|
674
666
|
function fail(field, problem) {
|
|
675
|
-
throw Object.assign(
|
|
676
|
-
new TypeError(`package-build config: \`${field}\` ${problem}.`),
|
|
677
|
-
{ field },
|
|
678
|
-
);
|
|
667
|
+
throw Object.assign(new TypeError(`package-build config: \`${field}\` ${problem}.`), { field });
|
|
679
668
|
}
|
|
680
669
|
|
|
681
670
|
/**
|
|
@@ -752,10 +741,7 @@ function normalizePack(value, where, nested = false) {
|
|
|
752
741
|
typeof type !== "string" ||
|
|
753
742
|
!(/** @type {readonly string[]} */ (PACK_DOCUMENT_TYPES).includes(type))
|
|
754
743
|
) {
|
|
755
|
-
fail(
|
|
756
|
-
`${where}.type`,
|
|
757
|
-
`must be one of: ${PACK_DOCUMENT_TYPES.join(", ")}`,
|
|
758
|
-
);
|
|
744
|
+
fail(`${where}.type`, `must be one of: ${PACK_DOCUMENT_TYPES.join(", ")}`);
|
|
759
745
|
}
|
|
760
746
|
|
|
761
747
|
if (pack.folders !== undefined && pack.folders !== null) {
|
|
@@ -837,20 +823,14 @@ function normalizePack(value, where, nested = false) {
|
|
|
837
823
|
name,
|
|
838
824
|
type: /** @type {PackDocumentType} */ (type),
|
|
839
825
|
label:
|
|
840
|
-
pack.label === undefined ?
|
|
841
|
-
name
|
|
842
|
-
: requireNonEmptyString(pack.label, `${where}.label`),
|
|
826
|
+
pack.label === undefined ? name : requireNonEmptyString(pack.label, `${where}.label`),
|
|
843
827
|
private: optionalBoolean(pack.private, `${where}.private`, false),
|
|
844
828
|
folders:
|
|
845
829
|
pack.folders === undefined || pack.folders === null ?
|
|
846
830
|
null
|
|
847
831
|
: /** @type {string} */ (pack.folders),
|
|
848
832
|
companions: Object.freeze(companions),
|
|
849
|
-
mayBeEmpty: optionalBoolean(
|
|
850
|
-
pack.mayBeEmpty,
|
|
851
|
-
`${where}.mayBeEmpty`,
|
|
852
|
-
false,
|
|
853
|
-
),
|
|
833
|
+
mayBeEmpty: optionalBoolean(pack.mayBeEmpty, `${where}.mayBeEmpty`, false),
|
|
854
834
|
// Which pack of a type receives a note that declares none. Validated
|
|
855
835
|
// across the whole list in `defineConfig` — at most one per type.
|
|
856
836
|
default: optionalBoolean(pack.default, `${where}.default`, false),
|
|
@@ -938,10 +918,7 @@ function normalizeStats(value, derived) {
|
|
|
938
918
|
// the package-wide answer for everything that has no pack in hand.
|
|
939
919
|
systemId: derived.systemId,
|
|
940
920
|
systemVersion: derived.systemVersion,
|
|
941
|
-
lastModifiedBy: requireNonEmptyString(
|
|
942
|
-
input.lastModifiedBy,
|
|
943
|
-
"stats.lastModifiedBy",
|
|
944
|
-
),
|
|
921
|
+
lastModifiedBy: requireNonEmptyString(input.lastModifiedBy, "stats.lastModifiedBy"),
|
|
945
922
|
});
|
|
946
923
|
}
|
|
947
924
|
|
|
@@ -1056,10 +1033,7 @@ function normalizeSectionMeta(value, where) {
|
|
|
1056
1033
|
out.banner = requireNonEmptyString(input.banner, `${where}.banner`);
|
|
1057
1034
|
}
|
|
1058
1035
|
if (input.description !== undefined) {
|
|
1059
|
-
out.description = requireNonEmptyString(
|
|
1060
|
-
input.description,
|
|
1061
|
-
`${where}.description`,
|
|
1062
|
-
);
|
|
1036
|
+
out.description = requireNonEmptyString(input.description, `${where}.description`);
|
|
1063
1037
|
}
|
|
1064
1038
|
return Object.freeze(out);
|
|
1065
1039
|
}
|
|
@@ -1075,9 +1049,7 @@ function normalizeSectionMap(value, where) {
|
|
|
1075
1049
|
if (value === undefined) return Object.freeze({});
|
|
1076
1050
|
if (!isPlainObject(value)) fail(where, "must be a mapping");
|
|
1077
1051
|
const out = {};
|
|
1078
|
-
for (const [name, meta] of Object.entries(
|
|
1079
|
-
/** @type {Record<string, unknown>} */ (value),
|
|
1080
|
-
)) {
|
|
1052
|
+
for (const [name, meta] of Object.entries(/** @type {Record<string, unknown>} */ (value))) {
|
|
1081
1053
|
out[name] = normalizeSectionMeta(meta, `${where}.${name}`);
|
|
1082
1054
|
}
|
|
1083
1055
|
return Object.freeze(out);
|
|
@@ -1124,10 +1096,7 @@ function normalizeSite(value) {
|
|
|
1124
1096
|
trees.push(
|
|
1125
1097
|
Object.freeze({
|
|
1126
1098
|
from: requireNonEmptyString(tree.from, `${where}.from`),
|
|
1127
|
-
section: requireNonEmptyString(
|
|
1128
|
-
tree.section,
|
|
1129
|
-
`${where}.section`,
|
|
1130
|
-
),
|
|
1099
|
+
section: requireNonEmptyString(tree.section, `${where}.section`),
|
|
1131
1100
|
// The tree's own path, POSIX-separated — what a
|
|
1132
1101
|
// repository-relative link inside it is resolved against.
|
|
1133
1102
|
rel: String(tree.from).split(path.sep).join("/"),
|
|
@@ -1141,9 +1110,7 @@ function normalizeSite(value) {
|
|
|
1141
1110
|
if (!Array.isArray(input.packages)) {
|
|
1142
1111
|
fail("site.packages", "must be a list");
|
|
1143
1112
|
}
|
|
1144
|
-
packages = input.packages.map((p, i) =>
|
|
1145
|
-
requireNonEmptyString(p, `site.packages[${i}]`),
|
|
1146
|
-
);
|
|
1113
|
+
packages = input.packages.map((p, i) => requireNonEmptyString(p, `site.packages[${i}]`));
|
|
1147
1114
|
}
|
|
1148
1115
|
|
|
1149
1116
|
let landing = null;
|
|
@@ -1157,35 +1124,19 @@ function normalizeSite(value) {
|
|
|
1157
1124
|
}
|
|
1158
1125
|
|
|
1159
1126
|
return Object.freeze({
|
|
1160
|
-
out:
|
|
1161
|
-
|
|
1162
|
-
""
|
|
1163
|
-
: requireNonEmptyString(input.out, "site.out"),
|
|
1164
|
-
base:
|
|
1165
|
-
input.base === undefined ?
|
|
1166
|
-
""
|
|
1167
|
-
: requireNonEmptyString(input.base, "site.base"),
|
|
1127
|
+
out: input.out === undefined ? "" : requireNonEmptyString(input.out, "site.out"),
|
|
1128
|
+
base: input.base === undefined ? "" : requireNonEmptyString(input.base, "site.base"),
|
|
1168
1129
|
packages: Object.freeze(packages),
|
|
1169
1130
|
sections: normalizeSectionMap(input.sections, "site.sections"),
|
|
1170
|
-
readmeSections: normalizeSectionMap(
|
|
1171
|
-
input.readmeSections,
|
|
1172
|
-
"site.readmeSections",
|
|
1173
|
-
),
|
|
1131
|
+
readmeSections: normalizeSectionMap(input.readmeSections, "site.readmeSections"),
|
|
1174
1132
|
landing,
|
|
1175
1133
|
trees: Object.freeze(trees),
|
|
1176
|
-
pass:
|
|
1177
|
-
input.pass === undefined ?
|
|
1178
|
-
""
|
|
1179
|
-
: requireNonEmptyString(input.pass, "site.pass"),
|
|
1134
|
+
pass: input.pass === undefined ? "" : requireNonEmptyString(input.pass, "site.pass"),
|
|
1180
1135
|
passOptions:
|
|
1181
1136
|
input.passOptions === undefined ?
|
|
1182
1137
|
Object.freeze({})
|
|
1183
1138
|
: Object.freeze({ ...input.passOptions }),
|
|
1184
|
-
backfillSections: optionalBoolean(
|
|
1185
|
-
input.backfillSections,
|
|
1186
|
-
"site.backfillSections",
|
|
1187
|
-
false,
|
|
1188
|
-
),
|
|
1139
|
+
backfillSections: optionalBoolean(input.backfillSections, "site.backfillSections", false),
|
|
1189
1140
|
});
|
|
1190
1141
|
}
|
|
1191
1142
|
|
|
@@ -1213,10 +1164,7 @@ function normalizeCompatibility(value, where, requireMinimum = true) {
|
|
|
1213
1164
|
out.minimum = requireNonEmptyString(input.minimum, `${where}.minimum`);
|
|
1214
1165
|
}
|
|
1215
1166
|
if (input.verified !== undefined) {
|
|
1216
|
-
out.verified = requireNonEmptyString(
|
|
1217
|
-
input.verified,
|
|
1218
|
-
`${where}.verified`,
|
|
1219
|
-
);
|
|
1167
|
+
out.verified = requireNonEmptyString(input.verified, `${where}.verified`);
|
|
1220
1168
|
}
|
|
1221
1169
|
return Object.freeze(out);
|
|
1222
1170
|
}
|
|
@@ -1255,8 +1203,7 @@ function normalizeCompatibility(value, where, requireMinimum = true) {
|
|
|
1255
1203
|
*/
|
|
1256
1204
|
function normalizeSystems(value) {
|
|
1257
1205
|
if (value === undefined || value === null) return Object.freeze({});
|
|
1258
|
-
if (!isPlainObject(value))
|
|
1259
|
-
fail("systems", "must be a mapping of id to spec");
|
|
1206
|
+
if (!isPlainObject(value)) fail("systems", "must be a mapping of id to spec");
|
|
1260
1207
|
const input = /** @type {Record<string, unknown>} */ (value);
|
|
1261
1208
|
|
|
1262
1209
|
const out = {};
|
|
@@ -1276,10 +1223,7 @@ function normalizeSystems(value) {
|
|
|
1276
1223
|
// `verified` is required because it is the value a pack stamps. A
|
|
1277
1224
|
// declaration that cannot answer "which version was this built
|
|
1278
1225
|
// against" is the gap this block exists to close.
|
|
1279
|
-
const verified = requireNonEmptyString(
|
|
1280
|
-
compat.verified,
|
|
1281
|
-
`${at}.compatibility.verified`,
|
|
1282
|
-
);
|
|
1226
|
+
const verified = requireNonEmptyString(compat.verified, `${at}.compatibility.verified`);
|
|
1283
1227
|
|
|
1284
1228
|
out[id] = Object.freeze({
|
|
1285
1229
|
manifest:
|
|
@@ -1290,10 +1234,7 @@ function normalizeSystems(value) {
|
|
|
1290
1234
|
minimum:
|
|
1291
1235
|
compat.minimum === undefined || compat.minimum === null ?
|
|
1292
1236
|
null
|
|
1293
|
-
: requireNonEmptyString(
|
|
1294
|
-
compat.minimum,
|
|
1295
|
-
`${at}.compatibility.minimum`,
|
|
1296
|
-
),
|
|
1237
|
+
: requireNonEmptyString(compat.minimum, `${at}.compatibility.minimum`),
|
|
1297
1238
|
verified,
|
|
1298
1239
|
}),
|
|
1299
1240
|
});
|
|
@@ -1346,10 +1287,7 @@ function normalizeRelationships(value) {
|
|
|
1346
1287
|
};
|
|
1347
1288
|
for (const key of ["type", "manifest"]) {
|
|
1348
1289
|
if (rel[key] !== undefined) {
|
|
1349
|
-
spec[key] = requireNonEmptyString(
|
|
1350
|
-
rel[key],
|
|
1351
|
-
`${at}.${key}`,
|
|
1352
|
-
);
|
|
1290
|
+
spec[key] = requireNonEmptyString(rel[key], `${at}.${key}`);
|
|
1353
1291
|
}
|
|
1354
1292
|
}
|
|
1355
1293
|
const compat = normalizeCompatibility(
|
|
@@ -1367,10 +1305,7 @@ function normalizeRelationships(value) {
|
|
|
1367
1305
|
fail(`${at}.itemCatalog`, "must be true or false");
|
|
1368
1306
|
}
|
|
1369
1307
|
if (rel.itemCatalog && spec.manifest === undefined) {
|
|
1370
|
-
fail(
|
|
1371
|
-
`${at}.itemCatalog`,
|
|
1372
|
-
"needs a `manifest` naming the package to fetch",
|
|
1373
|
-
);
|
|
1308
|
+
fail(`${at}.itemCatalog`, "needs a `manifest` naming the package to fetch");
|
|
1374
1309
|
}
|
|
1375
1310
|
spec.itemCatalog = rel.itemCatalog;
|
|
1376
1311
|
}
|
|
@@ -1397,9 +1332,7 @@ function normalizePackageBuild(value) {
|
|
|
1397
1332
|
"reads, and that package validates what is inside it",
|
|
1398
1333
|
);
|
|
1399
1334
|
}
|
|
1400
|
-
return /** @type {Readonly<PackageBuildSection>} */ (
|
|
1401
|
-
deepFreeze(structuredClone(value))
|
|
1402
|
-
);
|
|
1335
|
+
return /** @type {Readonly<PackageBuildSection>} */ (deepFreeze(structuredClone(value)));
|
|
1403
1336
|
}
|
|
1404
1337
|
|
|
1405
1338
|
/**
|
|
@@ -1467,10 +1400,7 @@ function normalizeItemBuilders(value) {
|
|
|
1467
1400
|
}
|
|
1468
1401
|
itemBuilders[type] = /** @type {Function} */ (paired.system);
|
|
1469
1402
|
if (paired.img !== undefined) {
|
|
1470
|
-
itemArt[type] = requireNonEmptyString(
|
|
1471
|
-
paired.img,
|
|
1472
|
-
`itemBuilders.${type}.img`,
|
|
1473
|
-
);
|
|
1403
|
+
itemArt[type] = requireNonEmptyString(paired.img, `itemBuilders.${type}.img`);
|
|
1474
1404
|
}
|
|
1475
1405
|
if (paired.fields !== undefined) {
|
|
1476
1406
|
if (!Array.isArray(paired.fields)) {
|
|
@@ -1556,9 +1486,7 @@ function normalizePublish(value) {
|
|
|
1556
1486
|
if (manifestsInput !== undefined && !isPlainObject(manifestsInput)) {
|
|
1557
1487
|
fail("publish.manifests", "must be an object");
|
|
1558
1488
|
}
|
|
1559
|
-
const manifests = /** @type {Record<string, unknown>} */ (
|
|
1560
|
-
manifestsInput ?? {}
|
|
1561
|
-
);
|
|
1489
|
+
const manifests = /** @type {Record<string, unknown>} */ (manifestsInput ?? {});
|
|
1562
1490
|
rejectUnknownKeys(manifests, MANIFEST_KEYS, "publish.manifests.");
|
|
1563
1491
|
|
|
1564
1492
|
const addressInput = publish.address;
|
|
@@ -1589,26 +1517,15 @@ function normalizePublish(value) {
|
|
|
1589
1517
|
DEFAULT_ADDRESS_SCHEME.landing
|
|
1590
1518
|
: optionalString(address.landing, "publish.address.landing");
|
|
1591
1519
|
if (!LANDING_RULES.includes(landing)) {
|
|
1592
|
-
fail(
|
|
1593
|
-
"publish.address.landing",
|
|
1594
|
-
`must be one of ${LANDING_RULES.join(", ")}`,
|
|
1595
|
-
);
|
|
1520
|
+
fail("publish.address.landing", `must be one of ${LANDING_RULES.join(", ")}`);
|
|
1596
1521
|
}
|
|
1597
1522
|
|
|
1598
1523
|
return Object.freeze({
|
|
1599
1524
|
site: normalizeSiteMode(publish.site),
|
|
1600
1525
|
address: Object.freeze({ prefix, landing }),
|
|
1601
1526
|
manifests: Object.freeze({
|
|
1602
|
-
publish: optionalBoolean(
|
|
1603
|
-
|
|
1604
|
-
"publish.manifests.publish",
|
|
1605
|
-
false,
|
|
1606
|
-
),
|
|
1607
|
-
consume: optionalBoolean(
|
|
1608
|
-
manifests.consume,
|
|
1609
|
-
"publish.manifests.consume",
|
|
1610
|
-
false,
|
|
1611
|
-
),
|
|
1527
|
+
publish: optionalBoolean(manifests.publish, "publish.manifests.publish", false),
|
|
1528
|
+
consume: optionalBoolean(manifests.consume, "publish.manifests.consume", false),
|
|
1612
1529
|
}),
|
|
1613
1530
|
});
|
|
1614
1531
|
}
|
|
@@ -1629,13 +1546,9 @@ function normalizePublish(value) {
|
|
|
1629
1546
|
*/
|
|
1630
1547
|
export function defineConfig(config) {
|
|
1631
1548
|
if (!isPlainObject(config)) {
|
|
1632
|
-
throw new TypeError(
|
|
1633
|
-
"package-build config: expected a configuration object.",
|
|
1634
|
-
);
|
|
1549
|
+
throw new TypeError("package-build config: expected a configuration object.");
|
|
1635
1550
|
}
|
|
1636
|
-
const input = /** @type {Record<string, unknown>} */ (
|
|
1637
|
-
/** @type {unknown} */ (config)
|
|
1638
|
-
);
|
|
1551
|
+
const input = /** @type {Record<string, unknown>} */ (/** @type {unknown} */ (config));
|
|
1639
1552
|
rejectUnknownKeys(input, CONFIG_KEYS, "");
|
|
1640
1553
|
|
|
1641
1554
|
const rootDir = requireNonEmptyString(input.rootDir, "rootDir");
|
|
@@ -1650,21 +1563,14 @@ export function defineConfig(config) {
|
|
|
1650
1563
|
const packageKind = input.packageKind;
|
|
1651
1564
|
if (
|
|
1652
1565
|
typeof packageKind !== "string" ||
|
|
1653
|
-
!(
|
|
1654
|
-
/** @type {readonly string[]} */ (PACKAGE_KINDS).includes(
|
|
1655
|
-
packageKind,
|
|
1656
|
-
)
|
|
1657
|
-
)
|
|
1566
|
+
!(/** @type {readonly string[]} */ (PACKAGE_KINDS).includes(packageKind))
|
|
1658
1567
|
) {
|
|
1659
1568
|
fail("packageKind", `must be one of: ${PACKAGE_KINDS.join(", ")}`);
|
|
1660
1569
|
}
|
|
1661
1570
|
|
|
1662
1571
|
if (!Array.isArray(input.packs)) fail("packs", "must be an array");
|
|
1663
|
-
if (input.packs.length === 0)
|
|
1664
|
-
|
|
1665
|
-
const packs = input.packs.map((pack, index) =>
|
|
1666
|
-
normalizePack(pack, `packs[${index}]`),
|
|
1667
|
-
);
|
|
1572
|
+
if (input.packs.length === 0) fail("packs", "must declare at least one pack");
|
|
1573
|
+
const packs = input.packs.map((pack, index) => normalizePack(pack, `packs[${index}]`));
|
|
1668
1574
|
|
|
1669
1575
|
// One list, so the compile order and the directory list cannot disagree —
|
|
1670
1576
|
// they used to be `PACK_CONFIGS` and `SOURCE_PACKS`, maintained apart (#1508).
|
|
@@ -1686,9 +1592,7 @@ export function defineConfig(config) {
|
|
|
1686
1592
|
const declaredSystems = new Set(Object.keys(systems));
|
|
1687
1593
|
/** `relationships.systems`, for the derivations that still consult it. */
|
|
1688
1594
|
const relationshipSystems = /** @type {{id?: string}[]} */ (
|
|
1689
|
-
(isPlainObject(input.relationships) ?
|
|
1690
|
-
input.relationships.systems
|
|
1691
|
-
: null) ?? []
|
|
1595
|
+
(isPlainObject(input.relationships) ? input.relationships.systems : null) ?? []
|
|
1692
1596
|
);
|
|
1693
1597
|
|
|
1694
1598
|
// A name that resolves to nothing is a build error rather than a
|
|
@@ -1747,32 +1651,21 @@ export function defineConfig(config) {
|
|
|
1747
1651
|
defaultsByType.set(pack.type, pack.name);
|
|
1748
1652
|
}
|
|
1749
1653
|
|
|
1750
|
-
if (
|
|
1751
|
-
input.skipDirectories !== undefined &&
|
|
1752
|
-
!Array.isArray(input.skipDirectories)
|
|
1753
|
-
) {
|
|
1654
|
+
if (input.skipDirectories !== undefined && !Array.isArray(input.skipDirectories)) {
|
|
1754
1655
|
fail("skipDirectories", "must be an array");
|
|
1755
1656
|
}
|
|
1756
1657
|
const skipDirectories = (input.skipDirectories ?? []).map((name, index) =>
|
|
1757
1658
|
requireNonEmptyString(name, `skipDirectories[${index}]`),
|
|
1758
1659
|
);
|
|
1759
1660
|
|
|
1760
|
-
const foundryPackage = requireNonEmptyString(
|
|
1761
|
-
input.foundryPackage,
|
|
1762
|
-
"foundryPackage",
|
|
1763
|
-
);
|
|
1661
|
+
const foundryPackage = requireNonEmptyString(input.foundryPackage, "foundryPackage");
|
|
1764
1662
|
|
|
1765
|
-
const { itemBuilders, itemArt, itemFields } = normalizeItemBuilders(
|
|
1766
|
-
input.itemBuilders,
|
|
1767
|
-
);
|
|
1663
|
+
const { itemBuilders, itemArt, itemFields } = normalizeItemBuilders(input.itemBuilders);
|
|
1768
1664
|
const itemTypes = Object.freeze(new Set(Object.keys(itemBuilders)));
|
|
1769
1665
|
|
|
1770
1666
|
return Object.freeze({
|
|
1771
1667
|
rootDir,
|
|
1772
|
-
contentPackage: requireNonEmptyString(
|
|
1773
|
-
input.contentPackage,
|
|
1774
|
-
"contentPackage",
|
|
1775
|
-
),
|
|
1668
|
+
contentPackage: requireNonEmptyString(input.contentPackage, "contentPackage"),
|
|
1776
1669
|
foundryPackage,
|
|
1777
1670
|
packageKind: /** @type {PackageKind} */ (packageKind),
|
|
1778
1671
|
// Foundry serves a package's files from `<kind>/<id>/`, so this is the
|
|
@@ -1798,9 +1691,8 @@ export function defineConfig(config) {
|
|
|
1798
1691
|
// which is the duplication this whole change exists to
|
|
1799
1692
|
// remove. Several entries have no single answer and get
|
|
1800
1693
|
// none.
|
|
1801
|
-
: relationshipSystems.length === 1 ?
|
|
1802
|
-
|
|
1803
|
-
: null,
|
|
1694
|
+
: relationshipSystems.length === 1 ? (relationshipSystems[0]?.id ?? null)
|
|
1695
|
+
: null,
|
|
1804
1696
|
// Derived here where the answer is pure data — the `verified` of
|
|
1805
1697
|
// whichever system the package-wide block takes — and supplied by
|
|
1806
1698
|
// the loader otherwise. The loader is the half that may do I/O, and
|
|
@@ -1811,16 +1703,10 @@ export function defineConfig(config) {
|
|
|
1811
1703
|
(() => {
|
|
1812
1704
|
const id =
|
|
1813
1705
|
requiresSystem ??
|
|
1814
|
-
(Object.keys(systems).length === 1 ?
|
|
1815
|
-
|
|
1816
|
-
: null);
|
|
1817
|
-
return id ?
|
|
1818
|
-
(systems[id]?.compatibility?.verified ?? null)
|
|
1819
|
-
: null;
|
|
1706
|
+
(Object.keys(systems).length === 1 ? Object.keys(systems)[0] : null);
|
|
1707
|
+
return id ? (systems[id]?.compatibility?.verified ?? null) : null;
|
|
1820
1708
|
})() ??
|
|
1821
|
-
(isPlainObject(input.stats) ?
|
|
1822
|
-
input.stats[DERIVED_SYSTEM_VERSION]
|
|
1823
|
-
: null) ??
|
|
1709
|
+
(isPlainObject(input.stats) ? input.stats[DERIVED_SYSTEM_VERSION] : null) ??
|
|
1824
1710
|
null,
|
|
1825
1711
|
}),
|
|
1826
1712
|
itemBuilders,
|
|
@@ -1833,18 +1719,13 @@ export function defineConfig(config) {
|
|
|
1833
1719
|
// runtime. Two would drift, which is the whole reason the composition
|
|
1834
1720
|
// was written down in one place to begin with.
|
|
1835
1721
|
itemTypes,
|
|
1836
|
-
docEntryTypes: Object.freeze(
|
|
1837
|
-
new Set([...itemTypes, "macro", ...MAP_TYPES]),
|
|
1838
|
-
),
|
|
1722
|
+
docEntryTypes: Object.freeze(new Set([...itemTypes, "macro", ...MAP_TYPES])),
|
|
1839
1723
|
skipDirectories: Object.freeze(skipDirectories),
|
|
1840
1724
|
packs: Object.freeze(packs),
|
|
1841
1725
|
packDirectories: Object.freeze(packDirectories),
|
|
1842
1726
|
docs: normalizeDocs(input.docs),
|
|
1843
1727
|
site: normalizeSite(input.site),
|
|
1844
|
-
compatibility: normalizeCompatibility(
|
|
1845
|
-
input.compatibility,
|
|
1846
|
-
"compatibility",
|
|
1847
|
-
),
|
|
1728
|
+
compatibility: normalizeCompatibility(input.compatibility, "compatibility"),
|
|
1848
1729
|
relationships: normalizeRelationships(input.relationships),
|
|
1849
1730
|
systems,
|
|
1850
1731
|
requiresSystem,
|