@valbuild/core 0.126.0 → 0.127.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.
Files changed (27) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/dist/declarations/src/index.d.ts +5 -1
  3. package/dist/declarations/src/initSchema.d.ts +16 -0
  4. package/dist/declarations/src/locale.d.ts +55 -0
  5. package/dist/declarations/src/schema/array.d.ts +4 -0
  6. package/dist/declarations/src/schema/declaredKeys.d.ts +37 -0
  7. package/dist/declarations/src/schema/discriminatedUnion.d.ts +4 -0
  8. package/dist/declarations/src/schema/discriminatedUnionBranch.d.ts +20 -0
  9. package/dist/declarations/src/schema/enum.d.ts +9 -0
  10. package/dist/declarations/src/schema/index.d.ts +116 -3
  11. package/dist/declarations/src/schema/literal.d.ts +2 -0
  12. package/dist/declarations/src/schema/locale.d.ts +132 -0
  13. package/dist/declarations/src/schema/object.d.ts +7 -0
  14. package/dist/declarations/src/schema/record.d.ts +51 -1
  15. package/dist/declarations/src/schema/settings.d.ts +54 -1
  16. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  17. package/dist/declarations/src/source/settings.d.ts +51 -0
  18. package/dist/{index-cd25c2dc.esm.js → index-5a6e6398.esm.js} +1035 -54
  19. package/dist/{index-b41b638f.cjs.dev.js → index-889ac441.cjs.dev.js} +1040 -53
  20. package/dist/{index-6db78f3c.cjs.prod.js → index-d44deccb.cjs.prod.js} +1040 -53
  21. package/dist/valbuild-core.cjs.dev.js +7 -1
  22. package/dist/valbuild-core.cjs.prod.js +7 -1
  23. package/dist/valbuild-core.esm.js +1 -1
  24. package/package.json +1 -1
  25. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  26. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  27. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -163,19 +163,217 @@ function _inherits(t, e) {
163
163
  // import { SerializedI18nSchema } from "./future/i18n";
164
164
  // import { SerializedOneOfSchema } from "./future/oneOf";
165
165
 
166
+ /**
167
+ * A locale scope's path, as something to read in a message.
168
+ *
169
+ * The walk names the item of an array or record `*`, which says nothing to
170
+ * whoever has to fix this. `[]` is the convention people already read as "each
171
+ * of these", and a path that is nothing BUT items has no field to name at all.
172
+ */
173
+ function describeScopePath(path) {
174
+ if (path.every(function (segment) {
175
+ return segment === "*";
176
+ })) {
177
+ return "its entries";
178
+ }
179
+ var rendered = "";
180
+ var _iterator = result._createForOfIteratorHelper(path),
181
+ _step;
182
+ try {
183
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
184
+ var segment = _step.value;
185
+ if (segment === "*") {
186
+ rendered += "[]";
187
+ } else {
188
+ rendered += rendered === "" ? segment : ".".concat(segment);
189
+ }
190
+ }
191
+ } catch (err) {
192
+ _iterator.e(err);
193
+ } finally {
194
+ _iterator.f();
195
+ }
196
+ return "'".concat(rendered, "'");
197
+ }
166
198
  var Schema = /*#__PURE__*/function () {
167
199
  function Schema() {
168
200
  _classCallCheck(this, Schema);
201
+ /**
202
+ * The answer, computed once per schema.
203
+ *
204
+ * Memoised because the question is asked from `executeValidate`, which runs
205
+ * once per SOURCE instance: an array of five hundred blocks asks the item
206
+ * schema five hundred times, and each answer walks the schema below it
207
+ * looking for a nested scope. The answer cannot differ between two instances
208
+ * of the same schema — nothing here reads the source — so the walk is done
209
+ * once and the result handed back after that.
210
+ *
211
+ * The error is still reported at every instance's path. Val's validation
212
+ * errors are keyed by source path and that is where the Studio draws them, so
213
+ * a schema error on a row is a schema error on every row; reporting it on one
214
+ * arbitrary row would put it somewhere nobody was looking.
215
+ */
216
+ _defineProperty(this, "localeScopeErrorsMemo", void 0);
169
217
  }
170
218
  return _createClass(Schema, [{
219
+ key: "isLocaleField",
220
+ value:
221
+ /**
222
+ * Whether this node is a locale — the field that MARKS a scope, `s.locale()`.
223
+ *
224
+ * Only `LocaleSchema` overrides this. A base implementation rather than an
225
+ * abstract one on purpose: every other schema class answers no, and a
226
+ * question every class had to answer would be twenty edits for one yes.
227
+ *
228
+ * Not the same question as {@link opensLocaleScope}: a locale field marks the
229
+ * scope, the object AROUND it is the scope. See `localeScope.ts`.
230
+ */
231
+ function isLocaleField() {
232
+ return false;
233
+ }
234
+
235
+ /**
236
+ * Whether this node OPENS a locale scope, and what opens it.
237
+ *
238
+ * An object with a `s.locale()` field opens one; so does a record keyed by
239
+ * `s.locale()`. Everything below such a node is in that one language, which
240
+ * is why a scope may not contain another — see `localeScope.ts` for the rule
241
+ * and the reason it is validated rather than typed.
242
+ */
243
+ }, {
244
+ key: "opensLocaleScope",
245
+ value: function opensLocaleScope() {
246
+ return null;
247
+ }
248
+
249
+ /**
250
+ * The child schemas a locale scope reaches, by the path segment that reaches
251
+ * them.
252
+ *
253
+ * A structural walk that deliberately does NOT go through `executeSerialize`:
254
+ * serializing a subtree at every node to ask a question about its shape is
255
+ * quadratic, and this is asked during validation. `*` stands for the item of
256
+ * an array or record, which has no name of its own.
257
+ */
258
+ }, {
259
+ key: "localeScopeChildren",
260
+ value: function localeScopeChildren() {
261
+ return [];
262
+ }
263
+
264
+ /**
265
+ * Every locale scope opened strictly BELOW this node, by path.
266
+ *
267
+ * Stops descending at each one it finds, so a scope three deep is reported
268
+ * once, by the scope immediately enclosing it, rather than by every ancestor.
269
+ */
270
+ }, {
271
+ key: "localeScopesBelow",
272
+ value: function localeScopesBelow() {
273
+ var prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
274
+ var found = [];
275
+ var _iterator2 = result._createForOfIteratorHelper(this.localeScopeChildren()),
276
+ _step2;
277
+ try {
278
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
279
+ var _step2$value = _step2.value,
280
+ key = _step2$value.key,
281
+ schema = _step2$value.schema;
282
+ var _path = [].concat(_toConsumableArray(prefix), [key]);
283
+ var opened = schema.opensLocaleScope();
284
+ if (opened !== null) {
285
+ found.push({
286
+ path: _path,
287
+ kind: opened
288
+ });
289
+ continue;
290
+ }
291
+ found.push.apply(found, _toConsumableArray(schema.localeScopesBelow(_path)));
292
+ }
293
+ } catch (err) {
294
+ _iterator2.e(err);
295
+ } finally {
296
+ _iterator2.f();
297
+ }
298
+ return found;
299
+ }
300
+
301
+ /**
302
+ * The scope rule, as errors at this node — or `false` if it is not broken.
303
+ *
304
+ * Two things are wrong and both are wrong in the SCHEMA rather than in the
305
+ * content, so both are `schemaError`s: an object with two locale fields (the
306
+ * subtree below it would be in two languages at once), and a locale scope
307
+ * inside another (the inner one would silently override the outer for part
308
+ * of a subtree that is supposed to be one language throughout).
309
+ *
310
+ * Validated rather than typed on purpose. Expressing "no scope below this
311
+ * one" as a constraint means threading it through every schema class's type
312
+ * parameter, and the errors that fall out of a recursive constraint like
313
+ * that name the whole tree — an unrelated typo in a `.val.ts` would print
314
+ * pages. See the design notes on the locales PR.
315
+ */
316
+ }, {
317
+ key: "localeScopeErrors",
318
+ value: function localeScopeErrors() {
319
+ if (this.localeScopeErrorsMemo === undefined) {
320
+ this.localeScopeErrorsMemo = this.computeLocaleScopeErrors();
321
+ }
322
+ return this.localeScopeErrorsMemo;
323
+ }
324
+ }, {
325
+ key: "computeLocaleScopeErrors",
326
+ value: function computeLocaleScopeErrors() {
327
+ var errors = [];
328
+ var localeFields = this.localeFieldNames();
329
+ if (localeFields.length > 1) {
330
+ errors.push({
331
+ message: "An object can be in one language, so it can have one locale field. Found ".concat(localeFields.map(function (each) {
332
+ return "'".concat(each, "'");
333
+ }).join(", "), "."),
334
+ schemaError: true
335
+ });
336
+ }
337
+ var opened = this.opensLocaleScope();
338
+ if (opened !== null) {
339
+ var _iterator3 = result._createForOfIteratorHelper(this.localeScopesBelow()),
340
+ _step3;
341
+ try {
342
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
343
+ var nested = _step3.value;
344
+ errors.push({
345
+ message: "Everything here is already in one language, so ".concat(describeScopePath(nested.path), " cannot set another. Move the ").concat(nested.kind === "key" ? "locale-keyed record" : "locale field", " out of this ").concat(opened === "key" ? "locale-keyed record" : "object", ", or take the outer one away."),
346
+ schemaError: true
347
+ });
348
+ }
349
+ } catch (err) {
350
+ _iterator3.e(err);
351
+ } finally {
352
+ _iterator3.f();
353
+ }
354
+ }
355
+ return errors;
356
+ }
357
+
358
+ /**
359
+ * This node's own `s.locale()` fields, where it is an object that has any.
360
+ *
361
+ * Empty everywhere else, so `localeScopeErrors` can live on the base class.
362
+ */
363
+ }, {
364
+ key: "localeFieldNames",
365
+ value: function localeFieldNames() {
366
+ return [];
367
+ }
368
+ }, {
171
369
  key: "executeCustomValidateFunctions",
172
370
  value: function executeCustomValidateFunctions(src, customValidateFunctions, ctx) {
173
371
  var errors = [];
174
- var _iterator = result._createForOfIteratorHelper(customValidateFunctions),
175
- _step;
372
+ var _iterator4 = result._createForOfIteratorHelper(customValidateFunctions),
373
+ _step4;
176
374
  try {
177
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
178
- var customValidateFunction = _step.value;
375
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
376
+ var customValidateFunction = _step4.value;
179
377
  try {
180
378
  var result$1 = customValidateFunction(src, ctx);
181
379
  if (result$1) {
@@ -193,9 +391,9 @@ var Schema = /*#__PURE__*/function () {
193
391
  }
194
392
  }
195
393
  } catch (err) {
196
- _iterator.e(err);
394
+ _iterator4.e(err);
197
395
  } finally {
198
- _iterator.f();
396
+ _iterator4.f();
199
397
  }
200
398
  return errors;
201
399
  }
@@ -294,11 +492,11 @@ var Schema = /*#__PURE__*/function () {
294
492
  return incoming;
295
493
  }
296
494
  for (var pathS in incoming) {
297
- var _path = pathS;
298
- if (current[_path]) {
299
- current[_path] = current[_path].concat(incoming[_path]);
495
+ var _path2 = pathS;
496
+ if (current[_path2]) {
497
+ current[_path2] = current[_path2].concat(incoming[_path2]);
300
498
  } else {
301
- current[_path] = incoming[_path];
499
+ current[_path2] = incoming[_path2];
302
500
  }
303
501
  }
304
502
  return current;
@@ -333,6 +531,10 @@ var GetSource = Symbol["for"]("@valbuild/core/GetSource");
333
531
  var ValError = Symbol["for"]("@valbuild/core/ValError");
334
532
  var GenericSelector = /*#__PURE__*/_createClass(function GenericSelector(valOrExpr, path, schema, error) {
335
533
  _classCallCheck(this, GenericSelector);
534
+ _defineProperty(this, Path, void 0);
535
+ _defineProperty(this, GetSource, void 0);
536
+ _defineProperty(this, ValError, void 0);
537
+ _defineProperty(this, GetSchema, void 0);
336
538
  this[Path] = path;
337
539
  this[GetSource] = valOrExpr;
338
540
  this[ValError] = error;
@@ -935,6 +1137,18 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
935
1137
  } finally {
936
1138
  _iterator.f();
937
1139
  }
1140
+ var _iterator2 = result._createForOfIteratorHelper(this.localeScopeErrors()),
1141
+ _step2;
1142
+ try {
1143
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1144
+ var scopeError = _step2.value;
1145
+ error = this.appendValidationError(error, path, scopeError.message, src, scopeError.schemaError);
1146
+ }
1147
+ } catch (err) {
1148
+ _iterator2.e(err);
1149
+ } finally {
1150
+ _iterator2.f();
1151
+ }
938
1152
  for (var _i = 0, _Object$entries = Object.entries(this.items); _i < _Object$entries.length; _i++) {
939
1153
  var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
940
1154
  _key = _Object$entries$_i[0],
@@ -1018,7 +1232,7 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1018
1232
  key: "nullable",
1019
1233
  value: function nullable() {
1020
1234
  // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
1021
- return new ObjectSchema(this.items, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1235
+ return new ObjectSchema(this.items, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1022
1236
  }
1023
1237
  }, {
1024
1238
  key: "readonly",
@@ -1032,6 +1246,35 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1032
1246
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1033
1247
  return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
1034
1248
  }
1249
+
1250
+ /** The names of this object's `s.locale()` fields, in declaration order. */
1251
+ }, {
1252
+ key: "localeFieldNames",
1253
+ value: function localeFieldNames() {
1254
+ var _this2 = this;
1255
+ return Object.keys(this.items).filter(function (key) {
1256
+ return _this2.items[key]["isLocaleField"]();
1257
+ });
1258
+ }
1259
+ }, {
1260
+ key: "opensLocaleScope",
1261
+ value: function opensLocaleScope() {
1262
+ // More than one is itself the error, reported by `localeScopeErrors`. It
1263
+ // still opens a scope: reporting "two locale fields" AND "a scope inside a
1264
+ // scope" for the same object would be two errors about one mistake.
1265
+ return this.localeFieldNames().length > 0 ? "field" : null;
1266
+ }
1267
+ }, {
1268
+ key: "localeScopeChildren",
1269
+ value: function localeScopeChildren() {
1270
+ var _this3 = this;
1271
+ return Object.keys(this.items).map(function (key) {
1272
+ return {
1273
+ key: key,
1274
+ schema: _this3.items[key]
1275
+ };
1276
+ });
1277
+ }
1035
1278
  }, {
1036
1279
  key: "executeCustomValidateAt",
1037
1280
  value: function executeCustomValidateAt(path, src) {
@@ -1296,7 +1539,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1296
1539
  key: "nullable",
1297
1540
  value: function nullable() {
1298
1541
  // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
1299
- return new ArraySchema(this.item, true, [], this.isReadonly, this.isHidden, this.description, this.previewInput, this.renderInput);
1542
+ return new ArraySchema(this.item, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.previewInput, this.renderInput);
1300
1543
  }
1301
1544
  }, {
1302
1545
  key: "readonly",
@@ -1310,6 +1553,14 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1310
1553
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
1311
1554
  return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.previewInput, this.renderInput);
1312
1555
  }
1556
+ }, {
1557
+ key: "localeScopeChildren",
1558
+ value: function localeScopeChildren() {
1559
+ return [{
1560
+ key: "*",
1561
+ schema: this.item
1562
+ }];
1563
+ }
1313
1564
  }, {
1314
1565
  key: "executeCustomValidateAt",
1315
1566
  value: function executeCustomValidateAt(path, src) {
@@ -1483,6 +1734,8 @@ var array = function array(schema) {
1483
1734
  };
1484
1735
 
1485
1736
  var LiteralSchema = /*#__PURE__*/function (_Schema) {
1737
+ /** Type-only marker: as a record key, this declares the key set. See `LocaleSchema`. */
1738
+
1486
1739
  function LiteralSchema(value) {
1487
1740
  var _this;
1488
1741
  var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
@@ -1614,7 +1867,7 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
1614
1867
  }, {
1615
1868
  key: "nullable",
1616
1869
  value: function nullable() {
1617
- return new LiteralSchema(this.value, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1870
+ return new LiteralSchema(this.value, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
1618
1871
  }
1619
1872
  }, {
1620
1873
  key: "readonly",
@@ -2035,7 +2288,7 @@ var DiscriminatedUnionSchema = /*#__PURE__*/function (_Schema) {
2035
2288
  key: "nullable",
2036
2289
  value: function nullable() {
2037
2290
  // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
2038
- return new DiscriminatedUnionSchema(this.key, this.items, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
2291
+ return new DiscriminatedUnionSchema(this.key, this.items, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
2039
2292
  }
2040
2293
  }, {
2041
2294
  key: "readonly",
@@ -2049,6 +2302,20 @@ var DiscriminatedUnionSchema = /*#__PURE__*/function (_Schema) {
2049
2302
  var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
2050
2303
  return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
2051
2304
  }
2305
+ }, {
2306
+ key: "localeScopeChildren",
2307
+ value: function localeScopeChildren() {
2308
+ // Every variant is walked under the SAME path: whichever one the value
2309
+ // takes, that is where it sits. `s.enum()` has no children at all — its
2310
+ // values are strings, not schemas — which is why only this half of the old
2311
+ // `s.union` has this.
2312
+ return this.items.map(function (item) {
2313
+ return {
2314
+ key: "*",
2315
+ schema: item
2316
+ };
2317
+ });
2318
+ }
2052
2319
  }, {
2053
2320
  key: "executeCustomValidateAt",
2054
2321
  value: function executeCustomValidateAt(path, src) {
@@ -4459,7 +4726,7 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
4459
4726
  }, {
4460
4727
  key: "nullable",
4461
4728
  value: function nullable() {
4462
- return new RichTextSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
4729
+ return new RichTextSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
4463
4730
  }
4464
4731
  }, {
4465
4732
  key: "readonly",
@@ -4976,6 +5243,68 @@ function hasInlineExternalEntries(source) {
4976
5243
  return _typeof(source) === "object" && source !== null && !Array.isArray(source) && !isExternal(source) && Object.keys(source).length > 0;
4977
5244
  }
4978
5245
 
5246
+ /**
5247
+ * The keys a record is REQUIRED to hold, where its key schema says what they are.
5248
+ *
5249
+ * Most records have an open key set — `s.record(s.string(), item)` holds
5250
+ * whatever anyone adds — and this returns `null` for those. A record keyed by
5251
+ * something that enumerates its values is different in kind: the keys are part
5252
+ * of the schema, so a missing one is a hole in the content rather than content
5253
+ * nobody has written yet.
5254
+ *
5255
+ * Two key schemas enumerate. A union of literals does it locally, so its keys
5256
+ * are here. `s.locale()` does it in the settings module, which is another file
5257
+ * and so cannot be read from a serialized schema — that case says only which
5258
+ * kind it is, and is resolved against `locales.available` by
5259
+ * `resolveSchemaSourceFixes`, the same crossing `keyOf` and `route` make.
5260
+ */
5261
+
5262
+ /**
5263
+ * What `key` requires a record to hold, or `null` where it requires nothing.
5264
+ *
5265
+ * Works from the SERIALIZED schema so that the Studio, the validation worker
5266
+ * and the server all answer this the same way — none of them has the schema
5267
+ * instance, and `SchemaStore` deliberately holds serialized schemas only.
5268
+ */
5269
+ function declaredKeySetOf(key) {
5270
+ if (key === undefined) {
5271
+ return null;
5272
+ }
5273
+ if (key.type === "literal") {
5274
+ return {
5275
+ kind: "literals",
5276
+ keys: [key.value]
5277
+ };
5278
+ }
5279
+ if (key.type === "enum") {
5280
+ // An enum names every value it may take, so those values ARE the key set.
5281
+ // `discriminated-union` is deliberately absent: it discriminates objects
5282
+ // and cannot be a record key at all.
5283
+ return {
5284
+ kind: "literals",
5285
+ keys: _toConsumableArray(key.values)
5286
+ };
5287
+ }
5288
+ if (key.type === "locale") {
5289
+ return {
5290
+ kind: "locale"
5291
+ };
5292
+ }
5293
+ return null;
5294
+ }
5295
+
5296
+ /**
5297
+ * The declared keys a record is missing, in the order the schema declares them.
5298
+ *
5299
+ * Declaration order rather than the source's: this is read as "what is left to
5300
+ * write", and the answer should not reshuffle itself as entries are added.
5301
+ */
5302
+ function missingDeclaredKeys(declared, present) {
5303
+ return declared.filter(function (key) {
5304
+ return !present.includes(key);
5305
+ });
5306
+ }
5307
+
4979
5308
  /**
4980
5309
  * The source type of a `.jsonValues()` record: every entry value is EITHER a
4981
5310
  * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
@@ -5007,6 +5336,16 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5007
5336
  var externalLabel = arguments.length > 12 && arguments[12] !== undefined ? arguments[12] : null;
5008
5337
  _classCallCheck(this, RecordSchema);
5009
5338
  _this = _callSuper(this, RecordSchema);
5339
+ /**
5340
+ * The key set this record's schema declares, computed once.
5341
+ *
5342
+ * `declaredKeySetOf` reads a SERIALIZED schema, and serializing the key
5343
+ * schema walks it — twice per validate, and once per record instance, for an
5344
+ * answer that is a property of the schema and cannot move between them. A
5345
+ * schema is built once and validated against many times, so the walk happens
5346
+ * on the first question and not on any after it.
5347
+ */
5348
+ _defineProperty(_this, "declaredKeys", void 0);
5010
5349
  _this.item = item;
5011
5350
  _this.opt = opt;
5012
5351
  _this.customValidateFunctions = customValidateFunctions;
@@ -5153,6 +5492,11 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5153
5492
  error = _objectSpread2(_objectSpread2({}, error), {}, _defineProperty({}, path, [allFilesCheckError]));
5154
5493
  }
5155
5494
  }
5495
+ // A record whose keys are declared by its schema holds every one of them,
5496
+ // and an entry nobody has written yet is `null` rather than absent — so
5497
+ // `null` is a value here, not a value of the wrong type, and the item
5498
+ // schema is not asked about it.
5499
+ var hasDeclaredKeys = this.declaredKeySet() !== null;
5156
5500
  Object.entries(src).forEach(function (_ref5) {
5157
5501
  var _ref6 = _slicedToArray(_ref5, 2),
5158
5502
  key = _ref6[0],
@@ -5192,7 +5536,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5192
5536
  _this2.markKeyErrorsAtPath(entryErr, subPath);
5193
5537
  }
5194
5538
  error = _this2.mergeValidationErrors(error, entryErr);
5195
- } else if (_this2.isJsonValues && isJson(elem)) ; else {
5539
+ } else if (hasDeclaredKeys && elem === null) ; else if (_this2.isJsonValues && isJson(elem)) ; else {
5196
5540
  // Falls through for a jsonValues record whose entry content is inlined
5197
5541
  // (loaded in the UI, or hand-authored): same as a plain record — validate
5198
5542
  // the value against the item schema.
@@ -5200,8 +5544,79 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5200
5544
  error = _this2.mergeValidationErrors(error, subError);
5201
5545
  }
5202
5546
  });
5547
+ var declaredKeys = this.getDeclaredKeysValidation(path, src);
5548
+ error = this.mergeValidationErrors(error, declaredKeys);
5549
+ var _iterator2 = result._createForOfIteratorHelper(this.localeScopeErrors()),
5550
+ _step2;
5551
+ try {
5552
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
5553
+ var scopeError = _step2.value;
5554
+ error = this.appendValidationError(error, path, scopeError.message, src, scopeError.schemaError);
5555
+ }
5556
+ } catch (err) {
5557
+ _iterator2.e(err);
5558
+ } finally {
5559
+ _iterator2.f();
5560
+ }
5203
5561
  return error;
5204
5562
  }
5563
+
5564
+ /**
5565
+ * The check that a record with a DECLARED key set holds every one of them.
5566
+ *
5567
+ * `s.record(s.locale(), item)` has one entry per language and
5568
+ * `s.record(s.union(s.literal("a"), s.literal("b")), item)` has both — the
5569
+ * keys are part of the schema either way, so a missing one is a hole in the
5570
+ * content rather than content nobody has written yet. TypeScript already
5571
+ * demanded both keys of the second; this is the validator catching up, which
5572
+ * is why the two now behave the same.
5573
+ *
5574
+ * Deferred to `resolveSchemaSourceFixes` even for the literal case, where the
5575
+ * keys are known right here: a locale record's keys are in another file, and
5576
+ * one code path for both is one message, one fix and one thing to be wrong.
5577
+ */
5578
+ }, {
5579
+ key: "getDeclaredKeysValidation",
5580
+ value: function getDeclaredKeysValidation(path, src) {
5581
+ if (this.keySchema === null) {
5582
+ return false;
5583
+ }
5584
+ var declared = this.declaredKeySet();
5585
+ if (declared === null) {
5586
+ return false;
5587
+ }
5588
+ return _defineProperty({}, path, [{
5589
+ fixes: ["record:fill-keys"],
5590
+ message: "Did not validate record keys. This error (record:fill-keys) should typically be processed by Val internally. Seeing this error most likely means you have a Val version mismatch.",
5591
+ value: {
5592
+ present: Object.keys(src),
5593
+ declared: declared.kind === "literals" ? declared.keys : null
5594
+ }
5595
+ }]);
5596
+ }
5597
+ }, {
5598
+ key: "declaredKeySet",
5599
+ value: function declaredKeySet() {
5600
+ if (this.declaredKeys === undefined) {
5601
+ this.declaredKeys = this.keySchema === null ? null : declaredKeySetOf(this.keySchema["executeSerialize"]());
5602
+ }
5603
+ return this.declaredKeys;
5604
+ }
5605
+ }, {
5606
+ key: "opensLocaleScope",
5607
+ value: function opensLocaleScope() {
5608
+ return this.keySchema !== null && this.keySchema["isLocaleField"]() ? "key" : null;
5609
+ }
5610
+ }, {
5611
+ key: "localeScopeChildren",
5612
+ value: function localeScopeChildren() {
5613
+ // The KEY schema is not a child here. A locale key is what opens this
5614
+ // record's scope; it is not something inside the scope.
5615
+ return [{
5616
+ key: "*",
5617
+ schema: this.item
5618
+ }];
5619
+ }
5205
5620
  }, {
5206
5621
  key: "isRemoteUrl",
5207
5622
  value: function isRemoteUrl(url) {
@@ -5896,6 +6311,23 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
5896
6311
  }]);
5897
6312
  }(Schema);
5898
6313
 
6314
+ /**
6315
+ * The source of a record, given what its key schema says about its keys.
6316
+ *
6317
+ * A key schema that ENUMERATES its keys (a union of literals, or `s.locale()`)
6318
+ * makes every one of them an entry of the record, and an entry nobody has
6319
+ * written yet is `null` rather than absent — so the value type widens by
6320
+ * `null`. That is the whole of option F at the type level: a half-translated
6321
+ * record is a record with nulls in it, which is data you can count, filter and
6322
+ * see in a diff, rather than keys that are simply not there.
6323
+ *
6324
+ * For a union of literals TypeScript already required every key, since
6325
+ * `SelectorOfSchema<K>` is the literal union itself. `s.locale()` is a flavoured
6326
+ * string, so it requires nothing here and the requirement is the validator's —
6327
+ * deliberately: which languages exist is in the settings module, where the
6328
+ * project can change it without a deploy.
6329
+ */
6330
+
5899
6331
  // Overload: with key schema
5900
6332
 
5901
6333
  // Overload: without key schema
@@ -5934,6 +6366,31 @@ function record(keyOrSchema, schema) {
5934
6366
  * written without removing the key.
5935
6367
  */
5936
6368
 
6369
+ /**
6370
+ * The languages this project publishes.
6371
+ *
6372
+ * Content rather than configuration, and deliberately: which languages a site
6373
+ * has is a decision the people who write it make, and under a build-time
6374
+ * constant it took a developer and a deploy. It is the same move `assistant`
6375
+ * makes with `enabled`.
6376
+ *
6377
+ * Val ships no list of its own. A project with no `locales` section has not
6378
+ * said it is translated, and nothing about locales appears anywhere — no picker
6379
+ * in the Studio, no checks, nothing.
6380
+ *
6381
+ * **This list is a decision with a blast radius.** Every locale in content is
6382
+ * checked against it, so removing one invalidates the content that uses it, and
6383
+ * adding one leaves every locale-keyed record short of a language until it is
6384
+ * filled in. That is the intended behaviour — a language that is declared and
6385
+ * missing everywhere is worth being told about — but it is why the Studio warns
6386
+ * before saving a removal rather than treating this as an ordinary field.
6387
+ *
6388
+ * There is no default language, deliberately. Every locale-specific field asks
6389
+ * which language it is in, and a default is exactly the answer that lets that
6390
+ * question go unanswered — content ends up filed under a language nobody chose,
6391
+ * which is the state translation is meant to make visible.
6392
+ */
6393
+
5937
6394
  /**
5938
6395
  * The assistant: whether editors have one, and what it is told about the
5939
6396
  * project on every message.
@@ -5994,6 +6451,263 @@ settings) {
5994
6451
  return "unconfigured";
5995
6452
  }
5996
6453
 
6454
+ /**
6455
+ * One of the languages the project publishes.
6456
+ *
6457
+ * The set is NOT here. It is declared in the settings module — `locales.available`
6458
+ * — so that adding a language is something the people who write the content can
6459
+ * do, and so that one list drives validation, the Studio's picker and the
6460
+ * translation notes. This schema knows only that the value is one of them, which
6461
+ * is checked cross-module through the `locale:check-locale` fix, exactly as
6462
+ * `keyOf` and `route` check theirs.
6463
+ *
6464
+ * Never stega encoded (see `stegaEncode.ts`): a locale goes into `<html lang>`,
6465
+ * into `hreflang` and into `Intl` constructors, none of which survive invisible
6466
+ * characters.
6467
+ */
6468
+ var LocaleSchema = /*#__PURE__*/function (_Schema) {
6469
+ /**
6470
+ * Type-only marker: as a record key, this schema DECLARES the key set.
6471
+ *
6472
+ * `declare` so it exists in the type and nowhere at runtime — reading it off
6473
+ * an instance gives `undefined`, and nothing should. It is how `record()`
6474
+ * knows to type entries as `Item | null`: a language nobody has translated
6475
+ * into is a null entry, not an absent key. See `DeclaredKeySet` and
6476
+ * `RecordSrcOf`.
6477
+ */
6478
+
6479
+ function LocaleSchema() {
6480
+ var _this;
6481
+ var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
6482
+ var customValidateFunctions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
6483
+ var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
6484
+ var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
6485
+ var description = arguments.length > 4 ? arguments[4] : undefined;
6486
+ var renderInput = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
6487
+ var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
6488
+ _classCallCheck(this, LocaleSchema);
6489
+ _this = _callSuper(this, LocaleSchema);
6490
+ _this.opt = opt;
6491
+ _this.customValidateFunctions = customValidateFunctions;
6492
+ _this.isReadonly = isReadonly;
6493
+ _this.isHidden = isHidden;
6494
+ _this.description = description;
6495
+ _this.renderInput = renderInput;
6496
+ _this.previewInput = previewInput;
6497
+ return _this;
6498
+ }
6499
+
6500
+ /**
6501
+ * A note to whoever edits this field, shown under it in the Studio.
6502
+ *
6503
+ * Pass `null` to clear a description set earlier.
6504
+ *
6505
+ * @example
6506
+ * const schema = s.object({
6507
+ * locale: s.locale().describe("The language everything below is written in"),
6508
+ * title: s.string(),
6509
+ * });
6510
+ * export default c.define("/example.val.ts", schema, {
6511
+ * locale: "nb-NO",
6512
+ * title: "Vinterjakke",
6513
+ * });
6514
+ */
6515
+ _inherits(LocaleSchema, _Schema);
6516
+ return _createClass(LocaleSchema, [{
6517
+ key: "describe",
6518
+ value: function describe(description) {
6519
+ return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
6520
+ }
6521
+
6522
+ /**
6523
+ * A check of your own, on top of "is this one of the project's languages".
6524
+ *
6525
+ * Return a message when the value is WRONG and `false` when it is fine — the
6526
+ * two answers are a complaint and no complaint, so write the check as a
6527
+ * ternary rather than as `ok || "message"`, which returns `true` and `true`
6528
+ * is neither.
6529
+ *
6530
+ * @example
6531
+ * const schema = s.object({
6532
+ * locale: s.locale().validate((val) =>
6533
+ * val === "en-US" ? "This section is not translated into English yet" : false,
6534
+ * ),
6535
+ * title: s.string(),
6536
+ * });
6537
+ * export default c.define("/example.val.ts", schema, {
6538
+ * locale: "nb-NO",
6539
+ * title: "Vinterjakke",
6540
+ * });
6541
+ */
6542
+ }, {
6543
+ key: "validate",
6544
+ value: function validate(validationFunction) {
6545
+ return new LocaleSchema(this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6546
+ }
6547
+ }, {
6548
+ key: "executeValidate",
6549
+ value: function executeValidate(path, src) {
6550
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
6551
+ path: path
6552
+ });
6553
+ if (this.opt && (src === null || src === undefined)) {
6554
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
6555
+ }
6556
+ if (typeof src !== "string") {
6557
+ return _defineProperty({}, path, [{
6558
+ message: "Expected 'string', got '".concat(_typeof(src), "'"),
6559
+ value: src
6560
+ }]);
6561
+ }
6562
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
6563
+ // Which languages exist is in another module, so this cannot be
6564
+ // answered here — the same shape `keyOf` and `route` use, resolved by
6565
+ // `resolveSchemaSourceFixes` against the settings module.
6566
+ fixes: ["locale:check-locale"],
6567
+ message: "Did not validate locale. This error (locale:check-locale) should typically be processed by Val internally. Seeing this error most likely means you have a Val version mismatch.",
6568
+ value: {
6569
+ locale: src,
6570
+ sourcePath: path
6571
+ }
6572
+ }]));
6573
+ }
6574
+ }, {
6575
+ key: "executeAssert",
6576
+ value: function executeAssert(path, src) {
6577
+ if (this.opt && src === null) {
6578
+ return {
6579
+ success: true,
6580
+ data: src
6581
+ };
6582
+ }
6583
+ if (typeof src === "string") {
6584
+ return {
6585
+ success: true,
6586
+ data: src
6587
+ };
6588
+ }
6589
+ return {
6590
+ success: false,
6591
+ errors: _defineProperty({}, path, [{
6592
+ message: "Expected 'string', got '".concat(_typeof(src), "'"),
6593
+ typeError: true
6594
+ }])
6595
+ };
6596
+ }
6597
+ }, {
6598
+ key: "nullable",
6599
+ value: function nullable() {
6600
+ // Asserted whole, exactly as `RouteSchema.nullable` does: the source type
6601
+ // widens by `null` while the caller's validators and preview stay typed
6602
+ // against the value, and `executeValidate` returns before either sees one.
6603
+ return new LocaleSchema(true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6604
+ }
6605
+ }, {
6606
+ key: "readonly",
6607
+ value: function readonly() {
6608
+ return new LocaleSchema(this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
6609
+ }
6610
+ }, {
6611
+ key: "hidden",
6612
+ value: function hidden() {
6613
+ return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
6614
+ }
6615
+ }, {
6616
+ key: "isLocaleField",
6617
+ value: function isLocaleField() {
6618
+ return true;
6619
+ }
6620
+ }, {
6621
+ key: "executeCustomValidateAt",
6622
+ value: function executeCustomValidateAt(path, src) {
6623
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
6624
+ path: path
6625
+ });
6626
+ }
6627
+
6628
+ /**
6629
+ * How this field is laid out where it is the item of an array or a record.
6630
+ * Static configuration, not a callback — see `render.ts`.
6631
+ *
6632
+ * @example
6633
+ * const schema = s.array(s.locale().render({ as: "inline" }));
6634
+ * export default c.define("/example.val.ts", schema, ["nb-NO", "en-US"]);
6635
+ */
6636
+ }, {
6637
+ key: "render",
6638
+ value: function render(input) {
6639
+ return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
6640
+ }
6641
+
6642
+ /**
6643
+ * How this VALUE is shown where a preview of it is needed. Never how the field
6644
+ * itself is edited (that is `render`). See `preview.ts`.
6645
+ *
6646
+ * @example
6647
+ * const schema = s.array(
6648
+ * s.locale().preview(({ val }) => ({ title: val })),
6649
+ * );
6650
+ * export default c.define("/example.val.ts", schema, ["nb-NO", "en-US"]);
6651
+ */
6652
+ }, {
6653
+ key: "preview",
6654
+ value: function preview(select) {
6655
+ return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
6656
+ }
6657
+ }, {
6658
+ key: "executePreviewItem",
6659
+ value: function executePreviewItem(src) {
6660
+ if (this.previewInput === null) {
6661
+ return null;
6662
+ }
6663
+ return this.previewInput({
6664
+ val: src
6665
+ });
6666
+ }
6667
+ }, {
6668
+ key: "declaresItemPreview",
6669
+ value: function declaresItemPreview() {
6670
+ return this.previewInput !== null;
6671
+ }
6672
+ }, {
6673
+ key: "executeSerialize",
6674
+ value: function executeSerialize() {
6675
+ var _this$renderInput, _this$customValidateF;
6676
+ return {
6677
+ type: "locale",
6678
+ render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
6679
+ preview: this.previewInput ? true : undefined,
6680
+ opt: this.opt,
6681
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
6682
+ readonly: this.isReadonly,
6683
+ hidden: this.isHidden,
6684
+ description: this.description
6685
+ };
6686
+ }
6687
+ }, {
6688
+ key: "executePreview",
6689
+ value: function executePreview() {
6690
+ return {};
6691
+ }
6692
+ }]);
6693
+ }(Schema);
6694
+
6695
+ /**
6696
+ * Define one of the project's languages.
6697
+ *
6698
+ * The languages themselves are declared in the settings module, under
6699
+ * `locales.available` — this says only that a value is one of them.
6700
+ *
6701
+ * @example // a field: everything under this object is in this language
6702
+ * const schema = s.object({ locale: s.locale(), title: s.string() });
6703
+ *
6704
+ * @example // a key: one entry per language
6705
+ * const schema = s.record(s.locale(), s.object({ title: s.string() }));
6706
+ */
6707
+ var locale = function locale() {
6708
+ return new LocaleSchema();
6709
+ };
6710
+
5997
6711
  var BooleanSchema = /*#__PURE__*/function (_Schema) {
5998
6712
  function BooleanSchema() {
5999
6713
  var _this;
@@ -6111,7 +6825,7 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
6111
6825
  }, {
6112
6826
  key: "nullable",
6113
6827
  value: function nullable() {
6114
- return new BooleanSchema(true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6828
+ return new BooleanSchema(true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
6115
6829
  }
6116
6830
  }, {
6117
6831
  key: "readonly",
@@ -6207,6 +6921,99 @@ var _boolean = function _boolean() {
6207
6921
  return new BooleanSchema();
6208
6922
  };
6209
6923
 
6924
+ /**
6925
+ * Language tags, and what makes one wrong.
6926
+ *
6927
+ * Val does not ship a list of locales. Which languages a project publishes is a
6928
+ * property of that project, so it is declared in the settings module — see
6929
+ * `LocalesSettingsSource` — and everything downstream reads it from there.
6930
+ *
6931
+ * What Val does own is the SPELLING. A tag is checked against BCP 47
6932
+ * (RFC 5646) through `Intl.getCanonicalLocales`, which is the same
6933
+ * implementation the browser, `<html lang>` and every `Intl` constructor use.
6934
+ * Delegating rather than writing a matcher is the point: a tag this accepts is
6935
+ * a tag those accept.
6936
+ */
6937
+
6938
+ /**
6939
+ * What is wrong with `tag` as a language tag, or `false` if nothing is.
6940
+ *
6941
+ * Canonical form, not merely parseable, and the difference is what makes this
6942
+ * worth checking at all. `nb-no` parses; `Intl.DisplayNames` and a
6943
+ * case-sensitive comparison against a stored key do not agree about it. Since a
6944
+ * locale is compared as a string everywhere — a record key, a URL segment, a
6945
+ * value in content — one spelling has to win, and the canonical one is the
6946
+ * spelling every other tool already produces.
6947
+ *
6948
+ * The message names the canonical form where there is one, because "not
6949
+ * canonical" is not an instruction and `nb-NO` is.
6950
+ */
6951
+ function localeTagError(tag) {
6952
+ var canonical;
6953
+ try {
6954
+ canonical = Intl.getCanonicalLocales(tag);
6955
+ } catch (_unused) {
6956
+ // RangeError, for anything the grammar rejects: an underscore instead of a
6957
+ // hyphen (`nb_NO`, which is POSIX rather than BCP 47), an empty subtag, a
6958
+ // subtag of the wrong length.
6959
+ return "'".concat(tag, "' is not a language tag. Language then region, separated by a hyphen \u2014 'nb-NO', not 'nb_NO'");
6960
+ }
6961
+ if (canonical.length !== 1) {
6962
+ // A comma-separated list, or something that canonicalised to nothing.
6963
+ return "'".concat(tag, "' is not a single language tag");
6964
+ }
6965
+ if (canonical[0] !== tag) {
6966
+ return "'".concat(tag, "' is not canonical. Write it as '").concat(canonical[0], "'");
6967
+ }
6968
+ return false;
6969
+ }
6970
+
6971
+ /**
6972
+ * A language tag, as content holds it.
6973
+ *
6974
+ * A *flavoured* string rather than a union or a strict brand. Which languages a
6975
+ * project has is declared in its settings module, where the project can change
6976
+ * it, so there is no set for a type to enumerate — and a strict brand would make
6977
+ * `"nb-NO"` unassignable, which would mean writing every locale in a `.val.ts`
6978
+ * through a constructor. Content stays plain data.
6979
+ *
6980
+ * So this carries no compile-time guarantee, and is not meant to. It names the
6981
+ * concept where a bare `string` would say nothing, and the guarantee is the
6982
+ * `locale:check-locale` validation against `locales.available`.
6983
+ */
6984
+
6985
+ /**
6986
+ * The locale a stored value means, or `null` if it means none of them.
6987
+ *
6988
+ * A lookup against the project's languages, and today that is all it is. It
6989
+ * stays a named function because it is the one place the question is asked —
6990
+ * the Studio, the validation worker and the server all come here rather than
6991
+ * comparing strings themselves, so they cannot disagree about what a stored
6992
+ * value is.
6993
+ */
6994
+ function localeOfValue(value, available) {
6995
+ return available.includes(value) ? value : null;
6996
+ }
6997
+
6998
+ /**
6999
+ * A rule about a section that its individual fields cannot state.
7000
+ *
7001
+ * Paths are WITHIN the section, so an error lands on the value it is about —
7002
+ * including a row of a list, which is what makes this different from a
7003
+ * `.validate()` on the field.
7004
+ */
7005
+
7006
+ /**
7007
+ * Every section's rules, by the name that travels in the serialized schema.
7008
+ *
7009
+ * Typed with `| undefined` on the value rather than as a `Partial`: the whole
7010
+ * point is that a lookup can miss, because the name comes off a serialized
7011
+ * schema that may have been written by a newer Val than the one reading it.
7012
+ */
7013
+ var sectionValidators = {
7014
+ locales: localesSectionErrors
7015
+ };
7016
+
6210
7017
  /**
6211
7018
  * An object whose keys are all optional: absent means unset.
6212
7019
  *
@@ -6225,6 +7032,23 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6225
7032
  var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
6226
7033
  var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
6227
7034
  var description = arguments.length > 4 ? arguments[4] : undefined;
7035
+ var
7036
+ /**
7037
+ * Which section this is, where Val has rules about it beyond its keys.
7038
+ *
7039
+ * Not the `validate` the class deliberately does not offer: that one is the
7040
+ * schema author's, and `s.settings()` takes no arguments to declare it
7041
+ * with. This names a rule Val states about a shape Val owns — no language
7042
+ * declared twice in `locales.available` is true of every project, and
7043
+ * there is nowhere else it can be said. A single value's rules stay on its
7044
+ * own schema; this is for the ones that need to see more than one value,
7045
+ * or to report on a row of a list.
7046
+ *
7047
+ * A NAME rather than the function, so it survives serialization: the schema
7048
+ * reaches the Studio's validation worker as JSON, and a closure would be
7049
+ * dropped on the way — which is how these rules once went missing there.
7050
+ */
7051
+ section = arguments.length > 5 ? arguments[5] : undefined;
6228
7052
  _classCallCheck(this, SettingsSchema);
6229
7053
  _this = _callSuper(this, SettingsSchema);
6230
7054
  _this.items = items;
@@ -6232,10 +7056,24 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6232
7056
  _this.isReadonly = isReadonly;
6233
7057
  _this.isHidden = isHidden;
6234
7058
  _this.description = description;
7059
+ _this.section = section;
6235
7060
  return _this;
6236
7061
  }
7062
+
7063
+ /**
7064
+ * This section's rules, or `undefined` where there are none to run.
7065
+ *
7066
+ * A name this Val does not know means a schema written by a newer one. Its
7067
+ * per-field validation still runs; only the section's own rule is missed,
7068
+ * which is the mild half of the failure and better than refusing the schema.
7069
+ */
6237
7070
  _inherits(SettingsSchema, _Schema);
6238
7071
  return _createClass(SettingsSchema, [{
7072
+ key: "sectionValidate",
7073
+ value: function sectionValidate() {
7074
+ return this.section === undefined ? undefined : sectionValidators[this.section];
7075
+ }
7076
+ }, {
6239
7077
  key: "executeValidate",
6240
7078
  value: function executeValidate(path, src) {
6241
7079
  var error = false;
@@ -6288,6 +7126,39 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6288
7126
  }).join(", ")), src, true);
6289
7127
  }
6290
7128
  }
7129
+ var sectionValidate = this.sectionValidate();
7130
+ if (sectionValidate) {
7131
+ var _iterator = result._createForOfIteratorHelper(sectionValidate(src)),
7132
+ _step;
7133
+ try {
7134
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
7135
+ var _ref4;
7136
+ var _step$value = _step.value,
7137
+ keys = _step$value.path,
7138
+ message = _step$value.message;
7139
+ var _subPath = path;
7140
+ var _iterator2 = result._createForOfIteratorHelper(keys),
7141
+ _step2;
7142
+ try {
7143
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
7144
+ var _key3 = _step2.value;
7145
+ _subPath = _subPath && createValPathOfItem(_subPath, _key3);
7146
+ }
7147
+ } catch (err) {
7148
+ _iterator2.e(err);
7149
+ } finally {
7150
+ _iterator2.f();
7151
+ }
7152
+ error = this.appendValidationError(error, // Falls back to the section itself, which is where an error belongs
7153
+ // when the value it is about is not addressable.
7154
+ (_ref4 = _subPath) !== null && _ref4 !== void 0 ? _ref4 : path, message, src);
7155
+ }
7156
+ } catch (err) {
7157
+ _iterator.e(err);
7158
+ } finally {
7159
+ _iterator.f();
7160
+ }
7161
+ }
6291
7162
  return error;
