@wildwinter/toolkit 0.2.6 → 0.3.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 +16 -0
- package/conformance/extensions/defaults.json +1 -1
- package/conformance/extensions/manifest.json +121 -172
- package/conformance/extensions/values.json +0 -86
- package/dist/extensions.cjs +28 -134
- package/dist/extensions.cjs.map +1 -1
- package/dist/extensions.d.cts +2 -48
- package/dist/extensions.d.ts +2 -48
- package/dist/extensions.js +29 -131
- package/dist/extensions.js.map +1 -1
- package/extensions.md +15 -27
- package/package.json +1 -1
package/dist/extensions.cjs
CHANGED
|
@@ -14,13 +14,11 @@ var MANIFEST_FILE_SUFFIX = ".extension.json";
|
|
|
14
14
|
var HOSTS = {
|
|
15
15
|
patter: {
|
|
16
16
|
kinds: ["scene", "block", "snippet", "line", "text", "gameEvent", "option", "project"],
|
|
17
|
-
references: ["cast", "scene", "block", "snippet", "line"]
|
|
18
|
-
claimable: ["scene", "block", "snippet", "line", "text", "gameEvent", "option"]
|
|
17
|
+
references: ["cast", "scene", "block", "snippet", "line"]
|
|
19
18
|
},
|
|
20
19
|
storylets: {
|
|
21
20
|
kinds: ["box", "tagGroup", "tag", "deck", "card", "outcome", "handTemplate", "hand", "project"],
|
|
22
|
-
references: ["box", "deck", "card", "outcome", "tag"]
|
|
23
|
-
claimable: ["card", "outcome"]
|
|
21
|
+
references: ["box", "deck", "card", "outcome", "tag"]
|
|
24
22
|
}
|
|
25
23
|
};
|
|
26
24
|
var SCALAR_TYPES = ["text", "multiline", "number", "boolean", "enum", "flags", "quality"];
|
|
@@ -368,9 +366,14 @@ var VERSION = /^\d+\.\d+\.\d+$/;
|
|
|
368
366
|
var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
369
367
|
var TYPE_KEYS = ["type", "values", "stages", "renamedStages", "to", "from", "fields", "key", "of", "id", "min", "max", "valueHelp", "default"];
|
|
370
368
|
var FIELD_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "name", "label", "help", "required", "group", "editorOnly"]);
|
|
371
|
-
var CLAIM_KEYS = /* @__PURE__ */ new Set([...TYPE_KEYS, "setting", "label", "help", "required"]);
|
|
372
369
|
var BARE_KEYS = new Set(TYPE_KEYS);
|
|
373
|
-
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "
|
|
370
|
+
var MANIFEST_KEYS = /* @__PURE__ */ new Set(["schema", "id", "name", "version", "docs", "targets", "views", "reads"]);
|
|
371
|
+
var REMOVED_MANIFEST_KEYS = {
|
|
372
|
+
settings: "settings were removed with claims; declare the extension's own fields, or a project field for a project-wide value"
|
|
373
|
+
};
|
|
374
|
+
var REMOVED_TARGET_KEYS = {
|
|
375
|
+
claims: "claims on host fields were removed; declare a field of the extension's own, which the runtimes hand the game"
|
|
376
|
+
};
|
|
374
377
|
var VIEW_KEYS = /* @__PURE__ */ new Set(["id", "name", "entry", "element", "hosts"]);
|
|
375
378
|
var ELEMENT = /^[a-z][a-z0-9._]*-[a-z0-9._-]*$/;
|
|
376
379
|
var err2 = (code, path, message) => ({ severity: "error", code, path, message });
|
|
@@ -381,7 +384,7 @@ function manifestProblems(manifest) {
|
|
|
381
384
|
const out = [];
|
|
382
385
|
if (!isObject(manifest)) return [err2("not-an-object", "", "a manifest is a JSON object")];
|
|
383
386
|
const m = manifest;
|
|
384
|
-
unknownKeys(m, MANIFEST_KEYS, "", out);
|
|
387
|
+
unknownKeys(m, MANIFEST_KEYS, "", out, REMOVED_MANIFEST_KEYS);
|
|
385
388
|
if (m["schema"] !== MANIFEST_SCHEMA) {
|
|
386
389
|
out.push(err2("schema", "schema", `the schema tag is ${JSON.stringify(m["schema"])}, not "${MANIFEST_SCHEMA}"`));
|
|
387
390
|
}
|
|
@@ -393,7 +396,6 @@ function manifestProblems(manifest) {
|
|
|
393
396
|
out.push(err2("version", "version", "the version is major.minor.patch, such as 1.0.0"));
|
|
394
397
|
}
|
|
395
398
|
if (m["docs"] !== void 0 && typeof m["docs"] !== "string") out.push(err2("docs", "docs", "docs is a link, as text"));
|
|
396
|
-
const settings = settingsProblems(m["settings"], out);
|
|
397
399
|
viewsProblems(m["views"], m["targets"], out);
|
|
398
400
|
readsProblems(m["reads"], m["id"], out);
|
|
399
401
|
const targets = m["targets"];
|
|
@@ -418,12 +420,16 @@ function manifestProblems(manifest) {
|
|
|
418
420
|
out.push(err2("unknown-kind", kindPath, `"${kind}" is not a node kind of ${host}; it has ${spec.kinds.join(", ")}`));
|
|
419
421
|
continue;
|
|
420
422
|
}
|
|
421
|
-
targetProblems(host,
|
|
423
|
+
targetProblems(host, target, kindPath, out);
|
|
422
424
|
}
|
|
423
425
|
pickListProblems(kinds, hostPath, out);
|
|
424
426
|
}
|
|
425
427
|
return out;
|
|
426
428
|
}
|
|
429
|
+
function pickWords(from) {
|
|
430
|
+
if (!Array.isArray(from)) return [];
|
|
431
|
+
return from.flatMap((s) => isObject(s) && Array.isArray(s["words"]) ? s["words"].filter((w) => typeof w === "string") : []);
|
|
432
|
+
}
|
|
427
433
|
function pickSourcesSound(host, from, path, out) {
|
|
428
434
|
if (!Array.isArray(from) || from.length === 0) {
|
|
429
435
|
out.push(err2("pick-from", path, 'a pick lists its sources in "from": { "words": [...] }, { "to": a node kind }, or { "list": a project list }'));
|
|
@@ -560,81 +566,23 @@ function viewsFor(manifest, host) {
|
|
|
560
566
|
const targeted = Object.keys(manifest.targets ?? {});
|
|
561
567
|
return (Array.isArray(manifest.views) ? manifest.views : []).filter((v) => isObject(v) && typeof v.id === "string" && ID.test(v.id) && typeof v.name === "string" && isViewEntry(v.entry) && typeof v.element === "string" && ELEMENT.test(v.element) && (v.hosts === void 0 ? targeted.includes(host) : Array.isArray(v.hosts) && v.hosts.includes(host)));
|
|
562
568
|
}
|
|
563
|
-
function unknownKeys(obj, known, path, out) {
|
|
569
|
+
function unknownKeys(obj, known, path, out, removed = {}) {
|
|
564
570
|
for (const k of Object.keys(obj)) {
|
|
565
|
-
if (
|
|
571
|
+
if (own(removed, k)) {
|
|
572
|
+
out.push({ severity: "warning", code: "removed-key", path: atKey(path, k), message: `"${k}" is ignored: ${removed[k]}` });
|
|
573
|
+
} else if (!known.has(k)) {
|
|
566
574
|
out.push({ severity: "warning", code: "unknown-key", path: atKey(path, k), message: `"${k}" means nothing here; it is ignored` });
|
|
567
575
|
}
|
|
568
576
|
}
|
|
569
577
|
}
|
|
570
|
-
function
|
|
571
|
-
const names = /* @__PURE__ */ new Set();
|
|
572
|
-
if (settings === void 0) return names;
|
|
573
|
-
if (!Array.isArray(settings)) {
|
|
574
|
-
out.push(err2("not-a-list", "settings", "settings are a list"));
|
|
575
|
-
return names;
|
|
576
|
-
}
|
|
577
|
-
settings.forEach((s, i) => {
|
|
578
|
-
const at = atIndex("settings", i);
|
|
579
|
-
if (!isObject(s)) {
|
|
580
|
-
out.push(err2("not-an-object", at, "a setting is an object"));
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
const name = s["name"];
|
|
584
|
-
if (typeof name !== "string" || !NAME.test(name)) {
|
|
585
|
-
out.push(err2("setting-name", atKey(at, "name"), "a setting's name is an identifier"));
|
|
586
|
-
} else if (names.has(name)) {
|
|
587
|
-
out.push(err2("setting-duplicate", atKey(at, "name"), `setting "${name}" is declared twice`));
|
|
588
|
-
} else {
|
|
589
|
-
names.add(name);
|
|
590
|
-
}
|
|
591
|
-
const dflt = s.default;
|
|
592
|
-
if (typeof dflt !== "string" || !NAME.test(dflt)) {
|
|
593
|
-
out.push(err2("setting-default", atKey(at, "default"), "a setting names a host field by default, so its default is a field name"));
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
return names;
|
|
597
|
-
}
|
|
598
|
-
function targetProblems(host, kind, target, path, settings, out) {
|
|
578
|
+
function targetProblems(host, target, path, out) {
|
|
599
579
|
if (!isObject(target)) {
|
|
600
580
|
out.push(err2("not-an-object", path, "a target is an object"));
|
|
601
581
|
return;
|
|
602
582
|
}
|
|
603
|
-
unknownKeys(target, /* @__PURE__ */ new Set(["fields"
|
|
583
|
+
unknownKeys(target, /* @__PURE__ */ new Set(["fields"]), path, out, REMOVED_TARGET_KEYS);
|
|
604
584
|
const t = target;
|
|
605
585
|
if (t.fields !== void 0) fieldListProblems(host, t.fields, atKey(path, "fields"), true, out);
|
|
606
|
-
if (t.claims === void 0) return;
|
|
607
|
-
if (!Array.isArray(t.claims)) {
|
|
608
|
-
out.push(err2("not-a-list", atKey(path, "claims"), "claims are a list"));
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
const claimable = HOSTS[host].claimable.includes(kind);
|
|
612
|
-
const claimed = /* @__PURE__ */ new Set();
|
|
613
|
-
t.claims.forEach((c, i) => {
|
|
614
|
-
const at = atIndex(atKey(path, "claims"), i);
|
|
615
|
-
if (!claimable) {
|
|
616
|
-
out.push(err2("claim-kind", at, `a ${kind} has no host fields to claim; ${host} has them on ${HOSTS[host].claimable.join(", ")}`));
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
if (!isObject(c)) {
|
|
620
|
-
out.push(err2("not-an-object", at, "a claim is an object"));
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
const claim = c;
|
|
624
|
-
unknownKeys(c, CLAIM_KEYS, at, out);
|
|
625
|
-
if (!SCALAR_TYPES.includes(claim.type)) {
|
|
626
|
-
out.push(err2("claim-type", atKey(at, "type"), "a claim presents a host field, which is a scalar"));
|
|
627
|
-
} else {
|
|
628
|
-
typeProblems(host, claim, at, false, out, true);
|
|
629
|
-
}
|
|
630
|
-
if (typeof claim.setting !== "string" || !settings.has(claim.setting)) {
|
|
631
|
-
out.push(err2("claim-setting", atKey(at, "setting"), `a claim names its field through a setting, and "${String(claim.setting)}" is not one of the manifest's settings`));
|
|
632
|
-
} else if (claimed.has(claim.setting)) {
|
|
633
|
-
out.push(err2("claim-duplicate", atKey(at, "setting"), `setting "${claim.setting}" is claimed twice for one kind`));
|
|
634
|
-
} else {
|
|
635
|
-
claimed.add(claim.setting);
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
586
|
}
|
|
639
587
|
function fieldListProblems(host, fields, path, topLevel, out) {
|
|
640
588
|
if (!Array.isArray(fields)) {
|
|
@@ -668,7 +616,7 @@ function fieldListProblems(host, fields, path, topLevel, out) {
|
|
|
668
616
|
}
|
|
669
617
|
});
|
|
670
618
|
}
|
|
671
|
-
function typeProblems(host, decl, path, named, out
|
|
619
|
+
function typeProblems(host, decl, path, named, out) {
|
|
672
620
|
const typeAt = atKey(path, "type");
|
|
673
621
|
if (decl.type === "string") {
|
|
674
622
|
out.push(err2("string-type", typeAt, 'the text type is spelled "text"'));
|
|
@@ -684,7 +632,6 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
684
632
|
case "enum":
|
|
685
633
|
case "flags": {
|
|
686
634
|
const values = decl.values;
|
|
687
|
-
if (claim && values === void 0) break;
|
|
688
635
|
if (!Array.isArray(values) || values.length === 0) {
|
|
689
636
|
out.push(err2("values-empty", at("values"), `an ${decl.type === "enum" ? "enum" : "flags field"} lists its values`));
|
|
690
637
|
sound = false;
|
|
@@ -703,7 +650,6 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
703
650
|
break;
|
|
704
651
|
}
|
|
705
652
|
case "quality": {
|
|
706
|
-
if (claim && decl.stages === void 0) break;
|
|
707
653
|
for (const p of expr.qualityDeclarationProblems(decl.stages)) {
|
|
708
654
|
out.push(err2(
|
|
709
655
|
`quality-${p.kind === "default-not-a-stage" ? "default" : p.kind}`,
|
|
@@ -766,17 +712,15 @@ function typeProblems(host, decl, path, named, out, claim = false) {
|
|
|
766
712
|
}
|
|
767
713
|
}
|
|
768
714
|
if (decl.renamedStages !== void 0) renamedStagesProblems(decl, at("renamedStages"), out);
|
|
769
|
-
if (decl.valueHelp !== void 0
|
|
770
|
-
|
|
771
|
-
out.push(err2("value-help", at("valueHelp"), "value help describes the values of an enum or flags field, or a quality's stages"));
|
|
772
|
-
}
|
|
773
|
-
} else if (decl.valueHelp !== void 0) {
|
|
774
|
-
const vocabulary = decl.type === "quality" ? decl.stages : decl.type === "enum" || decl.type === "flags" ? decl.values : void 0;
|
|
715
|
+
if (decl.valueHelp !== void 0) {
|
|
716
|
+
const vocabulary = decl.type === "quality" ? decl.stages : decl.type === "enum" || decl.type === "flags" ? decl.values : decl.type === "pick" ? pickWords(decl.from) : void 0;
|
|
775
717
|
if (vocabulary === void 0 || !isObject(decl.valueHelp)) {
|
|
776
|
-
out.push(err2("value-help", at("valueHelp"), "value help describes the values of an enum or flags field, or a
|
|
718
|
+
out.push(err2("value-help", at("valueHelp"), "value help describes the values of an enum or flags field, a quality's stages, or a pick's words"));
|
|
777
719
|
} else {
|
|
778
720
|
for (const k of Object.keys(decl.valueHelp)) {
|
|
779
|
-
if (!vocabulary.includes(k))
|
|
721
|
+
if (!vocabulary.includes(k)) {
|
|
722
|
+
out.push(err2("value-help", atKey(at("valueHelp"), k), decl.type === "pick" ? `"${k}" is not one of its words: value help describes a pick's fixed words, never the project's lists or nodes` : `"${k}" is not one of its values`));
|
|
723
|
+
}
|
|
780
724
|
}
|
|
781
725
|
}
|
|
782
726
|
}
|
|
@@ -809,56 +753,10 @@ function renamedStagesProblems(decl, path, out) {
|
|
|
809
753
|
}
|
|
810
754
|
}
|
|
811
755
|
}
|
|
812
|
-
function settingValues(manifest, chosen) {
|
|
813
|
-
const out = {};
|
|
814
|
-
for (const s of manifest.settings ?? []) {
|
|
815
|
-
const v = chosen !== void 0 && own(chosen, s.name) ? chosen[s.name] : void 0;
|
|
816
|
-
out[s.name] = typeof v === "string" && v !== "" ? v : s.default;
|
|
817
|
-
}
|
|
818
|
-
return out;
|
|
819
|
-
}
|
|
820
|
-
function resolvedClaims(manifest, host, chosen) {
|
|
821
|
-
const settings = settingValues(manifest, chosen);
|
|
822
|
-
const out = [];
|
|
823
|
-
for (const [kind, target] of Object.entries(manifest.targets[host] ?? {})) {
|
|
824
|
-
for (const claim of target.claims ?? []) {
|
|
825
|
-
const field = settings[claim.setting];
|
|
826
|
-
if (field !== void 0) out.push({ extension: manifest.id, host, kind, field, claim });
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
return out;
|
|
830
|
-
}
|
|
831
|
-
function claimClashes(claims) {
|
|
832
|
-
const out = [];
|
|
833
|
-
const first = /* @__PURE__ */ new Map();
|
|
834
|
-
for (const c of claims) {
|
|
835
|
-
const key = `${c.host}\0${c.kind}\0${c.field}`;
|
|
836
|
-
const prior = first.get(key);
|
|
837
|
-
if (prior === void 0) {
|
|
838
|
-
first.set(key, c);
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
if (prior.extension === c.extension) continue;
|
|
842
|
-
out.push(err2(
|
|
843
|
-
"claim-clash",
|
|
844
|
-
`${c.kind}.${c.field}`,
|
|
845
|
-
`extensions "${prior.extension}" and "${c.extension}" both claim the ${c.kind} field "${c.field}"`
|
|
846
|
-
));
|
|
847
|
-
}
|
|
848
|
-
return out;
|
|
849
|
-
}
|
|
850
756
|
function targetOf(manifest, host, kind) {
|
|
851
757
|
const kinds = manifest?.targets[host];
|
|
852
758
|
return kinds !== void 0 && own(kinds, kind) ? kinds[kind] : void 0;
|
|
853
759
|
}
|
|
854
|
-
function effectiveClaim(claim, hostDecl) {
|
|
855
|
-
return {
|
|
856
|
-
...claim,
|
|
857
|
-
...claim.values === void 0 && hostDecl.values !== void 0 ? { values: hostDecl.values } : {},
|
|
858
|
-
...claim.stages === void 0 && hostDecl.stages !== void 0 ? { stages: hostDecl.stages } : {},
|
|
859
|
-
...claim.default === void 0 && hostDecl.default !== void 0 ? { default: hostDecl.default } : {}
|
|
860
|
-
};
|
|
861
|
-
}
|
|
862
760
|
|
|
863
761
|
// src/extensions/merge.ts
|
|
864
762
|
var ATOMIC = { kind: "atomic" };
|
|
@@ -1208,11 +1106,9 @@ exports.UNRESOLVED_KEY = UNRESOLVED_KEY;
|
|
|
1208
1106
|
exports.VALUE_TYPES = VALUE_TYPES;
|
|
1209
1107
|
exports.atIndex = atIndex;
|
|
1210
1108
|
exports.atKey = atKey;
|
|
1211
|
-
exports.claimClashes = claimClashes;
|
|
1212
1109
|
exports.compileEntry = compileEntry;
|
|
1213
1110
|
exports.compiledTarget = compiledTarget;
|
|
1214
1111
|
exports.defaultOf = defaultOf;
|
|
1215
|
-
exports.effectiveClaim = effectiveClaim;
|
|
1216
1112
|
exports.entryProblems = entryProblems;
|
|
1217
1113
|
exports.extensionDataStrategy = extensionDataStrategy;
|
|
1218
1114
|
exports.isTextList = isTextList;
|
|
@@ -1231,8 +1127,6 @@ exports.pickChoices = pickChoices;
|
|
|
1231
1127
|
exports.pickClashes = pickClashes;
|
|
1232
1128
|
exports.pickLists = pickLists;
|
|
1233
1129
|
exports.renameStages = renameStages;
|
|
1234
|
-
exports.resolvedClaims = resolvedClaims;
|
|
1235
|
-
exports.settingValues = settingValues;
|
|
1236
1130
|
exports.stableStringify = stableStringify;
|
|
1237
1131
|
exports.strategyForTarget = strategyForTarget;
|
|
1238
1132
|
exports.strategyForType = strategyForType;
|