@dreamboard-games/sdk 0.5.0-alpha.2 → 0.5.0-alpha.3
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 +136 -45
- package/dist/chunk-DMFVAZI2.js +16 -0
- package/dist/chunk-DMFVAZI2.js.map +1 -0
- package/dist/chunk-FMM5LVJW.js +833 -0
- package/dist/chunk-FMM5LVJW.js.map +1 -0
- package/dist/{chunk-S2JEDVWH.js → chunk-LRILEVKC.js} +6113 -6489
- package/dist/chunk-LRILEVKC.js.map +1 -0
- package/dist/chunk-SP234IY4.js +1363 -0
- package/dist/chunk-SP234IY4.js.map +1 -0
- package/dist/chunk-VUWNJXLJ.js +52 -0
- package/dist/chunk-VUWNJXLJ.js.map +1 -0
- package/dist/chunk-ZPRKWPEP.js +511 -0
- package/dist/chunk-ZPRKWPEP.js.map +1 -0
- package/dist/definition-BaHNPZol.d.ts +4639 -0
- package/dist/diagnostics-B0lgnuZ6.d.ts +65 -0
- package/dist/index.d.ts +3553 -1
- package/dist/index.js +1045 -6
- package/dist/index.js.map +1 -1
- package/dist/model-BHro6yXu.d.ts +288 -0
- package/dist/react.d.ts +32 -0
- package/dist/react.js +80 -0
- package/dist/react.js.map +1 -0
- package/dist/reducer.d.ts +1194 -79
- package/dist/reducer.js +4326 -121
- package/dist/reducer.js.map +1 -1
- package/dist/testing.d.ts +518 -564
- package/dist/testing.js +2448 -915
- package/dist/testing.js.map +1 -1
- package/dist/types-DimqnJBq.d.ts +86 -0
- package/package.json +26 -131
- package/dist/HandView-Bi2lxzQP.d.ts +0 -79
- package/dist/ResourceCounter-BFxJknqp.d.ts +0 -98
- package/dist/ThemeProvider-CElaL2ik.d.ts +0 -99
- package/dist/attributes-DbvyMbXw.d.ts +0 -68
- package/dist/browser-interaction.d.ts +0 -910
- package/dist/browser-interaction.js +0 -119
- package/dist/browser-interaction.js.map +0 -1
- package/dist/chunk-32PFKDV7.js +0 -11705
- package/dist/chunk-32PFKDV7.js.map +0 -1
- package/dist/chunk-3BAD4VC2.js +0 -263
- package/dist/chunk-3BAD4VC2.js.map +0 -1
- package/dist/chunk-3SKDNDPG.js +0 -104
- package/dist/chunk-3SKDNDPG.js.map +0 -1
- package/dist/chunk-5YV2WHJ4.js +0 -25
- package/dist/chunk-5YV2WHJ4.js.map +0 -1
- package/dist/chunk-ANRB4XKA.js +0 -90
- package/dist/chunk-ANRB4XKA.js.map +0 -1
- package/dist/chunk-BI4G3PM2.js +0 -1864
- package/dist/chunk-BI4G3PM2.js.map +0 -1
- package/dist/chunk-EVCLTY4Q.js +0 -935
- package/dist/chunk-EVCLTY4Q.js.map +0 -1
- package/dist/chunk-GDPKTBUR.js +0 -564
- package/dist/chunk-GDPKTBUR.js.map +0 -1
- package/dist/chunk-H6VDGFL5.js +0 -2903
- package/dist/chunk-H6VDGFL5.js.map +0 -1
- package/dist/chunk-LR3ZTWQF.js +0 -5960
- package/dist/chunk-LR3ZTWQF.js.map +0 -1
- package/dist/chunk-PF7L4BMG.js +0 -117
- package/dist/chunk-PF7L4BMG.js.map +0 -1
- package/dist/chunk-PN5O6GG2.js +0 -32
- package/dist/chunk-PN5O6GG2.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-S2JEDVWH.js.map +0 -1
- package/dist/chunk-T3ZKNUZ7.js +0 -1
- package/dist/chunk-T3ZKNUZ7.js.map +0 -1
- package/dist/chunk-UGH54WZ2.js +0 -223
- package/dist/chunk-UGH54WZ2.js.map +0 -1
- package/dist/chunk-VCDWP5VL.js +0 -746
- package/dist/chunk-VCDWP5VL.js.map +0 -1
- package/dist/chunk-VDXOF4FW.js +0 -69
- package/dist/chunk-VDXOF4FW.js.map +0 -1
- package/dist/chunk-WHR5UW3F.js +0 -1988
- package/dist/chunk-WHR5UW3F.js.map +0 -1
- package/dist/chunk-Y75CFE77.js +0 -17
- package/dist/chunk-Y75CFE77.js.map +0 -1
- package/dist/chunk-Z7QCREWI.js +0 -3435
- package/dist/chunk-Z7QCREWI.js.map +0 -1
- package/dist/chunk-ZZGN2ATS.js +0 -1941
- package/dist/chunk-ZZGN2ATS.js.map +0 -1
- package/dist/components-gAbIz7hK.d.ts +0 -1284
- package/dist/definitions-BgmV_GhC.d.ts +0 -300
- package/dist/diagnostics-DIi3ina7.d.ts +0 -50
- package/dist/digest.d.ts +0 -8
- package/dist/game-CsZScpcn.d.ts +0 -763
- package/dist/hex-board-view-aKkblDp6.d.ts +0 -1228
- package/dist/index-CcT9Q7N7.d.ts +0 -193
- package/dist/index.d-DjzoK7zn.d.ts +0 -2101
- package/dist/package-set.d.ts +0 -13
- package/dist/package-set.js +0 -12
- package/dist/package-set.js.map +0 -1
- package/dist/player-state-Cqpyeql0.d.ts +0 -371
- package/dist/plugin-runtime-contract.d.ts +0 -17
- package/dist/plugin-runtime-contract.js +0 -92
- package/dist/plugin-runtime-contract.js.map +0 -1
- package/dist/primitive-props-BNHDkgd7.d.ts +0 -16
- package/dist/protocol-dYgafTYY.d.ts +0 -314
- package/dist/reducer/advanced.d.ts +0 -82
- package/dist/reducer/advanced.js +0 -51
- package/dist/reducer/advanced.js.map +0 -1
- package/dist/reducer-contract.d.ts +0 -11
- package/dist/reducer-contract.js +0 -16
- package/dist/reducer-contract.js.map +0 -1
- package/dist/reference-games/index.d.ts +0 -31
- package/dist/reference-games/index.js +0 -48
- package/dist/reference-games/index.js.map +0 -1
- package/dist/runtime/primitives.d.ts +0 -250
- package/dist/runtime/primitives.js +0 -189
- package/dist/runtime/primitives.js.map +0 -1
- package/dist/runtime/runtime-api.d.ts +0 -2
- package/dist/runtime/runtime-api.js +0 -1
- package/dist/runtime/runtime-api.js.map +0 -1
- package/dist/runtime/workspace-contract.d.ts +0 -392
- package/dist/runtime/workspace-contract.js +0 -28
- package/dist/runtime/workspace-contract.js.map +0 -1
- package/dist/runtime-RJ5orDJU.d.ts +0 -1699
- package/dist/runtime-api-Bz5pwNU_.d.ts +0 -296
- package/dist/runtime-json-CQ9QbLZ5.d.ts +0 -5
- package/dist/runtime.d.ts +0 -83
- package/dist/runtime.js +0 -242
- package/dist/runtime.js.map +0 -1
- package/dist/schema.d.ts +0 -379
- package/dist/stale-contract-artifact-error-XLaweZtF.d.ts +0 -18
- package/dist/testing-compiler.d.ts +0 -37
- package/dist/testing-compiler.js +0 -272
- package/dist/testing-compiler.js.map +0 -1
- package/dist/testing-runtime.d.ts +0 -119
- package/dist/testing-runtime.js +0 -212
- package/dist/testing-runtime.js.map +0 -1
- package/dist/types-DJj5MJkl.d.ts +0 -256
- package/dist/types-DR7DoB1x.d.ts +0 -28
- package/dist/types-JWCYHmu7.d.ts +0 -122
- package/dist/types.d.ts +0 -1958
- package/dist/types.js +0 -14
- package/dist/types.js.map +0 -1
- package/dist/ui/components.d.ts +0 -17
- package/dist/ui/components.js +0 -216
- package/dist/ui/components.js.map +0 -1
- package/dist/ui/defaults.d.ts +0 -19
- package/dist/ui/defaults.js +0 -104
- package/dist/ui/defaults.js.map +0 -1
- package/dist/ui/player-state.d.ts +0 -2
- package/dist/ui/player-state.js +0 -1
- package/dist/ui/player-state.js.map +0 -1
- package/dist/ui/plugin-styles.css +0 -2
- package/dist/ui-contract-GTUPkf8z.d.ts +0 -1168
- package/dist/ui.d.ts +0 -317
- package/dist/ui.js +0 -277
- package/dist/ui.js.map +0 -1
- package/dist/views-BpuWcOyN.d.ts +0 -1641
package/dist/chunk-ZZGN2ATS.js
DELETED
|
@@ -1,1941 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
asPlayerId,
|
|
3
|
-
assumeManifestSchema,
|
|
4
|
-
cardInput,
|
|
5
|
-
cardTarget,
|
|
6
|
-
createManifestGameStateSchema,
|
|
7
|
-
createManifestRuntimeSchema,
|
|
8
|
-
createManifestStringLiteralSchema,
|
|
9
|
-
createTargetRule,
|
|
10
|
-
createTargetRuleBuilder,
|
|
11
|
-
isManifestScopedSchema,
|
|
12
|
-
isPerPlayer,
|
|
13
|
-
markManifestScopedSchema,
|
|
14
|
-
perPlayer,
|
|
15
|
-
perPlayerSchema
|
|
16
|
-
} from "./chunk-H6VDGFL5.js";
|
|
17
|
-
import {
|
|
18
|
-
buildTypedRecord
|
|
19
|
-
} from "./chunk-5YV2WHJ4.js";
|
|
20
|
-
import {
|
|
21
|
-
analyzeManifest,
|
|
22
|
-
materializeManifestTable
|
|
23
|
-
} from "./chunk-Z7QCREWI.js";
|
|
24
|
-
|
|
25
|
-
// src/reducer/schema-helpers.ts
|
|
26
|
-
import { z } from "zod";
|
|
27
|
-
var sparseSchemas = /* @__PURE__ */ new WeakMap();
|
|
28
|
-
function sparseMap(keySchema, valueSchema) {
|
|
29
|
-
const schema = z.partialRecord(keySchema, valueSchema);
|
|
30
|
-
sparseSchemas.set(schema, {
|
|
31
|
-
keySchema,
|
|
32
|
-
valueSchema
|
|
33
|
-
});
|
|
34
|
-
return schema;
|
|
35
|
-
}
|
|
36
|
-
function sparseCounts(keySchema) {
|
|
37
|
-
return sparseMap(keySchema, z.number().int().min(0));
|
|
38
|
-
}
|
|
39
|
-
function getZodDef(schema) {
|
|
40
|
-
const anySchema = schema;
|
|
41
|
-
const fromInternal = anySchema?._zod?.def;
|
|
42
|
-
if (fromInternal && typeof fromInternal === "object") {
|
|
43
|
-
return fromInternal;
|
|
44
|
-
}
|
|
45
|
-
const fromLegacy = anySchema?.def;
|
|
46
|
-
if (fromLegacy && typeof fromLegacy === "object") {
|
|
47
|
-
return fromLegacy;
|
|
48
|
-
}
|
|
49
|
-
return {};
|
|
50
|
-
}
|
|
51
|
-
function unwrapWrappers(schema) {
|
|
52
|
-
let current = schema;
|
|
53
|
-
while (true) {
|
|
54
|
-
const def = getZodDef(current);
|
|
55
|
-
const innerType = def.innerType;
|
|
56
|
-
if ((def.type === "nullable" || def.type === "optional" || def.type === "default" || def.type === "readonly" || def.type === "catch") && innerType) {
|
|
57
|
-
current = innerType;
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
return current;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function isPlainZodString(schema) {
|
|
64
|
-
return getZodDef(schema).type === "string";
|
|
65
|
-
}
|
|
66
|
-
function isZodArray(schema) {
|
|
67
|
-
return getZodDef(schema).type === "array";
|
|
68
|
-
}
|
|
69
|
-
function isEnumKeyedRecordSchema(schema) {
|
|
70
|
-
const def = getZodDef(schema);
|
|
71
|
-
const keyType = def.keyType;
|
|
72
|
-
return def.type === "record" && typeof keyType === "object" && keyType !== null && getZodDef(keyType).type === "enum";
|
|
73
|
-
}
|
|
74
|
-
function isSparseMapSchema(schema) {
|
|
75
|
-
const inner = unwrapWrappers(schema);
|
|
76
|
-
return typeof inner === "object" && inner !== null && sparseSchemas.has(inner);
|
|
77
|
-
}
|
|
78
|
-
function getSparseSchemaMetadata(schema) {
|
|
79
|
-
const inner = unwrapWrappers(schema);
|
|
80
|
-
if (typeof inner !== "object" || inner === null) {
|
|
81
|
-
return void 0;
|
|
82
|
-
}
|
|
83
|
-
return sparseSchemas.get(inner);
|
|
84
|
-
}
|
|
85
|
-
function isPlainObject(value) {
|
|
86
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
87
|
-
}
|
|
88
|
-
function getObjectShape(schema) {
|
|
89
|
-
const def = getZodDef(schema);
|
|
90
|
-
if (def.type !== "object") {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
const shape = def.shape;
|
|
94
|
-
if (typeof shape === "function") {
|
|
95
|
-
const resolved = shape();
|
|
96
|
-
return resolved && typeof resolved === "object" ? resolved : null;
|
|
97
|
-
}
|
|
98
|
-
return shape && typeof shape === "object" ? shape : null;
|
|
99
|
-
}
|
|
100
|
-
function normalizeSchemaInput(schema, input) {
|
|
101
|
-
const inner = unwrapWrappers(schema);
|
|
102
|
-
const sparse = getSparseSchemaMetadata(inner);
|
|
103
|
-
if (sparse && isPlainObject(input)) {
|
|
104
|
-
const filtered = Object.fromEntries(
|
|
105
|
-
Object.entries(input).filter(
|
|
106
|
-
([key, value]) => typeof value !== "undefined" && sparse.keySchema.safeParse(key).success
|
|
107
|
-
).map(([key, value]) => [
|
|
108
|
-
key,
|
|
109
|
-
normalizeSchemaInput(sparse.valueSchema, value)
|
|
110
|
-
])
|
|
111
|
-
);
|
|
112
|
-
return filtered;
|
|
113
|
-
}
|
|
114
|
-
const shape = getObjectShape(inner);
|
|
115
|
-
if (shape && isPlainObject(input)) {
|
|
116
|
-
return Object.fromEntries(
|
|
117
|
-
Object.entries(input).map(([key, value]) => {
|
|
118
|
-
const fieldSchema = shape[key];
|
|
119
|
-
return [
|
|
120
|
-
key,
|
|
121
|
-
typeof fieldSchema === "undefined" ? value : normalizeSchemaInput(fieldSchema, value)
|
|
122
|
-
];
|
|
123
|
-
})
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const def = getZodDef(inner);
|
|
127
|
-
if (def.type === "array" && Array.isArray(input) && def.element) {
|
|
128
|
-
return input.map((value) => normalizeSchemaInput(def.element, value));
|
|
129
|
-
}
|
|
130
|
-
return input;
|
|
131
|
-
}
|
|
132
|
-
function normalizeCommandParams(schema, input) {
|
|
133
|
-
return schema.parse(normalizeSchemaInput(schema, input));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// src/reducer/inputs/defineInputs.ts
|
|
137
|
-
var InputBuilder = class {
|
|
138
|
-
add(key, collector) {
|
|
139
|
-
return { key, collector };
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
function defineInputs(define) {
|
|
143
|
-
const refs = define(new InputBuilder());
|
|
144
|
-
return Object.fromEntries(
|
|
145
|
-
Object.entries(refs).map(([key, ref]) => [key, ref.collector])
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// src/reducer/inputs/many.ts
|
|
150
|
-
import { z as z2 } from "zod";
|
|
151
|
-
function normalizeManyOptions(options) {
|
|
152
|
-
if ("count" in options) {
|
|
153
|
-
assertNonNegativeInteger(options.count, "many(...).count");
|
|
154
|
-
return {
|
|
155
|
-
mode: "many",
|
|
156
|
-
min: options.count,
|
|
157
|
-
max: options.count,
|
|
158
|
-
distinct: options.distinct
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
const min = options.min ?? 0;
|
|
162
|
-
assertNonNegativeInteger(min, "many(...).min");
|
|
163
|
-
if (options.max !== void 0) {
|
|
164
|
-
assertNonNegativeInteger(options.max, "many(...).max");
|
|
165
|
-
if (options.max < min) {
|
|
166
|
-
throw new Error("many(...).max must be greater than or equal to min.");
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
mode: "many",
|
|
171
|
-
min,
|
|
172
|
-
max: options.max,
|
|
173
|
-
distinct: options.distinct
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
function assertNonNegativeInteger(value, label) {
|
|
177
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
178
|
-
throw new Error(`${label} must be a non-negative integer.`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
function many(collector, options) {
|
|
182
|
-
if (collector.kind === "rng") {
|
|
183
|
-
throw new Error("many(...) cannot wrap rngInput collectors.");
|
|
184
|
-
}
|
|
185
|
-
const selection = normalizeManyOptions(options);
|
|
186
|
-
const rest = { ...collector };
|
|
187
|
-
delete rest.schema;
|
|
188
|
-
delete rest.selection;
|
|
189
|
-
delete rest.defaultValue;
|
|
190
|
-
return {
|
|
191
|
-
...rest,
|
|
192
|
-
schema: z2.array(
|
|
193
|
-
collector.schema
|
|
194
|
-
),
|
|
195
|
-
selection
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// src/reducer/inputs/formInput.ts
|
|
200
|
-
import { z as z3 } from "zod";
|
|
201
|
-
function isResourceMapChoiceSource(choices) {
|
|
202
|
-
return choices === "resourceMap" || typeof choices === "object" && choices !== null && !Array.isArray(choices) && "source" in choices && choices.source === "resourceMap";
|
|
203
|
-
}
|
|
204
|
-
function resolveDomainNumber(value, context, fallback) {
|
|
205
|
-
if (typeof value === "function") return value(context);
|
|
206
|
-
return value ?? fallback;
|
|
207
|
-
}
|
|
208
|
-
function resolveDomainChoices(choices, context) {
|
|
209
|
-
if (isResourceMapChoiceSource(choices)) {
|
|
210
|
-
return resolveResourceMapChoices(choices, context);
|
|
211
|
-
}
|
|
212
|
-
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
213
|
-
return resolved.map((choice) => ({
|
|
214
|
-
value: choice.value,
|
|
215
|
-
label: choice.label,
|
|
216
|
-
icon: choice.icon,
|
|
217
|
-
badge: choice.badge,
|
|
218
|
-
description: choice.description,
|
|
219
|
-
disabled: choice.disabled,
|
|
220
|
-
disabledReason: choice.disabledReason
|
|
221
|
-
}));
|
|
222
|
-
}
|
|
223
|
-
function resolveDependentDomainChoices(choices, context) {
|
|
224
|
-
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
225
|
-
return resolved.map((choice) => ({
|
|
226
|
-
value: choice.value,
|
|
227
|
-
label: choice.label,
|
|
228
|
-
icon: choice.icon,
|
|
229
|
-
badge: choice.badge,
|
|
230
|
-
description: choice.description,
|
|
231
|
-
disabled: choice.disabled,
|
|
232
|
-
disabledReason: choice.disabledReason
|
|
233
|
-
}));
|
|
234
|
-
}
|
|
235
|
-
function choiceValuesInclude(choices, value) {
|
|
236
|
-
return choices.some((choice) => Object.is(choice.value, value));
|
|
237
|
-
}
|
|
238
|
-
function assertChoiceDefaultInChoices(inputName, choices, defaultValue) {
|
|
239
|
-
if (choiceValuesInclude(choices, defaultValue)) return;
|
|
240
|
-
const printable = defaultValue === null ? "null" : `'${defaultValue}'`;
|
|
241
|
-
throw new Error(
|
|
242
|
-
`${inputName} defaultValue ${printable} must be one of its choices. If null is a valid value, add an explicit { value: null, label: ... } choice.`
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
function choiceSchema(choices) {
|
|
246
|
-
const values = choices.map((choice) => choice.value);
|
|
247
|
-
const stringValues = values.filter(
|
|
248
|
-
(value) => value !== null
|
|
249
|
-
);
|
|
250
|
-
const hasNull = values.some((value) => value === null);
|
|
251
|
-
if (stringValues.length === 0) {
|
|
252
|
-
return z3.null();
|
|
253
|
-
}
|
|
254
|
-
const stringSchema = z3.enum(
|
|
255
|
-
stringValues
|
|
256
|
-
);
|
|
257
|
-
if (hasNull) {
|
|
258
|
-
return z3.union([stringSchema, z3.null()]);
|
|
259
|
-
}
|
|
260
|
-
return stringSchema;
|
|
261
|
-
}
|
|
262
|
-
function resolveResourceMapChoices(choices, context) {
|
|
263
|
-
const resources = context.state.table.resources;
|
|
264
|
-
const firstResourceMap = isPerPlayer(resources) && resources.entries.length > 0 ? resources.entries[0]?.[1] : resources;
|
|
265
|
-
if (typeof firstResourceMap !== "object" || firstResourceMap === null || Array.isArray(firstResourceMap)) {
|
|
266
|
-
return [];
|
|
267
|
-
}
|
|
268
|
-
const decorate = choices === "resourceMap" ? void 0 : choices.decorate;
|
|
269
|
-
return Object.keys(firstResourceMap).sort().map((resourceId) => {
|
|
270
|
-
const label = resourceId;
|
|
271
|
-
const presentation = decorate?.({ ...context, resourceId, label });
|
|
272
|
-
return {
|
|
273
|
-
value: resourceId,
|
|
274
|
-
label,
|
|
275
|
-
badge: presentation?.badge,
|
|
276
|
-
description: presentation?.description,
|
|
277
|
-
disabled: presentation?.disabled,
|
|
278
|
-
disabledReason: presentation?.disabledReason
|
|
279
|
-
};
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
function createFormInput(schema, options) {
|
|
283
|
-
return {
|
|
284
|
-
kind: "form",
|
|
285
|
-
schema,
|
|
286
|
-
...options && "defaultValue" in options ? { defaultValue: options.defaultValue } : {}
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
function baseFormInput(schema, options) {
|
|
290
|
-
return createFormInput(schema, options);
|
|
291
|
-
}
|
|
292
|
-
function resourceMapInput(options) {
|
|
293
|
-
return {
|
|
294
|
-
kind: "form",
|
|
295
|
-
schema: z3.record(z3.string(), z3.number().int().nonnegative()),
|
|
296
|
-
..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
|
|
297
|
-
domain: (state, playerId, q, derived) => {
|
|
298
|
-
const context = {
|
|
299
|
-
state,
|
|
300
|
-
playerId,
|
|
301
|
-
q,
|
|
302
|
-
derived,
|
|
303
|
-
values: {}
|
|
304
|
-
};
|
|
305
|
-
return {
|
|
306
|
-
type: "resourceMap",
|
|
307
|
-
resources: options.resources.map((resource) => ({
|
|
308
|
-
resourceId: resource.resourceId,
|
|
309
|
-
label: resource.label,
|
|
310
|
-
icon: resource.icon,
|
|
311
|
-
min: resolveDomainNumber(resource.min, context, 0),
|
|
312
|
-
max: resolveDomainNumber(resource.max, context, 0)
|
|
313
|
-
}))
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
function numberInput(options) {
|
|
319
|
-
return {
|
|
320
|
-
kind: "form",
|
|
321
|
-
schema: z3.number(),
|
|
322
|
-
..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
|
|
323
|
-
domain: (state, playerId, q, derived) => {
|
|
324
|
-
const context = {
|
|
325
|
-
state,
|
|
326
|
-
playerId,
|
|
327
|
-
q,
|
|
328
|
-
derived,
|
|
329
|
-
values: {}
|
|
330
|
-
};
|
|
331
|
-
return {
|
|
332
|
-
type: "boundedNumber",
|
|
333
|
-
min: resolveDomainNumber(options.min, context, 0),
|
|
334
|
-
max: resolveDomainNumber(options.max, context, 0),
|
|
335
|
-
step: options.step === void 0 ? void 0 : resolveDomainNumber(options.step, context, 1)
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
function choiceInput(options) {
|
|
341
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
342
|
-
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
343
|
-
throw new Error("formInput.choice requires at least one choice.");
|
|
344
|
-
}
|
|
345
|
-
const staticChoices = Array.isArray(options.choices) ? options.choices : null;
|
|
346
|
-
const hasStaticDefault = typeof options.defaultValue !== "function";
|
|
347
|
-
const staticDefault = options.defaultValue;
|
|
348
|
-
if (staticChoices && hasStaticDefault) {
|
|
349
|
-
assertChoiceDefaultInChoices(
|
|
350
|
-
"formInput.choice",
|
|
351
|
-
staticChoices,
|
|
352
|
-
staticDefault
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
const schema = staticChoices ? choiceSchema(staticChoices) : z3.string().nullable();
|
|
356
|
-
const dynamicDefault = typeof options.defaultValue === "function" ? options.defaultValue : void 0;
|
|
357
|
-
return {
|
|
358
|
-
kind: "form",
|
|
359
|
-
schema,
|
|
360
|
-
...hasStaticDefault ? { defaultValue: staticDefault } : {},
|
|
361
|
-
...dependsOn ? { dependsOn } : {},
|
|
362
|
-
domain: (state, playerId, q, derived, values) => {
|
|
363
|
-
const context = {
|
|
364
|
-
state,
|
|
365
|
-
playerId,
|
|
366
|
-
q,
|
|
367
|
-
derived
|
|
368
|
-
};
|
|
369
|
-
const choices = dependsOn ? resolveDependentDomainChoices(
|
|
370
|
-
options.choices,
|
|
371
|
-
{
|
|
372
|
-
...context,
|
|
373
|
-
values: values ?? {}
|
|
374
|
-
}
|
|
375
|
-
) : resolveDomainChoices(options.choices, {
|
|
376
|
-
...context,
|
|
377
|
-
values: {}
|
|
378
|
-
});
|
|
379
|
-
if (hasStaticDefault) {
|
|
380
|
-
assertChoiceDefaultInChoices(
|
|
381
|
-
"formInput.choice",
|
|
382
|
-
choices,
|
|
383
|
-
staticDefault
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
return {
|
|
387
|
-
type: "choice",
|
|
388
|
-
choices
|
|
389
|
-
};
|
|
390
|
-
},
|
|
391
|
-
...dynamicDefault ? {
|
|
392
|
-
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
393
|
-
const choices = domain.type === "choice" ? domain.choices.map((choice) => ({
|
|
394
|
-
value: choice.value,
|
|
395
|
-
label: choice.label,
|
|
396
|
-
icon: choice.icon,
|
|
397
|
-
badge: choice.badge,
|
|
398
|
-
description: choice.description,
|
|
399
|
-
disabled: choice.disabled,
|
|
400
|
-
disabledReason: choice.disabledReason
|
|
401
|
-
})) : [];
|
|
402
|
-
const resolved = dynamicDefault({
|
|
403
|
-
state,
|
|
404
|
-
playerId,
|
|
405
|
-
q,
|
|
406
|
-
derived,
|
|
407
|
-
values: {},
|
|
408
|
-
choices
|
|
409
|
-
});
|
|
410
|
-
if (resolved === void 0) return void 0;
|
|
411
|
-
assertChoiceDefaultInChoices("formInput.choice", choices, resolved);
|
|
412
|
-
return resolved;
|
|
413
|
-
}
|
|
414
|
-
} : {}
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
function choiceListInput(options) {
|
|
418
|
-
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
419
|
-
throw new Error("formInput.choiceList requires at least one choice.");
|
|
420
|
-
}
|
|
421
|
-
const staticDefaultValue = Array.isArray(options.defaultValue) ? options.defaultValue : void 0;
|
|
422
|
-
const dynamicDefaultValue = options.defaultValue === "all" || typeof options.defaultValue === "function" ? options.defaultValue : void 0;
|
|
423
|
-
return {
|
|
424
|
-
kind: "form",
|
|
425
|
-
schema: z3.array(z3.string()),
|
|
426
|
-
...staticDefaultValue !== void 0 ? { defaultValue: staticDefaultValue } : {},
|
|
427
|
-
domain: (state, playerId, q, derived) => {
|
|
428
|
-
const context = {
|
|
429
|
-
state,
|
|
430
|
-
playerId,
|
|
431
|
-
q,
|
|
432
|
-
derived,
|
|
433
|
-
values: {}
|
|
434
|
-
};
|
|
435
|
-
const choices = resolveDomainChoices(options.choices, context).map(
|
|
436
|
-
(choice) => ({
|
|
437
|
-
...choice,
|
|
438
|
-
value: choice.value
|
|
439
|
-
})
|
|
440
|
-
);
|
|
441
|
-
return {
|
|
442
|
-
type: "choiceList",
|
|
443
|
-
choices,
|
|
444
|
-
min: resolveDomainNumber(options.min, context, 0),
|
|
445
|
-
max: resolveDomainNumber(options.max, context, choices.length)
|
|
446
|
-
};
|
|
447
|
-
},
|
|
448
|
-
...dynamicDefaultValue ? {
|
|
449
|
-
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
450
|
-
const choices = domain.type === "choiceList" ? domain.choices.map((choice) => ({
|
|
451
|
-
value: choice.value,
|
|
452
|
-
label: choice.label,
|
|
453
|
-
icon: choice.icon,
|
|
454
|
-
badge: choice.badge,
|
|
455
|
-
description: choice.description,
|
|
456
|
-
disabled: choice.disabled,
|
|
457
|
-
disabledReason: choice.disabledReason
|
|
458
|
-
})) : [];
|
|
459
|
-
if (dynamicDefaultValue === "all") {
|
|
460
|
-
return choices.map((choice) => choice.value);
|
|
461
|
-
}
|
|
462
|
-
return dynamicDefaultValue({
|
|
463
|
-
state,
|
|
464
|
-
playerId,
|
|
465
|
-
q,
|
|
466
|
-
derived,
|
|
467
|
-
values: {},
|
|
468
|
-
choices
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
} : {}
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
function formInputForState() {
|
|
475
|
-
return Object.assign(
|
|
476
|
-
((schema, options) => baseFormInput(schema, options)),
|
|
477
|
-
{
|
|
478
|
-
resourceMap: (options) => resourceMapInput(options),
|
|
479
|
-
resourceChoices: (options) => formInput.resourceChoices(options),
|
|
480
|
-
number: (options) => numberInput(options),
|
|
481
|
-
choice: (options) => choiceInput(options),
|
|
482
|
-
choiceList: (options) => choiceListInput(options)
|
|
483
|
-
}
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
var formInput = Object.assign(baseFormInput, {
|
|
487
|
-
resourceMap: resourceMapInput,
|
|
488
|
-
resourceChoices: (options) => ({
|
|
489
|
-
source: "resourceMap",
|
|
490
|
-
...options
|
|
491
|
-
}),
|
|
492
|
-
number: numberInput,
|
|
493
|
-
choice: choiceInput,
|
|
494
|
-
choiceList: choiceListInput,
|
|
495
|
-
forState: formInputForState
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
// src/reducer/inputs/boardInput.ts
|
|
499
|
-
import { z as z4 } from "zod";
|
|
500
|
-
function makeBoardCollector(kind) {
|
|
501
|
-
return function collector(options) {
|
|
502
|
-
const target = options.target;
|
|
503
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
504
|
-
return {
|
|
505
|
-
kind,
|
|
506
|
-
schema: z4.string(),
|
|
507
|
-
eligibleTargets: ((state, playerId, q, values) => target.eligible({
|
|
508
|
-
state,
|
|
509
|
-
playerId,
|
|
510
|
-
q,
|
|
511
|
-
values
|
|
512
|
-
})),
|
|
513
|
-
validateTarget: ((state, playerId, q, targetId, values) => target.validate(
|
|
514
|
-
{
|
|
515
|
-
state,
|
|
516
|
-
playerId,
|
|
517
|
-
q,
|
|
518
|
-
values
|
|
519
|
-
},
|
|
520
|
-
targetId
|
|
521
|
-
)),
|
|
522
|
-
...dependsOn ? { dependsOn } : {},
|
|
523
|
-
domain: (state, playerId, q, _derived, values) => ({
|
|
524
|
-
type: "boardTarget",
|
|
525
|
-
projection: "resolved",
|
|
526
|
-
targetKind: target.targetKind,
|
|
527
|
-
boardId: target.boardId,
|
|
528
|
-
valueKind: target.valueKind,
|
|
529
|
-
eligibleTargets: target.eligible({
|
|
530
|
-
state,
|
|
531
|
-
playerId,
|
|
532
|
-
q,
|
|
533
|
-
values
|
|
534
|
-
}).map(String)
|
|
535
|
-
}),
|
|
536
|
-
meta: {
|
|
537
|
-
targetKind: target.targetKind,
|
|
538
|
-
boardId: target.boardId,
|
|
539
|
-
valueKind: target.valueKind
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
var vertexInput = makeBoardCollector("board-vertex");
|
|
545
|
-
var edgeInput = makeBoardCollector("board-edge");
|
|
546
|
-
var tileInput = makeBoardCollector("board-tile");
|
|
547
|
-
var spaceInput = makeBoardCollector("board-space");
|
|
548
|
-
function playerSpaceInput(options) {
|
|
549
|
-
const target = options.target;
|
|
550
|
-
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
551
|
-
const playerIdSchema = markManifestScopedSchema(
|
|
552
|
-
z4.string(),
|
|
553
|
-
"playerId"
|
|
554
|
-
);
|
|
555
|
-
return {
|
|
556
|
-
kind: "board-space",
|
|
557
|
-
schema: z4.object({
|
|
558
|
-
boardId: z4.literal(target.boardId),
|
|
559
|
-
playerId: playerIdSchema,
|
|
560
|
-
spaceId: z4.string()
|
|
561
|
-
}),
|
|
562
|
-
eligibleTargets: ((state, playerId, q, values) => target.eligible({
|
|
563
|
-
state,
|
|
564
|
-
playerId,
|
|
565
|
-
q,
|
|
566
|
-
values
|
|
567
|
-
})),
|
|
568
|
-
validateTarget: ((state, playerId, q, targetValue, values) => target.validate(
|
|
569
|
-
{
|
|
570
|
-
state,
|
|
571
|
-
playerId,
|
|
572
|
-
q,
|
|
573
|
-
values
|
|
574
|
-
},
|
|
575
|
-
targetValue
|
|
576
|
-
)),
|
|
577
|
-
...dependsOn ? { dependsOn } : {},
|
|
578
|
-
domain: (state, playerId, q, _derived, values) => ({
|
|
579
|
-
type: "boardTarget",
|
|
580
|
-
projection: "resolved",
|
|
581
|
-
targetKind: target.targetKind,
|
|
582
|
-
boardId: target.boardId,
|
|
583
|
-
valueKind: target.valueKind,
|
|
584
|
-
eligibleTargets: target.eligible({
|
|
585
|
-
state,
|
|
586
|
-
playerId,
|
|
587
|
-
q,
|
|
588
|
-
values
|
|
589
|
-
}).map((candidate) => candidate.spaceId)
|
|
590
|
-
}),
|
|
591
|
-
meta: {
|
|
592
|
-
targetKind: target.targetKind,
|
|
593
|
-
boardId: target.boardId,
|
|
594
|
-
valueKind: target.valueKind
|
|
595
|
-
}
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
var boardInput = {
|
|
599
|
-
vertex: vertexInput,
|
|
600
|
-
edge: edgeInput,
|
|
601
|
-
tile: tileInput,
|
|
602
|
-
space: spaceInput,
|
|
603
|
-
playerSpace: playerSpaceInput
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
// src/reducer/inputs/boardTarget.ts
|
|
607
|
-
function candidateIdsForKind(q, boardId, targetKind) {
|
|
608
|
-
if (targetKind === "edge") {
|
|
609
|
-
return idsFromCollection(q.board.tiled(boardId).edges);
|
|
610
|
-
}
|
|
611
|
-
if (targetKind === "vertex") {
|
|
612
|
-
return idsFromCollection(q.board.tiled(boardId).vertices);
|
|
613
|
-
}
|
|
614
|
-
return idsFromCollection(q.board.get(boardId)?.spaces);
|
|
615
|
-
}
|
|
616
|
-
function idsFromCollection(collection) {
|
|
617
|
-
if (!collection) return [];
|
|
618
|
-
const values = Array.isArray(collection) ? collection : Object.values(collection);
|
|
619
|
-
return values.flatMap((value) => {
|
|
620
|
-
if (typeof value === "string") return [value];
|
|
621
|
-
if (typeof value === "object" && value !== null && "id" in value && typeof value.id === "string") {
|
|
622
|
-
return [value.id];
|
|
623
|
-
}
|
|
624
|
-
return [];
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
function createBoardTargetBuilder(targetKind, boardId) {
|
|
628
|
-
return createTargetRuleBuilder(
|
|
629
|
-
(predicates) => ({
|
|
630
|
-
...createTargetRule(
|
|
631
|
-
({ q }) => candidateIdsForKind(q, boardId, targetKind),
|
|
632
|
-
predicates,
|
|
633
|
-
{
|
|
634
|
-
missingCandidateIssue: {
|
|
635
|
-
errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
|
|
636
|
-
message: "Board target is not eligible."
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
),
|
|
640
|
-
boardId,
|
|
641
|
-
targetKind,
|
|
642
|
-
valueKind: "board-id"
|
|
643
|
-
})
|
|
644
|
-
);
|
|
645
|
-
}
|
|
646
|
-
function createPlayerSpaceTargetBuilder(boardId) {
|
|
647
|
-
return createTargetRuleBuilder(
|
|
648
|
-
(predicates) => ({
|
|
649
|
-
...createTargetRule(
|
|
650
|
-
({ state, q }) => {
|
|
651
|
-
const spacesForPlayer = (playerId) => candidateIdsForKind(
|
|
652
|
-
q,
|
|
653
|
-
`${boardId}:${playerId}`,
|
|
654
|
-
"space"
|
|
655
|
-
);
|
|
656
|
-
return state.table.playerOrder.flatMap(
|
|
657
|
-
(playerId) => spacesForPlayer(playerId).map((spaceId) => ({
|
|
658
|
-
boardId,
|
|
659
|
-
playerId,
|
|
660
|
-
spaceId
|
|
661
|
-
}))
|
|
662
|
-
);
|
|
663
|
-
},
|
|
664
|
-
predicates,
|
|
665
|
-
{
|
|
666
|
-
missingCandidateIssue: {
|
|
667
|
-
errorCode: "BOARD_TARGET_NOT_ELIGIBLE",
|
|
668
|
-
message: "Board target is not eligible."
|
|
669
|
-
},
|
|
670
|
-
equals: (left, right) => isPlayerBoardSpaceTarget(left) && isPlayerBoardSpaceTarget(right) && left.boardId === right.boardId && left.playerId === right.playerId && left.spaceId === right.spaceId
|
|
671
|
-
}
|
|
672
|
-
),
|
|
673
|
-
boardId,
|
|
674
|
-
targetKind: "space",
|
|
675
|
-
valueKind: "player-board-space"
|
|
676
|
-
})
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
function isPlayerBoardSpaceTarget(value) {
|
|
680
|
-
return typeof value === "object" && value !== null && "boardId" in value && "playerId" in value && "spaceId" in value;
|
|
681
|
-
}
|
|
682
|
-
function makeBoardTargetFactory(targetKind) {
|
|
683
|
-
return function target(boardId) {
|
|
684
|
-
return createBoardTargetBuilder(targetKind, boardId);
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
var boardTarget = {
|
|
688
|
-
edge: makeBoardTargetFactory("edge"),
|
|
689
|
-
vertex: makeBoardTargetFactory("vertex"),
|
|
690
|
-
space: makeBoardTargetFactory("space"),
|
|
691
|
-
tile: makeBoardTargetFactory("tile"),
|
|
692
|
-
playerSpace(boardId) {
|
|
693
|
-
return createPlayerSpaceTargetBuilder(boardId);
|
|
694
|
-
}
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
// src/reducer/inputs/choiceTarget.ts
|
|
698
|
-
function normalizeOptions(options) {
|
|
699
|
-
if (typeof options === "function") return options;
|
|
700
|
-
return () => options;
|
|
701
|
-
}
|
|
702
|
-
function createChoiceTargetBuilder(options) {
|
|
703
|
-
const optionsFactory = normalizeOptions(options);
|
|
704
|
-
return createTargetRuleBuilder(
|
|
705
|
-
(predicates) => {
|
|
706
|
-
const baseRule = createTargetRule(
|
|
707
|
-
(ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).map(
|
|
708
|
-
(option) => option.id
|
|
709
|
-
),
|
|
710
|
-
predicates,
|
|
711
|
-
{
|
|
712
|
-
missingCandidateIssue: {
|
|
713
|
-
errorCode: "CHOICE_TARGET_NOT_ELIGIBLE",
|
|
714
|
-
message: "Choice target is not eligible."
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
);
|
|
718
|
-
return {
|
|
719
|
-
...baseRule,
|
|
720
|
-
targetKind: "choice",
|
|
721
|
-
options: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q),
|
|
722
|
-
eligibleOptions: (ctx) => optionsFactory(ctx.state, ctx.playerId, ctx.q).filter(
|
|
723
|
-
(option) => baseRule.isEligible(ctx, option.id)
|
|
724
|
-
)
|
|
725
|
-
};
|
|
726
|
-
}
|
|
727
|
-
);
|
|
728
|
-
}
|
|
729
|
-
var choiceTarget = {
|
|
730
|
-
options(options) {
|
|
731
|
-
return createChoiceTargetBuilder(options);
|
|
732
|
-
}
|
|
733
|
-
};
|
|
734
|
-
|
|
735
|
-
// src/reducer/inputs/promptInput.ts
|
|
736
|
-
function promptInput(options) {
|
|
737
|
-
const target = options.target;
|
|
738
|
-
return {
|
|
739
|
-
kind: "prompt",
|
|
740
|
-
schema: options.schema,
|
|
741
|
-
eligibleTargets: target ? ((state, playerId, q) => target.eligible({
|
|
742
|
-
state,
|
|
743
|
-
playerId,
|
|
744
|
-
q
|
|
745
|
-
})) : void 0,
|
|
746
|
-
validateTarget: target ? ((state, playerId, q, targetId) => target.validate(
|
|
747
|
-
{
|
|
748
|
-
state,
|
|
749
|
-
playerId,
|
|
750
|
-
q
|
|
751
|
-
},
|
|
752
|
-
targetId
|
|
753
|
-
)) : void 0,
|
|
754
|
-
meta: target ? {
|
|
755
|
-
options: (state, playerId, q) => target.options({
|
|
756
|
-
state,
|
|
757
|
-
playerId,
|
|
758
|
-
q
|
|
759
|
-
}),
|
|
760
|
-
eligibleOptions: (state, playerId, q) => target.eligibleOptions({
|
|
761
|
-
state,
|
|
762
|
-
playerId,
|
|
763
|
-
q
|
|
764
|
-
})
|
|
765
|
-
} : void 0,
|
|
766
|
-
domain: (state, playerId, q) => ({
|
|
767
|
-
type: "choice",
|
|
768
|
-
choices: target ? target.options({
|
|
769
|
-
state,
|
|
770
|
-
playerId,
|
|
771
|
-
q
|
|
772
|
-
}).map((option) => ({
|
|
773
|
-
value: String(option.id),
|
|
774
|
-
label: option.label ?? String(option.id)
|
|
775
|
-
})) : []
|
|
776
|
-
})
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// src/reducer/inputs/rngInput.ts
|
|
781
|
-
import { z as z5 } from "zod";
|
|
782
|
-
function d6(count = 1) {
|
|
783
|
-
return {
|
|
784
|
-
kind: "rng",
|
|
785
|
-
schema: z5.object({
|
|
786
|
-
values: z5.array(z5.number().int().min(1).max(6)).length(count)
|
|
787
|
-
}),
|
|
788
|
-
meta: { rng: "d6", count }
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
function coin() {
|
|
792
|
-
return {
|
|
793
|
-
kind: "rng",
|
|
794
|
-
schema: z5.object({
|
|
795
|
-
value: z5.enum(["heads", "tails"])
|
|
796
|
-
}),
|
|
797
|
-
meta: { rng: "coin" }
|
|
798
|
-
};
|
|
799
|
-
}
|
|
800
|
-
var rngInput = { d6, coin };
|
|
801
|
-
|
|
802
|
-
// src/reducer/manifest/compiler.ts
|
|
803
|
-
import { z as z7 } from "zod";
|
|
804
|
-
|
|
805
|
-
// src/reducer/manifest/schema.ts
|
|
806
|
-
import { z as z6 } from "zod";
|
|
807
|
-
function createTableSchema(analysis, ids) {
|
|
808
|
-
const unknownRecordSchema = z6.record(z6.string(), z6.unknown());
|
|
809
|
-
const objectSchema = (schema) => schema && Object.keys(schema.properties).length ? z6.object(
|
|
810
|
-
Object.fromEntries(
|
|
811
|
-
Object.entries(schema.properties).map(([key, value]) => [
|
|
812
|
-
key,
|
|
813
|
-
propertySchema(value)
|
|
814
|
-
])
|
|
815
|
-
)
|
|
816
|
-
) : unknownRecordSchema;
|
|
817
|
-
function propertySchema(schema) {
|
|
818
|
-
if (!schema) return z6.unknown();
|
|
819
|
-
let result;
|
|
820
|
-
switch (schema.type) {
|
|
821
|
-
case "string":
|
|
822
|
-
result = z6.string();
|
|
823
|
-
break;
|
|
824
|
-
case "integer":
|
|
825
|
-
result = z6.number().int();
|
|
826
|
-
break;
|
|
827
|
-
case "number":
|
|
828
|
-
result = z6.number();
|
|
829
|
-
break;
|
|
830
|
-
case "boolean":
|
|
831
|
-
result = z6.boolean();
|
|
832
|
-
break;
|
|
833
|
-
case "enum":
|
|
834
|
-
result = schema.enums?.length ? z6.enum(schema.enums) : z6.string();
|
|
835
|
-
break;
|
|
836
|
-
case "array":
|
|
837
|
-
result = z6.array(propertySchema(schema.items));
|
|
838
|
-
break;
|
|
839
|
-
case "record":
|
|
840
|
-
result = z6.record(z6.string(), propertySchema(schema.values));
|
|
841
|
-
break;
|
|
842
|
-
case "object":
|
|
843
|
-
result = objectSchema({ properties: schema.properties ?? {} });
|
|
844
|
-
break;
|
|
845
|
-
default:
|
|
846
|
-
result = ids[schema.type];
|
|
847
|
-
}
|
|
848
|
-
if (schema.nullable) result = result.nullable();
|
|
849
|
-
if (schema.optional) result = result.optional();
|
|
850
|
-
if (Object.prototype.hasOwnProperty.call(schema, "default"))
|
|
851
|
-
result = result.default(schema.default);
|
|
852
|
-
return result;
|
|
853
|
-
}
|
|
854
|
-
const shape = (items, getKey, getSchema) => z6.object(
|
|
855
|
-
Object.fromEntries(items.map((item) => [getKey(item), getSchema(item)]))
|
|
856
|
-
);
|
|
857
|
-
const cardStateByIdSchema = shape(
|
|
858
|
-
analysis.cardIds,
|
|
859
|
-
(id) => id,
|
|
860
|
-
(id) => {
|
|
861
|
-
const setId = analysis.cardSetIdByCardId.get(id);
|
|
862
|
-
const type = analysis.cardTypeByCardId.get(id);
|
|
863
|
-
const schema = analysis.cardSets.find(
|
|
864
|
-
(set) => set.id === setId
|
|
865
|
-
).cardSchema;
|
|
866
|
-
const properties = schema && "variants" in schema ? objectSchema({
|
|
867
|
-
properties: {
|
|
868
|
-
...schema.shared,
|
|
869
|
-
...schema.variants[type]?.properties
|
|
870
|
-
}
|
|
871
|
-
}) : objectSchema(schema);
|
|
872
|
-
return z6.object({
|
|
873
|
-
componentType: z6.string().optional(),
|
|
874
|
-
id: z6.literal(id),
|
|
875
|
-
cardSetId: z6.literal(setId),
|
|
876
|
-
cardType: z6.literal(type),
|
|
877
|
-
name: z6.string().optional(),
|
|
878
|
-
text: z6.string().optional(),
|
|
879
|
-
properties
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
);
|
|
883
|
-
const pieceStateByIdSchema = shape(
|
|
884
|
-
analysis.pieceIds,
|
|
885
|
-
(id) => id,
|
|
886
|
-
(id) => {
|
|
887
|
-
const type = analysis.pieceTypeIdByPieceId.get(id);
|
|
888
|
-
return z6.object({
|
|
889
|
-
componentType: z6.string().optional(),
|
|
890
|
-
id: z6.literal(id),
|
|
891
|
-
pieceTypeId: z6.literal(type),
|
|
892
|
-
pieceName: z6.string().nullish(),
|
|
893
|
-
ownerId: ids.playerId.nullish(),
|
|
894
|
-
properties: objectSchema(analysis.pieceTypeSchemasById.get(type))
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
);
|
|
898
|
-
const dieStateByIdSchema = shape(
|
|
899
|
-
analysis.dieIds,
|
|
900
|
-
(id) => id,
|
|
901
|
-
(id) => {
|
|
902
|
-
const type = analysis.dieTypeIdByDieId.get(id);
|
|
903
|
-
return z6.object({
|
|
904
|
-
componentType: z6.string().optional(),
|
|
905
|
-
id: z6.literal(id),
|
|
906
|
-
dieTypeId: z6.literal(type),
|
|
907
|
-
dieName: z6.string().nullish(),
|
|
908
|
-
ownerId: ids.playerId.nullish(),
|
|
909
|
-
sides: z6.literal(
|
|
910
|
-
analysis.manifest.dieTypes?.find((die) => die.id === type)?.sides ?? 6
|
|
911
|
-
),
|
|
912
|
-
value: z6.number().int().nullish(),
|
|
913
|
-
properties: objectSchema(analysis.dieTypeSchemasById.get(type))
|
|
914
|
-
});
|
|
915
|
-
}
|
|
916
|
-
);
|
|
917
|
-
const sharedZoneSchema = shape(
|
|
918
|
-
analysis.sharedZones,
|
|
919
|
-
(zone) => zone.id,
|
|
920
|
-
() => z6.array(ids.cardId)
|
|
921
|
-
);
|
|
922
|
-
const playerZoneSchema = shape(
|
|
923
|
-
analysis.playerZones,
|
|
924
|
-
(zone) => zone.id,
|
|
925
|
-
() => perPlayerSchema(z6.array(ids.cardId))
|
|
926
|
-
);
|
|
927
|
-
const zoneIdSchema = ids.zoneId;
|
|
928
|
-
const playerZoneIdSchema = ids.playerZoneId;
|
|
929
|
-
const slotVariants = analysis.strictSlotHosts.flatMap(
|
|
930
|
-
(host) => host.slotIds.map(
|
|
931
|
-
(slotId) => z6.object({
|
|
932
|
-
type: z6.literal("InSlot"),
|
|
933
|
-
host: z6.object({ kind: z6.literal(host.kind), id: z6.literal(host.id) }),
|
|
934
|
-
slotId: z6.literal(slotId),
|
|
935
|
-
position: z6.number().int().nullish()
|
|
936
|
-
})
|
|
937
|
-
)
|
|
938
|
-
);
|
|
939
|
-
const slotLocationSchema = slotVariants.length ? z6.union(
|
|
940
|
-
slotVariants
|
|
941
|
-
) : z6.never();
|
|
942
|
-
const boardSpaceTypeIdSchema = ids.spaceTypeId.nullable().optional();
|
|
943
|
-
const boardSpaceStateSchema = z6.object({
|
|
944
|
-
id: ids.spaceId,
|
|
945
|
-
name: z6.string().nullable().optional(),
|
|
946
|
-
typeId: boardSpaceTypeIdSchema,
|
|
947
|
-
fields: unknownRecordSchema,
|
|
948
|
-
zoneId: z6.string().nullable().optional()
|
|
949
|
-
});
|
|
950
|
-
const hexSpaceStateSchema = boardSpaceStateSchema.extend({
|
|
951
|
-
q: z6.number().int(),
|
|
952
|
-
r: z6.number().int()
|
|
953
|
-
});
|
|
954
|
-
const squareSpaceStateSchema = boardSpaceStateSchema.extend({
|
|
955
|
-
row: z6.number().int(),
|
|
956
|
-
col: z6.number().int()
|
|
957
|
-
});
|
|
958
|
-
const boardRelationStateSchema = z6.object({
|
|
959
|
-
id: z6.string().nullable().optional(),
|
|
960
|
-
typeId: ids.relationTypeId,
|
|
961
|
-
fromSpaceId: ids.spaceId,
|
|
962
|
-
toSpaceId: ids.spaceId,
|
|
963
|
-
directed: z6.boolean(),
|
|
964
|
-
fields: unknownRecordSchema
|
|
965
|
-
});
|
|
966
|
-
const boardContainerStateSchema = z6.object({
|
|
967
|
-
id: ids.boardContainerId,
|
|
968
|
-
name: z6.string(),
|
|
969
|
-
host: z6.discriminatedUnion("type", [
|
|
970
|
-
z6.object({ type: z6.literal("board") }),
|
|
971
|
-
z6.object({ type: z6.literal("space"), spaceId: ids.spaceId })
|
|
972
|
-
]),
|
|
973
|
-
allowedCardSetIds: z6.array(ids.cardSetId).optional(),
|
|
974
|
-
zoneId: z6.string(),
|
|
975
|
-
fields: unknownRecordSchema
|
|
976
|
-
});
|
|
977
|
-
const runtimeGenericBoardStateSchema = z6.object({
|
|
978
|
-
id: ids.boardId,
|
|
979
|
-
baseId: ids.boardBaseId,
|
|
980
|
-
layout: z6.literal("generic"),
|
|
981
|
-
typeId: ids.boardTypeId.nullable().optional(),
|
|
982
|
-
scope: z6.enum(["shared", "perPlayer"]),
|
|
983
|
-
playerId: ids.playerId.nullable().optional(),
|
|
984
|
-
templateId: z6.string().nullable().optional(),
|
|
985
|
-
fields: unknownRecordSchema,
|
|
986
|
-
// T220: per-board state.spaces is loose-keyed by string. See the
|
|
987
|
-
// codegen-template comment in renderGenericBoardStateSchema for
|
|
988
|
-
// the rationale; the wire shape is unchanged (additionalProperties
|
|
989
|
-
// JSON), and the inner id field narrows at parse time.
|
|
990
|
-
spaces: z6.record(z6.string(), boardSpaceStateSchema),
|
|
991
|
-
relations: z6.array(boardRelationStateSchema),
|
|
992
|
-
containers: z6.record(z6.string(), boardContainerStateSchema)
|
|
993
|
-
});
|
|
994
|
-
const hexEdgeStateSchema = z6.object({
|
|
995
|
-
id: ids.edgeId,
|
|
996
|
-
spaceIds: z6.array(ids.spaceId).min(1).max(2),
|
|
997
|
-
typeId: ids.edgeTypeId.nullable().optional(),
|
|
998
|
-
label: z6.string().nullable().optional(),
|
|
999
|
-
ownerId: ids.playerId.nullable().optional(),
|
|
1000
|
-
fields: unknownRecordSchema
|
|
1001
|
-
});
|
|
1002
|
-
const hexVertexStateSchema = z6.object({
|
|
1003
|
-
id: ids.vertexId,
|
|
1004
|
-
spaceIds: z6.array(ids.spaceId).min(1).max(3),
|
|
1005
|
-
typeId: ids.vertexTypeId.nullable().optional(),
|
|
1006
|
-
label: z6.string().nullable().optional(),
|
|
1007
|
-
ownerId: ids.playerId.nullable().optional(),
|
|
1008
|
-
fields: unknownRecordSchema
|
|
1009
|
-
});
|
|
1010
|
-
const squareVertexStateSchema = z6.object({
|
|
1011
|
-
id: ids.vertexId,
|
|
1012
|
-
spaceIds: z6.array(ids.spaceId).min(1).max(4),
|
|
1013
|
-
typeId: ids.vertexTypeId.nullable().optional(),
|
|
1014
|
-
label: z6.string().nullable().optional(),
|
|
1015
|
-
ownerId: ids.playerId.nullable().optional(),
|
|
1016
|
-
fields: unknownRecordSchema
|
|
1017
|
-
});
|
|
1018
|
-
const runtimeHexBoardStateSchema = runtimeGenericBoardStateSchema.extend({
|
|
1019
|
-
layout: z6.literal("hex"),
|
|
1020
|
-
// T220: loose-keyed by string — see comment above.
|
|
1021
|
-
spaces: z6.record(z6.string(), hexSpaceStateSchema),
|
|
1022
|
-
relations: z6.array(boardRelationStateSchema),
|
|
1023
|
-
containers: z6.object({}),
|
|
1024
|
-
orientation: z6.enum(["pointy-top", "flat-top"]),
|
|
1025
|
-
edges: z6.array(hexEdgeStateSchema),
|
|
1026
|
-
vertices: z6.array(hexVertexStateSchema)
|
|
1027
|
-
});
|
|
1028
|
-
const runtimeSquareBoardStateSchema = runtimeGenericBoardStateSchema.extend({
|
|
1029
|
-
layout: z6.literal("square"),
|
|
1030
|
-
// T220: loose-keyed by string — see comment above.
|
|
1031
|
-
spaces: z6.record(z6.string(), squareSpaceStateSchema),
|
|
1032
|
-
relations: z6.array(boardRelationStateSchema),
|
|
1033
|
-
containers: z6.record(z6.string(), boardContainerStateSchema),
|
|
1034
|
-
edges: z6.array(hexEdgeStateSchema),
|
|
1035
|
-
vertices: z6.array(squareVertexStateSchema)
|
|
1036
|
-
});
|
|
1037
|
-
const boards = analysis.analyzedBoards.flatMap(
|
|
1038
|
-
(board) => board.runtimeBoardIds.map((id) => {
|
|
1039
|
-
const base = {
|
|
1040
|
-
id: board.board.scope === "perPlayer" ? z6.templateLiteral([board.board.id, ":", z6.string().min(1)]) : z6.literal(id),
|
|
1041
|
-
baseId: z6.literal(board.board.id),
|
|
1042
|
-
scope: z6.literal(board.board.scope),
|
|
1043
|
-
fields: objectSchema(board.boardFieldsSchema)
|
|
1044
|
-
};
|
|
1045
|
-
const spaces = boardSpaceStateSchema.extend({
|
|
1046
|
-
fields: objectSchema(board.spaceFieldsSchema)
|
|
1047
|
-
});
|
|
1048
|
-
const relations = z6.array(
|
|
1049
|
-
boardRelationStateSchema.extend({
|
|
1050
|
-
fields: objectSchema(
|
|
1051
|
-
"relationFieldsSchema" in board ? board.relationFieldsSchema : void 0
|
|
1052
|
-
)
|
|
1053
|
-
})
|
|
1054
|
-
);
|
|
1055
|
-
const containers = "containers" in board ? shape(
|
|
1056
|
-
board.containers,
|
|
1057
|
-
(item) => item.id,
|
|
1058
|
-
(item) => boardContainerStateSchema.extend({
|
|
1059
|
-
id: z6.literal(item.id),
|
|
1060
|
-
fields: objectSchema(board.containerFieldsSchema)
|
|
1061
|
-
})
|
|
1062
|
-
) : z6.object({});
|
|
1063
|
-
if (board.layout === "generic")
|
|
1064
|
-
return {
|
|
1065
|
-
id,
|
|
1066
|
-
scope: board.board.scope,
|
|
1067
|
-
layout: board.layout,
|
|
1068
|
-
schema: runtimeGenericBoardStateSchema.extend({
|
|
1069
|
-
...base,
|
|
1070
|
-
spaces: z6.record(z6.string(), spaces),
|
|
1071
|
-
relations,
|
|
1072
|
-
containers
|
|
1073
|
-
})
|
|
1074
|
-
};
|
|
1075
|
-
const edges = z6.array(
|
|
1076
|
-
hexEdgeStateSchema.extend({
|
|
1077
|
-
fields: objectSchema(board.edgeFieldsSchema)
|
|
1078
|
-
})
|
|
1079
|
-
);
|
|
1080
|
-
const vertices = z6.array(
|
|
1081
|
-
(board.layout === "hex" ? hexVertexStateSchema : squareVertexStateSchema).extend({ fields: objectSchema(board.vertexFieldsSchema) })
|
|
1082
|
-
);
|
|
1083
|
-
return {
|
|
1084
|
-
id,
|
|
1085
|
-
scope: board.board.scope,
|
|
1086
|
-
layout: board.layout,
|
|
1087
|
-
schema: board.layout === "hex" ? runtimeHexBoardStateSchema.extend({
|
|
1088
|
-
...base,
|
|
1089
|
-
spaces: z6.record(
|
|
1090
|
-
z6.string(),
|
|
1091
|
-
spaces.extend({ q: z6.number().int(), r: z6.number().int() })
|
|
1092
|
-
),
|
|
1093
|
-
edges,
|
|
1094
|
-
vertices
|
|
1095
|
-
}) : runtimeSquareBoardStateSchema.extend({
|
|
1096
|
-
...base,
|
|
1097
|
-
spaces: z6.record(
|
|
1098
|
-
z6.string(),
|
|
1099
|
-
spaces.extend({
|
|
1100
|
-
row: z6.number().int(),
|
|
1101
|
-
col: z6.number().int()
|
|
1102
|
-
})
|
|
1103
|
-
),
|
|
1104
|
-
relations,
|
|
1105
|
-
containers,
|
|
1106
|
-
edges,
|
|
1107
|
-
vertices
|
|
1108
|
-
})
|
|
1109
|
-
};
|
|
1110
|
-
})
|
|
1111
|
-
);
|
|
1112
|
-
const boardCollection = (entries) => {
|
|
1113
|
-
const shared = entries.filter((board) => board.scope === "shared");
|
|
1114
|
-
const scoped = entries.filter((board) => board.scope === "perPlayer").map((board) => board.schema);
|
|
1115
|
-
return shape(
|
|
1116
|
-
shared,
|
|
1117
|
-
(board) => board.id,
|
|
1118
|
-
(board) => board.schema
|
|
1119
|
-
).catchall(scoped.length ? z6.union(scoped) : z6.never());
|
|
1120
|
-
};
|
|
1121
|
-
const boardStateByIdSchema = boardCollection(boards);
|
|
1122
|
-
const hexBoardStateByIdSchema = boardCollection(
|
|
1123
|
-
boards.filter((board) => board.layout === "hex")
|
|
1124
|
-
);
|
|
1125
|
-
const squareBoardStateByIdSchema = boardCollection(
|
|
1126
|
-
boards.filter((board) => board.layout === "square")
|
|
1127
|
-
);
|
|
1128
|
-
return z6.object({
|
|
1129
|
-
playerOrder: z6.array(ids.playerId),
|
|
1130
|
-
zones: z6.object({
|
|
1131
|
-
shared: sharedZoneSchema,
|
|
1132
|
-
perPlayer: playerZoneSchema,
|
|
1133
|
-
visibility: z6.record(
|
|
1134
|
-
zoneIdSchema,
|
|
1135
|
-
z6.enum(["all", "ownerOnly", "public", "hidden"])
|
|
1136
|
-
),
|
|
1137
|
-
cardSetIdsByZoneId: z6.record(zoneIdSchema, z6.array(ids.cardSetId)).optional()
|
|
1138
|
-
}),
|
|
1139
|
-
decks: sharedZoneSchema,
|
|
1140
|
-
hands: playerZoneSchema,
|
|
1141
|
-
handVisibility: z6.record(
|
|
1142
|
-
playerZoneIdSchema,
|
|
1143
|
-
z6.enum(["all", "ownerOnly", "public", "hidden"])
|
|
1144
|
-
),
|
|
1145
|
-
cards: cardStateByIdSchema,
|
|
1146
|
-
pieces: pieceStateByIdSchema,
|
|
1147
|
-
componentLocations: z6.record(
|
|
1148
|
-
z6.string(),
|
|
1149
|
-
z6.union([
|
|
1150
|
-
z6.object({ type: z6.literal("Detached") }),
|
|
1151
|
-
z6.object({
|
|
1152
|
-
type: z6.literal("InDeck"),
|
|
1153
|
-
deckId: ids.deckId,
|
|
1154
|
-
playedBy: ids.playerId.nullable(),
|
|
1155
|
-
position: z6.number().int().nullable().optional()
|
|
1156
|
-
}),
|
|
1157
|
-
z6.object({
|
|
1158
|
-
type: z6.literal("InHand"),
|
|
1159
|
-
handId: ids.handId,
|
|
1160
|
-
playerId: ids.playerId,
|
|
1161
|
-
position: z6.number().int().nullable().optional()
|
|
1162
|
-
}),
|
|
1163
|
-
z6.object({
|
|
1164
|
-
type: z6.literal("InZone"),
|
|
1165
|
-
zoneId: z6.string(),
|
|
1166
|
-
playedBy: ids.playerId.nullable().optional(),
|
|
1167
|
-
position: z6.number().int().nullable().optional()
|
|
1168
|
-
}),
|
|
1169
|
-
z6.object({
|
|
1170
|
-
type: z6.literal("OnSpace"),
|
|
1171
|
-
boardId: ids.boardId,
|
|
1172
|
-
spaceId: ids.spaceId,
|
|
1173
|
-
position: z6.number().int().nullable().optional()
|
|
1174
|
-
}),
|
|
1175
|
-
z6.object({
|
|
1176
|
-
type: z6.literal("InContainer"),
|
|
1177
|
-
boardId: ids.boardId,
|
|
1178
|
-
containerId: ids.boardContainerId,
|
|
1179
|
-
position: z6.number().int().nullable().optional()
|
|
1180
|
-
}),
|
|
1181
|
-
z6.object({
|
|
1182
|
-
type: z6.literal("OnEdge"),
|
|
1183
|
-
boardId: ids.boardId,
|
|
1184
|
-
edgeId: ids.edgeId,
|
|
1185
|
-
position: z6.number().int().nullable().optional()
|
|
1186
|
-
}),
|
|
1187
|
-
z6.object({
|
|
1188
|
-
type: z6.literal("OnVertex"),
|
|
1189
|
-
boardId: ids.boardId,
|
|
1190
|
-
vertexId: ids.vertexId,
|
|
1191
|
-
position: z6.number().int().nullable().optional()
|
|
1192
|
-
}),
|
|
1193
|
-
slotLocationSchema
|
|
1194
|
-
])
|
|
1195
|
-
),
|
|
1196
|
-
ownerOfCard: z6.record(ids.cardId, ids.playerId.nullable()),
|
|
1197
|
-
visibility: z6.record(
|
|
1198
|
-
ids.cardId,
|
|
1199
|
-
z6.object({
|
|
1200
|
-
faceUp: z6.boolean(),
|
|
1201
|
-
visibleTo: z6.array(ids.playerId).nullable().optional()
|
|
1202
|
-
})
|
|
1203
|
-
),
|
|
1204
|
-
resources: perPlayerSchema(z6.record(ids.resourceId, z6.number().int())),
|
|
1205
|
-
boards: z6.object({
|
|
1206
|
-
byId: boardStateByIdSchema,
|
|
1207
|
-
hex: hexBoardStateByIdSchema,
|
|
1208
|
-
square: squareBoardStateByIdSchema,
|
|
1209
|
-
network: z6.record(z6.string(), unknownRecordSchema).default({}),
|
|
1210
|
-
track: z6.record(z6.string(), unknownRecordSchema).default({})
|
|
1211
|
-
}),
|
|
1212
|
-
dice: dieStateByIdSchema
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
// src/reducer/manifest/compiler.ts
|
|
1217
|
-
function compileManifest(manifest) {
|
|
1218
|
-
const source = manifest;
|
|
1219
|
-
const analysis = analyzeManifest(source);
|
|
1220
|
-
const initial = materializeManifestTable({
|
|
1221
|
-
manifest: source,
|
|
1222
|
-
playerIds: analysis.playerIds,
|
|
1223
|
-
shuffleItems: (values) => [...values]
|
|
1224
|
-
});
|
|
1225
|
-
const sharedZoneIds = analysis.sharedZones.map((zone) => zone.id).sort();
|
|
1226
|
-
const playerZoneIds = analysis.playerZones.map((zone) => zone.id).sort();
|
|
1227
|
-
const literals = {
|
|
1228
|
-
...Object.fromEntries(
|
|
1229
|
-
Object.entries(analysis).filter(([key]) => key.endsWith("Ids") || key === "cardTypes").map(([key, value]) => [key, value])
|
|
1230
|
-
),
|
|
1231
|
-
playerIds: analysis.playerIds.map(asPlayerId),
|
|
1232
|
-
phaseNames: [],
|
|
1233
|
-
boardLayouts: ["generic", "hex", "square"],
|
|
1234
|
-
deckIds: sharedZoneIds,
|
|
1235
|
-
handIds: playerZoneIds,
|
|
1236
|
-
sharedZoneIds,
|
|
1237
|
-
playerZoneIds,
|
|
1238
|
-
resourcePresentationById: analysis.resourcePresentationById,
|
|
1239
|
-
handVisibilityById: Object.fromEntries(
|
|
1240
|
-
playerZoneIds.map((id) => [
|
|
1241
|
-
id,
|
|
1242
|
-
analysis.zoneVisibilityById.get(id) ?? "ownerOnly"
|
|
1243
|
-
])
|
|
1244
|
-
),
|
|
1245
|
-
zoneVisibilityById: Object.fromEntries(analysis.zoneVisibilityById),
|
|
1246
|
-
cardSetIdByCardId: Object.fromEntries(analysis.cardSetIdByCardId),
|
|
1247
|
-
cardTypeByCardId: Object.fromEntries(analysis.cardTypeByCardId),
|
|
1248
|
-
setupChoiceIdsByOptionId: Object.fromEntries(
|
|
1249
|
-
analysis.setupChoiceIdsByOptionId
|
|
1250
|
-
),
|
|
1251
|
-
cardSetIdsBySharedZoneId: Object.fromEntries(analysis.sharedZoneCardSetIds),
|
|
1252
|
-
cardSetIdsByPlayerZoneId: Object.fromEntries(analysis.playerZoneCardSetIds)
|
|
1253
|
-
};
|
|
1254
|
-
const families = [
|
|
1255
|
-
"phaseName",
|
|
1256
|
-
"boardLayout",
|
|
1257
|
-
"setupOptionId",
|
|
1258
|
-
"setupProfileId",
|
|
1259
|
-
"cardSetId",
|
|
1260
|
-
"cardType",
|
|
1261
|
-
"cardId",
|
|
1262
|
-
"deckId",
|
|
1263
|
-
"handId",
|
|
1264
|
-
"sharedZoneId",
|
|
1265
|
-
"playerZoneId",
|
|
1266
|
-
"zoneId",
|
|
1267
|
-
"resourceId",
|
|
1268
|
-
"pieceTypeId",
|
|
1269
|
-
"pieceId",
|
|
1270
|
-
"dieTypeId",
|
|
1271
|
-
"dieId",
|
|
1272
|
-
"boardTypeId",
|
|
1273
|
-
"boardBaseId",
|
|
1274
|
-
"boardId",
|
|
1275
|
-
"boardContainerId",
|
|
1276
|
-
"relationTypeId",
|
|
1277
|
-
"edgeId",
|
|
1278
|
-
"edgeTypeId",
|
|
1279
|
-
"vertexId",
|
|
1280
|
-
"vertexTypeId",
|
|
1281
|
-
"spaceId",
|
|
1282
|
-
"spaceTypeId"
|
|
1283
|
-
];
|
|
1284
|
-
const ids = {
|
|
1285
|
-
...Object.fromEntries(
|
|
1286
|
-
families.map((family) => {
|
|
1287
|
-
const values = literals[`${family}s`];
|
|
1288
|
-
return [
|
|
1289
|
-
family,
|
|
1290
|
-
family === "phaseName" ? markManifestScopedSchema(z7.string(), family) : values.length ? createManifestStringLiteralSchema(values, family) : markManifestScopedSchema(z7.never(), family)
|
|
1291
|
-
];
|
|
1292
|
-
})
|
|
1293
|
-
),
|
|
1294
|
-
playerId: markManifestScopedSchema(
|
|
1295
|
-
z7.string().min(1).transform(asPlayerId),
|
|
1296
|
-
"playerId"
|
|
1297
|
-
)
|
|
1298
|
-
};
|
|
1299
|
-
const boardIdSchemas = analysis.analyzedBoards.map(
|
|
1300
|
-
(board) => board.board.scope === "perPlayer" ? z7.templateLiteral([board.board.id, ":", z7.string().min(1)]) : z7.literal(board.board.id)
|
|
1301
|
-
);
|
|
1302
|
-
ids.boardId = markManifestScopedSchema(
|
|
1303
|
-
boardIdSchemas.length ? z7.union(boardIdSchemas) : z7.never(),
|
|
1304
|
-
"boardId"
|
|
1305
|
-
);
|
|
1306
|
-
const tableSchema = assumeManifestSchema(
|
|
1307
|
-
createTableSchema(analysis, ids)
|
|
1308
|
-
);
|
|
1309
|
-
const resolvePlayers = (players = analysis.playerIds) => players.map(asPlayerId);
|
|
1310
|
-
const emptyDecks = () => Object.fromEntries(sharedZoneIds.map((id) => [id, []]));
|
|
1311
|
-
const hands = (players) => Object.fromEntries(
|
|
1312
|
-
playerZoneIds.map((id) => [
|
|
1313
|
-
id,
|
|
1314
|
-
perPlayer(resolvePlayers(players), () => [])
|
|
1315
|
-
])
|
|
1316
|
-
);
|
|
1317
|
-
const defaults = {
|
|
1318
|
-
zones: (players) => ({
|
|
1319
|
-
shared: emptyDecks(),
|
|
1320
|
-
perPlayer: hands(players),
|
|
1321
|
-
visibility: structuredClone(literals.zoneVisibilityById),
|
|
1322
|
-
cardSetIdsByZoneId: Object.fromEntries(analysis.zoneCardSetIdsById)
|
|
1323
|
-
}),
|
|
1324
|
-
decks: emptyDecks,
|
|
1325
|
-
hands,
|
|
1326
|
-
handVisibility: () => structuredClone(literals.handVisibilityById),
|
|
1327
|
-
ownerOfCard: () => Object.fromEntries(analysis.cardIds.map((id) => [id, null])),
|
|
1328
|
-
visibility: () => Object.fromEntries(analysis.cardIds.map((id) => [id, { faceUp: true }])),
|
|
1329
|
-
resources: (players) => perPlayer(
|
|
1330
|
-
resolvePlayers(players),
|
|
1331
|
-
() => Object.fromEntries(analysis.resourceIds.map((id) => [id, 0]))
|
|
1332
|
-
)
|
|
1333
|
-
};
|
|
1334
|
-
const runtimeSchema = createManifestRuntimeSchema({
|
|
1335
|
-
phaseNameSchema: z7.string(),
|
|
1336
|
-
playerIdSchema: ids.playerId,
|
|
1337
|
-
setupProfileIdSchema: ids.setupProfileId
|
|
1338
|
-
});
|
|
1339
|
-
const createInitialTable = (options = {}) => tableSchema.parse(
|
|
1340
|
-
materializeManifestTable({
|
|
1341
|
-
manifest: source,
|
|
1342
|
-
playerIds: options.playerIds ?? analysis.playerIds,
|
|
1343
|
-
shuffleItems: options.shuffleItems ?? ((values) => [...values])
|
|
1344
|
-
})
|
|
1345
|
-
);
|
|
1346
|
-
return {
|
|
1347
|
-
literals,
|
|
1348
|
-
ids,
|
|
1349
|
-
defaults,
|
|
1350
|
-
records: Object.fromEntries(
|
|
1351
|
-
[...families, "playerId"].map((family) => [
|
|
1352
|
-
`${family}s`,
|
|
1353
|
-
(initial2) => buildTypedRecord(
|
|
1354
|
-
literals[`${family}s`],
|
|
1355
|
-
initial2
|
|
1356
|
-
)
|
|
1357
|
-
])
|
|
1358
|
-
),
|
|
1359
|
-
tableSchema,
|
|
1360
|
-
runtimeSchema,
|
|
1361
|
-
schemas: { table: tableSchema, runtime: runtimeSchema },
|
|
1362
|
-
staticBoards: initial.boards,
|
|
1363
|
-
setupOptionsById: analysis.setupOptionsById,
|
|
1364
|
-
setupChoiceIdsByOptionId: literals.setupChoiceIdsByOptionId,
|
|
1365
|
-
setupProfilesById: analysis.setupProfilesById,
|
|
1366
|
-
createInitialTable,
|
|
1367
|
-
normalSetup: {
|
|
1368
|
-
minPlayers: source.players.minPlayers,
|
|
1369
|
-
maxPlayers: source.players.maxPlayers,
|
|
1370
|
-
createInitialTable
|
|
1371
|
-
},
|
|
1372
|
-
createGameStateSchema: (config) => createManifestGameStateSchema({
|
|
1373
|
-
...config,
|
|
1374
|
-
tableSchema,
|
|
1375
|
-
playerIdSchema: ids.playerId,
|
|
1376
|
-
setupProfileIdSchema: ids.setupProfileId
|
|
1377
|
-
})
|
|
1378
|
-
};
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
// src/reducer/authoring/validation.ts
|
|
1382
|
-
var MANIFEST_SCOPED_ID_NAMES = [
|
|
1383
|
-
"playerId",
|
|
1384
|
-
"cardId",
|
|
1385
|
-
"deckId",
|
|
1386
|
-
"handId",
|
|
1387
|
-
"zoneId",
|
|
1388
|
-
"sharedZoneId",
|
|
1389
|
-
"playerZoneId",
|
|
1390
|
-
"boardId",
|
|
1391
|
-
"boardContainerId",
|
|
1392
|
-
"boardTypeId",
|
|
1393
|
-
"boardBaseId",
|
|
1394
|
-
"edgeId",
|
|
1395
|
-
"edgeTypeId",
|
|
1396
|
-
"vertexId",
|
|
1397
|
-
"vertexTypeId",
|
|
1398
|
-
"spaceId",
|
|
1399
|
-
"spaceTypeId",
|
|
1400
|
-
"relationTypeId",
|
|
1401
|
-
"resourceId",
|
|
1402
|
-
"pieceId",
|
|
1403
|
-
"pieceTypeId",
|
|
1404
|
-
"dieId",
|
|
1405
|
-
"dieTypeId",
|
|
1406
|
-
"setupOptionId",
|
|
1407
|
-
"setupProfileId",
|
|
1408
|
-
"cardSetId",
|
|
1409
|
-
"cardType"
|
|
1410
|
-
];
|
|
1411
|
-
function matchManifestScopedIdName(key) {
|
|
1412
|
-
for (const name of MANIFEST_SCOPED_ID_NAMES) {
|
|
1413
|
-
const capitalized = `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
1414
|
-
if (key === name || key.endsWith(capitalized)) {
|
|
1415
|
-
return { name, kind: "singular" };
|
|
1416
|
-
}
|
|
1417
|
-
const plural = `${name}s`;
|
|
1418
|
-
const capitalizedPlural = `${capitalized}s`;
|
|
1419
|
-
if (key === plural || key.endsWith(capitalizedPlural)) {
|
|
1420
|
-
return { name, kind: "plural" };
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
return null;
|
|
1424
|
-
}
|
|
1425
|
-
function validateInteractionParamsSchema(schema, context, path) {
|
|
1426
|
-
const inner = unwrapWrappers(schema);
|
|
1427
|
-
if (isEnumKeyedRecordSchema(inner) && !isSparseMapSchema(inner)) {
|
|
1428
|
-
throw new Error(
|
|
1429
|
-
`${context}: ${path} uses an enum-keyed z.record(...), which parses as a total map at runtime. Use sparseMap(...) or sparseCounts(...) from @dreamboard-games/sdk/reducer instead so interaction params stay sparse and match runtime validation.`
|
|
1430
|
-
);
|
|
1431
|
-
}
|
|
1432
|
-
const shape = getObjectShape(inner);
|
|
1433
|
-
if (shape) {
|
|
1434
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
1435
|
-
validateInteractionParamsSchema(fieldSchema, context, `${path}.${key}`);
|
|
1436
|
-
}
|
|
1437
|
-
return;
|
|
1438
|
-
}
|
|
1439
|
-
const def = getZodDef(inner);
|
|
1440
|
-
if (def.type === "array" && def.element) {
|
|
1441
|
-
validateInteractionParamsSchema(def.element, context, `${path}[]`);
|
|
1442
|
-
return;
|
|
1443
|
-
}
|
|
1444
|
-
if (def.type === "record" && def.valueType) {
|
|
1445
|
-
validateInteractionParamsSchema(def.valueType, context, `${path}.*`);
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
function validateInteractionInputsSchema(inputs, context) {
|
|
1449
|
-
if (!inputs) return;
|
|
1450
|
-
for (const [key, collector] of Object.entries(inputs)) {
|
|
1451
|
-
validateInteractionParamsSchema(collector.schema, context, `inputs.${key}`);
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
function validateManyCommitPolicy(input) {
|
|
1455
|
-
if (input.commit?.mode !== "autoWhenReady") return;
|
|
1456
|
-
if (Object.values(input.inputs ?? {}).some(
|
|
1457
|
-
(collector) => collector.selection?.mode === "many"
|
|
1458
|
-
)) {
|
|
1459
|
-
throw new Error(
|
|
1460
|
-
`${input.context}: interactions with many(...) inputs must use commit: { mode: "manual" }.`
|
|
1461
|
-
);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
function validateInteractionLikeDefinition(input, context) {
|
|
1465
|
-
validateInteractionInputsSchema(input.inputs, context);
|
|
1466
|
-
validateManyCommitPolicy({
|
|
1467
|
-
inputs: input.inputs,
|
|
1468
|
-
commit: input.commit,
|
|
1469
|
-
context
|
|
1470
|
-
});
|
|
1471
|
-
if (input.paramsSchema) {
|
|
1472
|
-
validateInteractionParamsSchema(
|
|
1473
|
-
input.paramsSchema,
|
|
1474
|
-
context,
|
|
1475
|
-
"paramsSchema"
|
|
1476
|
-
);
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
function validateStateSchemaIdBranding(schema, scope) {
|
|
1480
|
-
const def = getZodDef(schema);
|
|
1481
|
-
if (def.type !== "object") {
|
|
1482
|
-
return;
|
|
1483
|
-
}
|
|
1484
|
-
const shape = def.shape;
|
|
1485
|
-
if (!shape) {
|
|
1486
|
-
return;
|
|
1487
|
-
}
|
|
1488
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
1489
|
-
const match = matchManifestScopedIdName(key);
|
|
1490
|
-
if (!match) {
|
|
1491
|
-
continue;
|
|
1492
|
-
}
|
|
1493
|
-
const inner = unwrapWrappers(fieldSchema);
|
|
1494
|
-
if (match.kind === "singular") {
|
|
1495
|
-
if (isPlainZodString(inner) && !isManifestScopedSchema(inner)) {
|
|
1496
|
-
throw new Error(
|
|
1497
|
-
`defineGameContract: state.${scope}.${key} uses a raw z.string() but its name identifies it as a manifest-scoped '${match.name}'. Use gameContract.schemas.${match.name} (or manifest.ids.${match.name}) so the branded literal union flows through state types.`
|
|
1498
|
-
);
|
|
1499
|
-
}
|
|
1500
|
-
continue;
|
|
1501
|
-
}
|
|
1502
|
-
if (match.kind === "plural" && isZodArray(inner)) {
|
|
1503
|
-
const element = unwrapWrappers(getZodDef(inner).element);
|
|
1504
|
-
if (isPlainZodString(element) && !isManifestScopedSchema(element)) {
|
|
1505
|
-
throw new Error(
|
|
1506
|
-
`defineGameContract: state.${scope}.${key} uses z.array(z.string()) but its name identifies it as manifest-scoped '${match.name}' values. Use z.array(gameContract.schemas.${match.name}) (or manifest.ids.${match.name}) so the branded literal union flows through state types.`
|
|
1507
|
-
);
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
function validateDefineGamePhaseNames(definition) {
|
|
1513
|
-
const contractPhaseNames = definition.contract.phaseNames;
|
|
1514
|
-
if (!Array.isArray(contractPhaseNames)) {
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
const declared = new Set(contractPhaseNames);
|
|
1518
|
-
const actual = new Set(Object.keys(definition.phases));
|
|
1519
|
-
const missing = [...declared].filter((name) => !actual.has(name));
|
|
1520
|
-
const extra = [...actual].filter((name) => !declared.has(name));
|
|
1521
|
-
if (missing.length > 0 || extra.length > 0) {
|
|
1522
|
-
const parts = [];
|
|
1523
|
-
if (missing.length > 0) {
|
|
1524
|
-
parts.push(`missing: [${missing.join(", ")}]`);
|
|
1525
|
-
}
|
|
1526
|
-
if (extra.length > 0) {
|
|
1527
|
-
parts.push(`extra: [${extra.join(", ")}]`);
|
|
1528
|
-
}
|
|
1529
|
-
throw new Error(
|
|
1530
|
-
`defineGame: phases record does not match contract.phaseNames (${parts.join(
|
|
1531
|
-
"; "
|
|
1532
|
-
)}). Update contract.phaseNames or the phases record so they agree.`
|
|
1533
|
-
);
|
|
1534
|
-
}
|
|
1535
|
-
if (definition.initialPhase !== void 0 && !declared.has(definition.initialPhase)) {
|
|
1536
|
-
throw new Error(
|
|
1537
|
-
`defineGame: initialPhase '${definition.initialPhase}' is not declared in contract.phaseNames.`
|
|
1538
|
-
);
|
|
1539
|
-
}
|
|
1540
|
-
if (definition.setupProfiles) {
|
|
1541
|
-
for (const [profileId, profile] of Object.entries(
|
|
1542
|
-
definition.setupProfiles
|
|
1543
|
-
)) {
|
|
1544
|
-
const initial = profile?.initialPhase;
|
|
1545
|
-
if (initial !== void 0 && !declared.has(initial)) {
|
|
1546
|
-
throw new Error(
|
|
1547
|
-
`defineGame: setupProfiles.${profileId}.initialPhase '${initial}' is not declared in contract.phaseNames.`
|
|
1548
|
-
);
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
function validateDefineGameZoneWiring(definition) {
|
|
1554
|
-
const manifestPlayerZoneIds = new Set(
|
|
1555
|
-
definition.contract.manifest.literals.playerZoneIds ?? []
|
|
1556
|
-
);
|
|
1557
|
-
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
1558
|
-
const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
|
|
1559
|
-
if (!phaseRecord) continue;
|
|
1560
|
-
if (phaseRecord.zones !== void 0 && !Array.isArray(phaseRecord.zones)) {
|
|
1561
|
-
const zonesRecord = typeof phaseRecord.zones === "object" && phaseRecord.zones !== null ? phaseRecord.zones : null;
|
|
1562
|
-
const hasRemovedZoneSpec = zonesRecord && Object.values(zonesRecord).some(
|
|
1563
|
-
(zone) => typeof zone === "object" && zone !== null && ("cardsFrom" in zone || "playableVia" in zone || "from" in zone)
|
|
1564
|
-
);
|
|
1565
|
-
if (hasRemovedZoneSpec) {
|
|
1566
|
-
throw new Error(
|
|
1567
|
-
`defineGame: phases.${phaseName}.zones uses removed zone spec objects. Use zones: ["manifest-player-zone-id"] and cardActions[*].playFrom instead.`
|
|
1568
|
-
);
|
|
1569
|
-
}
|
|
1570
|
-
throw new Error(
|
|
1571
|
-
`defineGame: phases.${phaseName}.zones must be an array of manifest player zone ids.`
|
|
1572
|
-
);
|
|
1573
|
-
}
|
|
1574
|
-
for (const [index, zoneId] of (phaseRecord.zones ?? []).entries()) {
|
|
1575
|
-
if (typeof zoneId !== "string") {
|
|
1576
|
-
throw new Error(
|
|
1577
|
-
`defineGame: phases.${phaseName}.zones[${index}] must be a manifest player zone id string.`
|
|
1578
|
-
);
|
|
1579
|
-
}
|
|
1580
|
-
if (!manifestPlayerZoneIds.has(zoneId)) {
|
|
1581
|
-
throw new Error(
|
|
1582
|
-
`defineGame: phases.${phaseName}.zones[${index}] '${zoneId}' is not declared in manifest.literals.playerZoneIds.`
|
|
1583
|
-
);
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
for (const [actionId, action] of Object.entries(
|
|
1587
|
-
phaseRecord.cardActions ?? {}
|
|
1588
|
-
)) {
|
|
1589
|
-
const actionRecord = typeof action === "object" && action !== null ? action : null;
|
|
1590
|
-
const playFrom = actionRecord?.playFrom;
|
|
1591
|
-
if (typeof playFrom === "string" && !manifestPlayerZoneIds.has(playFrom)) {
|
|
1592
|
-
throw new Error(
|
|
1593
|
-
`defineGame: phases.${phaseName}.cardActions.${actionId}.playFrom '${playFrom}' is not declared in manifest.literals.playerZoneIds.`
|
|
1594
|
-
);
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
function validateDefineGameSimultaneousPhases(definition) {
|
|
1600
|
-
for (const [phaseName, phase] of Object.entries(definition.phases)) {
|
|
1601
|
-
const phaseRecord = typeof phase === "object" && phase !== null ? phase : null;
|
|
1602
|
-
if (!phaseRecord || phaseRecord.kind !== "simultaneousPlayer") {
|
|
1603
|
-
continue;
|
|
1604
|
-
}
|
|
1605
|
-
if (!phaseRecord.submit) {
|
|
1606
|
-
throw new Error(
|
|
1607
|
-
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare submit.`
|
|
1608
|
-
);
|
|
1609
|
-
}
|
|
1610
|
-
if (typeof phaseRecord.resolve !== "function") {
|
|
1611
|
-
throw new Error(
|
|
1612
|
-
`defineGame: phases.${phaseName} is kind 'simultaneousPlayer' but does not declare resolve.`
|
|
1613
|
-
);
|
|
1614
|
-
}
|
|
1615
|
-
if (phaseRecord.interactions?.submit) {
|
|
1616
|
-
throw new Error(
|
|
1617
|
-
`defineGame: phases.${phaseName}.interactions.submit conflicts with the reserved simultaneous submit interaction id.`
|
|
1618
|
-
);
|
|
1619
|
-
}
|
|
1620
|
-
validateInteractionInputsSchema(
|
|
1621
|
-
phaseRecord.submit.inputs,
|
|
1622
|
-
"defineInteraction"
|
|
1623
|
-
);
|
|
1624
|
-
validateManyCommitPolicy({
|
|
1625
|
-
inputs: phaseRecord.submit.inputs,
|
|
1626
|
-
commit: phaseRecord.submit.commit,
|
|
1627
|
-
context: `defineGame: phases.${phaseName}.submit`
|
|
1628
|
-
});
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
// src/reducer/authoring/interaction.ts
|
|
1633
|
-
function defineInteraction() {
|
|
1634
|
-
return (definition) => {
|
|
1635
|
-
validateInteractionLikeDefinition(
|
|
1636
|
-
definition,
|
|
1637
|
-
"defineInteraction"
|
|
1638
|
-
);
|
|
1639
|
-
return definition;
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
function defineInteractionRule() {
|
|
1643
|
-
return (definition) => definition;
|
|
1644
|
-
}
|
|
1645
|
-
function defineCardAction() {
|
|
1646
|
-
return (definition) => {
|
|
1647
|
-
validateInteractionLikeDefinition(
|
|
1648
|
-
definition,
|
|
1649
|
-
"defineCardAction"
|
|
1650
|
-
);
|
|
1651
|
-
return definition;
|
|
1652
|
-
};
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
// src/reducer/authoring/phase.ts
|
|
1656
|
-
import { z as z8 } from "zod";
|
|
1657
|
-
function stepStateSchema(schema, steps) {
|
|
1658
|
-
const stepSchema = z8.enum(steps);
|
|
1659
|
-
const maybeObject = schema;
|
|
1660
|
-
if (typeof maybeObject.extend === "function") {
|
|
1661
|
-
return maybeObject.extend({ step: stepSchema });
|
|
1662
|
-
}
|
|
1663
|
-
return z8.intersection(schema, z8.object({ step: stepSchema }));
|
|
1664
|
-
}
|
|
1665
|
-
function unwrapStepInteractions(interactions) {
|
|
1666
|
-
if (!interactions) return void 0;
|
|
1667
|
-
return Object.fromEntries(
|
|
1668
|
-
Object.entries(interactions).map(([key, entry]) => [
|
|
1669
|
-
key,
|
|
1670
|
-
{
|
|
1671
|
-
...entry.interaction,
|
|
1672
|
-
__steps: entry.steps
|
|
1673
|
-
}
|
|
1674
|
-
])
|
|
1675
|
-
);
|
|
1676
|
-
}
|
|
1677
|
-
function unwrapStepCardActions(cardActions) {
|
|
1678
|
-
if (!cardActions) return void 0;
|
|
1679
|
-
return Object.fromEntries(
|
|
1680
|
-
Object.entries(cardActions).map(([key, entry]) => [
|
|
1681
|
-
key,
|
|
1682
|
-
{
|
|
1683
|
-
...entry.action,
|
|
1684
|
-
__steps: entry.steps
|
|
1685
|
-
}
|
|
1686
|
-
])
|
|
1687
|
-
);
|
|
1688
|
-
}
|
|
1689
|
-
function definePhase() {
|
|
1690
|
-
return (definition) => {
|
|
1691
|
-
return definition;
|
|
1692
|
-
};
|
|
1693
|
-
}
|
|
1694
|
-
function defineStepPhase() {
|
|
1695
|
-
return (definition) => {
|
|
1696
|
-
const [initialStep] = definition.steps;
|
|
1697
|
-
const state = stepStateSchema(definition.state, definition.steps);
|
|
1698
|
-
const initialState = definition.initialState ? (ctx) => ({
|
|
1699
|
-
...definition.initialState?.(ctx),
|
|
1700
|
-
step: initialStep
|
|
1701
|
-
}) : () => ({ step: initialStep });
|
|
1702
|
-
const { steps: _steps, ...rest } = definition;
|
|
1703
|
-
void _steps;
|
|
1704
|
-
const normalized = {
|
|
1705
|
-
...rest,
|
|
1706
|
-
state,
|
|
1707
|
-
initialState,
|
|
1708
|
-
interactions: unwrapStepInteractions(definition.interactions),
|
|
1709
|
-
cardActions: unwrapStepCardActions(definition.cardActions)
|
|
1710
|
-
};
|
|
1711
|
-
return normalized;
|
|
1712
|
-
};
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
// src/reducer/authoring/view-stage.ts
|
|
1716
|
-
function defineSharedView() {
|
|
1717
|
-
return (definition) => definition;
|
|
1718
|
-
}
|
|
1719
|
-
function definePlayerView() {
|
|
1720
|
-
return (definition) => definition;
|
|
1721
|
-
}
|
|
1722
|
-
function defineEmptyView() {
|
|
1723
|
-
return {
|
|
1724
|
-
project: () => ({})
|
|
1725
|
-
};
|
|
1726
|
-
}
|
|
1727
|
-
function defineStaticView() {
|
|
1728
|
-
return (definition) => definition;
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
// src/reducer/authoring/contract-authoring.ts
|
|
1732
|
-
var PHANTOM_TYPES_MESSAGE = "`.types` is a compile-time carrier: use it only in `typeof` positions.";
|
|
1733
|
-
function phantomTypes() {
|
|
1734
|
-
return new Proxy(Object.freeze({}), {
|
|
1735
|
-
get() {
|
|
1736
|
-
throw new TypeError(PHANTOM_TYPES_MESSAGE);
|
|
1737
|
-
}
|
|
1738
|
-
});
|
|
1739
|
-
}
|
|
1740
|
-
function toPredicateList(where) {
|
|
1741
|
-
if (!where) return [];
|
|
1742
|
-
return Array.isArray(where) ? where : [where];
|
|
1743
|
-
}
|
|
1744
|
-
function applyWhere(builder, where) {
|
|
1745
|
-
return toPredicateList(where).reduce(
|
|
1746
|
-
(current, predicate) => current.where(predicate),
|
|
1747
|
-
builder
|
|
1748
|
-
);
|
|
1749
|
-
}
|
|
1750
|
-
function createFusedCardInput() {
|
|
1751
|
-
return ((options) => {
|
|
1752
|
-
const target = applyWhere(
|
|
1753
|
-
cardTarget.zones(options.from),
|
|
1754
|
-
options.where
|
|
1755
|
-
).build();
|
|
1756
|
-
return cardInput({
|
|
1757
|
-
target,
|
|
1758
|
-
...options.dependsOn ? { dependsOn: options.dependsOn } : {}
|
|
1759
|
-
});
|
|
1760
|
-
});
|
|
1761
|
-
}
|
|
1762
|
-
function createFusedBoardInputs() {
|
|
1763
|
-
const fuse = (kind) => (options) => {
|
|
1764
|
-
const target = applyWhere(
|
|
1765
|
-
boardTarget[kind](options.boardId),
|
|
1766
|
-
options.where
|
|
1767
|
-
).build();
|
|
1768
|
-
return boardInput[kind]({
|
|
1769
|
-
target,
|
|
1770
|
-
...options.dependsOn ? { dependsOn: options.dependsOn } : {}
|
|
1771
|
-
});
|
|
1772
|
-
};
|
|
1773
|
-
const playerSpace = (options) => boardInput.playerSpace({
|
|
1774
|
-
target: applyWhere(
|
|
1775
|
-
boardTarget.playerSpace(options.boardId),
|
|
1776
|
-
options.where
|
|
1777
|
-
).build(),
|
|
1778
|
-
...options.dependsOn ? { dependsOn: options.dependsOn } : {}
|
|
1779
|
-
});
|
|
1780
|
-
return {
|
|
1781
|
-
vertex: fuse("vertex"),
|
|
1782
|
-
edge: fuse("edge"),
|
|
1783
|
-
space: fuse("space"),
|
|
1784
|
-
tile: fuse("tile"),
|
|
1785
|
-
playerSpace
|
|
1786
|
-
};
|
|
1787
|
-
}
|
|
1788
|
-
function createFusedPromptInput() {
|
|
1789
|
-
return ((options) => promptInput({
|
|
1790
|
-
schema: options.schema,
|
|
1791
|
-
...options.choices ? {
|
|
1792
|
-
target: applyWhere(
|
|
1793
|
-
choiceTarget.options(
|
|
1794
|
-
options.choices
|
|
1795
|
-
),
|
|
1796
|
-
options.where
|
|
1797
|
-
).build()
|
|
1798
|
-
} : {}
|
|
1799
|
-
}));
|
|
1800
|
-
}
|
|
1801
|
-
function createBoundInputBuilders() {
|
|
1802
|
-
return {
|
|
1803
|
-
board: createFusedBoardInputs(),
|
|
1804
|
-
card: createFusedCardInput(),
|
|
1805
|
-
form: formInput.forState(),
|
|
1806
|
-
prompt: createFusedPromptInput(),
|
|
1807
|
-
rng: rngInput
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
function createPhaseAuthoring(_contract, schema) {
|
|
1811
|
-
return {
|
|
1812
|
-
interaction: (spec) => defineInteraction()(
|
|
1813
|
-
spec
|
|
1814
|
-
),
|
|
1815
|
-
cardAction: (spec) => defineCardAction()(
|
|
1816
|
-
spec
|
|
1817
|
-
),
|
|
1818
|
-
rule: (rule) => defineInteractionRule()(
|
|
1819
|
-
rule
|
|
1820
|
-
),
|
|
1821
|
-
define: (definition) => definePhase()({
|
|
1822
|
-
...definition,
|
|
1823
|
-
state: schema
|
|
1824
|
-
}),
|
|
1825
|
-
stepPhase: (definition) => defineStepPhase()({
|
|
1826
|
-
...definition,
|
|
1827
|
-
state: schema
|
|
1828
|
-
}),
|
|
1829
|
-
inputs: createBoundInputBuilders(),
|
|
1830
|
-
types: phantomTypes()
|
|
1831
|
-
};
|
|
1832
|
-
}
|
|
1833
|
-
function createContractAuthoring(contract) {
|
|
1834
|
-
const phaseCache = /* @__PURE__ */ new Map();
|
|
1835
|
-
const views = {
|
|
1836
|
-
shared: (definition) => defineSharedView()(definition),
|
|
1837
|
-
player: (definition) => definePlayerView()(definition),
|
|
1838
|
-
empty: () => defineEmptyView(),
|
|
1839
|
-
static: (definition) => defineStaticView()(definition)
|
|
1840
|
-
};
|
|
1841
|
-
const assemble = (definition) => defineGameDefinition({
|
|
1842
|
-
contract,
|
|
1843
|
-
...definition
|
|
1844
|
-
});
|
|
1845
|
-
return {
|
|
1846
|
-
contract,
|
|
1847
|
-
views,
|
|
1848
|
-
types: phantomTypes(),
|
|
1849
|
-
assemble,
|
|
1850
|
-
phase: (name) => {
|
|
1851
|
-
const cached = phaseCache.get(name);
|
|
1852
|
-
if (cached) return cached;
|
|
1853
|
-
const schema = contract.phases[name];
|
|
1854
|
-
const bound = createPhaseAuthoring(contract, schema);
|
|
1855
|
-
phaseCache.set(name, bound);
|
|
1856
|
-
return bound;
|
|
1857
|
-
}
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
// src/reducer/authoring/contract.ts
|
|
1862
|
-
function validateErrorMap(errors) {
|
|
1863
|
-
if (!errors) return;
|
|
1864
|
-
const codePattern = /^[A-Z][A-Z0-9_]*$/;
|
|
1865
|
-
for (const [code, message] of Object.entries(errors)) {
|
|
1866
|
-
if (!codePattern.test(code)) {
|
|
1867
|
-
throw new Error(
|
|
1868
|
-
`defineGameContract: error code '${code}' must use UPPER_SNAKE_CASE.`
|
|
1869
|
-
);
|
|
1870
|
-
}
|
|
1871
|
-
if (typeof message !== "string" || message.length === 0) {
|
|
1872
|
-
throw new Error(
|
|
1873
|
-
`defineGameContract: error code '${code}' must declare a non-empty default message.`
|
|
1874
|
-
);
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
function defineGameContract(definition) {
|
|
1879
|
-
validateStateSchemaIdBranding(definition.state.public, "public");
|
|
1880
|
-
validateStateSchemaIdBranding(definition.state.private, "private");
|
|
1881
|
-
validateStateSchemaIdBranding(definition.state.hidden, "hidden");
|
|
1882
|
-
validateErrorMap(definition.errors);
|
|
1883
|
-
const phaseNames = Object.keys(definition.phases);
|
|
1884
|
-
if (phaseNames.length === 0) {
|
|
1885
|
-
throw new Error(
|
|
1886
|
-
"defineGameContract: phases must be a non-empty record of phase schemas."
|
|
1887
|
-
);
|
|
1888
|
-
}
|
|
1889
|
-
for (const name of phaseNames) {
|
|
1890
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
1891
|
-
throw new Error(
|
|
1892
|
-
"defineGameContract: phase names must be non-empty strings."
|
|
1893
|
-
);
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
const phaseNameSchema = createManifestStringLiteralSchema(phaseNames);
|
|
1897
|
-
const narrowedManifest = {
|
|
1898
|
-
...definition.manifest,
|
|
1899
|
-
literals: {
|
|
1900
|
-
...definition.manifest.literals,
|
|
1901
|
-
phaseNames
|
|
1902
|
-
},
|
|
1903
|
-
ids: {
|
|
1904
|
-
...definition.manifest.ids,
|
|
1905
|
-
phaseName: phaseNameSchema
|
|
1906
|
-
}
|
|
1907
|
-
};
|
|
1908
|
-
const contract = {
|
|
1909
|
-
manifest: narrowedManifest,
|
|
1910
|
-
state: definition.state,
|
|
1911
|
-
phases: definition.phases,
|
|
1912
|
-
errors: definition.errors,
|
|
1913
|
-
phaseNames,
|
|
1914
|
-
schemas: narrowedManifest.ids
|
|
1915
|
-
};
|
|
1916
|
-
return contract;
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
// src/reducer/authoring/game.ts
|
|
1920
|
-
function defineGameDefinition(definition) {
|
|
1921
|
-
validateDefineGamePhaseNames(definition);
|
|
1922
|
-
validateDefineGameSimultaneousPhases(definition);
|
|
1923
|
-
validateDefineGameZoneWiring(definition);
|
|
1924
|
-
return definition;
|
|
1925
|
-
}
|
|
1926
|
-
function createGame(model) {
|
|
1927
|
-
const manifest = "literals" in model.manifest ? model.manifest : compileManifest(model.manifest);
|
|
1928
|
-
return createContractAuthoring(defineGameContract({ ...model, manifest }));
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
|
-
export {
|
|
1932
|
-
sparseMap,
|
|
1933
|
-
sparseCounts,
|
|
1934
|
-
normalizeCommandParams,
|
|
1935
|
-
defineInputs,
|
|
1936
|
-
many,
|
|
1937
|
-
compileManifest,
|
|
1938
|
-
defineGameDefinition,
|
|
1939
|
-
createGame
|
|
1940
|
-
};
|
|
1941
|
-
//# sourceMappingURL=chunk-ZZGN2ATS.js.map
|