6292
7163
  }
6293
7164
  }, {
@@ -6333,17 +7204,17 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6333
7204
  }, {
6334
7205
  key: "nullable",
6335
7206
  value: function nullable() {
6336
- return new SettingsSchema(this.items, true, this.isReadonly, this.isHidden, this.description);
7207
+ return new SettingsSchema(this.items, true, this.isReadonly, this.isHidden, this.description, this.section);
6337
7208
  }
6338
7209
  }, {
6339
7210
  key: "readonly",
6340
7211
  value: function readonly() {
6341
- return new SettingsSchema(this.items, this.opt, true, this.isHidden, this.description);
7212
+ return new SettingsSchema(this.items, this.opt, true, this.isHidden, this.description, this.section);
6342
7213
  }
6343
7214
  }, {
6344
7215
  key: "hidden",
6345
7216
  value: function hidden() {
6346
- return new SettingsSchema(this.items, this.opt, this.isReadonly, true, this.description);
7217
+ return new SettingsSchema(this.items, this.opt, this.isReadonly, true, this.description, this.section);
6347
7218
  }
6348
7219
  }, {
6349
7220
  key: "executeCustomValidateAt",
@@ -6358,16 +7229,17 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6358
7229
  value: function executeSerialize() {
6359
7230
  return {
6360
7231
  type: "settings",
6361
- items: Object.fromEntries(Object.entries(this.items).map(function (_ref4) {
6362
- var _ref5 = _slicedToArray(_ref4, 2),
6363
- key = _ref5[0],
6364
- schema = _ref5[1];
7232
+ items: Object.fromEntries(Object.entries(this.items).map(function (_ref5) {
7233
+ var _ref6 = _slicedToArray(_ref5, 2),
7234
+ key = _ref6[0],
7235
+ schema = _ref6[1];
6365
7236
  return [key, schema["executeSerialize"]()];
6366
7237
  })),
6367
7238
  opt: this.opt,
6368
7239
  readonly: this.isReadonly,
6369
7240
  hidden: this.isHidden,
6370
- description: this.description
7241
+ description: this.description,
7242
+ section: this.section
6371
7243
  };
6372
7244
  }
6373
7245
  }, {
@@ -6377,19 +7249,19 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
6377
7249
  if (src === null) {
6378
7250
  return res;
6379
7251
  }
6380
- for (var _key3 in this.items) {
6381
- var itemSrc = src[_key3];
7252
+ for (var _key4 in this.items) {
7253
+ var itemSrc = src[_key4];
6382
7254
  if (itemSrc === null || itemSrc === undefined) {
6383
7255
  continue;
6384
7256
  }
6385
- var subPath = unsafeCreateSourcePath(sourcePath, _key3);
7257
+ var subPath = unsafeCreateSourcePath(sourcePath, _key4);
6386
7258
  if (scope !== undefined && !scope.wantsUnder(subPath)) {
6387
7259
  continue;
6388
7260
  }
6389
- var itemResult = this.items[_key3]["executePreview"](subPath, itemSrc, scope);
7261
+ var itemResult = this.items[_key4]["executePreview"](subPath, itemSrc, scope);
6390
7262
  for (var keyS in itemResult) {
6391
- var _key4 = keyS;
6392
- res[_key4] = itemResult[_key4];
7263
+ var _key5 = keyS;
7264
+ res[_key5] = itemResult[_key5];
6393
7265
  }
6394
7266
  }
6395
7267
  return res;
@@ -6433,11 +7305,58 @@ function settings() {
6433
7305
  assistant: new SettingsSchema({
6434
7306
  enabled: _boolean().nullable().describe("Whether editors have an assistant in this project. Unset means nobody has decided: it is offered, and turned on when someone accepts."),
6435
7307
  context: string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable().describe("Background the assistant would otherwise have to guess: what this site is, who runs it, names and spellings that matter."),
6436
- tone: string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable().describe("How the assistant should write when it writes content: formal or playful, British or American, how headings are cased.")
6437
- })
7308
+ tone: string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable().describe("How the assistant should write when it writes content: formal or playful, British or American, how headings are cased."),
7309
+ translation: record(locale(), string().multiline().maxLength(ASSISTANT_SETTINGS_MAX_LENGTH).nullable()).nullable().describe("How to translate into each language: dialect, formality, and the words that stay untranslated.")
7310
+ }),
7311
+ locales: new SettingsSchema({
7312
+ // Nullable because the source type is, and because the Studio writes
7313
+ // `null` for every sibling the first time a section is created.
7314
+ available: array(string()).nullable().describe("The languages this project publishes, as BCP 47 tags: en-US, nb-NO. The order is kept: it is the order of the Studio's picker and of a locale-keyed record's rows.")
7315
+ }, false, false, false, undefined, "locales")
6438
7316
  });
6439
7317
  }
6440
7318
 
7319
+ /**
7320
+ * The rules about `locales` that need to see the whole list.
7321
+ *
7322
+ * Two of them, and both report on the ENTRY rather than the list: a tag has to
7323
+ * be spelled canonically, and a language cannot be declared twice. Neither can
7324
+ * live on the item schema — the item sees one string, and "twice" is a fact
7325
+ * about its siblings — and neither can be a `.validate()` on the array either,
7326
+ * since that reports one message on the array itself rather than on the row to
7327
+ * delete.
7328
+ *
7329
+ * Reads defensively rather than asserting the source's type. A settings module
7330
+ * is a file someone edits by hand, and validation runs against whatever is in
7331
+ * it — including the shapes the per-key pass is, in the same breath, reporting.
7332
+ */
7333
+ function localesSectionErrors(src) {
7334
+ var errors = [];
7335
+ var raw = Array.isArray(src["available"]) ? src["available"] : [];
7336
+ var seen = new Set();
7337
+ for (var i = 0; i < raw.length; i++) {
7338
+ var tag = raw[i];
7339
+ if (typeof tag !== "string") {
7340
+ // The item's own schema has already said what is wrong with it.
7341
+ continue;
7342
+ }
7343
+ var spelling = localeTagError(tag);
7344
+ if (spelling !== false) {
7345
+ errors.push({
7346
+ path: ["available", i],
7347
+ message: spelling
7348
+ });
7349
+ } else if (seen.has(tag)) {
7350
+ errors.push({
7351
+ path: ["available", i],
7352
+ message: "'".concat(tag, "' is declared twice")
7353
+ });
7354
+ }
7355
+ seen.add(tag);
7356
+ }
7357
+ return errors;
7358
+ }
7359
+
6441
7360
  /**
6442
7361
  * What may be WRITTEN as an external record's source, on top of the marker.
6443
7362
  *
@@ -7151,7 +8070,7 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
7151
8070
  }, {
7152
8071
  key: "nullable",
7153
8072
  value: function nullable() {
7154
- return new NumberSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
8073
+ return new NumberSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7155
8074
  }
7156
8075
  }, {
7157
8076
  key: "readonly",
@@ -7288,6 +8207,15 @@ var number = function number(options) {
7288
8207
  * discriminated union's variants and must not try to recurse into these.
7289
8208
  */
7290
8209
  var EnumSchema = /*#__PURE__*/function (_Schema) {
8210
+ /**
8211
+ * Type-only marker: as a record key, this declares the key set.
8212
+ *
8213
+ * An enum names every value it may take, so a record keyed by one holds
8214
+ * exactly those keys — the same claim `s.literal()` and `s.locale()` make.
8215
+ * `DiscriminatedUnionSchema` carries no marker: it discriminates objects and
8216
+ * cannot be a record key at all. See `LocaleSchema`.
8217
+ */
8218
+
7291
8219
  function EnumSchema(values) {
7292
8220
  var _this;
7293
8221
  var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
@@ -7441,7 +8369,7 @@ var EnumSchema = /*#__PURE__*/function (_Schema) {
7441
8369
  key: "nullable",
7442
8370
  value: function nullable() {
7443
8371
  // Explicit type args: `previewInput` would otherwise pin inference to `Src`.
7444
- return new EnumSchema(this.values, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
8372
+ return new EnumSchema(this.values, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7445
8373
  }
7446
8374
  }, {
7447
8375
  key: "readonly",
@@ -7832,7 +8760,7 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
7832
8760
  }, {
7833
8761
  key: "nullable",
7834
8762
  value: function nullable() {
7835
- return new KeyOfSchema(this.schema, this.sourcePath, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
8763
+ return new KeyOfSchema(this.schema, this.sourcePath, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
7836
8764
  }
7837
8765
  }, {
7838
8766
  key: "readonly",
@@ -8606,7 +9534,7 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
8606
9534
  }, {
8607
9535
  key: "nullable",
8608
9536
  value: function nullable() {
8609
- return new DateSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
9537
+ return new DateSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
8610
9538
  }
8611
9539
  }, {
8612
9540
  key: "readonly",
@@ -8942,7 +9870,7 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
8942
9870
  }, {
8943
9871
  key: "nullable",
8944
9872
  value: function nullable() {
8945
- return new DateTimeSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
9873
+ return new DateTimeSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
8946
9874
  }
8947
9875
  }, {
8948
9876
  key: "readonly",
@@ -9190,7 +10118,7 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
9190
10118
  }, {
9191
10119
  key: "nullable",
9192
10120
  value: function nullable() {
9193
- return new CodeSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
10121
+ return new CodeSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
9194
10122
  }
9195
10123
  }, {
9196
10124
  key: "readonly",
@@ -9938,7 +10866,7 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
9938
10866
  }, {
9939
10867
  key: "nullable",
9940
10868
  value: function nullable() {
9941
- return new ColorSchema(this.options, true, [], this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
10869
+ return new ColorSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
9942
10870
  }
9943
10871
  }, {
9944
10872
  key: "readonly",
@@ -10127,6 +11055,7 @@ function initSchema() {
10127
11055
  datetime: datetime,
10128
11056
  color: color,
10129
11057
  code: code,
11058
+ locale: locale,
10130
11059
  route: route,
10131
11060
  router: router,
10132
11061
  images: images,
@@ -10265,6 +11194,8 @@ var Hash = /*#__PURE__*/function () {
10265
11194
  _defineProperty(this, "F", 0x9b05688c | 0);
10266
11195
  _defineProperty(this, "G", 0x1f83d9ab | 0);
10267
11196
  _defineProperty(this, "H", 0x5be0cd19 | 0);
11197
+ _defineProperty(this, "_byte", void 0);
11198
+ _defineProperty(this, "_word", void 0);
10268
11199
  _defineProperty(this, "_size", 0);
10269
11200
  _defineProperty(this, "_sp", 0);
10270
11201
  if (!sharedBuffer || sharedOffset >= N.allocTotal) {
@@ -11051,7 +11982,7 @@ function hasRemoteFileSchema(schema) {
11051
11982
  return false;
11052
11983
  } else if (schema.type === "boolean" ||
11053
11984
  // An enum's values are strings, so there is nothing to look inside.
11054
- schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route") {
11985
+ schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" || schema.type === "locale") {
11055
11986
  return false;
11056
11987
  } else {
11057
11988
  var exhaustiveCheck = schema;
@@ -11123,7 +12054,7 @@ function hasMediaSchema(schema) {
11123
12054
  return false;
11124
12055
  } else if (schema.type === "boolean" ||
11125
12056
  // An enum's values are strings, so there is nothing to look inside.
11126
- schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" ||
12057
+ schema.type === "enum" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" || schema.type === "locale" ||
11127
12058
  // A settings module holds the assistant's configuration, not content, and
11128
12059
  // nothing in it is media.
11129
12060
  schema.type === "settings") {
@@ -11402,6 +12333,46 @@ function getFileHash(text) {
11402
12333
  return hashToRemoteFileHash(getSHA256Hash(new Uint8Array(text)));
11403
12334
  }
11404
12335
 
12336
+ /**
12337
+ * The variant of a discriminated union that a value takes, by its tag.
12338
+ *
12339
+ * A discriminated union is a fork rather than a level: the variant IS the node,
12340
+ * and everything a caller wants to know about that node — its fields, its
12341
+ * `locale` field, the schema to draw it with — is on the variant and not on the
12342
+ * union. Resolving it takes the source, so it cannot be done from the schema
12343
+ * alone, which is why every caller that has only the union ends up needing this.
12344
+ *
12345
+ * `undefined` where the tag matches nothing, rather than a fallback to the first
12346
+ * variant: a value whose tag names no variant is not a member of the union,
12347
+ * validation is already saying so, and reading fields out of the wrong shape
12348
+ * would answer confidently and wrongly.
12349
+ *
12350
+ * `s.enum()` never reaches here — it is a leaf whose values are strings, with no
12351
+ * variants to resolve — so anything that is not a discriminated union answers
12352
+ * `undefined` too.
12353
+ */
12354
+ function discriminatedUnionBranchOf(schema, tag) {
12355
+ if ((schema === null || schema === void 0 ? void 0 : schema.type) !== "discriminated-union") {
12356
+ return undefined;
12357
+ }
12358
+ var _iterator = result._createForOfIteratorHelper(schema.items),
12359
+ _step;
12360
+ try {
12361
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
12362
+ var item = _step.value;
12363
+ var discriminator = item.items[schema.key];
12364
+ if ((discriminator === null || discriminator === void 0 ? void 0 : discriminator.type) === "literal" && discriminator.value === tag) {
12365
+ return item;
12366
+ }
12367
+ }
12368
+ } catch (err) {
12369
+ _iterator.e(err);
12370
+ } finally {
12371
+ _iterator.f();
12372
+ }
12373
+ return undefined;
12374
+ }
12375
+
11405
12376
  function deserializeSchema(serialized) {
11406
12377
  var schema = deserializeSchemaImpl(serialized);
11407
12378
  if (serialized.readonly) {
@@ -11413,7 +12384,7 @@ function deserializeSchema(serialized) {
11413
12384
  return schema;
11414
12385
  }
11415
12386
  function deserializeSchemaImpl(serialized) {
11416
- var _serialized$options, _serialized$options2, _serialized$render, _serialized$multiline, _serialized$render2, _serialized$render3, _serialized$render4, _serialized$render5, _serialized$render6, _serialized$render7, _serialized$render8, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue, _serialized$render0, _serialized$external, _serialized$render1, _serialized$render11, _serialized$render12, _serialized$render13, _serialized$render14, _serialized$render15, _serialized$render16;
12387
+ var _serialized$options, _serialized$options2, _serialized$render, _serialized$multiline, _serialized$render2, _serialized$render3, _serialized$render4, _serialized$render5, _serialized$render6, _serialized$render7, _serialized$render8, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue, _serialized$render0, _serialized$external, _serialized$render1, _serialized$render12, _serialized$render13, _serialized$render14, _serialized$render15, _serialized$render16, _serialized$render17;
11417
12388
  switch (serialized.type) {
11418
12389
  case "string":
11419
12390
  return new StringSchema(_objectSpread2(_objectSpread2({}, serialized.options), {}, {
@@ -11442,7 +12413,12 @@ function deserializeSchemaImpl(serialized) {
11442
12413
  key = _ref4[0],
11443
12414
  item = _ref4[1];
11444
12415
  return [key, deserializeSchema(item)];
11445
- })), serialized.opt, false, false, serialized.description);
12416
+ })), serialized.opt, false, false, serialized.description,
12417
+ // Carried through, or the Studio's validation worker — which only ever
12418
+ // sees the deserialized schema — would run every field's own rules and
12419
+ // none of the section's, so a language declared twice would be reported
12420
+ // by the CLI and silently accepted in the Studio.
12421
+ serialized.section);
11446
12422
  case "array":
11447
12423
  return new ArraySchema(deserializeSchema(serialized.item), serialized.opt, [], false, false, serialized.description,
11448
12424
  // The preview closure cannot survive serialization; the render can.
@@ -11479,27 +12455,32 @@ function deserializeSchemaImpl(serialized) {
11479
12455
  (_serialized$external = serialized.external) !== null && _serialized$external !== void 0 ? _serialized$external : null);
11480
12456
  case "keyOf":
11481
12457
  return new KeyOfSchema(serialized.schema, serialized.path, serialized.opt, [], false, false, serialized.description, (_serialized$render1 = serialized.render) !== null && _serialized$render1 !== void 0 ? _serialized$render1 : null);
11482
- case "route":
12458
+ case "locale":
11483
12459
  {
11484
12460
  var _serialized$render10;
12461
+ return new LocaleSchema(serialized.opt, [], false, false, serialized.description, (_serialized$render10 = serialized.render) !== null && _serialized$render10 !== void 0 ? _serialized$render10 : null);
12462
+ }
12463
+ case "route":
12464
+ {
12465
+ var _serialized$render11;
11485
12466
  var routeOptions = serialized.options ? {
11486
12467
  include: serialized.options.include ? new RegExp(serialized.options.include.source, serialized.options.include.flags) : undefined,
11487
12468
  exclude: serialized.options.exclude ? new RegExp(serialized.options.exclude.source, serialized.options.exclude.flags) : undefined
11488
12469
  } : undefined;
11489
- return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render10 = serialized.render) !== null && _serialized$render10 !== void 0 ? _serialized$render10 : null);
12470
+ return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render11 = serialized.render) !== null && _serialized$render11 !== void 0 ? _serialized$render11 : null);
11490
12471
  }
11491
12472
  case "file":
11492
- return new FileSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render11 = serialized.render) !== null && _serialized$render11 !== void 0 ? _serialized$render11 : null);
12473
+ return new FileSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render12 = serialized.render) !== null && _serialized$render12 !== void 0 ? _serialized$render12 : null);
11493
12474
  case "image":
11494
- return new ImageSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render12 = serialized.render) !== null && _serialized$render12 !== void 0 ? _serialized$render12 : null);
12475
+ return new ImageSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$render13 = serialized.render) !== null && _serialized$render13 !== void 0 ? _serialized$render13 : null);
11495
12476
  case "date":
11496
- return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render13 = serialized.render) !== null && _serialized$render13 !== void 0 ? _serialized$render13 : null);
12477
+ return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render14 = serialized.render) !== null && _serialized$render14 !== void 0 ? _serialized$render14 : null);
11497
12478
  case "dateTime":
11498
- return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render14 = serialized.render) !== null && _serialized$render14 !== void 0 ? _serialized$render14 : null);
12479
+ return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render15 = serialized.render) !== null && _serialized$render15 !== void 0 ? _serialized$render15 : null);
11499
12480
  case "color":
11500
- return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render15 = serialized.render) !== null && _serialized$render15 !== void 0 ? _serialized$render15 : null);
12481
+ return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render16 = serialized.render) !== null && _serialized$render16 !== void 0 ? _serialized$render16 : null);
11501
12482
  case "code":
11502
- return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render16 = serialized.render) !== null && _serialized$render16 !== void 0 ? _serialized$render16 : null);
12483
+ return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render17 = serialized.render) !== null && _serialized$render17 !== void 0 ? _serialized$render17 : null);
11503
12484
  default:
11504
12485
  {
11505
12486
  var exhaustiveCheck = serialized;
@@ -12166,7 +13147,7 @@ function isPageRouter(routerId) {
12166
13147
 
12167
13148
  var corePackageJson = {
12168
13149
  name: "@valbuild/core",
12169
- version: "0.126.0",
13150
+ version: "0.127.0",
12170
13151
  "private": false,
12171
13152
  description: "Val - supercharged hard-coded content",
12172
13153
  repository: {
@@ -12359,6 +13340,7 @@ exports.ImageSchema = ImageSchema;
12359
13340
  exports.Internal = Internal;
12360
13341
  exports.KeyOfSchema = KeyOfSchema;
12361
13342
  exports.LiteralSchema = LiteralSchema;
13343
+ exports.LocaleSchema = LocaleSchema;
12362
13344
  exports.ModuleFilePathSep = ModuleFilePathSep;
12363
13345
  exports.NumberSchema = NumberSchema;
12364
13346
  exports.ObjectSchema = ObjectSchema;
@@ -12378,8 +13360,10 @@ exports._toConsumableArray = _toConsumableArray;
12378
13360
  exports._typeof = _typeof;
12379
13361
  exports.assistantAvailability = assistantAvailability;
12380
13362
  exports.computeValModuleShas = computeValModuleShas;
13363
+ exports.declaredKeySetOf = declaredKeySetOf;
12381
13364
  exports.derefPatch = derefPatch;
12382
13365
  exports.deserializeSchema = deserializeSchema;
13366
+ exports.discriminatedUnionBranchOf = discriminatedUnionBranchOf;
12383
13367
  exports.extractValModules = extractValModules;
12384
13368
  exports.getSourcePathFromRoute = getSourcePathFromRoute;
12385
13369
  exports.hasMediaSchema = hasMediaSchema;
@@ -12388,6 +13372,9 @@ exports.initVal = initVal;
12388
13372
  exports.isInlineRender = isInlineRender;
12389
13373
  exports.isPageRouter = isPageRouter;
12390
13374
  exports.isRootModuleFilePath = isRootModuleFilePath;
13375
+ exports.localeOfValue = localeOfValue;
13376
+ exports.localeTagError = localeTagError;
13377
+ exports.missingDeclaredKeys = missingDeclaredKeys;
12391
13378
  exports.modules = modules;
12392
13379
  exports.parseNextJsRoutePattern = parseNextJsRoutePattern;
12393
13380
  exports.parseTanStackRoutePattern = parseTanStackRoutePattern;