@valbuild/core 0.125.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.
- package/CHANGELOG.md +299 -0
- package/dist/declarations/src/index.d.ts +8 -2
- package/dist/declarations/src/initSchema.d.ts +62 -15
- package/dist/declarations/src/initVal.d.ts +108 -0
- package/dist/declarations/src/locale.d.ts +55 -0
- package/dist/declarations/src/render.d.ts +5 -4
- package/dist/declarations/src/schema/array.d.ts +69 -0
- package/dist/declarations/src/schema/boolean.d.ts +44 -0
- package/dist/declarations/src/schema/code.d.ts +63 -0
- package/dist/declarations/src/schema/color.d.ts +54 -0
- package/dist/declarations/src/schema/date.d.ts +64 -2
- package/dist/declarations/src/schema/datetime.d.ts +87 -2
- package/dist/declarations/src/schema/declaredKeys.d.ts +37 -0
- package/dist/declarations/src/schema/discriminatedUnion.d.ts +170 -0
- package/dist/declarations/src/schema/discriminatedUnionBranch.d.ts +20 -0
- package/dist/declarations/src/schema/enum.d.ts +131 -0
- package/dist/declarations/src/schema/file.d.ts +77 -0
- package/dist/declarations/src/schema/image.d.ts +102 -0
- package/dist/declarations/src/schema/index.d.ts +155 -2
- package/dist/declarations/src/schema/keyOf.d.ts +50 -0
- package/dist/declarations/src/schema/literal.d.ts +48 -0
- package/dist/declarations/src/schema/locale.d.ts +132 -0
- package/dist/declarations/src/schema/number.d.ts +58 -0
- package/dist/declarations/src/schema/object.d.ts +70 -0
- package/dist/declarations/src/schema/record.d.ts +187 -1
- package/dist/declarations/src/schema/richtext.d.ts +78 -0
- package/dist/declarations/src/schema/route.d.ts +44 -0
- package/dist/declarations/src/schema/settings.d.ts +54 -1
- package/dist/declarations/src/schema/string.d.ts +99 -0
- package/dist/declarations/src/schema/union.d.ts +54 -91
- package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
- package/dist/declarations/src/source/settings.d.ts +51 -0
- package/dist/{index-915dd675.esm.js → index-5a6e6398.esm.js} +3057 -573
- package/dist/{index-daa122af.cjs.dev.js → index-889ac441.cjs.dev.js} +3064 -573
- package/dist/{index-a3846321.cjs.prod.js → index-d44deccb.cjs.prod.js} +3064 -573
- package/dist/valbuild-core.cjs.dev.js +9 -2
- package/dist/valbuild-core.cjs.prod.js +9 -2
- package/dist/valbuild-core.esm.js +1 -1
- package/package.json +1 -1
- package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
- package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
- package/patch/dist/valbuild-core-patch.esm.js +2 -2
|
@@ -161,19 +161,217 @@ function _inherits(t, e) {
|
|
|
161
161
|
// import { SerializedI18nSchema } from "./future/i18n";
|
|
162
162
|
// import { SerializedOneOfSchema } from "./future/oneOf";
|
|
163
163
|
|
|
164
|
+
/**
|
|
165
|
+
* A locale scope's path, as something to read in a message.
|
|
166
|
+
*
|
|
167
|
+
* The walk names the item of an array or record `*`, which says nothing to
|
|
168
|
+
* whoever has to fix this. `[]` is the convention people already read as "each
|
|
169
|
+
* of these", and a path that is nothing BUT items has no field to name at all.
|
|
170
|
+
*/
|
|
171
|
+
function describeScopePath(path) {
|
|
172
|
+
if (path.every(function (segment) {
|
|
173
|
+
return segment === "*";
|
|
174
|
+
})) {
|
|
175
|
+
return "its entries";
|
|
176
|
+
}
|
|
177
|
+
var rendered = "";
|
|
178
|
+
var _iterator = _createForOfIteratorHelper(path),
|
|
179
|
+
_step;
|
|
180
|
+
try {
|
|
181
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
182
|
+
var segment = _step.value;
|
|
183
|
+
if (segment === "*") {
|
|
184
|
+
rendered += "[]";
|
|
185
|
+
} else {
|
|
186
|
+
rendered += rendered === "" ? segment : ".".concat(segment);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
_iterator.e(err);
|
|
191
|
+
} finally {
|
|
192
|
+
_iterator.f();
|
|
193
|
+
}
|
|
194
|
+
return "'".concat(rendered, "'");
|
|
195
|
+
}
|
|
164
196
|
var Schema = /*#__PURE__*/function () {
|
|
165
197
|
function Schema() {
|
|
166
198
|
_classCallCheck(this, Schema);
|
|
199
|
+
/**
|
|
200
|
+
* The answer, computed once per schema.
|
|
201
|
+
*
|
|
202
|
+
* Memoised because the question is asked from `executeValidate`, which runs
|
|
203
|
+
* once per SOURCE instance: an array of five hundred blocks asks the item
|
|
204
|
+
* schema five hundred times, and each answer walks the schema below it
|
|
205
|
+
* looking for a nested scope. The answer cannot differ between two instances
|
|
206
|
+
* of the same schema — nothing here reads the source — so the walk is done
|
|
207
|
+
* once and the result handed back after that.
|
|
208
|
+
*
|
|
209
|
+
* The error is still reported at every instance's path. Val's validation
|
|
210
|
+
* errors are keyed by source path and that is where the Studio draws them, so
|
|
211
|
+
* a schema error on a row is a schema error on every row; reporting it on one
|
|
212
|
+
* arbitrary row would put it somewhere nobody was looking.
|
|
213
|
+
*/
|
|
214
|
+
_defineProperty(this, "localeScopeErrorsMemo", void 0);
|
|
167
215
|
}
|
|
168
216
|
return _createClass(Schema, [{
|
|
217
|
+
key: "isLocaleField",
|
|
218
|
+
value:
|
|
219
|
+
/**
|
|
220
|
+
* Whether this node is a locale — the field that MARKS a scope, `s.locale()`.
|
|
221
|
+
*
|
|
222
|
+
* Only `LocaleSchema` overrides this. A base implementation rather than an
|
|
223
|
+
* abstract one on purpose: every other schema class answers no, and a
|
|
224
|
+
* question every class had to answer would be twenty edits for one yes.
|
|
225
|
+
*
|
|
226
|
+
* Not the same question as {@link opensLocaleScope}: a locale field marks the
|
|
227
|
+
* scope, the object AROUND it is the scope. See `localeScope.ts`.
|
|
228
|
+
*/
|
|
229
|
+
function isLocaleField() {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Whether this node OPENS a locale scope, and what opens it.
|
|
235
|
+
*
|
|
236
|
+
* An object with a `s.locale()` field opens one; so does a record keyed by
|
|
237
|
+
* `s.locale()`. Everything below such a node is in that one language, which
|
|
238
|
+
* is why a scope may not contain another — see `localeScope.ts` for the rule
|
|
239
|
+
* and the reason it is validated rather than typed.
|
|
240
|
+
*/
|
|
241
|
+
}, {
|
|
242
|
+
key: "opensLocaleScope",
|
|
243
|
+
value: function opensLocaleScope() {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The child schemas a locale scope reaches, by the path segment that reaches
|
|
249
|
+
* them.
|
|
250
|
+
*
|
|
251
|
+
* A structural walk that deliberately does NOT go through `executeSerialize`:
|
|
252
|
+
* serializing a subtree at every node to ask a question about its shape is
|
|
253
|
+
* quadratic, and this is asked during validation. `*` stands for the item of
|
|
254
|
+
* an array or record, which has no name of its own.
|
|
255
|
+
*/
|
|
256
|
+
}, {
|
|
257
|
+
key: "localeScopeChildren",
|
|
258
|
+
value: function localeScopeChildren() {
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Every locale scope opened strictly BELOW this node, by path.
|
|
264
|
+
*
|
|
265
|
+
* Stops descending at each one it finds, so a scope three deep is reported
|
|
266
|
+
* once, by the scope immediately enclosing it, rather than by every ancestor.
|
|
267
|
+
*/
|
|
268
|
+
}, {
|
|
269
|
+
key: "localeScopesBelow",
|
|
270
|
+
value: function localeScopesBelow() {
|
|
271
|
+
var prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
272
|
+
var found = [];
|
|
273
|
+
var _iterator2 = _createForOfIteratorHelper(this.localeScopeChildren()),
|
|
274
|
+
_step2;
|
|
275
|
+
try {
|
|
276
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
277
|
+
var _step2$value = _step2.value,
|
|
278
|
+
key = _step2$value.key,
|
|
279
|
+
schema = _step2$value.schema;
|
|
280
|
+
var _path = [].concat(_toConsumableArray(prefix), [key]);
|
|
281
|
+
var opened = schema.opensLocaleScope();
|
|
282
|
+
if (opened !== null) {
|
|
283
|
+
found.push({
|
|
284
|
+
path: _path,
|
|
285
|
+
kind: opened
|
|
286
|
+
});
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
found.push.apply(found, _toConsumableArray(schema.localeScopesBelow(_path)));
|
|
290
|
+
}
|
|
291
|
+
} catch (err) {
|
|
292
|
+
_iterator2.e(err);
|
|
293
|
+
} finally {
|
|
294
|
+
_iterator2.f();
|
|
295
|
+
}
|
|
296
|
+
return found;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* The scope rule, as errors at this node — or `false` if it is not broken.
|
|
301
|
+
*
|
|
302
|
+
* Two things are wrong and both are wrong in the SCHEMA rather than in the
|
|
303
|
+
* content, so both are `schemaError`s: an object with two locale fields (the
|
|
304
|
+
* subtree below it would be in two languages at once), and a locale scope
|
|
305
|
+
* inside another (the inner one would silently override the outer for part
|
|
306
|
+
* of a subtree that is supposed to be one language throughout).
|
|
307
|
+
*
|
|
308
|
+
* Validated rather than typed on purpose. Expressing "no scope below this
|
|
309
|
+
* one" as a constraint means threading it through every schema class's type
|
|
310
|
+
* parameter, and the errors that fall out of a recursive constraint like
|
|
311
|
+
* that name the whole tree — an unrelated typo in a `.val.ts` would print
|
|
312
|
+
* pages. See the design notes on the locales PR.
|
|
313
|
+
*/
|
|
314
|
+
}, {
|
|
315
|
+
key: "localeScopeErrors",
|
|
316
|
+
value: function localeScopeErrors() {
|
|
317
|
+
if (this.localeScopeErrorsMemo === undefined) {
|
|
318
|
+
this.localeScopeErrorsMemo = this.computeLocaleScopeErrors();
|
|
319
|
+
}
|
|
320
|
+
return this.localeScopeErrorsMemo;
|
|
321
|
+
}
|
|
322
|
+
}, {
|
|
323
|
+
key: "computeLocaleScopeErrors",
|
|
324
|
+
value: function computeLocaleScopeErrors() {
|
|
325
|
+
var errors = [];
|
|
326
|
+
var localeFields = this.localeFieldNames();
|
|
327
|
+
if (localeFields.length > 1) {
|
|
328
|
+
errors.push({
|
|
329
|
+
message: "An object can be in one language, so it can have one locale field. Found ".concat(localeFields.map(function (each) {
|
|
330
|
+
return "'".concat(each, "'");
|
|
331
|
+
}).join(", "), "."),
|
|
332
|
+
schemaError: true
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
var opened = this.opensLocaleScope();
|
|
336
|
+
if (opened !== null) {
|
|
337
|
+
var _iterator3 = _createForOfIteratorHelper(this.localeScopesBelow()),
|
|
338
|
+
_step3;
|
|
339
|
+
try {
|
|
340
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
341
|
+
var nested = _step3.value;
|
|
342
|
+
errors.push({
|
|
343
|
+
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."),
|
|
344
|
+
schemaError: true
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
} catch (err) {
|
|
348
|
+
_iterator3.e(err);
|
|
349
|
+
} finally {
|
|
350
|
+
_iterator3.f();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return errors;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* This node's own `s.locale()` fields, where it is an object that has any.
|
|
358
|
+
*
|
|
359
|
+
* Empty everywhere else, so `localeScopeErrors` can live on the base class.
|
|
360
|
+
*/
|
|
361
|
+
}, {
|
|
362
|
+
key: "localeFieldNames",
|
|
363
|
+
value: function localeFieldNames() {
|
|
364
|
+
return [];
|
|
365
|
+
}
|
|
366
|
+
}, {
|
|
169
367
|
key: "executeCustomValidateFunctions",
|
|
170
368
|
value: function executeCustomValidateFunctions(src, customValidateFunctions, ctx) {
|
|
171
369
|
var errors = [];
|
|
172
|
-
var
|
|
173
|
-
|
|
370
|
+
var _iterator4 = _createForOfIteratorHelper(customValidateFunctions),
|
|
371
|
+
_step4;
|
|
174
372
|
try {
|
|
175
|
-
for (
|
|
176
|
-
var customValidateFunction =
|
|
373
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
374
|
+
var customValidateFunction = _step4.value;
|
|
177
375
|
try {
|
|
178
376
|
var result = customValidateFunction(src, ctx);
|
|
179
377
|
if (result) {
|
|
@@ -191,9 +389,9 @@ var Schema = /*#__PURE__*/function () {
|
|
|
191
389
|
}
|
|
192
390
|
}
|
|
193
391
|
} catch (err) {
|
|
194
|
-
|
|
392
|
+
_iterator4.e(err);
|
|
195
393
|
} finally {
|
|
196
|
-
|
|
394
|
+
_iterator4.f();
|
|
197
395
|
}
|
|
198
396
|
return errors;
|
|
199
397
|
}
|
|
@@ -292,11 +490,11 @@ var Schema = /*#__PURE__*/function () {
|
|
|
292
490
|
return incoming;
|
|
293
491
|
}
|
|
294
492
|
for (var pathS in incoming) {
|
|
295
|
-
var
|
|
296
|
-
if (current[
|
|
297
|
-
current[
|
|
493
|
+
var _path2 = pathS;
|
|
494
|
+
if (current[_path2]) {
|
|
495
|
+
current[_path2] = current[_path2].concat(incoming[_path2]);
|
|
298
496
|
} else {
|
|
299
|
-
current[
|
|
497
|
+
current[_path2] = incoming[_path2];
|
|
300
498
|
}
|
|
301
499
|
}
|
|
302
500
|
return current;
|
|
@@ -331,6 +529,10 @@ var GetSource = Symbol["for"]("@valbuild/core/GetSource");
|
|
|
331
529
|
var ValError = Symbol["for"]("@valbuild/core/ValError");
|
|
332
530
|
var GenericSelector = /*#__PURE__*/_createClass(function GenericSelector(valOrExpr, path, schema, error) {
|
|
333
531
|
_classCallCheck(this, GenericSelector);
|
|
532
|
+
_defineProperty(this, Path, void 0);
|
|
533
|
+
_defineProperty(this, GetSource, void 0);
|
|
534
|
+
_defineProperty(this, ValError, void 0);
|
|
535
|
+
_defineProperty(this, GetSchema, void 0);
|
|
334
536
|
this[Path] = path;
|
|
335
537
|
this[GetSource] = valOrExpr;
|
|
336
538
|
this[ValError] = error;
|
|
@@ -462,6 +664,23 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
462
664
|
_this.isMultiline = isMultiline;
|
|
463
665
|
return _this;
|
|
464
666
|
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Describe this field.
|
|
670
|
+
*
|
|
671
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
672
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
673
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
674
|
+
* assistant and the MCP tools read.
|
|
675
|
+
*
|
|
676
|
+
* Pass `null` to clear a description set earlier.
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* const schema = s
|
|
680
|
+
* .string()
|
|
681
|
+
* .describe("Shown in the browser tab and in search results");
|
|
682
|
+
* export default c.define("/example.val.ts", schema, "Hello");
|
|
683
|
+
*/
|
|
465
684
|
_inherits(StringSchema, _Schema);
|
|
466
685
|
return _createClass(StringSchema, [{
|
|
467
686
|
key: "describe",
|
|
@@ -471,12 +690,24 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
471
690
|
|
|
472
691
|
/**
|
|
473
692
|
* @deprecated Use `minLength` instead
|
|
693
|
+
*
|
|
694
|
+
* @example
|
|
695
|
+
* const schema = s.string().minLength(2);
|
|
696
|
+
* export default c.define("/example.val.ts", schema, "Hi");
|
|
474
697
|
*/
|
|
475
698
|
}, {
|
|
476
699
|
key: "min",
|
|
477
700
|
value: function min(minLength) {
|
|
478
701
|
return this.minLength(minLength);
|
|
479
702
|
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Validate that the string is at least `minLength` characters long.
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* const schema = s.string().minLength(2);
|
|
709
|
+
* export default c.define("/example.val.ts", schema, "Hi");
|
|
710
|
+
*/
|
|
480
711
|
}, {
|
|
481
712
|
key: "minLength",
|
|
482
713
|
value: function minLength(_minLength) {
|
|
@@ -487,12 +718,24 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
487
718
|
|
|
488
719
|
/**
|
|
489
720
|
* @deprecated Use `maxLength` instead
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* const schema = s.string().maxLength(60);
|
|
724
|
+
* export default c.define("/example.val.ts", schema, "A title that fits");
|
|
490
725
|
*/
|
|
491
726
|
}, {
|
|
492
727
|
key: "max",
|
|
493
728
|
value: function max(maxLength) {
|
|
494
729
|
return this.maxLength(maxLength);
|
|
495
730
|
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Validate that the string is at most `maxLength` characters long.
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* const schema = s.string().maxLength(60);
|
|
737
|
+
* export default c.define("/example.val.ts", schema, "A title that fits");
|
|
738
|
+
*/
|
|
496
739
|
}, {
|
|
497
740
|
key: "maxLength",
|
|
498
741
|
value: function maxLength(_maxLength) {
|
|
@@ -500,6 +743,19 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
500
743
|
maxLength: _maxLength
|
|
501
744
|
}), this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, this.isHidden, this.description, this.previewInput, this.isMultiline);
|
|
502
745
|
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Validate that the string matches `regexp`.
|
|
749
|
+
*
|
|
750
|
+
* `message` is what the editor is shown when it does not match. Without one
|
|
751
|
+
* the error names the pattern, which is rarely what a non-developer needs.
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* const schema = s
|
|
755
|
+
* .string()
|
|
756
|
+
* .regexp(/^[a-z0-9-]+$/, "Lower case letters, digits and dashes only");
|
|
757
|
+
* export default c.define("/example.val.ts", schema, "my-slug");
|
|
758
|
+
*/
|
|
503
759
|
}, {
|
|
504
760
|
key: "regexp",
|
|
505
761
|
value: function regexp(_regexp, message) {
|
|
@@ -508,6 +764,27 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
508
764
|
regExpMessage: message
|
|
509
765
|
}), this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, this.isHidden, this.description, this.previewInput, this.isMultiline);
|
|
510
766
|
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Add a custom validation rule to this field.
|
|
770
|
+
*
|
|
771
|
+
* The function is called with the field's value and returns `false` when the
|
|
772
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
773
|
+
* more than once to add more rules — they all run, and every message is
|
|
774
|
+
* reported.
|
|
775
|
+
*
|
|
776
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
777
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
778
|
+
*
|
|
779
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
780
|
+
* before a publish.
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* const schema = s.string().validate((val) =>
|
|
784
|
+
* val.trim() === val ? false : "Must not start or end with a space",
|
|
785
|
+
* );
|
|
786
|
+
* export default c.define("/example.val.ts", schema, "Hello");
|
|
787
|
+
*/
|
|
511
788
|
}, {
|
|
512
789
|
key: "validate",
|
|
513
790
|
value: function validate(validationFunction) {
|
|
@@ -598,6 +875,26 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
598
875
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
599
876
|
return new StringSchema(this.options, this.opt, this.isRaw, this.customValidateFunctions, this.renderInput, this.isReadonly, isHidden, this.description, this.previewInput, this.isMultiline);
|
|
600
877
|
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Do not stega encode this string.
|
|
881
|
+
*
|
|
882
|
+
* Val normally encodes an invisible pointer back to the source into every
|
|
883
|
+
* string it hands your app, which is what makes click-to-edit work. A raw
|
|
884
|
+
* string is handed over exactly as written — use it wherever the value is
|
|
885
|
+
* not rendered as visible text: a slug, a class name, an `id`, a URL,
|
|
886
|
+
* anything parsed or compared.
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* const schema = s.object({
|
|
890
|
+
* title: s.string(),
|
|
891
|
+
* slug: s.string().raw(),
|
|
892
|
+
* });
|
|
893
|
+
* export default c.define("/example.val.ts", schema, {
|
|
894
|
+
* title: "Hello",
|
|
895
|
+
* slug: "hello",
|
|
896
|
+
* });
|
|
897
|
+
*/
|
|
601
898
|
}, {
|
|
602
899
|
key: "raw",
|
|
603
900
|
value: function raw() {
|
|
@@ -663,6 +960,10 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
663
960
|
*
|
|
664
961
|
* Static configuration, not a callback — see `render.ts`. What a CONTAINER
|
|
665
962
|
* shows for its items is a `preview`, which is a different thing entirely.
|
|
963
|
+
*
|
|
964
|
+
* @example
|
|
965
|
+
* const schema = s.array(s.string().render({ as: "inline" }));
|
|
966
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
666
967
|
*/
|
|
667
968
|
}, {
|
|
668
969
|
key: "render",
|
|
@@ -674,6 +975,12 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
|
|
|
674
975
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
675
976
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
676
977
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
978
|
+
*
|
|
979
|
+
* @example
|
|
980
|
+
* const schema = s.array(
|
|
981
|
+
* s.string().preview(({ val }) => ({ title: val })),
|
|
982
|
+
* );
|
|
983
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
677
984
|
*/
|
|
678
985
|
}, {
|
|
679
986
|
key: "preview",
|
|
@@ -734,12 +1041,59 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
734
1041
|
_this.previewInput = previewInput;
|
|
735
1042
|
return _this;
|
|
736
1043
|
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Describe this field.
|
|
1047
|
+
*
|
|
1048
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
1049
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
1050
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
1051
|
+
* assistant and the MCP tools read.
|
|
1052
|
+
*
|
|
1053
|
+
* Pass `null` to clear a description set earlier.
|
|
1054
|
+
*
|
|
1055
|
+
* @example
|
|
1056
|
+
* const schema = s
|
|
1057
|
+
* .object({ street: s.string(), city: s.string() })
|
|
1058
|
+
* .describe("Where the office is — shown on the contact page");
|
|
1059
|
+
* export default c.define("/example.val.ts", schema, {
|
|
1060
|
+
* street: "Torggata 1",
|
|
1061
|
+
* city: "Oslo",
|
|
1062
|
+
* });
|
|
1063
|
+
*/
|
|
737
1064
|
_inherits(ObjectSchema, _Schema);
|
|
738
1065
|
return _createClass(ObjectSchema, [{
|
|
739
1066
|
key: "describe",
|
|
740
1067
|
value: function describe(description) {
|
|
741
1068
|
return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
742
1069
|
}
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* Add a custom validation rule to this field.
|
|
1073
|
+
*
|
|
1074
|
+
* The function is called with the field's value and returns `false` when the
|
|
1075
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
1076
|
+
* more than once to add more rules — they all run, and every message is
|
|
1077
|
+
* reported.
|
|
1078
|
+
*
|
|
1079
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
1080
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
1081
|
+
*
|
|
1082
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
1083
|
+
* before a publish.
|
|
1084
|
+
*
|
|
1085
|
+
* An object validator is the place for a rule that spans FIELDS — one field
|
|
1086
|
+
* validated on its own belongs on that field's schema, where the error lands
|
|
1087
|
+
* on the field itself.
|
|
1088
|
+
*
|
|
1089
|
+
* @example
|
|
1090
|
+
* const schema = s
|
|
1091
|
+
* .object({ from: s.number(), to: s.number() })
|
|
1092
|
+
* .validate((val) =>
|
|
1093
|
+
* val.from <= val.to ? false : "'from' must not be after 'to'",
|
|
1094
|
+
* );
|
|
1095
|
+
* export default c.define("/example.val.ts", schema, { from: 1, to: 4 });
|
|
1096
|
+
*/
|
|
743
1097
|
}, {
|
|
744
1098
|
key: "validate",
|
|
745
1099
|
value: function validate(validationFunction) {
|
|
@@ -781,6 +1135,18 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
781
1135
|
} finally {
|
|
782
1136
|
_iterator.f();
|
|
783
1137
|
}
|
|
1138
|
+
var _iterator2 = _createForOfIteratorHelper(this.localeScopeErrors()),
|
|
1139
|
+
_step2;
|
|
1140
|
+
try {
|
|
1141
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
1142
|
+
var scopeError = _step2.value;
|
|
1143
|
+
error = this.appendValidationError(error, path, scopeError.message, src, scopeError.schemaError);
|
|
1144
|
+
}
|
|
1145
|
+
} catch (err) {
|
|
1146
|
+
_iterator2.e(err);
|
|
1147
|
+
} finally {
|
|
1148
|
+
_iterator2.f();
|
|
1149
|
+
}
|
|
784
1150
|
for (var _i = 0, _Object$entries = Object.entries(this.items); _i < _Object$entries.length; _i++) {
|
|
785
1151
|
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
786
1152
|
_key = _Object$entries$_i[0],
|
|
@@ -864,7 +1230,7 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
864
1230
|
key: "nullable",
|
|
865
1231
|
value: function nullable() {
|
|
866
1232
|
// Explicit type args: `previewInput` would otherwise pin inference to `Src`.
|
|
867
|
-
return new ObjectSchema(this.items, true,
|
|
1233
|
+
return new ObjectSchema(this.items, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
868
1234
|
}
|
|
869
1235
|
}, {
|
|
870
1236
|
key: "readonly",
|
|
@@ -878,6 +1244,35 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
878
1244
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
879
1245
|
return new ObjectSchema(this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
|
|
880
1246
|
}
|
|
1247
|
+
|
|
1248
|
+
/** The names of this object's `s.locale()` fields, in declaration order. */
|
|
1249
|
+
}, {
|
|
1250
|
+
key: "localeFieldNames",
|
|
1251
|
+
value: function localeFieldNames() {
|
|
1252
|
+
var _this2 = this;
|
|
1253
|
+
return Object.keys(this.items).filter(function (key) {
|
|
1254
|
+
return _this2.items[key]["isLocaleField"]();
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
}, {
|
|
1258
|
+
key: "opensLocaleScope",
|
|
1259
|
+
value: function opensLocaleScope() {
|
|
1260
|
+
// More than one is itself the error, reported by `localeScopeErrors`. It
|
|
1261
|
+
// still opens a scope: reporting "two locale fields" AND "a scope inside a
|
|
1262
|
+
// scope" for the same object would be two errors about one mistake.
|
|
1263
|
+
return this.localeFieldNames().length > 0 ? "field" : null;
|
|
1264
|
+
}
|
|
1265
|
+
}, {
|
|
1266
|
+
key: "localeScopeChildren",
|
|
1267
|
+
value: function localeScopeChildren() {
|
|
1268
|
+
var _this3 = this;
|
|
1269
|
+
return Object.keys(this.items).map(function (key) {
|
|
1270
|
+
return {
|
|
1271
|
+
key: key,
|
|
1272
|
+
schema: _this3.items[key]
|
|
1273
|
+
};
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
881
1276
|
}, {
|
|
882
1277
|
key: "executeCustomValidateAt",
|
|
883
1278
|
value: function executeCustomValidateAt(path, src) {
|
|
@@ -892,6 +1287,16 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
892
1287
|
* instead of a preview row that navigates to it.
|
|
893
1288
|
*
|
|
894
1289
|
* Static configuration, not a callback — see `render.ts`.
|
|
1290
|
+
*
|
|
1291
|
+
* @example
|
|
1292
|
+
* // A page builder: each row edits the object in place, instead of
|
|
1293
|
+
* // navigating to it.
|
|
1294
|
+
* const block = s
|
|
1295
|
+
* .object({ heading: s.string(), body: s.string() })
|
|
1296
|
+
* .render({ as: "inline" });
|
|
1297
|
+
* export default c.define("/example.val.ts", s.array(block), [
|
|
1298
|
+
* { heading: "Hello", body: "World" },
|
|
1299
|
+
* ]);
|
|
895
1300
|
*/
|
|
896
1301
|
}, {
|
|
897
1302
|
key: "render",
|
|
@@ -903,6 +1308,14 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
|
|
|
903
1308
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
904
1309
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
905
1310
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
1311
|
+
*
|
|
1312
|
+
* @example
|
|
1313
|
+
* const author = s
|
|
1314
|
+
* .object({ name: s.string(), role: s.string() })
|
|
1315
|
+
* .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
|
|
1316
|
+
* export default c.define("/example.val.ts", s.array(author), [
|
|
1317
|
+
* { name: "Ada", role: "Engineer" },
|
|
1318
|
+
* ]);
|
|
906
1319
|
*/
|
|
907
1320
|
}, {
|
|
908
1321
|
key: "preview",
|
|
@@ -1005,12 +1418,54 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
|
|
|
1005
1418
|
_this.renderInput = renderInput;
|
|
1006
1419
|
return _this;
|
|
1007
1420
|
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Describe this field.
|
|
1424
|
+
*
|
|
1425
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
1426
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
1427
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
1428
|
+
* assistant and the MCP tools read.
|
|
1429
|
+
*
|
|
1430
|
+
* Pass `null` to clear a description set earlier.
|
|
1431
|
+
*
|
|
1432
|
+
* @example
|
|
1433
|
+
* const schema = s
|
|
1434
|
+
* .array(s.string())
|
|
1435
|
+
* .describe("Bullet points shown under the heading");
|
|
1436
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
1437
|
+
*/
|
|
1008
1438
|
_inherits(ArraySchema, _Schema);
|
|
1009
1439
|
return _createClass(ArraySchema, [{
|
|
1010
1440
|
key: "describe",
|
|
1011
1441
|
value: function describe(description) {
|
|
1012
1442
|
return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.previewInput, this.renderInput);
|
|
1013
1443
|
}
|
|
1444
|
+
|
|
1445
|
+
/**
|
|
1446
|
+
* Add a custom validation rule to this field.
|
|
1447
|
+
*
|
|
1448
|
+
* The function is called with the field's value and returns `false` when the
|
|
1449
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
1450
|
+
* more than once to add more rules — they all run, and every message is
|
|
1451
|
+
* reported.
|
|
1452
|
+
*
|
|
1453
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
1454
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
1455
|
+
*
|
|
1456
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
1457
|
+
* before a publish.
|
|
1458
|
+
*
|
|
1459
|
+
* The function is given the whole array. To validate one item, put a
|
|
1460
|
+
* `.validate(...)` on the ITEM schema instead — that reports the error on
|
|
1461
|
+
* the item's own row.
|
|
1462
|
+
*
|
|
1463
|
+
* @example
|
|
1464
|
+
* const schema = s.array(s.string()).validate((val) =>
|
|
1465
|
+
* val.length <= 3 ? false : "At most 3 items",
|
|
1466
|
+
* );
|
|
1467
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
1468
|
+
*/
|
|
1014
1469
|
}, {
|
|
1015
1470
|
key: "validate",
|
|
1016
1471
|
value: function validate(validationFunction) {
|
|
@@ -1082,7 +1537,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
|
|
|
1082
1537
|
key: "nullable",
|
|
1083
1538
|
value: function nullable() {
|
|
1084
1539
|
// Explicit type args: `previewInput` would otherwise pin inference to `Src`.
|
|
1085
|
-
return new ArraySchema(this.item, true,
|
|
1540
|
+
return new ArraySchema(this.item, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.previewInput, this.renderInput);
|
|
1086
1541
|
}
|
|
1087
1542
|
}, {
|
|
1088
1543
|
key: "readonly",
|
|
@@ -1096,6 +1551,14 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
|
|
|
1096
1551
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
1097
1552
|
return new ArraySchema(this.item, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.previewInput, this.renderInput);
|
|
1098
1553
|
}
|
|
1554
|
+
}, {
|
|
1555
|
+
key: "localeScopeChildren",
|
|
1556
|
+
value: function localeScopeChildren() {
|
|
1557
|
+
return [{
|
|
1558
|
+
key: "*",
|
|
1559
|
+
schema: this.item
|
|
1560
|
+
}];
|
|
1561
|
+
}
|
|
1099
1562
|
}, {
|
|
1100
1563
|
key: "executeCustomValidateAt",
|
|
1101
1564
|
value: function executeCustomValidateAt(path, src) {
|
|
@@ -1218,6 +1681,25 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
|
|
|
1218
1681
|
* is the item of another container, in search, in references. What its rows
|
|
1219
1682
|
* show is the ITEM schema's `preview`, not this. Never how the field is
|
|
1220
1683
|
* edited (that is `render`). See `preview.ts`.
|
|
1684
|
+
*
|
|
1685
|
+
* @example
|
|
1686
|
+
* // The preview of the ARRAY, for where it is an item of something else.
|
|
1687
|
+
* // What its own rows show is the ITEM schema's preview — see below.
|
|
1688
|
+
* const tags = s.array(s.string()).preview(({ val }) => ({
|
|
1689
|
+
* title: `${val.length} tags`,
|
|
1690
|
+
* }));
|
|
1691
|
+
* export default c.define("/example.val.ts", s.record(tags), {
|
|
1692
|
+
* "a-post": ["news", "release"],
|
|
1693
|
+
* });
|
|
1694
|
+
*
|
|
1695
|
+
* @example
|
|
1696
|
+
* // Rows of an array come from the ITEM's preview, not the array's:
|
|
1697
|
+
* const author = s
|
|
1698
|
+
* .object({ name: s.string(), role: s.string() })
|
|
1699
|
+
* .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
|
|
1700
|
+
* export default c.define("/example.val.ts", s.array(author), [
|
|
1701
|
+
* { name: "Ada", role: "Engineer" },
|
|
1702
|
+
* ]);
|
|
1221
1703
|
*/
|
|
1222
1704
|
}, {
|
|
1223
1705
|
key: "preview",
|
|
@@ -1231,6 +1713,12 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
|
|
|
1231
1713
|
* instead of a preview row that navigates to it.
|
|
1232
1714
|
*
|
|
1233
1715
|
* Static configuration, not a callback — see `render.ts`.
|
|
1716
|
+
*
|
|
1717
|
+
* @example
|
|
1718
|
+
* const schema = s.record(s.array(s.string()).render({ as: "inline" }));
|
|
1719
|
+
* export default c.define("/example.val.ts", schema, {
|
|
1720
|
+
* "a-post": ["news", "release"],
|
|
1721
|
+
* });
|
|
1234
1722
|
*/
|
|
1235
1723
|
}, {
|
|
1236
1724
|
key: "render",
|
|
@@ -1244,6 +1732,8 @@ var array = function array(schema) {
|
|
|
1244
1732
|
};
|
|
1245
1733
|
|
|
1246
1734
|
var LiteralSchema = /*#__PURE__*/function (_Schema) {
|
|
1735
|
+
/** Type-only marker: as a record key, this declares the key set. See `LocaleSchema`. */
|
|
1736
|
+
|
|
1247
1737
|
function LiteralSchema(value) {
|
|
1248
1738
|
var _this;
|
|
1249
1739
|
var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
@@ -1265,12 +1755,50 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1265
1755
|
_this.previewInput = previewInput;
|
|
1266
1756
|
return _this;
|
|
1267
1757
|
}
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* Describe this field.
|
|
1761
|
+
*
|
|
1762
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
1763
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
1764
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
1765
|
+
* assistant and the MCP tools read.
|
|
1766
|
+
*
|
|
1767
|
+
* Pass `null` to clear a description set earlier.
|
|
1768
|
+
*
|
|
1769
|
+
* @example
|
|
1770
|
+
* const schema = s
|
|
1771
|
+
* .literal("hero")
|
|
1772
|
+
* .describe("The block type — it identifies the variant");
|
|
1773
|
+
* export default c.define("/example.val.ts", schema, "hero");
|
|
1774
|
+
*/
|
|
1268
1775
|
_inherits(LiteralSchema, _Schema);
|
|
1269
1776
|
return _createClass(LiteralSchema, [{
|
|
1270
1777
|
key: "describe",
|
|
1271
1778
|
value: function describe(description) {
|
|
1272
1779
|
return new LiteralSchema(this.value, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
1273
1780
|
}
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Add a custom validation rule to this field.
|
|
1784
|
+
*
|
|
1785
|
+
* The function is called with the field's value and returns `false` when the
|
|
1786
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
1787
|
+
* more than once to add more rules — they all run, and every message is
|
|
1788
|
+
* reported.
|
|
1789
|
+
*
|
|
1790
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
1791
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
1792
|
+
*
|
|
1793
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
1794
|
+
* before a publish.
|
|
1795
|
+
*
|
|
1796
|
+
* @example
|
|
1797
|
+
* const schema = s.literal("hero").validate((val) =>
|
|
1798
|
+
* val === "hero" ? false : "Unknown block type",
|
|
1799
|
+
* );
|
|
1800
|
+
* export default c.define("/example.val.ts", schema, "hero");
|
|
1801
|
+
*/
|
|
1274
1802
|
}, {
|
|
1275
1803
|
key: "validate",
|
|
1276
1804
|
value: function validate(validationFunction) {
|
|
@@ -1337,7 +1865,7 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1337
1865
|
}, {
|
|
1338
1866
|
key: "nullable",
|
|
1339
1867
|
value: function nullable() {
|
|
1340
|
-
return new LiteralSchema(this.value, true,
|
|
1868
|
+
return new LiteralSchema(this.value, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
1341
1869
|
}
|
|
1342
1870
|
}, {
|
|
1343
1871
|
key: "readonly",
|
|
@@ -1365,6 +1893,10 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1365
1893
|
* instead of a preview row that navigates to it.
|
|
1366
1894
|
*
|
|
1367
1895
|
* Static configuration, not a callback — see `render.ts`.
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* const schema = s.array(s.literal("hero").render({ as: "inline" }));
|
|
1899
|
+
* export default c.define("/example.val.ts", schema, ["hero"]);
|
|
1368
1900
|
*/
|
|
1369
1901
|
}, {
|
|
1370
1902
|
key: "render",
|
|
@@ -1376,6 +1908,12 @@ var LiteralSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1376
1908
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
1377
1909
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
1378
1910
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
1911
|
+
*
|
|
1912
|
+
* @example
|
|
1913
|
+
* const schema = s.array(
|
|
1914
|
+
* s.literal("hero").preview(({ val }) => ({ title: val })),
|
|
1915
|
+
* );
|
|
1916
|
+
* export default c.define("/example.val.ts", schema, ["hero"]);
|
|
1379
1917
|
*/
|
|
1380
1918
|
}, {
|
|
1381
1919
|
key: "preview",
|
|
@@ -1424,8 +1962,30 @@ var literal = function literal(value) {
|
|
|
1424
1962
|
return new LiteralSchema(value);
|
|
1425
1963
|
};
|
|
1426
1964
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1965
|
+
/** The variant objects a discriminated union on `Key` may be built from. */
|
|
1966
|
+
|
|
1967
|
+
/**
|
|
1968
|
+
* At least one variant, so a union with none cannot be written.
|
|
1969
|
+
*
|
|
1970
|
+
* Everything downstream reads the first one where it needs any — `emptyOf`
|
|
1971
|
+
* takes `items[0]` for the value a new entry starts as — and a union with
|
|
1972
|
+
* nothing to select is not a thing an author means. `s.enum` says the same
|
|
1973
|
+
* about its values.
|
|
1974
|
+
*/
|
|
1975
|
+
|
|
1976
|
+
/** The source type a discriminated union over `T` accepts. */
|
|
1977
|
+
|
|
1978
|
+
/**
|
|
1979
|
+
* One of several object shapes, told apart by a tag field.
|
|
1980
|
+
*
|
|
1981
|
+
* Every variant is an object with `key` set to a distinct `s.literal(...)`, and
|
|
1982
|
+
* the value of that field decides which variant a value is. Unlike
|
|
1983
|
+
* {@link EnumSchema} this is a CONTAINER: the variant's fields are the fields
|
|
1984
|
+
* being edited, and everything that walks the schema tree has to descend
|
|
1985
|
+
* through the matching variant.
|
|
1986
|
+
*/
|
|
1987
|
+
var DiscriminatedUnionSchema = /*#__PURE__*/function (_Schema) {
|
|
1988
|
+
function DiscriminatedUnionSchema(key, items) {
|
|
1429
1989
|
var _this;
|
|
1430
1990
|
var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
1431
1991
|
var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
|
|
@@ -1434,8 +1994,8 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1434
1994
|
var description = arguments.length > 6 ? arguments[6] : undefined;
|
|
1435
1995
|
var renderInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
|
|
1436
1996
|
var previewInput = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null;
|
|
1437
|
-
_classCallCheck(this,
|
|
1438
|
-
_this = _callSuper(this,
|
|
1997
|
+
_classCallCheck(this, DiscriminatedUnionSchema);
|
|
1998
|
+
_this = _callSuper(this, DiscriminatedUnionSchema);
|
|
1439
1999
|
_this.key = key;
|
|
1440
2000
|
_this.items = items;
|
|
1441
2001
|
_this.opt = opt;
|
|
@@ -1447,16 +2007,66 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1447
2007
|
_this.previewInput = previewInput;
|
|
1448
2008
|
return _this;
|
|
1449
2009
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
2010
|
+
|
|
2011
|
+
/**
|
|
2012
|
+
* Describe this field.
|
|
2013
|
+
*
|
|
2014
|
+
* The description is shown next to the field's label in the Val editor, so it is
|
|
2015
|
+
* where you say what an editor needs to know but the field name cannot carry. It
|
|
2016
|
+
* also travels in the serialized schema, which is what the AI assistant and the
|
|
2017
|
+
* MCP tools read.
|
|
2018
|
+
*
|
|
2019
|
+
* Pass `null` to clear a description set earlier.
|
|
2020
|
+
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* const hero = s.object({ type: s.literal("hero"), title: s.string() });
|
|
2023
|
+
* const text = s.object({ type: s.literal("text"), body: s.string() });
|
|
2024
|
+
* const schema = s
|
|
2025
|
+
* .discriminatedUnion("type", hero, text)
|
|
2026
|
+
* .describe("What this section of the page is");
|
|
2027
|
+
* export default c.define("/example.val.ts", schema, {
|
|
2028
|
+
* type: "hero",
|
|
2029
|
+
* title: "Hello",
|
|
2030
|
+
* });
|
|
2031
|
+
*/
|
|
2032
|
+
_inherits(DiscriminatedUnionSchema, _Schema);
|
|
2033
|
+
return _createClass(DiscriminatedUnionSchema, [{
|
|
1452
2034
|
key: "describe",
|
|
1453
2035
|
value: function describe(description) {
|
|
1454
|
-
return new
|
|
2036
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
1455
2037
|
}
|
|
2038
|
+
|
|
2039
|
+
/**
|
|
2040
|
+
* Add a custom validation rule to this field.
|
|
2041
|
+
*
|
|
2042
|
+
* The function is called with the field's value and returns `false` when the
|
|
2043
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
2044
|
+
* more than once to add more rules — they all run, and every message is
|
|
2045
|
+
* reported.
|
|
2046
|
+
*
|
|
2047
|
+
* Validation runs in the Studio as you type, in `npx val validate` and before a
|
|
2048
|
+
* publish.
|
|
2049
|
+
*
|
|
2050
|
+
* The function is given the whole value, whichever variant it took. A rule
|
|
2051
|
+
* that only concerns one variant belongs on that variant's object schema.
|
|
2052
|
+
*
|
|
2053
|
+
* @example
|
|
2054
|
+
* const hero = s.object({ type: s.literal("hero"), title: s.string() });
|
|
2055
|
+
* const text = s.object({ type: s.literal("text"), body: s.string() });
|
|
2056
|
+
* const schema = s
|
|
2057
|
+
* .discriminatedUnion("type", hero, text)
|
|
2058
|
+
* .validate((val) =>
|
|
2059
|
+
* val.type === "hero" && !val.title ? "A hero needs a title" : false,
|
|
2060
|
+
* );
|
|
2061
|
+
* export default c.define("/example.val.ts", schema, {
|
|
2062
|
+
* type: "hero",
|
|
2063
|
+
* title: "Hello",
|
|
2064
|
+
* });
|
|
2065
|
+
*/
|
|
1456
2066
|
}, {
|
|
1457
2067
|
key: "validate",
|
|
1458
2068
|
value: function validate(validationFunction) {
|
|
1459
|
-
return new
|
|
2069
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
1460
2070
|
}
|
|
1461
2071
|
}, {
|
|
1462
2072
|
key: "executeValidate",
|
|
@@ -1464,142 +2074,135 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1464
2074
|
var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
1465
2075
|
path: path
|
|
1466
2076
|
});
|
|
2077
|
+
/**
|
|
2078
|
+
* A structural error at this path, unless the custom validators already
|
|
2079
|
+
* reported — in which case theirs are the answer and this one is dropped.
|
|
2080
|
+
* Faithful to what `s.union` did; changing it is a separate decision.
|
|
2081
|
+
*/
|
|
2082
|
+
var structural = function structural(error) {
|
|
2083
|
+
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [error]);
|
|
2084
|
+
};
|
|
1467
2085
|
var unknownSrc = src;
|
|
1468
2086
|
if (this.opt && unknownSrc === null) {
|
|
1469
2087
|
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
|
|
1470
2088
|
}
|
|
1471
2089
|
if (!this.key) {
|
|
1472
|
-
return
|
|
1473
|
-
message: "Missing required first argument in union",
|
|
2090
|
+
return structural({
|
|
2091
|
+
message: "Missing required first argument in discriminated union",
|
|
1474
2092
|
schemaError: true
|
|
1475
|
-
}
|
|
2093
|
+
});
|
|
1476
2094
|
}
|
|
1477
2095
|
var key = this.key;
|
|
1478
2096
|
if (!Array.isArray(this.items)) {
|
|
1479
|
-
return
|
|
1480
|
-
message: "A union schema must take more than 1 schema arguments",
|
|
2097
|
+
return structural({
|
|
2098
|
+
message: "A discriminated union schema must take more than 1 schema arguments",
|
|
1481
2099
|
schemaError: true
|
|
1482
|
-
}
|
|
2100
|
+
});
|
|
1483
2101
|
}
|
|
1484
|
-
if (typeof key
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
})) {
|
|
1489
|
-
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
|
|
1490
|
-
message: "Key is a string, so all schema items must be objects",
|
|
1491
|
-
schemaError: true
|
|
1492
|
-
}]));
|
|
1493
|
-
}
|
|
1494
|
-
var objectSchemas = this.items;
|
|
1495
|
-
var serializedSchemas = objectSchemas.map(function (schema) {
|
|
1496
|
-
return schema["executeSerialize"]();
|
|
2102
|
+
if (typeof key !== "string") {
|
|
2103
|
+
return structural({
|
|
2104
|
+
message: "The key of a discriminated union must be a string",
|
|
2105
|
+
schemaError: true
|
|
1497
2106
|
});
|
|
1498
|
-
|
|
1499
|
-
|
|
2107
|
+
}
|
|
2108
|
+
if (this.items.some(function (item) {
|
|
2109
|
+
return !(item instanceof ObjectSchema);
|
|
2110
|
+
})) {
|
|
2111
|
+
return structural({
|
|
2112
|
+
message: "All schema items of a discriminated union must be objects",
|
|
2113
|
+
schemaError: true
|
|
1500
2114
|
});
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
2115
|
+
}
|
|
2116
|
+
var objectSchemas = this.items;
|
|
2117
|
+
var serializedSchemas = objectSchemas.map(function (schema) {
|
|
2118
|
+
return schema["executeSerialize"]();
|
|
2119
|
+
});
|
|
2120
|
+
// `items[key]?` — a variant that OMITS the discriminator is exactly what
|
|
2121
|
+
// this check exists to report, so it must not throw while finding it.
|
|
2122
|
+
var illegalSchemas = serializedSchemas.filter(function (schema) {
|
|
2123
|
+
var _schema$items$key;
|
|
2124
|
+
return !(schema.type === "object") || ((_schema$items$key = schema.items[key]) === null || _schema$items$key === void 0 ? void 0 : _schema$items$key.type) !== "literal";
|
|
2125
|
+
});
|
|
2126
|
+
if (illegalSchemas.length > 0) {
|
|
2127
|
+
return structural({
|
|
2128
|
+
message: "All schema items must be objects with a key: ".concat(key, " that is a literal schema. Found: ").concat(JSON.stringify(illegalSchemas, null, 2)),
|
|
2129
|
+
schemaError: true
|
|
1510
2130
|
});
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
typeError: true
|
|
1521
|
-
}]));
|
|
1522
|
-
}
|
|
1523
|
-
var objectSrc = unknownSrc;
|
|
1524
|
-
if (objectSrc[key] === undefined) {
|
|
1525
|
-
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
|
|
1526
|
-
message: "Missing required key: ".concat(key),
|
|
1527
|
-
typeError: true
|
|
1528
|
-
}]));
|
|
1529
|
-
}
|
|
1530
|
-
var foundSchemaLiterals = [];
|
|
1531
|
-
var _iterator = _createForOfIteratorHelper(serializedObjectSchemas),
|
|
1532
|
-
_step;
|
|
1533
|
-
try {
|
|
1534
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1535
|
-
var schema = _step.value;
|
|
1536
|
-
var schemaKey = schema.items[key];
|
|
1537
|
-
if (schemaKey.type === "literal") {
|
|
1538
|
-
if (!foundSchemaLiterals.includes(schemaKey.value)) {
|
|
1539
|
-
foundSchemaLiterals.push(schemaKey.value);
|
|
1540
|
-
} else {
|
|
1541
|
-
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
|
|
1542
|
-
message: "Found duplicate key in schema: ".concat(schemaKey.value),
|
|
1543
|
-
schemaError: true
|
|
1544
|
-
}]));
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
} catch (err) {
|
|
1549
|
-
_iterator.e(err);
|
|
1550
|
-
} finally {
|
|
1551
|
-
_iterator.f();
|
|
1552
|
-
}
|
|
1553
|
-
var objectSchemaAtKey = objectSchemas.find(function (schema) {
|
|
1554
|
-
return !schema["items"][key]["executeValidate"](path, objectSrc[key]);
|
|
2131
|
+
}
|
|
2132
|
+
var serializedObjectSchemas = serializedSchemas;
|
|
2133
|
+
var optionalLiterals = serializedObjectSchemas.filter(function (schema) {
|
|
2134
|
+
return schema.items[key].opt;
|
|
2135
|
+
});
|
|
2136
|
+
if (optionalLiterals.length > 1) {
|
|
2137
|
+
return structural({
|
|
2138
|
+
message: "Schema cannot have an optional keys: ".concat(key),
|
|
2139
|
+
schemaError: true
|
|
1555
2140
|
});
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
return !item["executeValidate"](path, unknownSrc);
|
|
1590
|
-
});
|
|
1591
|
-
if (!isMatch) {
|
|
1592
|
-
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
|
|
1593
|
-
message: "Union must match one of the following: ".concat(literalItems.map(function (item) {
|
|
1594
|
-
return "\"".concat(item["value"], "\"");
|
|
1595
|
-
}).join(", "))
|
|
1596
|
-
}]));
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
// `typeof null === "object"`, so null has to be named separately or it
|
|
2144
|
+
// reaches `objectSrc[key]` below and throws instead of reporting.
|
|
2145
|
+
if (unknownSrc === null || _typeof(unknownSrc) !== "object") {
|
|
2146
|
+
return structural({
|
|
2147
|
+
message: "Expected an object, got ".concat(unknownSrc === null ? "null" : _typeof(unknownSrc)),
|
|
2148
|
+
typeError: true
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
var objectSrc = unknownSrc;
|
|
2152
|
+
if (objectSrc[key] === undefined) {
|
|
2153
|
+
return structural({
|
|
2154
|
+
message: "Missing required key: ".concat(key),
|
|
2155
|
+
typeError: true
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
var foundSchemaLiterals = [];
|
|
2159
|
+
var _iterator = _createForOfIteratorHelper(serializedObjectSchemas),
|
|
2160
|
+
_step;
|
|
2161
|
+
try {
|
|
2162
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2163
|
+
var schema = _step.value;
|
|
2164
|
+
var schemaKey = schema.items[key];
|
|
2165
|
+
if (schemaKey.type === "literal") {
|
|
2166
|
+
if (!foundSchemaLiterals.includes(schemaKey.value)) {
|
|
2167
|
+
foundSchemaLiterals.push(schemaKey.value);
|
|
2168
|
+
} else {
|
|
2169
|
+
return structural({
|
|
2170
|
+
message: "Found duplicate key in schema: ".concat(schemaKey.value),
|
|
2171
|
+
schemaError: true
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
1597
2174
|
}
|
|
1598
2175
|
}
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
2176
|
+
} catch (err) {
|
|
2177
|
+
_iterator.e(err);
|
|
2178
|
+
} finally {
|
|
2179
|
+
_iterator.f();
|
|
2180
|
+
}
|
|
2181
|
+
var objectSchemaAtKey = objectSchemas.find(function (schema) {
|
|
2182
|
+
return !schema["items"][key]["executeValidate"](path, objectSrc[key]);
|
|
2183
|
+
});
|
|
2184
|
+
if (!objectSchemaAtKey) {
|
|
2185
|
+
var keyPath = createValPathOfItem(path, key);
|
|
2186
|
+
if (!keyPath) {
|
|
2187
|
+
throw new Error("Internal error: could not create path at ".concat(!path && typeof path === "string" ? "<empty string>" : path, " at key ").concat(key));
|
|
2188
|
+
}
|
|
2189
|
+
return _defineProperty({}, keyPath, [{
|
|
2190
|
+
message: "Invalid key: \"".concat(key, "\". Value was: \"").concat(objectSrc[key], "\". Valid values: ").concat(serializedObjectSchemas.map(function (schema) {
|
|
2191
|
+
var keySchema = schema.items[key];
|
|
2192
|
+
// The TYPE is the whole test: `s.literal("")` is a valid
|
|
2193
|
+
// discriminator, and a truthiness check threw on it here.
|
|
2194
|
+
if (keySchema.type === "literal") {
|
|
2195
|
+
return "\"".concat(keySchema.value, "\"");
|
|
2196
|
+
} else {
|
|
2197
|
+
// should not happen here, we already checked this
|
|
2198
|
+
throw new Error("Expected literal schema, got ".concat(JSON.stringify(keySchema, null, 2)));
|
|
2199
|
+
}
|
|
2200
|
+
}).join(", "))
|
|
2201
|
+
}]);
|
|
2202
|
+
}
|
|
2203
|
+
var error = objectSchemaAtKey["executeValidate"](path, objectSrc);
|
|
2204
|
+
if (error) {
|
|
2205
|
+
return error;
|
|
1603
2206
|
}
|
|
1604
2207
|
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
|
|
1605
2208
|
}
|
|
@@ -1621,11 +2224,11 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1621
2224
|
}])
|
|
1622
2225
|
};
|
|
1623
2226
|
}
|
|
1624
|
-
if (!this.key) {
|
|
2227
|
+
if (typeof this.key !== "string" || !this.key) {
|
|
1625
2228
|
return {
|
|
1626
2229
|
success: false,
|
|
1627
2230
|
errors: _defineProperty({}, path, [{
|
|
1628
|
-
message: "Missing required first argument in union schema",
|
|
2231
|
+
message: "Missing required first argument in discriminated union schema",
|
|
1629
2232
|
schemaError: true
|
|
1630
2233
|
}])
|
|
1631
2234
|
};
|
|
@@ -1634,135 +2237,82 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1634
2237
|
return {
|
|
1635
2238
|
success: false,
|
|
1636
2239
|
errors: _defineProperty({}, path, [{
|
|
1637
|
-
message: "The schema of this value is wrong.
|
|
2240
|
+
message: "The schema of this value is wrong. A discriminated union must have an array of object schemas",
|
|
1638
2241
|
schemaError: true
|
|
1639
2242
|
}])
|
|
1640
2243
|
};
|
|
1641
2244
|
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
errors[path] = [{
|
|
1662
|
-
message: "Expected 'string', got '".concat(_typeof(src), "'"),
|
|
1663
|
-
typeError: true
|
|
1664
|
-
}];
|
|
1665
|
-
continue;
|
|
1666
|
-
}
|
|
1667
|
-
var res = itemSchema["executeAssert"](path, src);
|
|
1668
|
-
if (res.success) {
|
|
1669
|
-
success = true;
|
|
1670
|
-
break;
|
|
1671
|
-
} else {
|
|
1672
|
-
for (var _i = 0, _Object$entries = Object.entries(res.errors); _i < _Object$entries.length; _i++) {
|
|
1673
|
-
var _errors5;
|
|
1674
|
-
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
1675
|
-
_key = _Object$entries$_i[0],
|
|
1676
|
-
value = _Object$entries$_i[1];
|
|
1677
|
-
if (!errors[_key]) {
|
|
1678
|
-
errors[_key] = [];
|
|
1679
|
-
}
|
|
1680
|
-
(_errors5 = errors[_key]).push.apply(_errors5, _toConsumableArray(value));
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
} catch (err) {
|
|
1685
|
-
_iterator2.e(err);
|
|
1686
|
-
} finally {
|
|
1687
|
-
_iterator2.f();
|
|
1688
|
-
}
|
|
1689
|
-
if (!success) {
|
|
1690
|
-
return {
|
|
1691
|
-
success: false,
|
|
1692
|
-
errors: errors
|
|
1693
|
-
};
|
|
1694
|
-
}
|
|
1695
|
-
return {
|
|
1696
|
-
success: true,
|
|
1697
|
-
data: src
|
|
1698
|
-
};
|
|
1699
|
-
} else if (typeof this.key === "string") {
|
|
1700
|
-
var _success = false;
|
|
1701
|
-
var _errors6 = {};
|
|
1702
|
-
var _iterator3 = _createForOfIteratorHelper(this.items),
|
|
1703
|
-
_step3;
|
|
1704
|
-
try {
|
|
1705
|
-
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1706
|
-
var _itemSchema = _step3.value;
|
|
1707
|
-
var _res = _itemSchema["executeAssert"](path, src);
|
|
1708
|
-
if (_res.success) {
|
|
1709
|
-
_success = true;
|
|
1710
|
-
break;
|
|
1711
|
-
} else {
|
|
1712
|
-
for (var _i2 = 0, _Object$entries2 = Object.entries(_res.errors); _i2 < _Object$entries2.length; _i2++) {
|
|
1713
|
-
var _errors7;
|
|
1714
|
-
var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
|
|
1715
|
-
_key2 = _Object$entries2$_i[0],
|
|
1716
|
-
_value = _Object$entries2$_i[1];
|
|
1717
|
-
if (!_errors6[_key2]) {
|
|
1718
|
-
_errors6[_key2] = [];
|
|
1719
|
-
}
|
|
1720
|
-
(_errors7 = _errors6[_key2]).push.apply(_errors7, _toConsumableArray(_value)); // by appending all type errors, we most likely get a lot of duplicate errors. Currently we believe this is correct though, but should probably be handled in when showing the errors to users
|
|
2245
|
+
var success = false;
|
|
2246
|
+
var errors = {};
|
|
2247
|
+
var _iterator2 = _createForOfIteratorHelper(this.items),
|
|
2248
|
+
_step2;
|
|
2249
|
+
try {
|
|
2250
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
2251
|
+
var itemSchema = _step2.value;
|
|
2252
|
+
var res = itemSchema["executeAssert"](path, src);
|
|
2253
|
+
if (res.success) {
|
|
2254
|
+
success = true;
|
|
2255
|
+
break;
|
|
2256
|
+
} else {
|
|
2257
|
+
for (var _i = 0, _Object$entries = Object.entries(res.errors); _i < _Object$entries.length; _i++) {
|
|
2258
|
+
var _errors4;
|
|
2259
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
2260
|
+
_key = _Object$entries$_i[0],
|
|
2261
|
+
value = _Object$entries$_i[1];
|
|
2262
|
+
if (!errors[_key]) {
|
|
2263
|
+
errors[_key] = [];
|
|
1721
2264
|
}
|
|
2265
|
+
(_errors4 = errors[_key]).push.apply(_errors4, _toConsumableArray(value)); // by appending all type errors, we most likely get a lot of duplicate errors. Currently we believe this is correct though, but should probably be handled in when showing the errors to users
|
|
1722
2266
|
}
|
|
1723
2267
|
}
|
|
1724
|
-
} catch (err) {
|
|
1725
|
-
_iterator3.e(err);
|
|
1726
|
-
} finally {
|
|
1727
|
-
_iterator3.f();
|
|
1728
|
-
}
|
|
1729
|
-
if (!_success) {
|
|
1730
|
-
return {
|
|
1731
|
-
success: false,
|
|
1732
|
-
errors: _errors6
|
|
1733
|
-
};
|
|
1734
2268
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
}
|
|
2269
|
+
} catch (err) {
|
|
2270
|
+
_iterator2.e(err);
|
|
2271
|
+
} finally {
|
|
2272
|
+
_iterator2.f();
|
|
2273
|
+
}
|
|
2274
|
+
if (!success) {
|
|
1740
2275
|
return {
|
|
1741
2276
|
success: false,
|
|
1742
|
-
errors:
|
|
1743
|
-
message: "The schema of this value is wrong. Schema is neither a union of literals nor a tagged union (of objects)",
|
|
1744
|
-
schemaError: true
|
|
1745
|
-
}])
|
|
2277
|
+
errors: errors
|
|
1746
2278
|
};
|
|
1747
2279
|
}
|
|
2280
|
+
return {
|
|
2281
|
+
success: true,
|
|
2282
|
+
data: src
|
|
2283
|
+
};
|
|
1748
2284
|
}
|
|
1749
2285
|
}, {
|
|
1750
2286
|
key: "nullable",
|
|
1751
2287
|
value: function nullable() {
|
|
1752
2288
|
// Explicit type args: `previewInput` would otherwise pin inference to `Src`.
|
|
1753
|
-
return new
|
|
2289
|
+
return new DiscriminatedUnionSchema(this.key, this.items, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
1754
2290
|
}
|
|
1755
2291
|
}, {
|
|
1756
2292
|
key: "readonly",
|
|
1757
2293
|
value: function readonly() {
|
|
1758
2294
|
var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
1759
|
-
return new
|
|
2295
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
1760
2296
|
}
|
|
1761
2297
|
}, {
|
|
1762
2298
|
key: "hidden",
|
|
1763
2299
|
value: function hidden() {
|
|
1764
2300
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
1765
|
-
return new
|
|
2301
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
|
|
2302
|
+
}
|
|
2303
|
+
}, {
|
|
2304
|
+
key: "localeScopeChildren",
|
|
2305
|
+
value: function localeScopeChildren() {
|
|
2306
|
+
// Every variant is walked under the SAME path: whichever one the value
|
|
2307
|
+
// takes, that is where it sits. `s.enum()` has no children at all — its
|
|
2308
|
+
// values are strings, not schemas — which is why only this half of the old
|
|
2309
|
+
// `s.union` has this.
|
|
2310
|
+
return this.items.map(function (item) {
|
|
2311
|
+
return {
|
|
2312
|
+
key: "*",
|
|
2313
|
+
schema: item
|
|
2314
|
+
};
|
|
2315
|
+
});
|
|
1766
2316
|
}
|
|
1767
2317
|
}, {
|
|
1768
2318
|
key: "executeCustomValidateAt",
|
|
@@ -1770,10 +2320,10 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1770
2320
|
var errors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
1771
2321
|
path: path
|
|
1772
2322
|
});
|
|
1773
|
-
// A
|
|
1774
|
-
// stops here and a variant's OWN validator would
|
|
1775
|
-
// into the variant this value takes — the union
|
|
1776
|
-
// which one that is.
|
|
2323
|
+
// A discriminated union's variants share the union's path, so
|
|
2324
|
+
// `Internal.resolvePath` stops here and a variant's OWN validator would
|
|
2325
|
+
// never be reached. Dispatch into the variant this value takes — the union
|
|
2326
|
+
// is the only node that knows which one that is.
|
|
1777
2327
|
var matched = this.matchedVariant(src);
|
|
1778
2328
|
if (matched) {
|
|
1779
2329
|
errors.push.apply(errors, _toConsumableArray(matched["executeCustomValidateAt"](path, src)));
|
|
@@ -1782,10 +2332,8 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1782
2332
|
}
|
|
1783
2333
|
|
|
1784
2334
|
/**
|
|
1785
|
-
* The variant schema a value takes
|
|
1786
|
-
*
|
|
1787
|
-
* when the value matches none of them — a structural error `executeValidate`
|
|
1788
|
-
* already reports.
|
|
2335
|
+
* The variant schema a value takes. `null` when the value matches none of
|
|
2336
|
+
* them — a structural error `executeValidate` already reports.
|
|
1789
2337
|
*/
|
|
1790
2338
|
}, {
|
|
1791
2339
|
key: "matchedVariant",
|
|
@@ -1802,11 +2350,11 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1802
2350
|
return null;
|
|
1803
2351
|
}
|
|
1804
2352
|
var objectSchemas = this.items;
|
|
1805
|
-
var
|
|
1806
|
-
|
|
2353
|
+
var _iterator3 = _createForOfIteratorHelper(objectSchemas),
|
|
2354
|
+
_step3;
|
|
1807
2355
|
try {
|
|
1808
|
-
for (
|
|
1809
|
-
var item =
|
|
2356
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
2357
|
+
var item = _step3.value;
|
|
1810
2358
|
if (!(item instanceof ObjectSchema)) {
|
|
1811
2359
|
continue;
|
|
1812
2360
|
}
|
|
@@ -1816,9 +2364,9 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1816
2364
|
}
|
|
1817
2365
|
}
|
|
1818
2366
|
} catch (err) {
|
|
1819
|
-
|
|
2367
|
+
_iterator3.e(err);
|
|
1820
2368
|
} finally {
|
|
1821
|
-
|
|
2369
|
+
_iterator3.f();
|
|
1822
2370
|
}
|
|
1823
2371
|
return null;
|
|
1824
2372
|
}
|
|
@@ -1829,11 +2377,21 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1829
2377
|
* instead of a preview row that navigates to it.
|
|
1830
2378
|
*
|
|
1831
2379
|
* Static configuration, not a callback — see `render.ts`.
|
|
2380
|
+
*
|
|
2381
|
+
* @example
|
|
2382
|
+
* // A page builder: the row draws the tag selector and the matched
|
|
2383
|
+
* // variant's fields.
|
|
2384
|
+
* const hero = s.object({ type: s.literal("hero"), title: s.string() });
|
|
2385
|
+
* const text = s.object({ type: s.literal("text"), body: s.string() });
|
|
2386
|
+
* const block = s.discriminatedUnion("type", hero, text).render({ as: "inline" });
|
|
2387
|
+
* export default c.define("/example.val.ts", s.array(block), [
|
|
2388
|
+
* { type: "hero", title: "Hello" },
|
|
2389
|
+
* ]);
|
|
1832
2390
|
*/
|
|
1833
2391
|
}, {
|
|
1834
2392
|
key: "render",
|
|
1835
2393
|
value: function render(input) {
|
|
1836
|
-
return new
|
|
2394
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
|
|
1837
2395
|
}
|
|
1838
2396
|
|
|
1839
2397
|
/**
|
|
@@ -1841,13 +2399,24 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1841
2399
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
1842
2400
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
1843
2401
|
*
|
|
1844
|
-
* Without one of its own, a
|
|
1845
|
-
* takes — declare `preview` on the member objects and the union
|
|
2402
|
+
* Without one of its own, a discriminated union previews as the VARIANT the
|
|
2403
|
+
* value takes — declare `preview` on the member objects and the union
|
|
2404
|
+
* dispatches.
|
|
2405
|
+
*
|
|
2406
|
+
* @example
|
|
2407
|
+
* const hero = s.object({ type: s.literal("hero"), title: s.string() });
|
|
2408
|
+
* const text = s.object({ type: s.literal("text"), body: s.string() });
|
|
2409
|
+
* const block = s
|
|
2410
|
+
* .discriminatedUnion("type", hero, text)
|
|
2411
|
+
* .preview(({ val }) => ({ title: val.type }));
|
|
2412
|
+
* export default c.define("/example.val.ts", s.array(block), [
|
|
2413
|
+
* { type: "hero", title: "Hello" },
|
|
2414
|
+
* ]);
|
|
1846
2415
|
*/
|
|
1847
2416
|
}, {
|
|
1848
2417
|
key: "preview",
|
|
1849
2418
|
value: function preview(select) {
|
|
1850
|
-
return new
|
|
2419
|
+
return new DiscriminatedUnionSchema(this.key, this.items, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
|
|
1851
2420
|
}
|
|
1852
2421
|
}, {
|
|
1853
2422
|
key: "executePreviewItem",
|
|
@@ -1878,34 +2447,19 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1878
2447
|
}, {
|
|
1879
2448
|
key: "executeSerialize",
|
|
1880
2449
|
value: function executeSerialize() {
|
|
1881
|
-
var _this$
|
|
1882
|
-
if (typeof this.key === "string") {
|
|
1883
|
-
var _this$renderInput, _this$customValidateF;
|
|
1884
|
-
return {
|
|
1885
|
-
type: "union",
|
|
1886
|
-
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
1887
|
-
preview: this.previewInput ? true : undefined,
|
|
1888
|
-
key: this.key,
|
|
1889
|
-
items: this.items.map(function (o) {
|
|
1890
|
-
return o["executeSerialize"]();
|
|
1891
|
-
}),
|
|
1892
|
-
opt: this.opt,
|
|
1893
|
-
customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
|
|
1894
|
-
readonly: this.isReadonly,
|
|
1895
|
-
hidden: this.isHidden,
|
|
1896
|
-
description: this.description
|
|
1897
|
-
};
|
|
1898
|
-
}
|
|
2450
|
+
var _this$renderInput, _this$customValidateF;
|
|
1899
2451
|
return {
|
|
1900
|
-
type: "union",
|
|
1901
|
-
render: (_this$
|
|
2452
|
+
type: "discriminated-union",
|
|
2453
|
+
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
1902
2454
|
preview: this.previewInput ? true : undefined,
|
|
1903
|
-
key: this.key
|
|
2455
|
+
key: this.key,
|
|
2456
|
+
// Every item is an ObjectSchema — `executeValidate` reports a schema
|
|
2457
|
+
// error for anything else, but the type of `T` cannot say so.
|
|
1904
2458
|
items: this.items.map(function (o) {
|
|
1905
2459
|
return o["executeSerialize"]();
|
|
1906
2460
|
}),
|
|
1907
2461
|
opt: this.opt,
|
|
1908
|
-
customValidate: this.customValidateFunctions && ((_this$
|
|
2462
|
+
customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
|
|
1909
2463
|
readonly: this.isReadonly,
|
|
1910
2464
|
hidden: this.isHidden,
|
|
1911
2465
|
description: this.description
|
|
@@ -1918,48 +2472,46 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
|
|
|
1918
2472
|
if (src === null) {
|
|
1919
2473
|
return res;
|
|
1920
2474
|
}
|
|
1921
|
-
if (this.key instanceof LiteralSchema) {
|
|
1922
|
-
return res;
|
|
1923
|
-
}
|
|
1924
2475
|
var unionKey = this.key;
|
|
1925
|
-
if (typeof unionKey
|
|
1926
|
-
var thisSchema = this.items.find(
|
|
1927
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1928
|
-
function (item) {
|
|
1929
|
-
if (item instanceof ObjectSchema) {
|
|
1930
|
-
var itemKey = item["items"][unionKey];
|
|
1931
|
-
if (itemKey instanceof LiteralSchema) {
|
|
1932
|
-
return _typeof(src) === "object" && unionKey in src && itemKey["value"] === src[unionKey];
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
return false;
|
|
1936
|
-
});
|
|
1937
|
-
if (thisSchema) {
|
|
1938
|
-
var itemResult = thisSchema["executePreview"](sourcePath, src, scope);
|
|
1939
|
-
for (var keyS in itemResult) {
|
|
1940
|
-
var _key3 = keyS;
|
|
1941
|
-
res[_key3] = itemResult[_key3];
|
|
1942
|
-
}
|
|
1943
|
-
return res;
|
|
1944
|
-
}
|
|
2476
|
+
if (typeof unionKey !== "string") {
|
|
1945
2477
|
res[sourcePath] = {
|
|
1946
2478
|
status: "error",
|
|
1947
|
-
message: "
|
|
2479
|
+
message: "The schema of this value is wrong. Expected the key of a discriminated union to be a string. Got: '".concat(JSON.stringify(unionKey, null, 2), "'")
|
|
1948
2480
|
};
|
|
2481
|
+
return res;
|
|
2482
|
+
}
|
|
2483
|
+
var thisSchema = this.items.find(
|
|
2484
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2485
|
+
function (item) {
|
|
2486
|
+
if (item instanceof ObjectSchema) {
|
|
2487
|
+
var itemKey = item["items"][unionKey];
|
|
2488
|
+
if (itemKey instanceof LiteralSchema) {
|
|
2489
|
+
return _typeof(src) === "object" && unionKey in src && itemKey["value"] === src[unionKey];
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return false;
|
|
2493
|
+
});
|
|
2494
|
+
if (thisSchema) {
|
|
2495
|
+
var itemResult = thisSchema["executePreview"](sourcePath, src, scope);
|
|
2496
|
+
for (var keyS in itemResult) {
|
|
2497
|
+
var _key2 = keyS;
|
|
2498
|
+
res[_key2] = itemResult[_key2];
|
|
2499
|
+
}
|
|
2500
|
+
return res;
|
|
1949
2501
|
}
|
|
1950
2502
|
res[sourcePath] = {
|
|
1951
2503
|
status: "error",
|
|
1952
|
-
message: "
|
|
2504
|
+
message: "Could not find a matching (object) schema for the discriminated union key: ".concat(unionKey)
|
|
1953
2505
|
};
|
|
1954
2506
|
return res;
|
|
1955
2507
|
}
|
|
1956
2508
|
}]);
|
|
1957
2509
|
}(Schema);
|
|
1958
|
-
var
|
|
1959
|
-
for (var _len = arguments.length, objects = new Array(_len > 1 ? _len - 1 : 0),
|
|
1960
|
-
objects[
|
|
2510
|
+
var discriminatedUnion = function discriminatedUnion(key) {
|
|
2511
|
+
for (var _len = arguments.length, objects = new Array(_len > 1 ? _len - 1 : 0), _key3 = 1; _key3 < _len; _key3++) {
|
|
2512
|
+
objects[_key3 - 1] = arguments[_key3];
|
|
1961
2513
|
}
|
|
1962
|
-
return new
|
|
2514
|
+
return new DiscriminatedUnionSchema(key, objects);
|
|
1963
2515
|
};
|
|
1964
2516
|
|
|
1965
2517
|
var RegEx$1 = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
|
|
@@ -2930,17 +3482,94 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
|
|
|
2930
3482
|
_this.previewInput = previewInput;
|
|
2931
3483
|
return _this;
|
|
2932
3484
|
}
|
|
3485
|
+
|
|
3486
|
+
/**
|
|
3487
|
+
* Describe this field.
|
|
3488
|
+
*
|
|
3489
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
3490
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
3491
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
3492
|
+
* assistant and the MCP tools read.
|
|
3493
|
+
*
|
|
3494
|
+
* Pass `null` to clear a description set earlier.
|
|
3495
|
+
*
|
|
3496
|
+
* @example
|
|
3497
|
+
* const schema = s
|
|
3498
|
+
* .image()
|
|
3499
|
+
* .describe("Shown at the top of the page, 16:9 works best");
|
|
3500
|
+
* export default c.define("/example.val.ts", schema, {
|
|
3501
|
+
* path: "/public/val/example.png",
|
|
3502
|
+
* width: 100,
|
|
3503
|
+
* height: 100,
|
|
3504
|
+
* mimeType: "image/png",
|
|
3505
|
+
* });
|
|
3506
|
+
*/
|
|
2933
3507
|
_inherits(ImageSchema, _Schema);
|
|
2934
3508
|
return _createClass(ImageSchema, [{
|
|
2935
3509
|
key: "describe",
|
|
2936
3510
|
value: function describe(description) {
|
|
2937
3511
|
return new ImageSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
2938
3512
|
}
|
|
3513
|
+
|
|
3514
|
+
/**
|
|
3515
|
+
* Store the image on Val's remote content host instead of in your repository.
|
|
3516
|
+
*
|
|
3517
|
+
* The bytes still go into the patch store when the image is uploaded — the
|
|
3518
|
+
* push to the remote host happens at publish. What changes is where the
|
|
3519
|
+
* published image lives: `path` becomes a remote URL rather than a path
|
|
3520
|
+
* under `/public`, so the repository does not grow with every upload.
|
|
3521
|
+
*
|
|
3522
|
+
* The `path` of a remote image is a URL on the content host, and it is not
|
|
3523
|
+
* something to write by hand: upload the image in the Studio, or write a
|
|
3524
|
+
* local path and let `npx val validate --fix` upload it and rewrite the
|
|
3525
|
+
* `path` to the ref below.
|
|
3526
|
+
*
|
|
3527
|
+
* @example
|
|
3528
|
+
* const schema = s
|
|
3529
|
+
* .image({ accept: "image/webp", directory: "/public/val/images" })
|
|
3530
|
+
* .remote();
|
|
3531
|
+
* export default c.define("/example.val.ts", schema, {
|
|
3532
|
+
* path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/example.webp",
|
|
3533
|
+
* width: 100,
|
|
3534
|
+
* height: 100,
|
|
3535
|
+
* mimeType: "image/webp",
|
|
3536
|
+
* });
|
|
3537
|
+
*/
|
|
2939
3538
|
}, {
|
|
2940
3539
|
key: "remote",
|
|
2941
3540
|
value: function remote() {
|
|
2942
3541
|
return new ImageSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
2943
3542
|
}
|
|
3543
|
+
|
|
3544
|
+
/**
|
|
3545
|
+
* Add a custom validation rule to this field.
|
|
3546
|
+
*
|
|
3547
|
+
* The function is called with the field's value and returns `false` when the
|
|
3548
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
3549
|
+
* more than once to add more rules — they all run, and every message is
|
|
3550
|
+
* reported.
|
|
3551
|
+
*
|
|
3552
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
3553
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
3554
|
+
*
|
|
3555
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
3556
|
+
* before a publish.
|
|
3557
|
+
*
|
|
3558
|
+
* The second argument carries the `path` of the field being validated, for
|
|
3559
|
+
* when the message needs to say where the problem is.
|
|
3560
|
+
*
|
|
3561
|
+
* @example
|
|
3562
|
+
* const schema = s.image().validate((val) =>
|
|
3563
|
+
* val.alt ? false : "Every image needs alt text",
|
|
3564
|
+
* );
|
|
3565
|
+
* export default c.define("/example.val.ts", schema, {
|
|
3566
|
+
* path: "/public/val/example.png",
|
|
3567
|
+
* width: 100,
|
|
3568
|
+
* height: 100,
|
|
3569
|
+
* mimeType: "image/png",
|
|
3570
|
+
* alt: "An example",
|
|
3571
|
+
* });
|
|
3572
|
+
*/
|
|
2944
3573
|
}, {
|
|
2945
3574
|
key: "validate",
|
|
2946
3575
|
value: function validate(validationFunction) {
|
|
@@ -3158,6 +3787,17 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3158
3787
|
* instead of a preview row that navigates to it.
|
|
3159
3788
|
*
|
|
3160
3789
|
* Static configuration, not a callback — see `render.ts`.
|
|
3790
|
+
*
|
|
3791
|
+
* @example
|
|
3792
|
+
* const schema = s.array(s.image().render({ as: "inline" }));
|
|
3793
|
+
* export default c.define("/example.val.ts", schema, [
|
|
3794
|
+
* {
|
|
3795
|
+
* path: "/public/val/example.png",
|
|
3796
|
+
* width: 100,
|
|
3797
|
+
* height: 100,
|
|
3798
|
+
* mimeType: "image/png",
|
|
3799
|
+
* },
|
|
3800
|
+
* ]);
|
|
3161
3801
|
*/
|
|
3162
3802
|
}, {
|
|
3163
3803
|
key: "render",
|
|
@@ -3169,6 +3809,23 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3169
3809
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
3170
3810
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
3171
3811
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
3812
|
+
*
|
|
3813
|
+
* @example
|
|
3814
|
+
* const schema = s.array(
|
|
3815
|
+
* s.image().preview(({ val }) => ({
|
|
3816
|
+
* title: val.alt ?? "Image",
|
|
3817
|
+
* image: val,
|
|
3818
|
+
* })),
|
|
3819
|
+
* );
|
|
3820
|
+
* export default c.define("/example.val.ts", schema, [
|
|
3821
|
+
* {
|
|
3822
|
+
* path: "/public/val/example.png",
|
|
3823
|
+
* width: 100,
|
|
3824
|
+
* height: 100,
|
|
3825
|
+
* mimeType: "image/png",
|
|
3826
|
+
* alt: "An example",
|
|
3827
|
+
* },
|
|
3828
|
+
* ]);
|
|
3172
3829
|
*/
|
|
3173
3830
|
}, {
|
|
3174
3831
|
key: "preview",
|
|
@@ -3265,6 +3922,21 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3265
3922
|
_this.previewInput = previewInput;
|
|
3266
3923
|
return _this;
|
|
3267
3924
|
}
|
|
3925
|
+
|
|
3926
|
+
/**
|
|
3927
|
+
* Describe this field.
|
|
3928
|
+
*
|
|
3929
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
3930
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
3931
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
3932
|
+
* assistant and the MCP tools read.
|
|
3933
|
+
*
|
|
3934
|
+
* Pass `null` to clear a description set earlier.
|
|
3935
|
+
*
|
|
3936
|
+
* @example
|
|
3937
|
+
* const schema = s.route().describe("Where the button goes");
|
|
3938
|
+
* export default c.define("/example.val.ts", schema, "/a-page-slug");
|
|
3939
|
+
*/
|
|
3268
3940
|
_inherits(RouteSchema, _Schema);
|
|
3269
3941
|
return _createClass(RouteSchema, [{
|
|
3270
3942
|
key: "describe",
|
|
@@ -3311,6 +3983,27 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3311
3983
|
exclude: pattern
|
|
3312
3984
|
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
3313
3985
|
}
|
|
3986
|
+
|
|
3987
|
+
/**
|
|
3988
|
+
* Add a custom validation rule to this field.
|
|
3989
|
+
*
|
|
3990
|
+
* The function is called with the field's value and returns `false` when the
|
|
3991
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
3992
|
+
* more than once to add more rules — they all run, and every message is
|
|
3993
|
+
* reported.
|
|
3994
|
+
*
|
|
3995
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
3996
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
3997
|
+
*
|
|
3998
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
3999
|
+
* before a publish.
|
|
4000
|
+
*
|
|
4001
|
+
* @example
|
|
4002
|
+
* const schema = s.route().validate((val) =>
|
|
4003
|
+
* val.endsWith("/") ? "Leave off the trailing slash" : false,
|
|
4004
|
+
* );
|
|
4005
|
+
* export default c.define("/example.val.ts", schema, "/a-page-slug");
|
|
4006
|
+
*/
|
|
3314
4007
|
}, {
|
|
3315
4008
|
key: "validate",
|
|
3316
4009
|
value: function validate(validationFunction) {
|
|
@@ -3397,6 +4090,10 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3397
4090
|
* instead of a preview row that navigates to it.
|
|
3398
4091
|
*
|
|
3399
4092
|
* Static configuration, not a callback — see `render.ts`.
|
|
4093
|
+
*
|
|
4094
|
+
* @example
|
|
4095
|
+
* const schema = s.array(s.route().render({ as: "inline" }));
|
|
4096
|
+
* export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
|
|
3400
4097
|
*/
|
|
3401
4098
|
}, {
|
|
3402
4099
|
key: "render",
|
|
@@ -3408,6 +4105,12 @@ var RouteSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3408
4105
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
3409
4106
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
3410
4107
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
4108
|
+
*
|
|
4109
|
+
* @example
|
|
4110
|
+
* const schema = s.array(
|
|
4111
|
+
* s.route().preview(({ val }) => ({ title: val })),
|
|
4112
|
+
* );
|
|
4113
|
+
* export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
|
|
3411
4114
|
*/
|
|
3412
4115
|
}, {
|
|
3413
4116
|
key: "preview",
|
|
@@ -3488,12 +4191,42 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3488
4191
|
_this.previewInput = previewInput;
|
|
3489
4192
|
return _this;
|
|
3490
4193
|
}
|
|
4194
|
+
|
|
4195
|
+
/**
|
|
4196
|
+
* Describe this field.
|
|
4197
|
+
*
|
|
4198
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
4199
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
4200
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
4201
|
+
* assistant and the MCP tools read.
|
|
4202
|
+
*
|
|
4203
|
+
* Pass `null` to clear a description set earlier.
|
|
4204
|
+
*
|
|
4205
|
+
* @example
|
|
4206
|
+
* const schema = s.richtext().describe("The body of the article");
|
|
4207
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4208
|
+
* { tag: "p", children: ["Hello"] },
|
|
4209
|
+
* ]);
|
|
4210
|
+
*/
|
|
3491
4211
|
_inherits(RichTextSchema, _Schema);
|
|
3492
4212
|
return _createClass(RichTextSchema, [{
|
|
3493
4213
|
key: "describe",
|
|
3494
4214
|
value: function describe(description) {
|
|
3495
4215
|
return new RichTextSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
3496
4216
|
}
|
|
4217
|
+
|
|
4218
|
+
/**
|
|
4219
|
+
* Validate that the rich text holds at most `max` characters.
|
|
4220
|
+
*
|
|
4221
|
+
* Counted over the TEXT, not the markup: tags, attributes and the structure
|
|
4222
|
+
* of the document do not add to it.
|
|
4223
|
+
*
|
|
4224
|
+
* @example
|
|
4225
|
+
* const schema = s.richtext().maxLength(280);
|
|
4226
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4227
|
+
* { tag: "p", children: ["Hello"] },
|
|
4228
|
+
* ]);
|
|
4229
|
+
*/
|
|
3497
4230
|
}, {
|
|
3498
4231
|
key: "maxLength",
|
|
3499
4232
|
value: function maxLength(max) {
|
|
@@ -3501,6 +4234,19 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3501
4234
|
maxLength: max
|
|
3502
4235
|
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
3503
4236
|
}
|
|
4237
|
+
|
|
4238
|
+
/**
|
|
4239
|
+
* Validate that the rich text holds at least `min` characters.
|
|
4240
|
+
*
|
|
4241
|
+
* Counted over the TEXT, not the markup: tags, attributes and the structure
|
|
4242
|
+
* of the document do not add to it.
|
|
4243
|
+
*
|
|
4244
|
+
* @example
|
|
4245
|
+
* const schema = s.richtext().minLength(20).maxLength(280);
|
|
4246
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4247
|
+
* { tag: "p", children: ["Long enough to clear the minimum length."] },
|
|
4248
|
+
* ]);
|
|
4249
|
+
*/
|
|
3504
4250
|
}, {
|
|
3505
4251
|
key: "minLength",
|
|
3506
4252
|
value: function minLength(min) {
|
|
@@ -3508,6 +4254,29 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3508
4254
|
minLength: min
|
|
3509
4255
|
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
3510
4256
|
}
|
|
4257
|
+
|
|
4258
|
+
/**
|
|
4259
|
+
* Add a custom validation rule to this field.
|
|
4260
|
+
*
|
|
4261
|
+
* The function is called with the field's value and returns `false` when the
|
|
4262
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
4263
|
+
* more than once to add more rules — they all run, and every message is
|
|
4264
|
+
* reported.
|
|
4265
|
+
*
|
|
4266
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
4267
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
4268
|
+
*
|
|
4269
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
4270
|
+
* before a publish.
|
|
4271
|
+
*
|
|
4272
|
+
* @example
|
|
4273
|
+
* const schema = s.richtext().validate((val) =>
|
|
4274
|
+
* val.length > 0 ? false : "Write something",
|
|
4275
|
+
* );
|
|
4276
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4277
|
+
* { tag: "p", children: ["Hello"] },
|
|
4278
|
+
* ]);
|
|
4279
|
+
*/
|
|
3511
4280
|
}, {
|
|
3512
4281
|
key: "validate",
|
|
3513
4282
|
value: function validate(validationFunction) {
|
|
@@ -3955,7 +4724,7 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3955
4724
|
}, {
|
|
3956
4725
|
key: "nullable",
|
|
3957
4726
|
value: function nullable() {
|
|
3958
|
-
return new RichTextSchema(this.options, true,
|
|
4727
|
+
return new RichTextSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
3959
4728
|
}
|
|
3960
4729
|
}, {
|
|
3961
4730
|
key: "readonly",
|
|
@@ -3983,6 +4752,12 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3983
4752
|
* instead of a preview row that navigates to it.
|
|
3984
4753
|
*
|
|
3985
4754
|
* Static configuration, not a callback — see `render.ts`.
|
|
4755
|
+
*
|
|
4756
|
+
* @example
|
|
4757
|
+
* const schema = s.array(s.richtext().render({ as: "inline" }));
|
|
4758
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4759
|
+
* [{ tag: "p", children: ["Hello"] }],
|
|
4760
|
+
* ]);
|
|
3986
4761
|
*/
|
|
3987
4762
|
}, {
|
|
3988
4763
|
key: "render",
|
|
@@ -3994,6 +4769,16 @@ var RichTextSchema = /*#__PURE__*/function (_Schema) {
|
|
|
3994
4769
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
3995
4770
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
3996
4771
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
4772
|
+
*
|
|
4773
|
+
* @example
|
|
4774
|
+
* const schema = s.array(
|
|
4775
|
+
* s.richtext().preview(({ val }) => ({
|
|
4776
|
+
* title: val.length > 0 ? "Rich text" : "Empty",
|
|
4777
|
+
* })),
|
|
4778
|
+
* );
|
|
4779
|
+
* export default c.define("/example.val.ts", schema, [
|
|
4780
|
+
* [{ tag: "p", children: ["Hello"] }],
|
|
4781
|
+
* ]);
|
|
3997
4782
|
*/
|
|
3998
4783
|
}, {
|
|
3999
4784
|
key: "preview",
|
|
@@ -4456,6 +5241,68 @@ function hasInlineExternalEntries(source) {
|
|
|
4456
5241
|
return _typeof(source) === "object" && source !== null && !Array.isArray(source) && !isExternal(source) && Object.keys(source).length > 0;
|
|
4457
5242
|
}
|
|
4458
5243
|
|
|
5244
|
+
/**
|
|
5245
|
+
* The keys a record is REQUIRED to hold, where its key schema says what they are.
|
|
5246
|
+
*
|
|
5247
|
+
* Most records have an open key set — `s.record(s.string(), item)` holds
|
|
5248
|
+
* whatever anyone adds — and this returns `null` for those. A record keyed by
|
|
5249
|
+
* something that enumerates its values is different in kind: the keys are part
|
|
5250
|
+
* of the schema, so a missing one is a hole in the content rather than content
|
|
5251
|
+
* nobody has written yet.
|
|
5252
|
+
*
|
|
5253
|
+
* Two key schemas enumerate. A union of literals does it locally, so its keys
|
|
5254
|
+
* are here. `s.locale()` does it in the settings module, which is another file
|
|
5255
|
+
* and so cannot be read from a serialized schema — that case says only which
|
|
5256
|
+
* kind it is, and is resolved against `locales.available` by
|
|
5257
|
+
* `resolveSchemaSourceFixes`, the same crossing `keyOf` and `route` make.
|
|
5258
|
+
*/
|
|
5259
|
+
|
|
5260
|
+
/**
|
|
5261
|
+
* What `key` requires a record to hold, or `null` where it requires nothing.
|
|
5262
|
+
*
|
|
5263
|
+
* Works from the SERIALIZED schema so that the Studio, the validation worker
|
|
5264
|
+
* and the server all answer this the same way — none of them has the schema
|
|
5265
|
+
* instance, and `SchemaStore` deliberately holds serialized schemas only.
|
|
5266
|
+
*/
|
|
5267
|
+
function declaredKeySetOf(key) {
|
|
5268
|
+
if (key === undefined) {
|
|
5269
|
+
return null;
|
|
5270
|
+
}
|
|
5271
|
+
if (key.type === "literal") {
|
|
5272
|
+
return {
|
|
5273
|
+
kind: "literals",
|
|
5274
|
+
keys: [key.value]
|
|
5275
|
+
};
|
|
5276
|
+
}
|
|
5277
|
+
if (key.type === "enum") {
|
|
5278
|
+
// An enum names every value it may take, so those values ARE the key set.
|
|
5279
|
+
// `discriminated-union` is deliberately absent: it discriminates objects
|
|
5280
|
+
// and cannot be a record key at all.
|
|
5281
|
+
return {
|
|
5282
|
+
kind: "literals",
|
|
5283
|
+
keys: _toConsumableArray(key.values)
|
|
5284
|
+
};
|
|
5285
|
+
}
|
|
5286
|
+
if (key.type === "locale") {
|
|
5287
|
+
return {
|
|
5288
|
+
kind: "locale"
|
|
5289
|
+
};
|
|
5290
|
+
}
|
|
5291
|
+
return null;
|
|
5292
|
+
}
|
|
5293
|
+
|
|
5294
|
+
/**
|
|
5295
|
+
* The declared keys a record is missing, in the order the schema declares them.
|
|
5296
|
+
*
|
|
5297
|
+
* Declaration order rather than the source's: this is read as "what is left to
|
|
5298
|
+
* write", and the answer should not reshuffle itself as entries are added.
|
|
5299
|
+
*/
|
|
5300
|
+
function missingDeclaredKeys(declared, present) {
|
|
5301
|
+
return declared.filter(function (key) {
|
|
5302
|
+
return !present.includes(key);
|
|
5303
|
+
});
|
|
5304
|
+
}
|
|
5305
|
+
|
|
4459
5306
|
/**
|
|
4460
5307
|
* The source type of a `.jsonValues()` record: every entry value is EITHER a
|
|
4461
5308
|
* lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
|
|
@@ -4487,6 +5334,16 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4487
5334
|
var externalLabel = arguments.length > 12 && arguments[12] !== undefined ? arguments[12] : null;
|
|
4488
5335
|
_classCallCheck(this, RecordSchema);
|
|
4489
5336
|
_this = _callSuper(this, RecordSchema);
|
|
5337
|
+
/**
|
|
5338
|
+
* The key set this record's schema declares, computed once.
|
|
5339
|
+
*
|
|
5340
|
+
* `declaredKeySetOf` reads a SERIALIZED schema, and serializing the key
|
|
5341
|
+
* schema walks it — twice per validate, and once per record instance, for an
|
|
5342
|
+
* answer that is a property of the schema and cannot move between them. A
|
|
5343
|
+
* schema is built once and validated against many times, so the walk happens
|
|
5344
|
+
* on the first question and not on any after it.
|
|
5345
|
+
*/
|
|
5346
|
+
_defineProperty(_this, "declaredKeys", void 0);
|
|
4490
5347
|
_this.item = item;
|
|
4491
5348
|
_this.opt = opt;
|
|
4492
5349
|
_this.customValidateFunctions = customValidateFunctions;
|
|
@@ -4502,19 +5359,62 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4502
5359
|
_this.externalLabel = externalLabel;
|
|
4503
5360
|
return _this;
|
|
4504
5361
|
}
|
|
5362
|
+
|
|
5363
|
+
/**
|
|
5364
|
+
* Describe this field.
|
|
5365
|
+
*
|
|
5366
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
5367
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
5368
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
5369
|
+
* assistant and the MCP tools read.
|
|
5370
|
+
*
|
|
5371
|
+
* Pass `null` to clear a description set earlier.
|
|
5372
|
+
*
|
|
5373
|
+
* @example
|
|
5374
|
+
* const schema = s
|
|
5375
|
+
* .record(s.string())
|
|
5376
|
+
* .describe("Button labels, keyed by locale");
|
|
5377
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
5378
|
+
*/
|
|
4505
5379
|
_inherits(RecordSchema, _Schema);
|
|
4506
5380
|
return _createClass(RecordSchema, [{
|
|
4507
5381
|
key: "describe",
|
|
4508
5382
|
value: function describe(description) {
|
|
4509
5383
|
return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
|
|
4510
5384
|
}
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
5385
|
+
|
|
5386
|
+
/**
|
|
5387
|
+
* Add a custom validation rule to this field.
|
|
5388
|
+
*
|
|
5389
|
+
* The function is called with the field's value and returns `false` when the
|
|
5390
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
5391
|
+
* more than once to add more rules — they all run, and every message is
|
|
5392
|
+
* reported.
|
|
5393
|
+
*
|
|
5394
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
5395
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
5396
|
+
*
|
|
5397
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
5398
|
+
* before a publish.
|
|
5399
|
+
*
|
|
5400
|
+
* The function is given the whole record. To validate one entry, put a
|
|
5401
|
+
* `.validate(...)` on the ITEM schema instead — that reports the error on
|
|
5402
|
+
* the entry's own row, and on a `.jsonValues()` record it does not force
|
|
5403
|
+
* every entry to be loaded.
|
|
5404
|
+
*
|
|
5405
|
+
* @example
|
|
5406
|
+
* const schema = s.record(s.string()).validate((val) =>
|
|
5407
|
+
* "en" in val ? false : "There has to be an 'en' entry",
|
|
5408
|
+
* );
|
|
5409
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
5410
|
+
*/
|
|
5411
|
+
}, {
|
|
5412
|
+
key: "validate",
|
|
5413
|
+
value: function validate(validationFunction) {
|
|
5414
|
+
return new RecordSchema(this.item, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
|
|
5415
|
+
}
|
|
5416
|
+
}, {
|
|
5417
|
+
key: "executeValidate",
|
|
4518
5418
|
value: function executeValidate(path, src) {
|
|
4519
5419
|
var _this2 = this;
|
|
4520
5420
|
var error = false;
|
|
@@ -4590,6 +5490,11 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4590
5490
|
error = _objectSpread2(_objectSpread2({}, error), {}, _defineProperty({}, path, [allFilesCheckError]));
|
|
4591
5491
|
}
|
|
4592
5492
|
}
|
|
5493
|
+
// A record whose keys are declared by its schema holds every one of them,
|
|
5494
|
+
// and an entry nobody has written yet is `null` rather than absent — so
|
|
5495
|
+
// `null` is a value here, not a value of the wrong type, and the item
|
|
5496
|
+
// schema is not asked about it.
|
|
5497
|
+
var hasDeclaredKeys = this.declaredKeySet() !== null;
|
|
4593
5498
|
Object.entries(src).forEach(function (_ref5) {
|
|
4594
5499
|
var _ref6 = _slicedToArray(_ref5, 2),
|
|
4595
5500
|
key = _ref6[0],
|
|
@@ -4629,7 +5534,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4629
5534
|
_this2.markKeyErrorsAtPath(entryErr, subPath);
|
|
4630
5535
|
}
|
|
4631
5536
|
error = _this2.mergeValidationErrors(error, entryErr);
|
|
4632
|
-
} else if (_this2.isJsonValues && isJson(elem)) ; else {
|
|
5537
|
+
} else if (hasDeclaredKeys && elem === null) ; else if (_this2.isJsonValues && isJson(elem)) ; else {
|
|
4633
5538
|
// Falls through for a jsonValues record whose entry content is inlined
|
|
4634
5539
|
// (loaded in the UI, or hand-authored): same as a plain record — validate
|
|
4635
5540
|
// the value against the item schema.
|
|
@@ -4637,8 +5542,79 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4637
5542
|
error = _this2.mergeValidationErrors(error, subError);
|
|
4638
5543
|
}
|
|
4639
5544
|
});
|
|
5545
|
+
var declaredKeys = this.getDeclaredKeysValidation(path, src);
|
|
5546
|
+
error = this.mergeValidationErrors(error, declaredKeys);
|
|
5547
|
+
var _iterator2 = _createForOfIteratorHelper(this.localeScopeErrors()),
|
|
5548
|
+
_step2;
|
|
5549
|
+
try {
|
|
5550
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
5551
|
+
var scopeError = _step2.value;
|
|
5552
|
+
error = this.appendValidationError(error, path, scopeError.message, src, scopeError.schemaError);
|
|
5553
|
+
}
|
|
5554
|
+
} catch (err) {
|
|
5555
|
+
_iterator2.e(err);
|
|
5556
|
+
} finally {
|
|
5557
|
+
_iterator2.f();
|
|
5558
|
+
}
|
|
4640
5559
|
return error;
|
|
4641
5560
|
}
|
|
5561
|
+
|
|
5562
|
+
/**
|
|
5563
|
+
* The check that a record with a DECLARED key set holds every one of them.
|
|
5564
|
+
*
|
|
5565
|
+
* `s.record(s.locale(), item)` has one entry per language and
|
|
5566
|
+
* `s.record(s.union(s.literal("a"), s.literal("b")), item)` has both — the
|
|
5567
|
+
* keys are part of the schema either way, so a missing one is a hole in the
|
|
5568
|
+
* content rather than content nobody has written yet. TypeScript already
|
|
5569
|
+
* demanded both keys of the second; this is the validator catching up, which
|
|
5570
|
+
* is why the two now behave the same.
|
|
5571
|
+
*
|
|
5572
|
+
* Deferred to `resolveSchemaSourceFixes` even for the literal case, where the
|
|
5573
|
+
* keys are known right here: a locale record's keys are in another file, and
|
|
5574
|
+
* one code path for both is one message, one fix and one thing to be wrong.
|
|
5575
|
+
*/
|
|
5576
|
+
}, {
|
|
5577
|
+
key: "getDeclaredKeysValidation",
|
|
5578
|
+
value: function getDeclaredKeysValidation(path, src) {
|
|
5579
|
+
if (this.keySchema === null) {
|
|
5580
|
+
return false;
|
|
5581
|
+
}
|
|
5582
|
+
var declared = this.declaredKeySet();
|
|
5583
|
+
if (declared === null) {
|
|
5584
|
+
return false;
|
|
5585
|
+
}
|
|
5586
|
+
return _defineProperty({}, path, [{
|
|
5587
|
+
fixes: ["record:fill-keys"],
|
|
5588
|
+
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.",
|
|
5589
|
+
value: {
|
|
5590
|
+
present: Object.keys(src),
|
|
5591
|
+
declared: declared.kind === "literals" ? declared.keys : null
|
|
5592
|
+
}
|
|
5593
|
+
}]);
|
|
5594
|
+
}
|
|
5595
|
+
}, {
|
|
5596
|
+
key: "declaredKeySet",
|
|
5597
|
+
value: function declaredKeySet() {
|
|
5598
|
+
if (this.declaredKeys === undefined) {
|
|
5599
|
+
this.declaredKeys = this.keySchema === null ? null : declaredKeySetOf(this.keySchema["executeSerialize"]());
|
|
5600
|
+
}
|
|
5601
|
+
return this.declaredKeys;
|
|
5602
|
+
}
|
|
5603
|
+
}, {
|
|
5604
|
+
key: "opensLocaleScope",
|
|
5605
|
+
value: function opensLocaleScope() {
|
|
5606
|
+
return this.keySchema !== null && this.keySchema["isLocaleField"]() ? "key" : null;
|
|
5607
|
+
}
|
|
5608
|
+
}, {
|
|
5609
|
+
key: "localeScopeChildren",
|
|
5610
|
+
value: function localeScopeChildren() {
|
|
5611
|
+
// The KEY schema is not a child here. A locale key is what opens this
|
|
5612
|
+
// record's scope; it is not something inside the scope.
|
|
5613
|
+
return [{
|
|
5614
|
+
key: "*",
|
|
5615
|
+
schema: this.item
|
|
5616
|
+
}];
|
|
5617
|
+
}
|
|
4642
5618
|
}, {
|
|
4643
5619
|
key: "isRemoteUrl",
|
|
4644
5620
|
value: function isRemoteUrl(url) {
|
|
@@ -4869,6 +5845,10 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4869
5845
|
* must come BEFORE `.external()`: afterwards the value is a `Schema`, and
|
|
4870
5846
|
* there is no `.readonly()` left to call — which is the error the compiler
|
|
4871
5847
|
* gives, and a clearer one than a runtime throw.
|
|
5848
|
+
*
|
|
5849
|
+
* @example
|
|
5850
|
+
* const schema = s.record(s.string()).readonly();
|
|
5851
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
4872
5852
|
*/
|
|
4873
5853
|
}, {
|
|
4874
5854
|
key: "readonly",
|
|
@@ -4882,11 +5862,54 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4882
5862
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
4883
5863
|
return new RecordSchema(this.item, this.opt, this.customValidateFunctions, this.currentRouter, this.keySchema, this.mediaOptions, this.isReadonly, isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
|
|
4884
5864
|
}
|
|
5865
|
+
|
|
5866
|
+
/**
|
|
5867
|
+
* Turn this record into a page router: its keys are route paths of your
|
|
5868
|
+
* application, and they are validated against the router's conventions.
|
|
5869
|
+
*
|
|
5870
|
+
* `s.router(router, item)` builds the same thing in one call and is what
|
|
5871
|
+
* most code should use — this is for adding a router to a record that
|
|
5872
|
+
* already exists.
|
|
5873
|
+
*
|
|
5874
|
+
* @example
|
|
5875
|
+
* import { nextAppRouter } from "../val.config";
|
|
5876
|
+
* const schema = s
|
|
5877
|
+
* .record(s.object({ title: s.string() }))
|
|
5878
|
+
* .router(nextAppRouter);
|
|
5879
|
+
* export default c.define("/app/[slug]/page.val.ts", schema, {
|
|
5880
|
+
* "/a-page-slug": { title: "First Page" },
|
|
5881
|
+
* });
|
|
5882
|
+
*/
|
|
4885
5883
|
}, {
|
|
4886
5884
|
key: "router",
|
|
4887
5885
|
value: function router(_router) {
|
|
4888
5886
|
return new RecordSchema(this.item, this.opt, this.customValidateFunctions, _router, this.keySchema, this.mediaOptions, this.isReadonly, this.isHidden, this.description, this.isJsonValues, this.previewInput, this.renderInput, this.externalLabel);
|
|
4889
5887
|
}
|
|
5888
|
+
|
|
5889
|
+
/**
|
|
5890
|
+
* Allow the files in this gallery to be stored on Val's remote content host
|
|
5891
|
+
* instead of in your repository.
|
|
5892
|
+
*
|
|
5893
|
+
* For `s.images()` and `s.files()`, which are records of media. Remote is off
|
|
5894
|
+
* until this is called.
|
|
5895
|
+
*
|
|
5896
|
+
* Each entry is then keyed by its URL on the content host rather than by a
|
|
5897
|
+
* path under `/public`. That key is not something to write by hand: upload
|
|
5898
|
+
* in the Studio, or add a local path and let `npx val validate --fix`
|
|
5899
|
+
* upload it and rewrite the key.
|
|
5900
|
+
*
|
|
5901
|
+
* @example
|
|
5902
|
+
* const schema = s.images({ directory: "/public/val/images" }).remote();
|
|
5903
|
+
* export default c.define("/content/images.val.ts", schema, {
|
|
5904
|
+
* "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/hero.webp":
|
|
5905
|
+
* {
|
|
5906
|
+
* width: 1920,
|
|
5907
|
+
* height: 1080,
|
|
5908
|
+
* mimeType: "image/webp",
|
|
5909
|
+
* alt: "Hero image",
|
|
5910
|
+
* },
|
|
5911
|
+
* });
|
|
5912
|
+
*/
|
|
4890
5913
|
}, {
|
|
4891
5914
|
key: "remote",
|
|
4892
5915
|
value: function remote() {
|
|
@@ -4908,6 +5931,20 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4908
5931
|
* nested inside an object/array/record is rejected at startup with a module
|
|
4909
5932
|
* error, because the single-entry fetch endpoint, the Studio's content
|
|
4910
5933
|
* substitution and content validation are all root-only.
|
|
5934
|
+
*
|
|
5935
|
+
* Must come BEFORE `.validate()` and `.preview()`: those are typed against
|
|
5936
|
+
* the un-lazy source shape, so a validator or preview declared first cannot
|
|
5937
|
+
* be carried over, and declaring one first throws rather than silently
|
|
5938
|
+
* dropping it.
|
|
5939
|
+
*
|
|
5940
|
+
* @example
|
|
5941
|
+
* import { nextAppRouter } from "../val.config";
|
|
5942
|
+
* const schema = s
|
|
5943
|
+
* .router(nextAppRouter, s.object({ title: s.string(), body: s.string() }))
|
|
5944
|
+
* .jsonValues();
|
|
5945
|
+
* export default c.define("/app/support/[slug]/page.val.ts", schema, {
|
|
5946
|
+
* "/support/faq": c.json(() => import("./content/faq.val.json")),
|
|
5947
|
+
* });
|
|
4911
5948
|
*/
|
|
4912
5949
|
}, {
|
|
4913
5950
|
key: "jsonValues",
|
|
@@ -4955,6 +5992,19 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
4955
5992
|
* nested external record would leave a hole in the middle of a module's
|
|
4956
5993
|
* source, and the Studio, patching and validation all assume a module's
|
|
4957
5994
|
* source is complete apart from its entries.
|
|
5995
|
+
*
|
|
5996
|
+
* @example
|
|
5997
|
+
* const schema = s.record(s.object({ title: s.string() })).external("posts");
|
|
5998
|
+
* export default c.define("/content/posts.val.ts", schema, c.external());
|
|
5999
|
+
*
|
|
6000
|
+
* @example
|
|
6001
|
+
* // A read-only external record: `.readonly()` must come FIRST, because
|
|
6002
|
+
* // afterwards there is no `.readonly()` left on the type to call.
|
|
6003
|
+
* const schema = s
|
|
6004
|
+
* .record(s.object({ title: s.string() }))
|
|
6005
|
+
* .readonly()
|
|
6006
|
+
* .external("posts");
|
|
6007
|
+
* export default c.define("/content/posts.val.ts", schema, c.external());
|
|
4958
6008
|
*/
|
|
4959
6009
|
}, {
|
|
4960
6010
|
key: "external",
|
|
@@ -5214,6 +6264,25 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5214
6264
|
* is the item of another container, in search, in references. What its
|
|
5215
6265
|
* entries show is the ITEM schema's `preview`, not this. Never how the field
|
|
5216
6266
|
* is edited (that is `render`). See `preview.ts`.
|
|
6267
|
+
*
|
|
6268
|
+
* @example
|
|
6269
|
+
* // The preview of the RECORD, for where it is an item of something else.
|
|
6270
|
+
* // What its own rows show is the ITEM schema's preview — see below.
|
|
6271
|
+
* const labels = s.record(s.string()).preview(({ val }) => ({
|
|
6272
|
+
* title: `${Object.keys(val).length} locales`,
|
|
6273
|
+
* }));
|
|
6274
|
+
* export default c.define("/example.val.ts", s.array(labels), [
|
|
6275
|
+
* { en: "Read more" },
|
|
6276
|
+
* ]);
|
|
6277
|
+
*
|
|
6278
|
+
* @example
|
|
6279
|
+
* // Rows of a record come from the ITEM's preview, not the record's:
|
|
6280
|
+
* const author = s
|
|
6281
|
+
* .object({ name: s.string(), role: s.string() })
|
|
6282
|
+
* .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
|
|
6283
|
+
* export default c.define("/example.val.ts", s.record(author), {
|
|
6284
|
+
* ada: { name: "Ada", role: "Engineer" },
|
|
6285
|
+
* });
|
|
5217
6286
|
*/
|
|
5218
6287
|
}, {
|
|
5219
6288
|
key: "preview",
|
|
@@ -5227,6 +6296,10 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5227
6296
|
* instead of a preview row that navigates to it.
|
|
5228
6297
|
*
|
|
5229
6298
|
* Static configuration, not a callback — see `render.ts`.
|
|
6299
|
+
*
|
|
6300
|
+
* @example
|
|
6301
|
+
* const schema = s.array(s.record(s.string()).render({ as: "inline" }));
|
|
6302
|
+
* export default c.define("/example.val.ts", schema, [{ en: "Read more" }]);
|
|
5230
6303
|
*/
|
|
5231
6304
|
}, {
|
|
5232
6305
|
key: "render",
|
|
@@ -5236,6 +6309,23 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5236
6309
|
}]);
|
|
5237
6310
|
}(Schema);
|
|
5238
6311
|
|
|
6312
|
+
/**
|
|
6313
|
+
* The source of a record, given what its key schema says about its keys.
|
|
6314
|
+
*
|
|
6315
|
+
* A key schema that ENUMERATES its keys (a union of literals, or `s.locale()`)
|
|
6316
|
+
* makes every one of them an entry of the record, and an entry nobody has
|
|
6317
|
+
* written yet is `null` rather than absent — so the value type widens by
|
|
6318
|
+
* `null`. That is the whole of option F at the type level: a half-translated
|
|
6319
|
+
* record is a record with nulls in it, which is data you can count, filter and
|
|
6320
|
+
* see in a diff, rather than keys that are simply not there.
|
|
6321
|
+
*
|
|
6322
|
+
* For a union of literals TypeScript already required every key, since
|
|
6323
|
+
* `SelectorOfSchema<K>` is the literal union itself. `s.locale()` is a flavoured
|
|
6324
|
+
* string, so it requires nothing here and the requirement is the validator's —
|
|
6325
|
+
* deliberately: which languages exist is in the settings module, where the
|
|
6326
|
+
* project can change it without a deploy.
|
|
6327
|
+
*/
|
|
6328
|
+
|
|
5239
6329
|
// Overload: with key schema
|
|
5240
6330
|
|
|
5241
6331
|
// Overload: without key schema
|
|
@@ -5274,6 +6364,31 @@ function record(keyOrSchema, schema) {
|
|
|
5274
6364
|
* written without removing the key.
|
|
5275
6365
|
*/
|
|
5276
6366
|
|
|
6367
|
+
/**
|
|
6368
|
+
* The languages this project publishes.
|
|
6369
|
+
*
|
|
6370
|
+
* Content rather than configuration, and deliberately: which languages a site
|
|
6371
|
+
* has is a decision the people who write it make, and under a build-time
|
|
6372
|
+
* constant it took a developer and a deploy. It is the same move `assistant`
|
|
6373
|
+
* makes with `enabled`.
|
|
6374
|
+
*
|
|
6375
|
+
* Val ships no list of its own. A project with no `locales` section has not
|
|
6376
|
+
* said it is translated, and nothing about locales appears anywhere — no picker
|
|
6377
|
+
* in the Studio, no checks, nothing.
|
|
6378
|
+
*
|
|
6379
|
+
* **This list is a decision with a blast radius.** Every locale in content is
|
|
6380
|
+
* checked against it, so removing one invalidates the content that uses it, and
|
|
6381
|
+
* adding one leaves every locale-keyed record short of a language until it is
|
|
6382
|
+
* filled in. That is the intended behaviour — a language that is declared and
|
|
6383
|
+
* missing everywhere is worth being told about — but it is why the Studio warns
|
|
6384
|
+
* before saving a removal rather than treating this as an ordinary field.
|
|
6385
|
+
*
|
|
6386
|
+
* There is no default language, deliberately. Every locale-specific field asks
|
|
6387
|
+
* which language it is in, and a default is exactly the answer that lets that
|
|
6388
|
+
* question go unanswered — content ends up filed under a language nobody chose,
|
|
6389
|
+
* which is the state translation is meant to make visible.
|
|
6390
|
+
*/
|
|
6391
|
+
|
|
5277
6392
|
/**
|
|
5278
6393
|
* The assistant: whether editors have one, and what it is told about the
|
|
5279
6394
|
* project on every message.
|
|
@@ -5334,8 +6449,32 @@ settings) {
|
|
|
5334
6449
|
return "unconfigured";
|
|
5335
6450
|
}
|
|
5336
6451
|
|
|
5337
|
-
|
|
5338
|
-
|
|
6452
|
+
/**
|
|
6453
|
+
* One of the languages the project publishes.
|
|
6454
|
+
*
|
|
6455
|
+
* The set is NOT here. It is declared in the settings module — `locales.available`
|
|
6456
|
+
* — so that adding a language is something the people who write the content can
|
|
6457
|
+
* do, and so that one list drives validation, the Studio's picker and the
|
|
6458
|
+
* translation notes. This schema knows only that the value is one of them, which
|
|
6459
|
+
* is checked cross-module through the `locale:check-locale` fix, exactly as
|
|
6460
|
+
* `keyOf` and `route` check theirs.
|
|
6461
|
+
*
|
|
6462
|
+
* Never stega encoded (see `stegaEncode.ts`): a locale goes into `<html lang>`,
|
|
6463
|
+
* into `hreflang` and into `Intl` constructors, none of which survive invisible
|
|
6464
|
+
* characters.
|
|
6465
|
+
*/
|
|
6466
|
+
var LocaleSchema = /*#__PURE__*/function (_Schema) {
|
|
6467
|
+
/**
|
|
6468
|
+
* Type-only marker: as a record key, this schema DECLARES the key set.
|
|
6469
|
+
*
|
|
6470
|
+
* `declare` so it exists in the type and nowhere at runtime — reading it off
|
|
6471
|
+
* an instance gives `undefined`, and nothing should. It is how `record()`
|
|
6472
|
+
* knows to type entries as `Item | null`: a language nobody has translated
|
|
6473
|
+
* into is a null entry, not an absent key. See `DeclaredKeySet` and
|
|
6474
|
+
* `RecordSrcOf`.
|
|
6475
|
+
*/
|
|
6476
|
+
|
|
6477
|
+
function LocaleSchema() {
|
|
5339
6478
|
var _this;
|
|
5340
6479
|
var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
5341
6480
|
var customValidateFunctions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
@@ -5344,8 +6483,8 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5344
6483
|
var description = arguments.length > 4 ? arguments[4] : undefined;
|
|
5345
6484
|
var renderInput = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
|
|
5346
6485
|
var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
|
|
5347
|
-
_classCallCheck(this,
|
|
5348
|
-
_this = _callSuper(this,
|
|
6486
|
+
_classCallCheck(this, LocaleSchema);
|
|
6487
|
+
_this = _callSuper(this, LocaleSchema);
|
|
5349
6488
|
_this.opt = opt;
|
|
5350
6489
|
_this.customValidateFunctions = customValidateFunctions;
|
|
5351
6490
|
_this.isReadonly = isReadonly;
|
|
@@ -5355,30 +6494,80 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5355
6494
|
_this.previewInput = previewInput;
|
|
5356
6495
|
return _this;
|
|
5357
6496
|
}
|
|
5358
|
-
|
|
5359
|
-
|
|
6497
|
+
|
|
6498
|
+
/**
|
|
6499
|
+
* A note to whoever edits this field, shown under it in the Studio.
|
|
6500
|
+
*
|
|
6501
|
+
* Pass `null` to clear a description set earlier.
|
|
6502
|
+
*
|
|
6503
|
+
* @example
|
|
6504
|
+
* const schema = s.object({
|
|
6505
|
+
* locale: s.locale().describe("The language everything below is written in"),
|
|
6506
|
+
* title: s.string(),
|
|
6507
|
+
* });
|
|
6508
|
+
* export default c.define("/example.val.ts", schema, {
|
|
6509
|
+
* locale: "nb-NO",
|
|
6510
|
+
* title: "Vinterjakke",
|
|
6511
|
+
* });
|
|
6512
|
+
*/
|
|
6513
|
+
_inherits(LocaleSchema, _Schema);
|
|
6514
|
+
return _createClass(LocaleSchema, [{
|
|
5360
6515
|
key: "describe",
|
|
5361
6516
|
value: function describe(description) {
|
|
5362
|
-
return new
|
|
6517
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
5363
6518
|
}
|
|
6519
|
+
|
|
6520
|
+
/**
|
|
6521
|
+
* A check of your own, on top of "is this one of the project's languages".
|
|
6522
|
+
*
|
|
6523
|
+
* Return a message when the value is WRONG and `false` when it is fine — the
|
|
6524
|
+
* two answers are a complaint and no complaint, so write the check as a
|
|
6525
|
+
* ternary rather than as `ok || "message"`, which returns `true` and `true`
|
|
6526
|
+
* is neither.
|
|
6527
|
+
*
|
|
6528
|
+
* @example
|
|
6529
|
+
* const schema = s.object({
|
|
6530
|
+
* locale: s.locale().validate((val) =>
|
|
6531
|
+
* val === "en-US" ? "This section is not translated into English yet" : false,
|
|
6532
|
+
* ),
|
|
6533
|
+
* title: s.string(),
|
|
6534
|
+
* });
|
|
6535
|
+
* export default c.define("/example.val.ts", schema, {
|
|
6536
|
+
* locale: "nb-NO",
|
|
6537
|
+
* title: "Vinterjakke",
|
|
6538
|
+
* });
|
|
6539
|
+
*/
|
|
5364
6540
|
}, {
|
|
5365
6541
|
key: "validate",
|
|
5366
6542
|
value: function validate(validationFunction) {
|
|
5367
|
-
return new
|
|
6543
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
5368
6544
|
}
|
|
5369
6545
|
}, {
|
|
5370
6546
|
key: "executeValidate",
|
|
5371
6547
|
value: function executeValidate(path, src) {
|
|
6548
|
+
var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
6549
|
+
path: path
|
|
6550
|
+
});
|
|
5372
6551
|
if (this.opt && (src === null || src === undefined)) {
|
|
5373
|
-
return false;
|
|
6552
|
+
return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
|
|
5374
6553
|
}
|
|
5375
|
-
if (typeof src !== "
|
|
6554
|
+
if (typeof src !== "string") {
|
|
5376
6555
|
return _defineProperty({}, path, [{
|
|
5377
|
-
message: "Expected '
|
|
6556
|
+
message: "Expected 'string', got '".concat(_typeof(src), "'"),
|
|
5378
6557
|
value: src
|
|
5379
6558
|
}]);
|
|
5380
6559
|
}
|
|
5381
|
-
return
|
|
6560
|
+
return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
|
|
6561
|
+
// Which languages exist is in another module, so this cannot be
|
|
6562
|
+
// answered here — the same shape `keyOf` and `route` use, resolved by
|
|
6563
|
+
// `resolveSchemaSourceFixes` against the settings module.
|
|
6564
|
+
fixes: ["locale:check-locale"],
|
|
6565
|
+
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.",
|
|
6566
|
+
value: {
|
|
6567
|
+
locale: src,
|
|
6568
|
+
sourcePath: path
|
|
6569
|
+
}
|
|
6570
|
+
}]));
|
|
5382
6571
|
}
|
|
5383
6572
|
}, {
|
|
5384
6573
|
key: "executeAssert",
|
|
@@ -5389,45 +6578,42 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5389
6578
|
data: src
|
|
5390
6579
|
};
|
|
5391
6580
|
}
|
|
5392
|
-
if (src ===
|
|
5393
|
-
return {
|
|
5394
|
-
success: false,
|
|
5395
|
-
errors: _defineProperty({}, path, [{
|
|
5396
|
-
message: "Expected 'boolean', got 'null'",
|
|
5397
|
-
typeError: true
|
|
5398
|
-
}])
|
|
5399
|
-
};
|
|
5400
|
-
}
|
|
5401
|
-
if (typeof src !== "boolean") {
|
|
6581
|
+
if (typeof src === "string") {
|
|
5402
6582
|
return {
|
|
5403
|
-
success:
|
|
5404
|
-
|
|
5405
|
-
message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
|
|
5406
|
-
typeError: true
|
|
5407
|
-
}])
|
|
6583
|
+
success: true,
|
|
6584
|
+
data: src
|
|
5408
6585
|
};
|
|
5409
6586
|
}
|
|
5410
6587
|
return {
|
|
5411
|
-
success:
|
|
5412
|
-
|
|
6588
|
+
success: false,
|
|
6589
|
+
errors: _defineProperty({}, path, [{
|
|
6590
|
+
message: "Expected 'string', got '".concat(_typeof(src), "'"),
|
|
6591
|
+
typeError: true
|
|
6592
|
+
}])
|
|
5413
6593
|
};
|
|
5414
6594
|
}
|
|
5415
6595
|
}, {
|
|
5416
6596
|
key: "nullable",
|
|
5417
6597
|
value: function nullable() {
|
|
5418
|
-
|
|
6598
|
+
// Asserted whole, exactly as `RouteSchema.nullable` does: the source type
|
|
6599
|
+
// widens by `null` while the caller's validators and preview stay typed
|
|
6600
|
+
// against the value, and `executeValidate` returns before either sees one.
|
|
6601
|
+
return new LocaleSchema(true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
5419
6602
|
}
|
|
5420
6603
|
}, {
|
|
5421
6604
|
key: "readonly",
|
|
5422
6605
|
value: function readonly() {
|
|
5423
|
-
|
|
5424
|
-
return new BooleanSchema(this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6606
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions, true, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
5425
6607
|
}
|
|
5426
6608
|
}, {
|
|
5427
6609
|
key: "hidden",
|
|
5428
6610
|
value: function hidden() {
|
|
5429
|
-
|
|
5430
|
-
|
|
6611
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, true, this.description, this.renderInput, this.previewInput);
|
|
6612
|
+
}
|
|
6613
|
+
}, {
|
|
6614
|
+
key: "isLocaleField",
|
|
6615
|
+
value: function isLocaleField() {
|
|
6616
|
+
return true;
|
|
5431
6617
|
}
|
|
5432
6618
|
}, {
|
|
5433
6619
|
key: "executeCustomValidateAt",
|
|
@@ -5438,27 +6624,33 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5438
6624
|
}
|
|
5439
6625
|
|
|
5440
6626
|
/**
|
|
5441
|
-
* How this field is laid out
|
|
5442
|
-
* or record: `{ as: "inline" }` renders the field itself inside each row,
|
|
5443
|
-
* instead of a preview row that navigates to it.
|
|
5444
|
-
*
|
|
6627
|
+
* How this field is laid out where it is the item of an array or a record.
|
|
5445
6628
|
* Static configuration, not a callback — see `render.ts`.
|
|
6629
|
+
*
|
|
6630
|
+
* @example
|
|
6631
|
+
* const schema = s.array(s.locale().render({ as: "inline" }));
|
|
6632
|
+
* export default c.define("/example.val.ts", schema, ["nb-NO", "en-US"]);
|
|
5446
6633
|
*/
|
|
5447
6634
|
}, {
|
|
5448
6635
|
key: "render",
|
|
5449
6636
|
value: function render(input) {
|
|
5450
|
-
return new
|
|
6637
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
|
|
5451
6638
|
}
|
|
5452
6639
|
|
|
5453
6640
|
/**
|
|
5454
|
-
* How this VALUE is shown where a preview of it is needed
|
|
5455
|
-
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
6641
|
+
* How this VALUE is shown where a preview of it is needed. Never how the field
|
|
5456
6642
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
6643
|
+
*
|
|
6644
|
+
* @example
|
|
6645
|
+
* const schema = s.array(
|
|
6646
|
+
* s.locale().preview(({ val }) => ({ title: val })),
|
|
6647
|
+
* );
|
|
6648
|
+
* export default c.define("/example.val.ts", schema, ["nb-NO", "en-US"]);
|
|
5457
6649
|
*/
|
|
5458
6650
|
}, {
|
|
5459
6651
|
key: "preview",
|
|
5460
6652
|
value: function preview(select) {
|
|
5461
|
-
return new
|
|
6653
|
+
return new LocaleSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
|
|
5462
6654
|
}
|
|
5463
6655
|
}, {
|
|
5464
6656
|
key: "executePreviewItem",
|
|
@@ -5480,7 +6672,7 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5480
6672
|
value: function executeSerialize() {
|
|
5481
6673
|
var _this$renderInput, _this$customValidateF;
|
|
5482
6674
|
return {
|
|
5483
|
-
type: "
|
|
6675
|
+
type: "locale",
|
|
5484
6676
|
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
5485
6677
|
preview: this.previewInput ? true : undefined,
|
|
5486
6678
|
opt: this.opt,
|
|
@@ -5497,71 +6689,421 @@ var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5497
6689
|
}
|
|
5498
6690
|
}]);
|
|
5499
6691
|
}(Schema);
|
|
5500
|
-
var _boolean = function _boolean() {
|
|
5501
|
-
return new BooleanSchema();
|
|
5502
|
-
};
|
|
5503
6692
|
|
|
5504
6693
|
/**
|
|
5505
|
-
*
|
|
6694
|
+
* Define one of the project's languages.
|
|
5506
6695
|
*
|
|
5507
|
-
*
|
|
5508
|
-
*
|
|
5509
|
-
* {@link settings} for what a settings module holds.
|
|
6696
|
+
* The languages themselves are declared in the settings module, under
|
|
6697
|
+
* `locales.available` — this says only that a value is one of them.
|
|
5510
6698
|
*
|
|
5511
|
-
*
|
|
5512
|
-
*
|
|
5513
|
-
*
|
|
6699
|
+
* @example // a field: everything under this object is in this language
|
|
6700
|
+
* const schema = s.object({ locale: s.locale(), title: s.string() });
|
|
6701
|
+
*
|
|
6702
|
+
* @example // a key: one entry per language
|
|
6703
|
+
* const schema = s.record(s.locale(), s.object({ title: s.string() }));
|
|
5514
6704
|
*/
|
|
5515
|
-
var
|
|
5516
|
-
|
|
6705
|
+
var locale = function locale() {
|
|
6706
|
+
return new LocaleSchema();
|
|
6707
|
+
};
|
|
6708
|
+
|
|
6709
|
+
var BooleanSchema = /*#__PURE__*/function (_Schema) {
|
|
6710
|
+
function BooleanSchema() {
|
|
5517
6711
|
var _this;
|
|
5518
|
-
var opt = arguments.length >
|
|
6712
|
+
var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
6713
|
+
var customValidateFunctions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
5519
6714
|
var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
5520
6715
|
var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
5521
6716
|
var description = arguments.length > 4 ? arguments[4] : undefined;
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
6717
|
+
var renderInput = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
|
|
6718
|
+
var previewInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
|
|
6719
|
+
_classCallCheck(this, BooleanSchema);
|
|
6720
|
+
_this = _callSuper(this, BooleanSchema);
|
|
5525
6721
|
_this.opt = opt;
|
|
6722
|
+
_this.customValidateFunctions = customValidateFunctions;
|
|
5526
6723
|
_this.isReadonly = isReadonly;
|
|
5527
6724
|
_this.isHidden = isHidden;
|
|
5528
6725
|
_this.description = description;
|
|
6726
|
+
_this.renderInput = renderInput;
|
|
6727
|
+
_this.previewInput = previewInput;
|
|
5529
6728
|
return _this;
|
|
5530
6729
|
}
|
|
5531
|
-
|
|
5532
|
-
|
|
6730
|
+
|
|
6731
|
+
/**
|
|
6732
|
+
* Describe this field.
|
|
6733
|
+
*
|
|
6734
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
6735
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
6736
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
6737
|
+
* assistant and the MCP tools read.
|
|
6738
|
+
*
|
|
6739
|
+
* Pass `null` to clear a description set earlier.
|
|
6740
|
+
*
|
|
6741
|
+
* @example
|
|
6742
|
+
* const schema = s.boolean().describe("Show this item in the main menu");
|
|
6743
|
+
* export default c.define("/example.val.ts", schema, true);
|
|
6744
|
+
*/
|
|
6745
|
+
_inherits(BooleanSchema, _Schema);
|
|
6746
|
+
return _createClass(BooleanSchema, [{
|
|
6747
|
+
key: "describe",
|
|
6748
|
+
value: function describe(description) {
|
|
6749
|
+
return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
6750
|
+
}
|
|
6751
|
+
|
|
6752
|
+
/**
|
|
6753
|
+
* Add a custom validation rule to this field.
|
|
6754
|
+
*
|
|
6755
|
+
* The function is called with the field's value and returns `false` when the
|
|
6756
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
6757
|
+
* more than once to add more rules — they all run, and every message is
|
|
6758
|
+
* reported.
|
|
6759
|
+
*
|
|
6760
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
6761
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
6762
|
+
*
|
|
6763
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
6764
|
+
* before a publish.
|
|
6765
|
+
*
|
|
6766
|
+
* @example
|
|
6767
|
+
* const schema = s.boolean().validate((val) =>
|
|
6768
|
+
* val === true ? false : "This has to be on for now",
|
|
6769
|
+
* );
|
|
6770
|
+
* export default c.define("/example.val.ts", schema, true);
|
|
6771
|
+
*/
|
|
6772
|
+
}, {
|
|
6773
|
+
key: "validate",
|
|
6774
|
+
value: function validate(validationFunction) {
|
|
6775
|
+
return new BooleanSchema(this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6776
|
+
}
|
|
6777
|
+
}, {
|
|
5533
6778
|
key: "executeValidate",
|
|
5534
6779
|
value: function executeValidate(path, src) {
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
if (this.opt) {
|
|
5538
|
-
return false;
|
|
5539
|
-
}
|
|
5540
|
-
return _defineProperty({}, path, [{
|
|
5541
|
-
message: "Expected 'object', got '".concat(src, "'")
|
|
5542
|
-
}]);
|
|
6780
|
+
if (this.opt && (src === null || src === undefined)) {
|
|
6781
|
+
return false;
|
|
5543
6782
|
}
|
|
5544
|
-
if (
|
|
6783
|
+
if (typeof src !== "boolean") {
|
|
5545
6784
|
return _defineProperty({}, path, [{
|
|
5546
|
-
message: "Expected '
|
|
6785
|
+
message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
|
|
6786
|
+
value: src
|
|
5547
6787
|
}]);
|
|
5548
6788
|
}
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
6789
|
+
return false;
|
|
6790
|
+
}
|
|
6791
|
+
}, {
|
|
6792
|
+
key: "executeAssert",
|
|
6793
|
+
value: function executeAssert(path, src) {
|
|
6794
|
+
if (this.opt && src === null) {
|
|
6795
|
+
return {
|
|
6796
|
+
success: true,
|
|
6797
|
+
data: src
|
|
6798
|
+
};
|
|
5553
6799
|
}
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
6800
|
+
if (src === null) {
|
|
6801
|
+
return {
|
|
6802
|
+
success: false,
|
|
6803
|
+
errors: _defineProperty({}, path, [{
|
|
6804
|
+
message: "Expected 'boolean', got 'null'",
|
|
6805
|
+
typeError: true
|
|
6806
|
+
}])
|
|
6807
|
+
};
|
|
6808
|
+
}
|
|
6809
|
+
if (typeof src !== "boolean") {
|
|
6810
|
+
return {
|
|
6811
|
+
success: false,
|
|
6812
|
+
errors: _defineProperty({}, path, [{
|
|
6813
|
+
message: "Expected 'boolean', got '".concat(_typeof(src), "'"),
|
|
6814
|
+
typeError: true
|
|
6815
|
+
}])
|
|
6816
|
+
};
|
|
6817
|
+
}
|
|
6818
|
+
return {
|
|
6819
|
+
success: true,
|
|
6820
|
+
data: src
|
|
6821
|
+
};
|
|
6822
|
+
}
|
|
6823
|
+
}, {
|
|
6824
|
+
key: "nullable",
|
|
6825
|
+
value: function nullable() {
|
|
6826
|
+
return new BooleanSchema(true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6827
|
+
}
|
|
6828
|
+
}, {
|
|
6829
|
+
key: "readonly",
|
|
6830
|
+
value: function readonly() {
|
|
6831
|
+
var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
6832
|
+
return new BooleanSchema(this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6833
|
+
}
|
|
6834
|
+
}, {
|
|
6835
|
+
key: "hidden",
|
|
6836
|
+
value: function hidden() {
|
|
6837
|
+
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
6838
|
+
return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
|
|
6839
|
+
}
|
|
6840
|
+
}, {
|
|
6841
|
+
key: "executeCustomValidateAt",
|
|
6842
|
+
value: function executeCustomValidateAt(path, src) {
|
|
6843
|
+
return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
6844
|
+
path: path
|
|
6845
|
+
});
|
|
6846
|
+
}
|
|
6847
|
+
|
|
6848
|
+
/**
|
|
6849
|
+
* How this field is laid out in the editor when it is the item of an array
|
|
6850
|
+
* or record: `{ as: "inline" }` renders the field itself inside each row,
|
|
6851
|
+
* instead of a preview row that navigates to it.
|
|
6852
|
+
*
|
|
6853
|
+
* Static configuration, not a callback — see `render.ts`.
|
|
6854
|
+
*
|
|
6855
|
+
* @example
|
|
6856
|
+
* const schema = s.array(s.boolean().render({ as: "inline" }));
|
|
6857
|
+
* export default c.define("/example.val.ts", schema, [true, false]);
|
|
6858
|
+
*/
|
|
6859
|
+
}, {
|
|
6860
|
+
key: "render",
|
|
6861
|
+
value: function render(input) {
|
|
6862
|
+
return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
|
|
6863
|
+
}
|
|
6864
|
+
|
|
6865
|
+
/**
|
|
6866
|
+
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
6867
|
+
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
6868
|
+
* itself is edited (that is `render`). See `preview.ts`.
|
|
6869
|
+
*
|
|
6870
|
+
* @example
|
|
6871
|
+
* const schema = s.array(
|
|
6872
|
+
* s.boolean().preview(({ val }) => ({ title: val ? "On" : "Off" })),
|
|
6873
|
+
* );
|
|
6874
|
+
* export default c.define("/example.val.ts", schema, [true, false]);
|
|
6875
|
+
*/
|
|
6876
|
+
}, {
|
|
6877
|
+
key: "preview",
|
|
6878
|
+
value: function preview(select) {
|
|
6879
|
+
return new BooleanSchema(this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
|
|
6880
|
+
}
|
|
6881
|
+
}, {
|
|
6882
|
+
key: "executePreviewItem",
|
|
6883
|
+
value: function executePreviewItem(src) {
|
|
6884
|
+
if (this.previewInput === null) {
|
|
6885
|
+
return null;
|
|
6886
|
+
}
|
|
6887
|
+
return this.previewInput({
|
|
6888
|
+
val: src
|
|
6889
|
+
});
|
|
6890
|
+
}
|
|
6891
|
+
}, {
|
|
6892
|
+
key: "declaresItemPreview",
|
|
6893
|
+
value: function declaresItemPreview() {
|
|
6894
|
+
return this.previewInput !== null;
|
|
6895
|
+
}
|
|
6896
|
+
}, {
|
|
6897
|
+
key: "executeSerialize",
|
|
6898
|
+
value: function executeSerialize() {
|
|
6899
|
+
var _this$renderInput, _this$customValidateF;
|
|
6900
|
+
return {
|
|
6901
|
+
type: "boolean",
|
|
6902
|
+
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
6903
|
+
preview: this.previewInput ? true : undefined,
|
|
6904
|
+
opt: this.opt,
|
|
6905
|
+
customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
|
|
6906
|
+
readonly: this.isReadonly,
|
|
6907
|
+
hidden: this.isHidden,
|
|
6908
|
+
description: this.description
|
|
6909
|
+
};
|
|
6910
|
+
}
|
|
6911
|
+
}, {
|
|
6912
|
+
key: "executePreview",
|
|
6913
|
+
value: function executePreview() {
|
|
6914
|
+
return {};
|
|
6915
|
+
}
|
|
6916
|
+
}]);
|
|
6917
|
+
}(Schema);
|
|
6918
|
+
var _boolean = function _boolean() {
|
|
6919
|
+
return new BooleanSchema();
|
|
6920
|
+
};
|
|
6921
|
+
|
|
6922
|
+
/**
|
|
6923
|
+
* Language tags, and what makes one wrong.
|
|
6924
|
+
*
|
|
6925
|
+
* Val does not ship a list of locales. Which languages a project publishes is a
|
|
6926
|
+
* property of that project, so it is declared in the settings module — see
|
|
6927
|
+
* `LocalesSettingsSource` — and everything downstream reads it from there.
|
|
6928
|
+
*
|
|
6929
|
+
* What Val does own is the SPELLING. A tag is checked against BCP 47
|
|
6930
|
+
* (RFC 5646) through `Intl.getCanonicalLocales`, which is the same
|
|
6931
|
+
* implementation the browser, `<html lang>` and every `Intl` constructor use.
|
|
6932
|
+
* Delegating rather than writing a matcher is the point: a tag this accepts is
|
|
6933
|
+
* a tag those accept.
|
|
6934
|
+
*/
|
|
6935
|
+
|
|
6936
|
+
/**
|
|
6937
|
+
* What is wrong with `tag` as a language tag, or `false` if nothing is.
|
|
6938
|
+
*
|
|
6939
|
+
* Canonical form, not merely parseable, and the difference is what makes this
|
|
6940
|
+
* worth checking at all. `nb-no` parses; `Intl.DisplayNames` and a
|
|
6941
|
+
* case-sensitive comparison against a stored key do not agree about it. Since a
|
|
6942
|
+
* locale is compared as a string everywhere — a record key, a URL segment, a
|
|
6943
|
+
* value in content — one spelling has to win, and the canonical one is the
|
|
6944
|
+
* spelling every other tool already produces.
|
|
6945
|
+
*
|
|
6946
|
+
* The message names the canonical form where there is one, because "not
|
|
6947
|
+
* canonical" is not an instruction and `nb-NO` is.
|
|
6948
|
+
*/
|
|
6949
|
+
function localeTagError(tag) {
|
|
6950
|
+
var canonical;
|
|
6951
|
+
try {
|
|
6952
|
+
canonical = Intl.getCanonicalLocales(tag);
|
|
6953
|
+
} catch (_unused) {
|
|
6954
|
+
// RangeError, for anything the grammar rejects: an underscore instead of a
|
|
6955
|
+
// hyphen (`nb_NO`, which is POSIX rather than BCP 47), an empty subtag, a
|
|
6956
|
+
// subtag of the wrong length.
|
|
6957
|
+
return "'".concat(tag, "' is not a language tag. Language then region, separated by a hyphen \u2014 'nb-NO', not 'nb_NO'");
|
|
6958
|
+
}
|
|
6959
|
+
if (canonical.length !== 1) {
|
|
6960
|
+
// A comma-separated list, or something that canonicalised to nothing.
|
|
6961
|
+
return "'".concat(tag, "' is not a single language tag");
|
|
6962
|
+
}
|
|
6963
|
+
if (canonical[0] !== tag) {
|
|
6964
|
+
return "'".concat(tag, "' is not canonical. Write it as '").concat(canonical[0], "'");
|
|
6965
|
+
}
|
|
6966
|
+
return false;
|
|
6967
|
+
}
|
|
6968
|
+
|
|
6969
|
+
/**
|
|
6970
|
+
* A language tag, as content holds it.
|
|
6971
|
+
*
|
|
6972
|
+
* A *flavoured* string rather than a union or a strict brand. Which languages a
|
|
6973
|
+
* project has is declared in its settings module, where the project can change
|
|
6974
|
+
* it, so there is no set for a type to enumerate — and a strict brand would make
|
|
6975
|
+
* `"nb-NO"` unassignable, which would mean writing every locale in a `.val.ts`
|
|
6976
|
+
* through a constructor. Content stays plain data.
|
|
6977
|
+
*
|
|
6978
|
+
* So this carries no compile-time guarantee, and is not meant to. It names the
|
|
6979
|
+
* concept where a bare `string` would say nothing, and the guarantee is the
|
|
6980
|
+
* `locale:check-locale` validation against `locales.available`.
|
|
6981
|
+
*/
|
|
6982
|
+
|
|
6983
|
+
/**
|
|
6984
|
+
* The locale a stored value means, or `null` if it means none of them.
|
|
6985
|
+
*
|
|
6986
|
+
* A lookup against the project's languages, and today that is all it is. It
|
|
6987
|
+
* stays a named function because it is the one place the question is asked —
|
|
6988
|
+
* the Studio, the validation worker and the server all come here rather than
|
|
6989
|
+
* comparing strings themselves, so they cannot disagree about what a stored
|
|
6990
|
+
* value is.
|
|
6991
|
+
*/
|
|
6992
|
+
function localeOfValue(value, available) {
|
|
6993
|
+
return available.includes(value) ? value : null;
|
|
6994
|
+
}
|
|
6995
|
+
|
|
6996
|
+
/**
|
|
6997
|
+
* A rule about a section that its individual fields cannot state.
|
|
6998
|
+
*
|
|
6999
|
+
* Paths are WITHIN the section, so an error lands on the value it is about —
|
|
7000
|
+
* including a row of a list, which is what makes this different from a
|
|
7001
|
+
* `.validate()` on the field.
|
|
7002
|
+
*/
|
|
7003
|
+
|
|
7004
|
+
/**
|
|
7005
|
+
* Every section's rules, by the name that travels in the serialized schema.
|
|
7006
|
+
*
|
|
7007
|
+
* Typed with `| undefined` on the value rather than as a `Partial`: the whole
|
|
7008
|
+
* point is that a lookup can miss, because the name comes off a serialized
|
|
7009
|
+
* schema that may have been written by a newer Val than the one reading it.
|
|
7010
|
+
*/
|
|
7011
|
+
var sectionValidators = {
|
|
7012
|
+
locales: localesSectionErrors
|
|
7013
|
+
};
|
|
7014
|
+
|
|
7015
|
+
/**
|
|
7016
|
+
* An object whose keys are all optional: absent means unset.
|
|
7017
|
+
*
|
|
7018
|
+
* Both the settings module itself and each of its sections are this. See
|
|
7019
|
+
* {@link SettingsSource} for why settings cannot be an object schema, and
|
|
7020
|
+
* {@link settings} for what a settings module holds.
|
|
7021
|
+
*
|
|
7022
|
+
* There is no `describe`, `validate`, `render` or `preview` on purpose: the
|
|
7023
|
+
* shape is Val's, not the schema author's — `s.settings()` takes no arguments —
|
|
7024
|
+
* and the Studio renders each section with a UI built for it.
|
|
7025
|
+
*/
|
|
7026
|
+
var SettingsSchema = /*#__PURE__*/function (_Schema) {
|
|
7027
|
+
function SettingsSchema(items) {
|
|
7028
|
+
var _this;
|
|
7029
|
+
var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
7030
|
+
var isReadonly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
7031
|
+
var isHidden = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
7032
|
+
var description = arguments.length > 4 ? arguments[4] : undefined;
|
|
7033
|
+
var
|
|
7034
|
+
/**
|
|
7035
|
+
* Which section this is, where Val has rules about it beyond its keys.
|
|
7036
|
+
*
|
|
7037
|
+
* Not the `validate` the class deliberately does not offer: that one is the
|
|
7038
|
+
* schema author's, and `s.settings()` takes no arguments to declare it
|
|
7039
|
+
* with. This names a rule Val states about a shape Val owns — no language
|
|
7040
|
+
* declared twice in `locales.available` is true of every project, and
|
|
7041
|
+
* there is nowhere else it can be said. A single value's rules stay on its
|
|
7042
|
+
* own schema; this is for the ones that need to see more than one value,
|
|
7043
|
+
* or to report on a row of a list.
|
|
7044
|
+
*
|
|
7045
|
+
* A NAME rather than the function, so it survives serialization: the schema
|
|
7046
|
+
* reaches the Studio's validation worker as JSON, and a closure would be
|
|
7047
|
+
* dropped on the way — which is how these rules once went missing there.
|
|
7048
|
+
*/
|
|
7049
|
+
section = arguments.length > 5 ? arguments[5] : undefined;
|
|
7050
|
+
_classCallCheck(this, SettingsSchema);
|
|
7051
|
+
_this = _callSuper(this, SettingsSchema);
|
|
7052
|
+
_this.items = items;
|
|
7053
|
+
_this.opt = opt;
|
|
7054
|
+
_this.isReadonly = isReadonly;
|
|
7055
|
+
_this.isHidden = isHidden;
|
|
7056
|
+
_this.description = description;
|
|
7057
|
+
_this.section = section;
|
|
7058
|
+
return _this;
|
|
7059
|
+
}
|
|
7060
|
+
|
|
7061
|
+
/**
|
|
7062
|
+
* This section's rules, or `undefined` where there are none to run.
|
|
7063
|
+
*
|
|
7064
|
+
* A name this Val does not know means a schema written by a newer one. Its
|
|
7065
|
+
* per-field validation still runs; only the section's own rule is missed,
|
|
7066
|
+
* which is the mild half of the failure and better than refusing the schema.
|
|
7067
|
+
*/
|
|
7068
|
+
_inherits(SettingsSchema, _Schema);
|
|
7069
|
+
return _createClass(SettingsSchema, [{
|
|
7070
|
+
key: "sectionValidate",
|
|
7071
|
+
value: function sectionValidate() {
|
|
7072
|
+
return this.section === undefined ? undefined : sectionValidators[this.section];
|
|
7073
|
+
}
|
|
7074
|
+
}, {
|
|
7075
|
+
key: "executeValidate",
|
|
7076
|
+
value: function executeValidate(path, src) {
|
|
7077
|
+
var error = false;
|
|
7078
|
+
if (src === null || src === undefined) {
|
|
7079
|
+
if (this.opt) {
|
|
7080
|
+
return false;
|
|
7081
|
+
}
|
|
7082
|
+
return _defineProperty({}, path, [{
|
|
7083
|
+
message: "Expected 'object', got '".concat(src, "'")
|
|
7084
|
+
}]);
|
|
7085
|
+
}
|
|
7086
|
+
if (_typeof(src) !== "object") {
|
|
7087
|
+
return _defineProperty({}, path, [{
|
|
7088
|
+
message: "Expected 'object', got '".concat(_typeof(src), "'")
|
|
7089
|
+
}]);
|
|
7090
|
+
}
|
|
7091
|
+
if (Array.isArray(src)) {
|
|
7092
|
+
return _defineProperty({}, path, [{
|
|
7093
|
+
message: "Expected 'object', got 'array'"
|
|
7094
|
+
}]);
|
|
7095
|
+
}
|
|
7096
|
+
for (var _i = 0, _Object$entries = Object.entries(this.items); _i < _Object$entries.length; _i++) {
|
|
7097
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
7098
|
+
_key = _Object$entries$_i[0],
|
|
7099
|
+
schema = _Object$entries$_i[1];
|
|
7100
|
+
// Absent is the unset value, so there is nothing to validate. A key that
|
|
7101
|
+
// is present as `undefined` is the same statement written differently.
|
|
7102
|
+
if (src[_key] === undefined) {
|
|
7103
|
+
continue;
|
|
7104
|
+
}
|
|
7105
|
+
var subPath = createValPathOfItem(path, _key);
|
|
7106
|
+
if (!subPath) {
|
|
5565
7107
|
error = this.appendValidationError(error, path, "Internal error: could not create path at ".concat(!path && typeof path === "string" ? "<empty string>" : path, " at key ").concat(_key),
|
|
5566
7108
|
// Should! never happen
|
|
5567
7109
|
src);
|
|
@@ -5582,6 +7124,39 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5582
7124
|
}).join(", ")), src, true);
|
|
5583
7125
|
}
|
|
5584
7126
|
}
|
|
7127
|
+
var sectionValidate = this.sectionValidate();
|
|
7128
|
+
if (sectionValidate) {
|
|
7129
|
+
var _iterator = _createForOfIteratorHelper(sectionValidate(src)),
|
|
7130
|
+
_step;
|
|
7131
|
+
try {
|
|
7132
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
7133
|
+
var _ref4;
|
|
7134
|
+
var _step$value = _step.value,
|
|
7135
|
+
keys = _step$value.path,
|
|
7136
|
+
message = _step$value.message;
|
|
7137
|
+
var _subPath = path;
|
|
7138
|
+
var _iterator2 = _createForOfIteratorHelper(keys),
|
|
7139
|
+
_step2;
|
|
7140
|
+
try {
|
|
7141
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
7142
|
+
var _key3 = _step2.value;
|
|
7143
|
+
_subPath = _subPath && createValPathOfItem(_subPath, _key3);
|
|
7144
|
+
}
|
|
7145
|
+
} catch (err) {
|
|
7146
|
+
_iterator2.e(err);
|
|
7147
|
+
} finally {
|
|
7148
|
+
_iterator2.f();
|
|
7149
|
+
}
|
|
7150
|
+
error = this.appendValidationError(error, // Falls back to the section itself, which is where an error belongs
|
|
7151
|
+
// when the value it is about is not addressable.
|
|
7152
|
+
(_ref4 = _subPath) !== null && _ref4 !== void 0 ? _ref4 : path, message, src);
|
|
7153
|
+
}
|
|
7154
|
+
} catch (err) {
|
|
7155
|
+
_iterator.e(err);
|
|
7156
|
+
} finally {
|
|
7157
|
+
_iterator.f();
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
5585
7160
|
return error;
|
|
5586
7161
|
}
|
|
5587
7162
|
}, {
|
|
@@ -5627,17 +7202,17 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5627
7202
|
}, {
|
|
5628
7203
|
key: "nullable",
|
|
5629
7204
|
value: function nullable() {
|
|
5630
|
-
return new SettingsSchema(this.items, true, this.isReadonly, this.isHidden, this.description);
|
|
7205
|
+
return new SettingsSchema(this.items, true, this.isReadonly, this.isHidden, this.description, this.section);
|
|
5631
7206
|
}
|
|
5632
7207
|
}, {
|
|
5633
7208
|
key: "readonly",
|
|
5634
7209
|
value: function readonly() {
|
|
5635
|
-
return new SettingsSchema(this.items, this.opt, true, this.isHidden, this.description);
|
|
7210
|
+
return new SettingsSchema(this.items, this.opt, true, this.isHidden, this.description, this.section);
|
|
5636
7211
|
}
|
|
5637
7212
|
}, {
|
|
5638
7213
|
key: "hidden",
|
|
5639
7214
|
value: function hidden() {
|
|
5640
|
-
return new SettingsSchema(this.items, this.opt, this.isReadonly, true, this.description);
|
|
7215
|
+
return new SettingsSchema(this.items, this.opt, this.isReadonly, true, this.description, this.section);
|
|
5641
7216
|
}
|
|
5642
7217
|
}, {
|
|
5643
7218
|
key: "executeCustomValidateAt",
|
|
@@ -5652,16 +7227,17 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5652
7227
|
value: function executeSerialize() {
|
|
5653
7228
|
return {
|
|
5654
7229
|
type: "settings",
|
|
5655
|
-
items: Object.fromEntries(Object.entries(this.items).map(function (
|
|
5656
|
-
var
|
|
5657
|
-
key =
|
|
5658
|
-
schema =
|
|
7230
|
+
items: Object.fromEntries(Object.entries(this.items).map(function (_ref5) {
|
|
7231
|
+
var _ref6 = _slicedToArray(_ref5, 2),
|
|
7232
|
+
key = _ref6[0],
|
|
7233
|
+
schema = _ref6[1];
|
|
5659
7234
|
return [key, schema["executeSerialize"]()];
|
|
5660
7235
|
})),
|
|
5661
7236
|
opt: this.opt,
|
|
5662
7237
|
readonly: this.isReadonly,
|
|
5663
7238
|
hidden: this.isHidden,
|
|
5664
|
-
description: this.description
|
|
7239
|
+
description: this.description,
|
|
7240
|
+
section: this.section
|
|
5665
7241
|
};
|
|
5666
7242
|
}
|
|
5667
7243
|
}, {
|
|
@@ -5671,19 +7247,19 @@ var SettingsSchema = /*#__PURE__*/function (_Schema) {
|
|
|
5671
7247
|
if (src === null) {
|
|
5672
7248
|
return res;
|
|
5673
7249
|
}
|
|
5674
|
-
for (var
|
|
5675
|
-
var itemSrc = src[
|
|
7250
|
+
for (var _key4 in this.items) {
|
|
7251
|
+
var itemSrc = src[_key4];
|
|
5676
7252
|
if (itemSrc === null || itemSrc === undefined) {
|
|
5677
7253
|
continue;
|
|
5678
7254
|
}
|
|
5679
|
-
var subPath = unsafeCreateSourcePath(sourcePath,
|
|
7255
|
+
var subPath = unsafeCreateSourcePath(sourcePath, _key4);
|
|
5680
7256
|
if (scope !== undefined && !scope.wantsUnder(subPath)) {
|
|
5681
7257
|
continue;
|
|
5682
7258
|
}
|
|
5683
|
-
var itemResult = this.items[
|
|
7259
|
+
var itemResult = this.items[_key4]["executePreview"](subPath, itemSrc, scope);
|
|
5684
7260
|
for (var keyS in itemResult) {
|
|
5685
|
-
var
|
|
5686
|
-
res[
|
|
7261
|
+
var _key5 = keyS;
|
|
7262
|
+
res[_key5] = itemResult[_key5];
|
|
5687
7263
|
}
|
|
5688
7264
|
}
|
|
5689
7265
|
return res;
|
|
@@ -5727,11 +7303,58 @@ function settings() {
|
|
|
5727
7303
|
assistant: new SettingsSchema({
|
|
5728
7304
|
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."),
|
|
5729
7305
|
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."),
|
|
5730
|
-
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.")
|
|
5731
|
-
|
|
7306
|
+
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."),
|
|
7307
|
+
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.")
|
|
7308
|
+
}),
|
|
7309
|
+
locales: new SettingsSchema({
|
|
7310
|
+
// Nullable because the source type is, and because the Studio writes
|
|
7311
|
+
// `null` for every sibling the first time a section is created.
|
|
7312
|
+
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.")
|
|
7313
|
+
}, false, false, false, undefined, "locales")
|
|
5732
7314
|
});
|
|
5733
7315
|
}
|
|
5734
7316
|
|
|
7317
|
+
/**
|
|
7318
|
+
* The rules about `locales` that need to see the whole list.
|
|
7319
|
+
*
|
|
7320
|
+
* Two of them, and both report on the ENTRY rather than the list: a tag has to
|
|
7321
|
+
* be spelled canonically, and a language cannot be declared twice. Neither can
|
|
7322
|
+
* live on the item schema — the item sees one string, and "twice" is a fact
|
|
7323
|
+
* about its siblings — and neither can be a `.validate()` on the array either,
|
|
7324
|
+
* since that reports one message on the array itself rather than on the row to
|
|
7325
|
+
* delete.
|
|
7326
|
+
*
|
|
7327
|
+
* Reads defensively rather than asserting the source's type. A settings module
|
|
7328
|
+
* is a file someone edits by hand, and validation runs against whatever is in
|
|
7329
|
+
* it — including the shapes the per-key pass is, in the same breath, reporting.
|
|
7330
|
+
*/
|
|
7331
|
+
function localesSectionErrors(src) {
|
|
7332
|
+
var errors = [];
|
|
7333
|
+
var raw = Array.isArray(src["available"]) ? src["available"] : [];
|
|
7334
|
+
var seen = new Set();
|
|
7335
|
+
for (var i = 0; i < raw.length; i++) {
|
|
7336
|
+
var tag = raw[i];
|
|
7337
|
+
if (typeof tag !== "string") {
|
|
7338
|
+
// The item's own schema has already said what is wrong with it.
|
|
7339
|
+
continue;
|
|
7340
|
+
}
|
|
7341
|
+
var spelling = localeTagError(tag);
|
|
7342
|
+
if (spelling !== false) {
|
|
7343
|
+
errors.push({
|
|
7344
|
+
path: ["available", i],
|
|
7345
|
+
message: spelling
|
|
7346
|
+
});
|
|
7347
|
+
} else if (seen.has(tag)) {
|
|
7348
|
+
errors.push({
|
|
7349
|
+
path: ["available", i],
|
|
7350
|
+
message: "'".concat(tag, "' is declared twice")
|
|
7351
|
+
});
|
|
7352
|
+
}
|
|
7353
|
+
seen.add(tag);
|
|
7354
|
+
}
|
|
7355
|
+
return errors;
|
|
7356
|
+
}
|
|
7357
|
+
|
|
5735
7358
|
/**
|
|
5736
7359
|
* What may be WRITTEN as an external record's source, on top of the marker.
|
|
5737
7360
|
*
|
|
@@ -5812,10 +7435,8 @@ function isArraySchema(schema) {
|
|
|
5812
7435
|
// );
|
|
5813
7436
|
// }
|
|
5814
7437
|
|
|
5815
|
-
function
|
|
5816
|
-
|
|
5817
|
-
) {
|
|
5818
|
-
return schema instanceof UnionSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "union";
|
|
7438
|
+
function isDiscriminatedUnionSchema(schema) {
|
|
7439
|
+
return schema instanceof DiscriminatedUnionSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "discriminated-union";
|
|
5819
7440
|
}
|
|
5820
7441
|
function isRichTextSchema(schema) {
|
|
5821
7442
|
return schema instanceof RichTextSchema || _typeof(schema) === "object" && "type" in schema && schema.type === "richtext";
|
|
@@ -5921,27 +7542,18 @@ function resolvePath(path, valModule, schema) {
|
|
|
5921
7542
|
source: resolvedSource
|
|
5922
7543
|
}
|
|
5923
7544
|
};
|
|
5924
|
-
} else if (
|
|
5925
|
-
var _key = resolvedSchema.key;
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
if (!Number.isNaN(Number(p))) {
|
|
5931
|
-
return p;
|
|
5932
|
-
} else {
|
|
5933
|
-
return JSON.stringify(p);
|
|
5934
|
-
}
|
|
5935
|
-
}).join("."),
|
|
5936
|
-
// TODO: create a function generate path from parts (not sure if this always works)
|
|
5937
|
-
schema: resolvedSchema,
|
|
5938
|
-
source: resolvedSource
|
|
5939
|
-
}
|
|
5940
|
-
};
|
|
7545
|
+
} else if (isDiscriminatedUnionSchema(resolvedSchema)) {
|
|
7546
|
+
var _key = resolvedSchema instanceof DiscriminatedUnionSchema ? resolvedSchema["key"] : resolvedSchema.key;
|
|
7547
|
+
// A nullable union holding `null` has no variant to descend into, and
|
|
7548
|
+
// `null[key]` throws before any of the reporting below can run.
|
|
7549
|
+
if (resolvedSource === null || _typeof(resolvedSource) !== "object") {
|
|
7550
|
+
throw Error("Schema type error: expected discriminated union source to be an object, but got ".concat(resolvedSource === null ? "null" : _typeof(resolvedSource), " in path: ").concat(path));
|
|
5941
7551
|
}
|
|
5942
7552
|
var keyValue = resolvedSource[_key];
|
|
5943
|
-
|
|
5944
|
-
|
|
7553
|
+
// `undefined`, not falsy: `s.literal("")` is a legal tag, and a variant
|
|
7554
|
+
// carrying it was reported as a missing key.
|
|
7555
|
+
if (keyValue === undefined) {
|
|
7556
|
+
throw Error("Invalid path: discriminated union source ".concat(resolvedSchema, " did not have required key ").concat(_key, " in path: ").concat(path));
|
|
5945
7557
|
}
|
|
5946
7558
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5947
7559
|
var schemaOfUnionKey = resolvedSchema.items.find(
|
|
@@ -5951,7 +7563,7 @@ function resolvePath(path, valModule, schema) {
|
|
|
5951
7563
|
return (child === null || child === void 0 || (_child$items = child.items) === null || _child$items === void 0 || (_child$items = _child$items[_key]) === null || _child$items === void 0 ? void 0 : _child$items.value) === keyValue;
|
|
5952
7564
|
});
|
|
5953
7565
|
if (!schemaOfUnionKey) {
|
|
5954
|
-
throw Error("Invalid path: union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key, " of value ").concat(keyValue, " in path: ").concat(path));
|
|
7566
|
+
throw Error("Invalid path: discriminated union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key, " of value ").concat(keyValue, " in path: ").concat(path));
|
|
5955
7567
|
}
|
|
5956
7568
|
resolvedSchema = schemaOfUnionKey.items[part];
|
|
5957
7569
|
resolvedSource = resolvedSource[part];
|
|
@@ -6171,31 +7783,25 @@ function safeResolvePath(path, valModule, schema) {
|
|
|
6171
7783
|
source: resolvedSource
|
|
6172
7784
|
}
|
|
6173
7785
|
};
|
|
6174
|
-
} else if (
|
|
6175
|
-
var _key2 = resolvedSchema.key;
|
|
6176
|
-
|
|
7786
|
+
} else if (isDiscriminatedUnionSchema(resolvedSchema)) {
|
|
7787
|
+
var _key2 = resolvedSchema instanceof DiscriminatedUnionSchema ? resolvedSchema["key"] : resolvedSchema.key;
|
|
7788
|
+
// See the note in `resolvePath`: a null union has no variant to descend
|
|
7789
|
+
// into, and this API promises a structured error rather than a throw.
|
|
7790
|
+
if (resolvedSource === null || _typeof(resolvedSource) !== "object") {
|
|
6177
7791
|
return {
|
|
6178
7792
|
v: {
|
|
6179
|
-
status: "
|
|
6180
|
-
|
|
6181
|
-
if (!Number.isNaN(Number(p))) {
|
|
6182
|
-
return p;
|
|
6183
|
-
} else {
|
|
6184
|
-
return JSON.stringify(p);
|
|
6185
|
-
}
|
|
6186
|
-
}).join("."),
|
|
6187
|
-
// TODO: create a function generate path from parts (not sure if this always works)
|
|
6188
|
-
schema: resolvedSchema,
|
|
6189
|
-
source: resolvedSource
|
|
7793
|
+
status: "error",
|
|
7794
|
+
message: "Schema type error: expected discriminated union source to be an object, but got ".concat(resolvedSource === null ? "null" : _typeof(resolvedSource), " in path: ").concat(path)
|
|
6190
7795
|
}
|
|
6191
7796
|
};
|
|
6192
7797
|
}
|
|
6193
7798
|
var keyValue = resolvedSource[_key2];
|
|
6194
|
-
|
|
7799
|
+
// See the note in `resolvePath`: an empty-string tag is a present key.
|
|
7800
|
+
if (keyValue === undefined) {
|
|
6195
7801
|
return {
|
|
6196
7802
|
v: {
|
|
6197
7803
|
status: "error",
|
|
6198
|
-
message: "Invalid path: union source ".concat(resolvedSchema, " did not have required key ").concat(_key2, " in path: ").concat(path)
|
|
7804
|
+
message: "Invalid path: discriminated union source ".concat(resolvedSchema, " did not have required key ").concat(_key2, " in path: ").concat(path)
|
|
6199
7805
|
}
|
|
6200
7806
|
};
|
|
6201
7807
|
}
|
|
@@ -6210,7 +7816,7 @@ function safeResolvePath(path, valModule, schema) {
|
|
|
6210
7816
|
return {
|
|
6211
7817
|
v: {
|
|
6212
7818
|
status: "error",
|
|
6213
|
-
message: "Invalid path: union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key2, " of value ").concat(keyValue, " in path: ").concat(path)
|
|
7819
|
+
message: "Invalid path: discriminated union schema ".concat(resolvedSchema, " did not have a child object with ").concat(_key2, " of value ").concat(keyValue, " in path: ").concat(path)
|
|
6214
7820
|
}
|
|
6215
7821
|
};
|
|
6216
7822
|
}
|
|
@@ -6347,12 +7953,48 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6347
7953
|
_this.previewInput = previewInput;
|
|
6348
7954
|
return _this;
|
|
6349
7955
|
}
|
|
7956
|
+
|
|
7957
|
+
/**
|
|
7958
|
+
* Describe this field.
|
|
7959
|
+
*
|
|
7960
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
7961
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
7962
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
7963
|
+
* assistant and the MCP tools read.
|
|
7964
|
+
*
|
|
7965
|
+
* Pass `null` to clear a description set earlier.
|
|
7966
|
+
*
|
|
7967
|
+
* @example
|
|
7968
|
+
* const schema = s.number().describe("How many columns the grid uses");
|
|
7969
|
+
* export default c.define("/example.val.ts", schema, 3);
|
|
7970
|
+
*/
|
|
6350
7971
|
_inherits(NumberSchema, _Schema);
|
|
6351
7972
|
return _createClass(NumberSchema, [{
|
|
6352
7973
|
key: "describe",
|
|
6353
7974
|
value: function describe(description) {
|
|
6354
7975
|
return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
6355
7976
|
}
|
|
7977
|
+
|
|
7978
|
+
/**
|
|
7979
|
+
* Add a custom validation rule to this field.
|
|
7980
|
+
*
|
|
7981
|
+
* The function is called with the field's value and returns `false` when the
|
|
7982
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
7983
|
+
* more than once to add more rules — they all run, and every message is
|
|
7984
|
+
* reported.
|
|
7985
|
+
*
|
|
7986
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
7987
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
7988
|
+
*
|
|
7989
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
7990
|
+
* before a publish.
|
|
7991
|
+
*
|
|
7992
|
+
* @example
|
|
7993
|
+
* const schema = s.number().validate((val) =>
|
|
7994
|
+
* Number.isInteger(val) ? false : "Must be a whole number",
|
|
7995
|
+
* );
|
|
7996
|
+
* export default c.define("/example.val.ts", schema, 3);
|
|
7997
|
+
*/
|
|
6356
7998
|
}, {
|
|
6357
7999
|
key: "validate",
|
|
6358
8000
|
value: function validate(validationFunction) {
|
|
@@ -6396,63 +8038,348 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6396
8038
|
value: function executeAssert(path, src) {
|
|
6397
8039
|
if (this.opt && src === null) {
|
|
6398
8040
|
return {
|
|
6399
|
-
success: true,
|
|
6400
|
-
data: src
|
|
8041
|
+
success: true,
|
|
8042
|
+
data: src
|
|
8043
|
+
};
|
|
8044
|
+
}
|
|
8045
|
+
if (src === null) {
|
|
8046
|
+
return {
|
|
8047
|
+
success: false,
|
|
8048
|
+
errors: _defineProperty({}, path, [{
|
|
8049
|
+
message: "Expected 'number', got 'null'",
|
|
8050
|
+
typeError: true
|
|
8051
|
+
}])
|
|
8052
|
+
};
|
|
8053
|
+
}
|
|
8054
|
+
if (typeof src === "number") {
|
|
8055
|
+
return {
|
|
8056
|
+
success: true,
|
|
8057
|
+
data: src
|
|
8058
|
+
};
|
|
8059
|
+
}
|
|
8060
|
+
return {
|
|
8061
|
+
success: false,
|
|
8062
|
+
errors: _defineProperty({}, path, [{
|
|
8063
|
+
message: "Expected 'number', got '".concat(_typeof(src), "'"),
|
|
8064
|
+
typeError: true
|
|
8065
|
+
}])
|
|
8066
|
+
};
|
|
8067
|
+
}
|
|
8068
|
+
}, {
|
|
8069
|
+
key: "nullable",
|
|
8070
|
+
value: function nullable() {
|
|
8071
|
+
return new NumberSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8072
|
+
}
|
|
8073
|
+
}, {
|
|
8074
|
+
key: "readonly",
|
|
8075
|
+
value: function readonly() {
|
|
8076
|
+
var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
8077
|
+
return new NumberSchema(this.options, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8078
|
+
}
|
|
8079
|
+
}, {
|
|
8080
|
+
key: "hidden",
|
|
8081
|
+
value: function hidden() {
|
|
8082
|
+
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
8083
|
+
return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
|
|
8084
|
+
}
|
|
8085
|
+
|
|
8086
|
+
/**
|
|
8087
|
+
* Validate that the number is at most `max` (inclusive).
|
|
8088
|
+
*
|
|
8089
|
+
* @example
|
|
8090
|
+
* const schema = s.number().max(4);
|
|
8091
|
+
* export default c.define("/example.val.ts", schema, 3);
|
|
8092
|
+
*/
|
|
8093
|
+
}, {
|
|
8094
|
+
key: "max",
|
|
8095
|
+
value: function max(_max) {
|
|
8096
|
+
return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
|
|
8097
|
+
max: _max
|
|
8098
|
+
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8099
|
+
}
|
|
8100
|
+
|
|
8101
|
+
/**
|
|
8102
|
+
* Validate that the number is at least `min` (inclusive).
|
|
8103
|
+
*
|
|
8104
|
+
* @example
|
|
8105
|
+
* const schema = s.number().min(1).max(4);
|
|
8106
|
+
* export default c.define("/example.val.ts", schema, 3);
|
|
8107
|
+
*/
|
|
8108
|
+
}, {
|
|
8109
|
+
key: "min",
|
|
8110
|
+
value: function min(_min) {
|
|
8111
|
+
return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
|
|
8112
|
+
min: _min
|
|
8113
|
+
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8114
|
+
}
|
|
8115
|
+
}, {
|
|
8116
|
+
key: "executeCustomValidateAt",
|
|
8117
|
+
value: function executeCustomValidateAt(path, src) {
|
|
8118
|
+
return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
8119
|
+
path: path
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
8122
|
+
|
|
8123
|
+
/**
|
|
8124
|
+
* How this field is laid out in the editor when it is the item of an array
|
|
8125
|
+
* or record: `{ as: "inline" }` renders the field itself inside each row,
|
|
8126
|
+
* instead of a preview row that navigates to it.
|
|
8127
|
+
*
|
|
8128
|
+
* Static configuration, not a callback — see `render.ts`.
|
|
8129
|
+
*
|
|
8130
|
+
* @example
|
|
8131
|
+
* const schema = s.array(s.number().render({ as: "inline" }));
|
|
8132
|
+
* export default c.define("/example.val.ts", schema, [1, 2]);
|
|
8133
|
+
*/
|
|
8134
|
+
}, {
|
|
8135
|
+
key: "render",
|
|
8136
|
+
value: function render(input) {
|
|
8137
|
+
return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
|
|
8138
|
+
}
|
|
8139
|
+
|
|
8140
|
+
/**
|
|
8141
|
+
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
8142
|
+
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
8143
|
+
* itself is edited (that is `render`). See `preview.ts`.
|
|
8144
|
+
*
|
|
8145
|
+
* @example
|
|
8146
|
+
* const schema = s.array(
|
|
8147
|
+
* s.number().preview(({ val }) => ({ title: String(val) })),
|
|
8148
|
+
* );
|
|
8149
|
+
* export default c.define("/example.val.ts", schema, [1, 2]);
|
|
8150
|
+
*/
|
|
8151
|
+
}, {
|
|
8152
|
+
key: "preview",
|
|
8153
|
+
value: function preview(select) {
|
|
8154
|
+
return new NumberSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
|
|
8155
|
+
}
|
|
8156
|
+
}, {
|
|
8157
|
+
key: "executePreviewItem",
|
|
8158
|
+
value: function executePreviewItem(src) {
|
|
8159
|
+
if (this.previewInput === null) {
|
|
8160
|
+
return null;
|
|
8161
|
+
}
|
|
8162
|
+
return this.previewInput({
|
|
8163
|
+
val: src
|
|
8164
|
+
});
|
|
8165
|
+
}
|
|
8166
|
+
}, {
|
|
8167
|
+
key: "declaresItemPreview",
|
|
8168
|
+
value: function declaresItemPreview() {
|
|
8169
|
+
return this.previewInput !== null;
|
|
8170
|
+
}
|
|
8171
|
+
}, {
|
|
8172
|
+
key: "executeSerialize",
|
|
8173
|
+
value: function executeSerialize() {
|
|
8174
|
+
var _this$renderInput, _this$customValidateF;
|
|
8175
|
+
return {
|
|
8176
|
+
type: "number",
|
|
8177
|
+
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
8178
|
+
preview: this.previewInput ? true : undefined,
|
|
8179
|
+
options: this.options,
|
|
8180
|
+
opt: this.opt,
|
|
8181
|
+
customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
|
|
8182
|
+
readonly: this.isReadonly,
|
|
8183
|
+
hidden: this.isHidden,
|
|
8184
|
+
description: this.description
|
|
8185
|
+
};
|
|
8186
|
+
}
|
|
8187
|
+
}, {
|
|
8188
|
+
key: "executePreview",
|
|
8189
|
+
value: function executePreview() {
|
|
8190
|
+
return {};
|
|
8191
|
+
}
|
|
8192
|
+
}]);
|
|
8193
|
+
}(Schema);
|
|
8194
|
+
var number = function number(options) {
|
|
8195
|
+
return new NumberSchema(options);
|
|
8196
|
+
};
|
|
8197
|
+
|
|
8198
|
+
/**
|
|
8199
|
+
* One of a fixed set of strings.
|
|
8200
|
+
*
|
|
8201
|
+
* The values are the schema — there are no member schemas to descend into, so
|
|
8202
|
+
* this is a LEAF, like `s.string()` with a closed domain. That is the whole
|
|
8203
|
+
* difference from {@link DiscriminatedUnionSchema}, and the reason the two are
|
|
8204
|
+
* separate: everything that walks a schema tree has to recurse into a
|
|
8205
|
+
* discriminated union's variants and must not try to recurse into these.
|
|
8206
|
+
*/
|
|
8207
|
+
var EnumSchema = /*#__PURE__*/function (_Schema) {
|
|
8208
|
+
/**
|
|
8209
|
+
* Type-only marker: as a record key, this declares the key set.
|
|
8210
|
+
*
|
|
8211
|
+
* An enum names every value it may take, so a record keyed by one holds
|
|
8212
|
+
* exactly those keys — the same claim `s.literal()` and `s.locale()` make.
|
|
8213
|
+
* `DiscriminatedUnionSchema` carries no marker: it discriminates objects and
|
|
8214
|
+
* cannot be a record key at all. See `LocaleSchema`.
|
|
8215
|
+
*/
|
|
8216
|
+
|
|
8217
|
+
function EnumSchema(values) {
|
|
8218
|
+
var _this;
|
|
8219
|
+
var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
8220
|
+
var customValidateFunctions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
|
8221
|
+
var isReadonly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
8222
|
+
var isHidden = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
8223
|
+
var description = arguments.length > 5 ? arguments[5] : undefined;
|
|
8224
|
+
var renderInput = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
|
|
8225
|
+
var previewInput = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
|
|
8226
|
+
_classCallCheck(this, EnumSchema);
|
|
8227
|
+
_this = _callSuper(this, EnumSchema);
|
|
8228
|
+
_this.values = values;
|
|
8229
|
+
_this.opt = opt;
|
|
8230
|
+
_this.customValidateFunctions = customValidateFunctions;
|
|
8231
|
+
_this.isReadonly = isReadonly;
|
|
8232
|
+
_this.isHidden = isHidden;
|
|
8233
|
+
_this.description = description;
|
|
8234
|
+
_this.renderInput = renderInput;
|
|
8235
|
+
_this.previewInput = previewInput;
|
|
8236
|
+
return _this;
|
|
8237
|
+
}
|
|
8238
|
+
|
|
8239
|
+
/**
|
|
8240
|
+
* Describe this field.
|
|
8241
|
+
*
|
|
8242
|
+
* The description is shown next to the field's label in the Val editor, so it is
|
|
8243
|
+
* where you say what an editor needs to know but the field name cannot carry. It
|
|
8244
|
+
* also travels in the serialized schema, which is what the AI assistant and the
|
|
8245
|
+
* MCP tools read.
|
|
8246
|
+
*
|
|
8247
|
+
* Pass `null` to clear a description set earlier.
|
|
8248
|
+
*
|
|
8249
|
+
* @example
|
|
8250
|
+
* const schema = s
|
|
8251
|
+
* .enum("draft", "published")
|
|
8252
|
+
* .describe("Only published pages are built");
|
|
8253
|
+
* export default c.define("/example.val.ts", schema, "draft");
|
|
8254
|
+
*/
|
|
8255
|
+
_inherits(EnumSchema, _Schema);
|
|
8256
|
+
return _createClass(EnumSchema, [{
|
|
8257
|
+
key: "describe",
|
|
8258
|
+
value: function describe(description) {
|
|
8259
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
8260
|
+
}
|
|
8261
|
+
|
|
8262
|
+
/**
|
|
8263
|
+
* Add a custom validation rule to this field.
|
|
8264
|
+
*
|
|
8265
|
+
* The function is called with the field's value and returns `false` when the
|
|
8266
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
8267
|
+
* more than once to add more rules — they all run, and every message is
|
|
8268
|
+
* reported.
|
|
8269
|
+
*
|
|
8270
|
+
* Validation runs in the Studio as you type, in `npx val validate` and before a
|
|
8271
|
+
* publish.
|
|
8272
|
+
*
|
|
8273
|
+
* @example
|
|
8274
|
+
* const schema = s
|
|
8275
|
+
* .enum("draft", "published")
|
|
8276
|
+
* .validate((val) =>
|
|
8277
|
+
* val === "published" ? "Publishing is frozen this week" : false,
|
|
8278
|
+
* );
|
|
8279
|
+
* export default c.define("/example.val.ts", schema, "draft");
|
|
8280
|
+
*/
|
|
8281
|
+
}, {
|
|
8282
|
+
key: "validate",
|
|
8283
|
+
value: function validate(validationFunction) {
|
|
8284
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions.concat(validationFunction), this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8285
|
+
}
|
|
8286
|
+
}, {
|
|
8287
|
+
key: "executeValidate",
|
|
8288
|
+
value: function executeValidate(path, src) {
|
|
8289
|
+
var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
|
|
8290
|
+
path: path
|
|
8291
|
+
});
|
|
8292
|
+
// The custom validators always report, whatever the structural answer is.
|
|
8293
|
+
var errors = customValidationErrors;
|
|
8294
|
+
var unknownSrc = src;
|
|
8295
|
+
if (this.opt && (unknownSrc === null || unknownSrc === undefined)) {
|
|
8296
|
+
return errors.length > 0 ? _defineProperty({}, path, errors) : false;
|
|
8297
|
+
}
|
|
8298
|
+
if (!Array.isArray(this.values) || this.values.length === 0) {
|
|
8299
|
+
errors.push({
|
|
8300
|
+
message: "An enum schema must have at least one value",
|
|
8301
|
+
schemaError: true
|
|
8302
|
+
});
|
|
8303
|
+
} else if (typeof unknownSrc !== "string") {
|
|
8304
|
+
errors.push({
|
|
8305
|
+
message: "Expected 'string', got '".concat(unknownSrc === null ? "null" : _typeof(unknownSrc), "'"),
|
|
8306
|
+
value: src,
|
|
8307
|
+
typeError: true
|
|
8308
|
+
});
|
|
8309
|
+
} else if (!this.values.includes(unknownSrc)) {
|
|
8310
|
+
errors.push({
|
|
8311
|
+
message: "Value must be one of the following: ".concat(this.values.map(function (value) {
|
|
8312
|
+
return "\"".concat(value, "\"");
|
|
8313
|
+
}).join(", ")),
|
|
8314
|
+
value: src
|
|
8315
|
+
});
|
|
8316
|
+
}
|
|
8317
|
+
return errors.length > 0 ? _defineProperty({}, path, errors) : false;
|
|
8318
|
+
}
|
|
8319
|
+
}, {
|
|
8320
|
+
key: "executeAssert",
|
|
8321
|
+
value: function executeAssert(path, src) {
|
|
8322
|
+
if (this.opt && src === null) {
|
|
8323
|
+
return {
|
|
8324
|
+
success: true,
|
|
8325
|
+
data: src
|
|
8326
|
+
};
|
|
8327
|
+
}
|
|
8328
|
+
var errors = {};
|
|
8329
|
+
if (typeof src !== "string") {
|
|
8330
|
+
errors[path] = [{
|
|
8331
|
+
message: "Expected 'string', got '".concat(src === null ? "null" : _typeof(src), "'"),
|
|
8332
|
+
typeError: true
|
|
8333
|
+
}];
|
|
8334
|
+
return {
|
|
8335
|
+
success: false,
|
|
8336
|
+
errors: errors
|
|
6401
8337
|
};
|
|
6402
8338
|
}
|
|
6403
|
-
if (
|
|
8339
|
+
if (!Array.isArray(this.values) || this.values.length === 0) {
|
|
8340
|
+
errors[path] = [{
|
|
8341
|
+
message: "An enum schema must have at least one value",
|
|
8342
|
+
schemaError: true
|
|
8343
|
+
}];
|
|
6404
8344
|
return {
|
|
6405
8345
|
success: false,
|
|
6406
|
-
errors:
|
|
6407
|
-
message: "Expected 'number', got 'null'",
|
|
6408
|
-
typeError: true
|
|
6409
|
-
}])
|
|
8346
|
+
errors: errors
|
|
6410
8347
|
};
|
|
6411
8348
|
}
|
|
6412
|
-
if (
|
|
8349
|
+
if (!this.values.includes(src)) {
|
|
8350
|
+
errors[path] = [{
|
|
8351
|
+
message: "Expected one of ".concat(this.values.map(function (value) {
|
|
8352
|
+
return "'".concat(value, "'");
|
|
8353
|
+
}).join(", "), ", got '").concat(src, "'"),
|
|
8354
|
+
typeError: true
|
|
8355
|
+
}];
|
|
6413
8356
|
return {
|
|
6414
|
-
success:
|
|
6415
|
-
|
|
8357
|
+
success: false,
|
|
8358
|
+
errors: errors
|
|
6416
8359
|
};
|
|
6417
8360
|
}
|
|
6418
8361
|
return {
|
|
6419
|
-
success:
|
|
6420
|
-
|
|
6421
|
-
message: "Expected 'number', got '".concat(_typeof(src), "'"),
|
|
6422
|
-
typeError: true
|
|
6423
|
-
}])
|
|
8362
|
+
success: true,
|
|
8363
|
+
data: src
|
|
6424
8364
|
};
|
|
6425
8365
|
}
|
|
6426
8366
|
}, {
|
|
6427
8367
|
key: "nullable",
|
|
6428
8368
|
value: function nullable() {
|
|
6429
|
-
|
|
8369
|
+
// Explicit type args: `previewInput` would otherwise pin inference to `Src`.
|
|
8370
|
+
return new EnumSchema(this.values, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6430
8371
|
}
|
|
6431
8372
|
}, {
|
|
6432
8373
|
key: "readonly",
|
|
6433
8374
|
value: function readonly() {
|
|
6434
8375
|
var isReadonly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
6435
|
-
return new
|
|
8376
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions, isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6436
8377
|
}
|
|
6437
8378
|
}, {
|
|
6438
8379
|
key: "hidden",
|
|
6439
8380
|
value: function hidden() {
|
|
6440
8381
|
var isHidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
6441
|
-
return new
|
|
6442
|
-
}
|
|
6443
|
-
}, {
|
|
6444
|
-
key: "max",
|
|
6445
|
-
value: function max(_max) {
|
|
6446
|
-
return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
|
|
6447
|
-
max: _max
|
|
6448
|
-
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6449
|
-
}
|
|
6450
|
-
}, {
|
|
6451
|
-
key: "min",
|
|
6452
|
-
value: function min(_min) {
|
|
6453
|
-
return new NumberSchema(_objectSpread2(_objectSpread2({}, this.options), {}, {
|
|
6454
|
-
min: _min
|
|
6455
|
-
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8382
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, isHidden, this.description, this.renderInput, this.previewInput);
|
|
6456
8383
|
}
|
|
6457
8384
|
}, {
|
|
6458
8385
|
key: "executeCustomValidateAt",
|
|
@@ -6468,22 +8395,34 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6468
8395
|
* instead of a preview row that navigates to it.
|
|
6469
8396
|
*
|
|
6470
8397
|
* Static configuration, not a callback — see `render.ts`.
|
|
8398
|
+
*
|
|
8399
|
+
* @example
|
|
8400
|
+
* const schema = s.array(
|
|
8401
|
+
* s.enum("draft", "published").render({ as: "inline" }),
|
|
8402
|
+
* );
|
|
8403
|
+
* export default c.define("/example.val.ts", schema, ["draft"]);
|
|
6471
8404
|
*/
|
|
6472
8405
|
}, {
|
|
6473
8406
|
key: "render",
|
|
6474
8407
|
value: function render(input) {
|
|
6475
|
-
return new
|
|
8408
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, input, this.previewInput);
|
|
6476
8409
|
}
|
|
6477
8410
|
|
|
6478
8411
|
/**
|
|
6479
8412
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
6480
8413
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
6481
8414
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
8415
|
+
*
|
|
8416
|
+
* @example
|
|
8417
|
+
* const schema = s.array(
|
|
8418
|
+
* s.enum("draft", "published").preview(({ val }) => ({ title: val })),
|
|
8419
|
+
* );
|
|
8420
|
+
* export default c.define("/example.val.ts", schema, ["draft"]);
|
|
6482
8421
|
*/
|
|
6483
8422
|
}, {
|
|
6484
8423
|
key: "preview",
|
|
6485
8424
|
value: function preview(select) {
|
|
6486
|
-
return new
|
|
8425
|
+
return new EnumSchema(this.values, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, select);
|
|
6487
8426
|
}
|
|
6488
8427
|
}, {
|
|
6489
8428
|
key: "executePreviewItem",
|
|
@@ -6505,10 +8444,10 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6505
8444
|
value: function executeSerialize() {
|
|
6506
8445
|
var _this$renderInput, _this$customValidateF;
|
|
6507
8446
|
return {
|
|
6508
|
-
type: "
|
|
8447
|
+
type: "enum",
|
|
6509
8448
|
render: (_this$renderInput = this.renderInput) !== null && _this$renderInput !== void 0 ? _this$renderInput : undefined,
|
|
6510
8449
|
preview: this.previewInput ? true : undefined,
|
|
6511
|
-
|
|
8450
|
+
values: _toConsumableArray(this.values),
|
|
6512
8451
|
opt: this.opt,
|
|
6513
8452
|
customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
|
|
6514
8453
|
readonly: this.isReadonly,
|
|
@@ -6519,14 +8458,104 @@ var NumberSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6519
8458
|
}, {
|
|
6520
8459
|
key: "executePreview",
|
|
6521
8460
|
value: function executePreview() {
|
|
8461
|
+
// A leaf: nothing below it to preview.
|
|
6522
8462
|
return {};
|
|
6523
8463
|
}
|
|
6524
8464
|
}]);
|
|
6525
8465
|
}(Schema);
|
|
6526
|
-
|
|
6527
|
-
|
|
8466
|
+
|
|
8467
|
+
/**
|
|
8468
|
+
* Define a string that must be one of a fixed set of values.
|
|
8469
|
+
*
|
|
8470
|
+
* Named `enumSchema` rather than `enum` because `enum` is a reserved word and
|
|
8471
|
+
* cannot be a binding name; it is exposed as `s.enum`.
|
|
8472
|
+
*/
|
|
8473
|
+
var enumSchema = function enumSchema() {
|
|
8474
|
+
for (var _len = arguments.length, values = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
8475
|
+
values[_key] = arguments[_key];
|
|
8476
|
+
}
|
|
8477
|
+
return new EnumSchema(values);
|
|
6528
8478
|
};
|
|
6529
8479
|
|
|
8480
|
+
/**
|
|
8481
|
+
* @deprecated Use {@link SerializedDiscriminatedUnionSchema} or
|
|
8482
|
+
* {@link SerializedEnumSchema}. A serialized union is now one or the other,
|
|
8483
|
+
* distinguished by `type` rather than by the shape of `key`.
|
|
8484
|
+
*/
|
|
8485
|
+
|
|
8486
|
+
/** @deprecated Use {@link SerializedEnumSchema}. */
|
|
8487
|
+
|
|
8488
|
+
/** @deprecated Use {@link SerializedDiscriminatedUnionSchema}. */
|
|
8489
|
+
|
|
8490
|
+
/**
|
|
8491
|
+
* @deprecated There is no single union schema class any more: name
|
|
8492
|
+
* {@link DiscriminatedUnionSchema} or {@link EnumSchema}. The type parameters
|
|
8493
|
+
* are kept so existing annotations still compile, but only `Src` is used.
|
|
8494
|
+
*/
|
|
8495
|
+
|
|
8496
|
+
/**
|
|
8497
|
+
* The value type of a list of literal schemas — how `s.union` typed a union of
|
|
8498
|
+
* literals. Inferred from `Schema<infer S>` rather than `LiteralSchema<infer S>`
|
|
8499
|
+
* because a `LiteralSchema` is invariant in its source (its custom validate
|
|
8500
|
+
* functions put it in a parameter position), so `LiteralSchema<"a">` is not
|
|
8501
|
+
* assignable to `LiteralSchema<"a" | "b">`.
|
|
8502
|
+
*/
|
|
8503
|
+
|
|
8504
|
+
/**
|
|
8505
|
+
* @deprecated Use `s.discriminatedUnion(key, ...objects)` for a tagged union of
|
|
8506
|
+
* objects, or `s.enum("a", "b")` for one of a fixed set of strings.
|
|
8507
|
+
*
|
|
8508
|
+
* One thing does NOT survive the literal form: an enum's values are strings,
|
|
8509
|
+
* so a member literal's own `.validate()` and `.describe()` are dropped rather
|
|
8510
|
+
* than carried over. `s.union(s.literal("a").validate(...), ...)` ran that
|
|
8511
|
+
* validator as part of deciding whether the value matched; `s.enum` has no
|
|
8512
|
+
* member to run. A validator on a single-valued literal could only accept or
|
|
8513
|
+
* reject that one value, which the enum's own value list already decides — but
|
|
8514
|
+
* if you rely on one, keep it by validating the enum itself.
|
|
8515
|
+
*
|
|
8516
|
+
* @example
|
|
8517
|
+
* // was: s.union("type", s.object({ type: s.literal("a"), a: s.string() }))
|
|
8518
|
+
* const schema = s.discriminatedUnion(
|
|
8519
|
+
* "type",
|
|
8520
|
+
* s.object({ type: s.literal("a"), a: s.string() }),
|
|
8521
|
+
* );
|
|
8522
|
+
* export default c.define("/example.val.ts", schema, { type: "a", a: "one" });
|
|
8523
|
+
*
|
|
8524
|
+
* @example
|
|
8525
|
+
* // was: s.union(s.literal("a"), s.literal("b"))
|
|
8526
|
+
* const schema = s.enum("a", "b");
|
|
8527
|
+
* export default c.define("/example.val.ts", schema, "a");
|
|
8528
|
+
*/
|
|
8529
|
+
|
|
8530
|
+
function union(keyOrFirstLiteral) {
|
|
8531
|
+
for (var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
8532
|
+
rest[_key - 1] = arguments[_key];
|
|
8533
|
+
}
|
|
8534
|
+
if (typeof keyOrFirstLiteral === "string") {
|
|
8535
|
+
return new DiscriminatedUnionSchema(keyOrFirstLiteral, rest);
|
|
8536
|
+
}
|
|
8537
|
+
// A literal union is an enum: the values ARE the schema, so the literals are
|
|
8538
|
+
// flattened into them. `key` was only ever the first member.
|
|
8539
|
+
var literals = [keyOrFirstLiteral].concat(rest);
|
|
8540
|
+
var values = [];
|
|
8541
|
+
var _iterator = _createForOfIteratorHelper(literals),
|
|
8542
|
+
_step;
|
|
8543
|
+
try {
|
|
8544
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
8545
|
+
var literal = _step.value;
|
|
8546
|
+
if (!(literal instanceof LiteralSchema)) {
|
|
8547
|
+
throw new Error("s.union: expected either a string key followed by object schemas, or literal schemas. Got: ".concat(JSON.stringify(literal)));
|
|
8548
|
+
}
|
|
8549
|
+
values.push(literal["value"]);
|
|
8550
|
+
}
|
|
8551
|
+
} catch (err) {
|
|
8552
|
+
_iterator.e(err);
|
|
8553
|
+
} finally {
|
|
8554
|
+
_iterator.f();
|
|
8555
|
+
}
|
|
8556
|
+
return new EnumSchema(values);
|
|
8557
|
+
}
|
|
8558
|
+
|
|
6530
8559
|
var KeyOfSchema = /*#__PURE__*/function (_Schema) {
|
|
6531
8560
|
function KeyOfSchema(schema, sourcePath) {
|
|
6532
8561
|
var _this;
|
|
@@ -6550,12 +8579,52 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6550
8579
|
_this.previewInput = previewInput;
|
|
6551
8580
|
return _this;
|
|
6552
8581
|
}
|
|
8582
|
+
|
|
8583
|
+
/**
|
|
8584
|
+
* Describe this field.
|
|
8585
|
+
*
|
|
8586
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
8587
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
8588
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
8589
|
+
* assistant and the MCP tools read.
|
|
8590
|
+
*
|
|
8591
|
+
* Pass `null` to clear a description set earlier.
|
|
8592
|
+
*
|
|
8593
|
+
* @example
|
|
8594
|
+
* import authorsVal from "./authors.val"; // a record module
|
|
8595
|
+
* const schema = s.keyOf(authorsVal).describe("Who wrote this post");
|
|
8596
|
+
* export default c.define("/example.val.ts", schema, "ada");
|
|
8597
|
+
*/
|
|
6553
8598
|
_inherits(KeyOfSchema, _Schema);
|
|
6554
8599
|
return _createClass(KeyOfSchema, [{
|
|
6555
8600
|
key: "describe",
|
|
6556
8601
|
value: function describe(description) {
|
|
6557
8602
|
return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
6558
8603
|
}
|
|
8604
|
+
|
|
8605
|
+
/**
|
|
8606
|
+
* Add a custom validation rule to this field.
|
|
8607
|
+
*
|
|
8608
|
+
* The function is called with the field's value and returns `false` when the
|
|
8609
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
8610
|
+
* more than once to add more rules — they all run, and every message is
|
|
8611
|
+
* reported.
|
|
8612
|
+
*
|
|
8613
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
8614
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
8615
|
+
*
|
|
8616
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
8617
|
+
* before a publish.
|
|
8618
|
+
*
|
|
8619
|
+
* @example
|
|
8620
|
+
* import authorsVal from "./authors.val"; // a record module
|
|
8621
|
+
* const schema = s
|
|
8622
|
+
* .keyOf(authorsVal)
|
|
8623
|
+
* .validate((val) =>
|
|
8624
|
+
* val === "placeholder" ? "Pick a real author" : false,
|
|
8625
|
+
* );
|
|
8626
|
+
* export default c.define("/example.val.ts", schema, "ada");
|
|
8627
|
+
*/
|
|
6559
8628
|
}, {
|
|
6560
8629
|
key: "validate",
|
|
6561
8630
|
value: function validate(validationFunction) {
|
|
@@ -6689,7 +8758,7 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6689
8758
|
}, {
|
|
6690
8759
|
key: "nullable",
|
|
6691
8760
|
value: function nullable() {
|
|
6692
|
-
return new KeyOfSchema(this.schema, this.sourcePath, true,
|
|
8761
|
+
return new KeyOfSchema(this.schema, this.sourcePath, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6693
8762
|
}
|
|
6694
8763
|
}, {
|
|
6695
8764
|
key: "readonly",
|
|
@@ -6717,6 +8786,11 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6717
8786
|
* instead of a preview row that navigates to it.
|
|
6718
8787
|
*
|
|
6719
8788
|
* Static configuration, not a callback — see `render.ts`.
|
|
8789
|
+
*
|
|
8790
|
+
* @example
|
|
8791
|
+
* import authorsVal from "./authors.val"; // a record module
|
|
8792
|
+
* const schema = s.array(s.keyOf(authorsVal).render({ as: "inline" }));
|
|
8793
|
+
* export default c.define("/example.val.ts", schema, ["ada"]);
|
|
6720
8794
|
*/
|
|
6721
8795
|
}, {
|
|
6722
8796
|
key: "render",
|
|
@@ -6728,6 +8802,13 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6728
8802
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
6729
8803
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
6730
8804
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
8805
|
+
*
|
|
8806
|
+
* @example
|
|
8807
|
+
* import authorsVal from "./authors.val"; // a record module
|
|
8808
|
+
* const schema = s.array(
|
|
8809
|
+
* s.keyOf(authorsVal).preview(({ val }) => ({ title: val })),
|
|
8810
|
+
* );
|
|
8811
|
+
* export default c.define("/example.val.ts", schema, ["ada"]);
|
|
6731
8812
|
*/
|
|
6732
8813
|
}, {
|
|
6733
8814
|
key: "preview",
|
|
@@ -6844,17 +8925,83 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
|
|
|
6844
8925
|
_this.previewInput = previewInput;
|
|
6845
8926
|
return _this;
|
|
6846
8927
|
}
|
|
8928
|
+
|
|
8929
|
+
/**
|
|
8930
|
+
* Describe this field.
|
|
8931
|
+
*
|
|
8932
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
8933
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
8934
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
8935
|
+
* assistant and the MCP tools read.
|
|
8936
|
+
*
|
|
8937
|
+
* Pass `null` to clear a description set earlier.
|
|
8938
|
+
*
|
|
8939
|
+
* @example
|
|
8940
|
+
* const schema = s.file().describe("The PDF offered for download");
|
|
8941
|
+
* export default c.define("/example.val.ts", schema, {
|
|
8942
|
+
* path: "/public/val/example.pdf",
|
|
8943
|
+
* mimeType: "application/pdf",
|
|
8944
|
+
* });
|
|
8945
|
+
*/
|
|
6847
8946
|
_inherits(FileSchema, _Schema);
|
|
6848
8947
|
return _createClass(FileSchema, [{
|
|
6849
8948
|
key: "describe",
|
|
6850
8949
|
value: function describe(description) {
|
|
6851
8950
|
return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
6852
8951
|
}
|
|
8952
|
+
|
|
8953
|
+
/**
|
|
8954
|
+
* Store the file on Val's remote content host instead of in your repository.
|
|
8955
|
+
*
|
|
8956
|
+
* The bytes still go into the patch store when the file is uploaded — the
|
|
8957
|
+
* push to the remote host happens at publish. What changes is where the
|
|
8958
|
+
* published file lives: `path` becomes a remote URL rather than a path under
|
|
8959
|
+
* `/public`, so the repository does not grow with every upload.
|
|
8960
|
+
*
|
|
8961
|
+
* The `path` of a remote file is a URL on the content host, and it is not
|
|
8962
|
+
* something to write by hand: upload the file in the Studio, or write a
|
|
8963
|
+
* local path and let `npx val validate --fix` upload it and rewrite the
|
|
8964
|
+
* `path` to the ref below.
|
|
8965
|
+
*
|
|
8966
|
+
* @example
|
|
8967
|
+
* const schema = s.file({ accept: "application/pdf" }).remote();
|
|
8968
|
+
* export default c.define("/example.val.ts", schema, {
|
|
8969
|
+
* path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/example.pdf",
|
|
8970
|
+
* mimeType: "application/pdf",
|
|
8971
|
+
* });
|
|
8972
|
+
*/
|
|
6853
8973
|
}, {
|
|
6854
8974
|
key: "remote",
|
|
6855
8975
|
value: function remote() {
|
|
6856
8976
|
return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
6857
8977
|
}
|
|
8978
|
+
|
|
8979
|
+
/**
|
|
8980
|
+
* Add a custom validation rule to this field.
|
|
8981
|
+
*
|
|
8982
|
+
* The function is called with the field's value and returns `false` when the
|
|
8983
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
8984
|
+
* more than once to add more rules — they all run, and every message is
|
|
8985
|
+
* reported.
|
|
8986
|
+
*
|
|
8987
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
8988
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
8989
|
+
*
|
|
8990
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
8991
|
+
* before a publish.
|
|
8992
|
+
*
|
|
8993
|
+
* The second argument carries the `path` of the field being validated, for
|
|
8994
|
+
* when the message needs to say where the problem is.
|
|
8995
|
+
*
|
|
8996
|
+
* @example
|
|
8997
|
+
* const schema = s.file().validate((val) =>
|
|
8998
|
+
* val.path.endsWith(".pdf") ? false : "Must be a PDF",
|
|
8999
|
+
* );
|
|
9000
|
+
* export default c.define("/example.val.ts", schema, {
|
|
9001
|
+
* path: "/public/val/example.pdf",
|
|
9002
|
+
* mimeType: "application/pdf",
|
|
9003
|
+
* });
|
|
9004
|
+
*/
|
|
6858
9005
|
}, {
|
|
6859
9006
|
key: "validate",
|
|
6860
9007
|
value: function validate(validationFunction) {
|
|
@@ -7061,6 +9208,12 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7061
9208
|
* instead of a preview row that navigates to it.
|
|
7062
9209
|
*
|
|
7063
9210
|
* Static configuration, not a callback — see `render.ts`.
|
|
9211
|
+
*
|
|
9212
|
+
* @example
|
|
9213
|
+
* const schema = s.array(s.file().render({ as: "inline" }));
|
|
9214
|
+
* export default c.define("/example.val.ts", schema, [
|
|
9215
|
+
* { path: "/public/val/example.pdf", mimeType: "application/pdf" },
|
|
9216
|
+
* ]);
|
|
7064
9217
|
*/
|
|
7065
9218
|
}, {
|
|
7066
9219
|
key: "render",
|
|
@@ -7072,6 +9225,14 @@ var FileSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7072
9225
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
7073
9226
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
7074
9227
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
9228
|
+
*
|
|
9229
|
+
* @example
|
|
9230
|
+
* const schema = s.array(
|
|
9231
|
+
* s.file().preview(({ val }) => ({ title: val.path })),
|
|
9232
|
+
* );
|
|
9233
|
+
* export default c.define("/example.val.ts", schema, [
|
|
9234
|
+
* { path: "/public/val/example.pdf", mimeType: "application/pdf" },
|
|
9235
|
+
* ]);
|
|
7075
9236
|
*/
|
|
7076
9237
|
}, {
|
|
7077
9238
|
key: "preview",
|
|
@@ -7205,12 +9366,48 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7205
9366
|
_this.previewInput = previewInput;
|
|
7206
9367
|
return _this;
|
|
7207
9368
|
}
|
|
9369
|
+
|
|
9370
|
+
/**
|
|
9371
|
+
* Describe this field.
|
|
9372
|
+
*
|
|
9373
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
9374
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
9375
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
9376
|
+
* assistant and the MCP tools read.
|
|
9377
|
+
*
|
|
9378
|
+
* Pass `null` to clear a description set earlier.
|
|
9379
|
+
*
|
|
9380
|
+
* @example
|
|
9381
|
+
* const schema = s.date().describe("First day the campaign is live");
|
|
9382
|
+
* export default c.define("/example.val.ts", schema, "2025-06-01");
|
|
9383
|
+
*/
|
|
7208
9384
|
_inherits(DateSchema, _Schema);
|
|
7209
9385
|
return _createClass(DateSchema, [{
|
|
7210
9386
|
key: "describe",
|
|
7211
9387
|
value: function describe(description) {
|
|
7212
9388
|
return new DateSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
7213
9389
|
}
|
|
9390
|
+
|
|
9391
|
+
/**
|
|
9392
|
+
* Add a custom validation rule to this field.
|
|
9393
|
+
*
|
|
9394
|
+
* The function is called with the field's value and returns `false` when the
|
|
9395
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
9396
|
+
* more than once to add more rules — they all run, and every message is
|
|
9397
|
+
* reported.
|
|
9398
|
+
*
|
|
9399
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
9400
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
9401
|
+
*
|
|
9402
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
9403
|
+
* before a publish.
|
|
9404
|
+
*
|
|
9405
|
+
* @example
|
|
9406
|
+
* const schema = s.date().validate((val) =>
|
|
9407
|
+
* val >= "2025-01-01" ? false : "Must be in 2025 or later",
|
|
9408
|
+
* );
|
|
9409
|
+
* export default c.define("/example.val.ts", schema, "2025-06-01");
|
|
9410
|
+
*/
|
|
7214
9411
|
}, {
|
|
7215
9412
|
key: "validate",
|
|
7216
9413
|
value: function validate(validationFunction) {
|
|
@@ -7298,6 +9495,16 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7298
9495
|
data: src
|
|
7299
9496
|
};
|
|
7300
9497
|
}
|
|
9498
|
+
|
|
9499
|
+
/**
|
|
9500
|
+
* Validate that the date is this date or after (inclusive).
|
|
9501
|
+
*
|
|
9502
|
+
* Written as `YYYY-MM-DD`, the same shape the value has.
|
|
9503
|
+
*
|
|
9504
|
+
* @example
|
|
9505
|
+
* const schema = s.date().from("2025-01-01");
|
|
9506
|
+
* export default c.define("/example.val.ts", schema, "2025-06-01");
|
|
9507
|
+
*/
|
|
7301
9508
|
}, {
|
|
7302
9509
|
key: "from",
|
|
7303
9510
|
value: function from(_from) {
|
|
@@ -7305,6 +9512,16 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7305
9512
|
from: _from
|
|
7306
9513
|
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
7307
9514
|
}
|
|
9515
|
+
|
|
9516
|
+
/**
|
|
9517
|
+
* Validate that the date is this date or before (inclusive).
|
|
9518
|
+
*
|
|
9519
|
+
* Written as `YYYY-MM-DD`, the same shape the value has.
|
|
9520
|
+
*
|
|
9521
|
+
* @example
|
|
9522
|
+
* const schema = s.date().from("2025-01-01").to("2025-12-31");
|
|
9523
|
+
* export default c.define("/example.val.ts", schema, "2025-06-01");
|
|
9524
|
+
*/
|
|
7308
9525
|
}, {
|
|
7309
9526
|
key: "to",
|
|
7310
9527
|
value: function to(_to) {
|
|
@@ -7315,7 +9532,7 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7315
9532
|
}, {
|
|
7316
9533
|
key: "nullable",
|
|
7317
9534
|
value: function nullable() {
|
|
7318
|
-
return new DateSchema(this.options, true,
|
|
9535
|
+
return new DateSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
7319
9536
|
}
|
|
7320
9537
|
}, {
|
|
7321
9538
|
key: "readonly",
|
|
@@ -7343,6 +9560,10 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7343
9560
|
* instead of a preview row that navigates to it.
|
|
7344
9561
|
*
|
|
7345
9562
|
* Static configuration, not a callback — see `render.ts`.
|
|
9563
|
+
*
|
|
9564
|
+
* @example
|
|
9565
|
+
* const schema = s.array(s.date().render({ as: "inline" }));
|
|
9566
|
+
* export default c.define("/example.val.ts", schema, ["2025-06-01"]);
|
|
7346
9567
|
*/
|
|
7347
9568
|
}, {
|
|
7348
9569
|
key: "render",
|
|
@@ -7354,6 +9575,12 @@ var DateSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7354
9575
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
7355
9576
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
7356
9577
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
9578
|
+
*
|
|
9579
|
+
* @example
|
|
9580
|
+
* const schema = s.array(
|
|
9581
|
+
* s.date().preview(({ val }) => ({ title: val })),
|
|
9582
|
+
* );
|
|
9583
|
+
* export default c.define("/example.val.ts", schema, ["2025-06-01"]);
|
|
7357
9584
|
*/
|
|
7358
9585
|
}, {
|
|
7359
9586
|
key: "preview",
|
|
@@ -7424,12 +9651,56 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7424
9651
|
_this.previewInput = previewInput;
|
|
7425
9652
|
return _this;
|
|
7426
9653
|
}
|
|
9654
|
+
|
|
9655
|
+
/**
|
|
9656
|
+
* Describe this field.
|
|
9657
|
+
*
|
|
9658
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
9659
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
9660
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
9661
|
+
* assistant and the MCP tools read.
|
|
9662
|
+
*
|
|
9663
|
+
* Pass `null` to clear a description set earlier.
|
|
9664
|
+
*
|
|
9665
|
+
* @example
|
|
9666
|
+
* const schema = s.datetime().describe("When the article goes live");
|
|
9667
|
+
* export default c.define(
|
|
9668
|
+
* "/example.val.ts",
|
|
9669
|
+
* schema,
|
|
9670
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9671
|
+
* );
|
|
9672
|
+
*/
|
|
7427
9673
|
_inherits(DateTimeSchema, _Schema);
|
|
7428
9674
|
return _createClass(DateTimeSchema, [{
|
|
7429
9675
|
key: "describe",
|
|
7430
9676
|
value: function describe(description) {
|
|
7431
9677
|
return new DateTimeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
7432
9678
|
}
|
|
9679
|
+
|
|
9680
|
+
/**
|
|
9681
|
+
* Add a custom validation rule to this field.
|
|
9682
|
+
*
|
|
9683
|
+
* The function is called with the field's value and returns `false` when the
|
|
9684
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
9685
|
+
* more than once to add more rules — they all run, and every message is
|
|
9686
|
+
* reported.
|
|
9687
|
+
*
|
|
9688
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
9689
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
9690
|
+
*
|
|
9691
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
9692
|
+
* before a publish.
|
|
9693
|
+
*
|
|
9694
|
+
* @example
|
|
9695
|
+
* const schema = s.datetime().validate((val) =>
|
|
9696
|
+
* val.endsWith("Z") ? false : "Must be in UTC",
|
|
9697
|
+
* );
|
|
9698
|
+
* export default c.define(
|
|
9699
|
+
* "/example.val.ts",
|
|
9700
|
+
* schema,
|
|
9701
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9702
|
+
* );
|
|
9703
|
+
*/
|
|
7433
9704
|
}, {
|
|
7434
9705
|
key: "validate",
|
|
7435
9706
|
value: function validate(validationFunction) {
|
|
@@ -7549,6 +9820,20 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7549
9820
|
data: src
|
|
7550
9821
|
};
|
|
7551
9822
|
}
|
|
9823
|
+
|
|
9824
|
+
/**
|
|
9825
|
+
* Validate that the datetime is this datetime or after (inclusive).
|
|
9826
|
+
*
|
|
9827
|
+
* Any ISO 8601 datetime string `Date.parse` understands.
|
|
9828
|
+
*
|
|
9829
|
+
* @example
|
|
9830
|
+
* const schema = s.datetime().from("2025-01-01T00:00:00Z");
|
|
9831
|
+
* export default c.define(
|
|
9832
|
+
* "/example.val.ts",
|
|
9833
|
+
* schema,
|
|
9834
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9835
|
+
* );
|
|
9836
|
+
*/
|
|
7552
9837
|
}, {
|
|
7553
9838
|
key: "from",
|
|
7554
9839
|
value: function from(_from) {
|
|
@@ -7556,6 +9841,23 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7556
9841
|
from: _from
|
|
7557
9842
|
}), this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
7558
9843
|
}
|
|
9844
|
+
|
|
9845
|
+
/**
|
|
9846
|
+
* Validate that the datetime is this datetime or before (inclusive).
|
|
9847
|
+
*
|
|
9848
|
+
* Any ISO 8601 datetime string `Date.parse` understands.
|
|
9849
|
+
*
|
|
9850
|
+
* @example
|
|
9851
|
+
* const schema = s
|
|
9852
|
+
* .datetime()
|
|
9853
|
+
* .from("2025-01-01T00:00:00Z")
|
|
9854
|
+
* .to("2025-12-31T23:59:59Z");
|
|
9855
|
+
* export default c.define(
|
|
9856
|
+
* "/example.val.ts",
|
|
9857
|
+
* schema,
|
|
9858
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9859
|
+
* );
|
|
9860
|
+
*/
|
|
7559
9861
|
}, {
|
|
7560
9862
|
key: "to",
|
|
7561
9863
|
value: function to(_to) {
|
|
@@ -7566,7 +9868,7 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7566
9868
|
}, {
|
|
7567
9869
|
key: "nullable",
|
|
7568
9870
|
value: function nullable() {
|
|
7569
|
-
return new DateTimeSchema(this.options, true,
|
|
9871
|
+
return new DateTimeSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
7570
9872
|
}
|
|
7571
9873
|
}, {
|
|
7572
9874
|
key: "readonly",
|
|
@@ -7594,6 +9896,12 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7594
9896
|
* instead of a preview row that navigates to it.
|
|
7595
9897
|
*
|
|
7596
9898
|
* Static configuration, not a callback — see `render.ts`.
|
|
9899
|
+
*
|
|
9900
|
+
* @example
|
|
9901
|
+
* const schema = s.array(s.datetime().render({ as: "inline" }));
|
|
9902
|
+
* export default c.define("/example.val.ts", schema, [
|
|
9903
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9904
|
+
* ]);
|
|
7597
9905
|
*/
|
|
7598
9906
|
}, {
|
|
7599
9907
|
key: "render",
|
|
@@ -7605,6 +9913,14 @@ var DateTimeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7605
9913
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
7606
9914
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
7607
9915
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
9916
|
+
*
|
|
9917
|
+
* @example
|
|
9918
|
+
* const schema = s.array(
|
|
9919
|
+
* s.datetime().preview(({ val }) => ({ title: val })),
|
|
9920
|
+
* );
|
|
9921
|
+
* export default c.define("/example.val.ts", schema, [
|
|
9922
|
+
* "2025-06-01T09:00:00.000Z",
|
|
9923
|
+
* ]);
|
|
7608
9924
|
*/
|
|
7609
9925
|
}, {
|
|
7610
9926
|
key: "preview",
|
|
@@ -7689,12 +10005,59 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7689
10005
|
_this.previewInput = previewInput;
|
|
7690
10006
|
return _this;
|
|
7691
10007
|
}
|
|
10008
|
+
|
|
10009
|
+
/**
|
|
10010
|
+
* Describe this field.
|
|
10011
|
+
*
|
|
10012
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
10013
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
10014
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
10015
|
+
* assistant and the MCP tools read.
|
|
10016
|
+
*
|
|
10017
|
+
* Pass `null` to clear a description set earlier.
|
|
10018
|
+
*
|
|
10019
|
+
* @example
|
|
10020
|
+
* const schema = s
|
|
10021
|
+
* .code({ language: "css" })
|
|
10022
|
+
* .describe("Injected into the page head — keep it small");
|
|
10023
|
+
* export default c.define(
|
|
10024
|
+
* "/example.val.ts",
|
|
10025
|
+
* schema,
|
|
10026
|
+
* ".hero { color: red; }",
|
|
10027
|
+
* );
|
|
10028
|
+
*/
|
|
7692
10029
|
_inherits(CodeSchema, _Schema);
|
|
7693
10030
|
return _createClass(CodeSchema, [{
|
|
7694
10031
|
key: "describe",
|
|
7695
10032
|
value: function describe(description) {
|
|
7696
10033
|
return new CodeSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
7697
10034
|
}
|
|
10035
|
+
|
|
10036
|
+
/**
|
|
10037
|
+
* Add a custom validation rule to this field.
|
|
10038
|
+
*
|
|
10039
|
+
* The function is called with the field's value and returns `false` when the
|
|
10040
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
10041
|
+
* more than once to add more rules — they all run, and every message is
|
|
10042
|
+
* reported.
|
|
10043
|
+
*
|
|
10044
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
10045
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
10046
|
+
*
|
|
10047
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
10048
|
+
* before a publish.
|
|
10049
|
+
*
|
|
10050
|
+
* @example
|
|
10051
|
+
* const schema = s.code({ language: "json" }).validate((val) => {
|
|
10052
|
+
* try {
|
|
10053
|
+
* JSON.parse(val);
|
|
10054
|
+
* return false;
|
|
10055
|
+
* } catch {
|
|
10056
|
+
* return "Must be valid JSON";
|
|
10057
|
+
* }
|
|
10058
|
+
* });
|
|
10059
|
+
* export default c.define("/example.val.ts", schema, '{ "a": 1 }');
|
|
10060
|
+
*/
|
|
7698
10061
|
}, {
|
|
7699
10062
|
key: "validate",
|
|
7700
10063
|
value: function validate(validationFunction) {
|
|
@@ -7753,7 +10116,7 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7753
10116
|
}, {
|
|
7754
10117
|
key: "nullable",
|
|
7755
10118
|
value: function nullable() {
|
|
7756
|
-
return new CodeSchema(this.options, true,
|
|
10119
|
+
return new CodeSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
7757
10120
|
}
|
|
7758
10121
|
}, {
|
|
7759
10122
|
key: "readonly",
|
|
@@ -7774,6 +10137,14 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7774
10137
|
* instead of a preview row that navigates to it.
|
|
7775
10138
|
*
|
|
7776
10139
|
* Static configuration, not a callback — see `render.ts`.
|
|
10140
|
+
*
|
|
10141
|
+
* @example
|
|
10142
|
+
* const schema = s.array(
|
|
10143
|
+
* s.code({ language: "css" }).render({ as: "inline" }),
|
|
10144
|
+
* );
|
|
10145
|
+
* export default c.define("/example.val.ts", schema, [
|
|
10146
|
+
* ".hero { color: red; }",
|
|
10147
|
+
* ]);
|
|
7777
10148
|
*/
|
|
7778
10149
|
}, {
|
|
7779
10150
|
key: "render",
|
|
@@ -7785,6 +10156,16 @@ var CodeSchema = /*#__PURE__*/function (_Schema) {
|
|
|
7785
10156
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
7786
10157
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
7787
10158
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
10159
|
+
*
|
|
10160
|
+
* @example
|
|
10161
|
+
* const schema = s.array(
|
|
10162
|
+
* s.code({ language: "css" }).preview(({ val }) => ({
|
|
10163
|
+
* title: val.split("\n")[0],
|
|
10164
|
+
* })),
|
|
10165
|
+
* );
|
|
10166
|
+
* export default c.define("/example.val.ts", schema, [
|
|
10167
|
+
* ".hero { color: red; }",
|
|
10168
|
+
* ]);
|
|
7788
10169
|
*/
|
|
7789
10170
|
}, {
|
|
7790
10171
|
key: "preview",
|
|
@@ -8335,12 +10716,54 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
|
|
|
8335
10716
|
_this.previewInput = previewInput;
|
|
8336
10717
|
return _this;
|
|
8337
10718
|
}
|
|
10719
|
+
|
|
10720
|
+
/**
|
|
10721
|
+
* Describe this field.
|
|
10722
|
+
*
|
|
10723
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
10724
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
10725
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
10726
|
+
* assistant and the MCP tools read.
|
|
10727
|
+
*
|
|
10728
|
+
* Pass `null` to clear a description set earlier.
|
|
10729
|
+
*
|
|
10730
|
+
* @example
|
|
10731
|
+
* const schema = s.color().describe("Background of the hero section");
|
|
10732
|
+
* export default c.define(
|
|
10733
|
+
* "/example.val.ts",
|
|
10734
|
+
* schema,
|
|
10735
|
+
* "hsl(217.22 91.22% 59.8%)",
|
|
10736
|
+
* );
|
|
10737
|
+
*/
|
|
8338
10738
|
_inherits(ColorSchema, _Schema);
|
|
8339
10739
|
return _createClass(ColorSchema, [{
|
|
8340
10740
|
key: "describe",
|
|
8341
10741
|
value: function describe(description) {
|
|
8342
10742
|
return new ColorSchema(this.options, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined, this.renderInput, this.previewInput);
|
|
8343
10743
|
}
|
|
10744
|
+
|
|
10745
|
+
/**
|
|
10746
|
+
* Add a custom validation rule to this field.
|
|
10747
|
+
*
|
|
10748
|
+
* The function is called with the field's value and returns `false` when the
|
|
10749
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
10750
|
+
* more than once to add more rules — they all run, and every message is
|
|
10751
|
+
* reported.
|
|
10752
|
+
*
|
|
10753
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
10754
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
10755
|
+
*
|
|
10756
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
10757
|
+
* before a publish.
|
|
10758
|
+
*
|
|
10759
|
+
* @example
|
|
10760
|
+
* const schema = s
|
|
10761
|
+
* .color({ format: "hex" })
|
|
10762
|
+
* .validate((val) =>
|
|
10763
|
+
* val === val.toLowerCase() ? false : "Write hex in lower case",
|
|
10764
|
+
* );
|
|
10765
|
+
* export default c.define("/example.val.ts", schema, "#3b82f6");
|
|
10766
|
+
*/
|
|
8344
10767
|
}, {
|
|
8345
10768
|
key: "validate",
|
|
8346
10769
|
value: function validate(validationFunction) {
|
|
@@ -8441,7 +10864,7 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
|
|
|
8441
10864
|
}, {
|
|
8442
10865
|
key: "nullable",
|
|
8443
10866
|
value: function nullable() {
|
|
8444
|
-
return new ColorSchema(this.options, true,
|
|
10867
|
+
return new ColorSchema(this.options, true, this.customValidateFunctions, this.isReadonly, this.isHidden, this.description, this.renderInput, this.previewInput);
|
|
8445
10868
|
}
|
|
8446
10869
|
}, {
|
|
8447
10870
|
key: "readonly",
|
|
@@ -8462,6 +10885,12 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
|
|
|
8462
10885
|
* instead of a preview row that navigates to it.
|
|
8463
10886
|
*
|
|
8464
10887
|
* Static configuration, not a callback — see `render.ts`.
|
|
10888
|
+
*
|
|
10889
|
+
* @example
|
|
10890
|
+
* const schema = s.array(s.color().render({ as: "inline" }));
|
|
10891
|
+
* export default c.define("/example.val.ts", schema, [
|
|
10892
|
+
* "hsl(217.22 91.22% 59.8%)",
|
|
10893
|
+
* ]);
|
|
8465
10894
|
*/
|
|
8466
10895
|
}, {
|
|
8467
10896
|
key: "render",
|
|
@@ -8473,6 +10902,14 @@ var ColorSchema = /*#__PURE__*/function (_Schema) {
|
|
|
8473
10902
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
8474
10903
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
8475
10904
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
10905
|
+
*
|
|
10906
|
+
* @example
|
|
10907
|
+
* const schema = s.array(
|
|
10908
|
+
* s.color().preview(({ val }) => ({ title: val })),
|
|
10909
|
+
* );
|
|
10910
|
+
* export default c.define("/example.val.ts", schema, [
|
|
10911
|
+
* "hsl(217.22 91.22% 59.8%)",
|
|
10912
|
+
* ]);
|
|
8476
10913
|
*/
|
|
8477
10914
|
}, {
|
|
8478
10915
|
key: "preview",
|
|
@@ -8601,6 +11038,8 @@ function initSchema() {
|
|
|
8601
11038
|
array: array,
|
|
8602
11039
|
object: object,
|
|
8603
11040
|
number: number,
|
|
11041
|
+
discriminatedUnion: discriminatedUnion,
|
|
11042
|
+
"enum": enumSchema,
|
|
8604
11043
|
union: union,
|
|
8605
11044
|
// oneOf,
|
|
8606
11045
|
richtext: richtext,
|
|
@@ -8614,6 +11053,7 @@ function initSchema() {
|
|
|
8614
11053
|
datetime: datetime,
|
|
8615
11054
|
color: color,
|
|
8616
11055
|
code: code,
|
|
11056
|
+
locale: locale,
|
|
8617
11057
|
route: route,
|
|
8618
11058
|
router: router,
|
|
8619
11059
|
images: images,
|
|
@@ -8752,6 +11192,8 @@ var Hash = /*#__PURE__*/function () {
|
|
|
8752
11192
|
_defineProperty(this, "F", 0x9b05688c | 0);
|
|
8753
11193
|
_defineProperty(this, "G", 0x1f83d9ab | 0);
|
|
8754
11194
|
_defineProperty(this, "H", 0x5be0cd19 | 0);
|
|
11195
|
+
_defineProperty(this, "_byte", void 0);
|
|
11196
|
+
_defineProperty(this, "_word", void 0);
|
|
8755
11197
|
_defineProperty(this, "_size", 0);
|
|
8756
11198
|
_defineProperty(this, "_sp", 0);
|
|
8757
11199
|
if (!sharedBuffer || sharedOffset >= N.allocTotal) {
|
|
@@ -9519,32 +11961,26 @@ function hasRemoteFileSchema(schema) {
|
|
|
9519
11961
|
}
|
|
9520
11962
|
}
|
|
9521
11963
|
return false;
|
|
9522
|
-
} else if (schema.type === "union") {
|
|
9523
|
-
var
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
_step;
|
|
9532
|
-
try {
|
|
9533
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
9534
|
-
var item = _step.value;
|
|
9535
|
-
var _hasRemoteFile = hasRemoteFileSchema(item);
|
|
9536
|
-
if (_hasRemoteFile) {
|
|
9537
|
-
return true;
|
|
9538
|
-
}
|
|
11964
|
+
} else if (schema.type === "discriminated-union") {
|
|
11965
|
+
var _iterator = _createForOfIteratorHelper(schema.items),
|
|
11966
|
+
_step;
|
|
11967
|
+
try {
|
|
11968
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
11969
|
+
var item = _step.value;
|
|
11970
|
+
var _hasRemoteFile = hasRemoteFileSchema(item);
|
|
11971
|
+
if (_hasRemoteFile) {
|
|
11972
|
+
return true;
|
|
9539
11973
|
}
|
|
9540
|
-
} catch (err) {
|
|
9541
|
-
_iterator.e(err);
|
|
9542
|
-
} finally {
|
|
9543
|
-
_iterator.f();
|
|
9544
11974
|
}
|
|
11975
|
+
} catch (err) {
|
|
11976
|
+
_iterator.e(err);
|
|
11977
|
+
} finally {
|
|
11978
|
+
_iterator.f();
|
|
9545
11979
|
}
|
|
9546
11980
|
return false;
|
|
9547
|
-
} else if (schema.type === "boolean" ||
|
|
11981
|
+
} else if (schema.type === "boolean" ||
|
|
11982
|
+
// An enum's values are strings, so there is nothing to look inside.
|
|
11983
|
+
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") {
|
|
9548
11984
|
return false;
|
|
9549
11985
|
} else {
|
|
9550
11986
|
var exhaustiveCheck = schema;
|
|
@@ -9598,27 +12034,25 @@ function hasMediaSchema(schema) {
|
|
|
9598
12034
|
}
|
|
9599
12035
|
}
|
|
9600
12036
|
return false;
|
|
9601
|
-
} else if (schema.type === "union") {
|
|
9602
|
-
var
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
if (hasMediaSchema(item)) {
|
|
9610
|
-
return true;
|
|
9611
|
-
}
|
|
12037
|
+
} else if (schema.type === "discriminated-union") {
|
|
12038
|
+
var _iterator2 = _createForOfIteratorHelper(schema.items),
|
|
12039
|
+
_step2;
|
|
12040
|
+
try {
|
|
12041
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
12042
|
+
var item = _step2.value;
|
|
12043
|
+
if (hasMediaSchema(item)) {
|
|
12044
|
+
return true;
|
|
9612
12045
|
}
|
|
9613
|
-
} catch (err) {
|
|
9614
|
-
_iterator2.e(err);
|
|
9615
|
-
} finally {
|
|
9616
|
-
_iterator2.f();
|
|
9617
12046
|
}
|
|
12047
|
+
} catch (err) {
|
|
12048
|
+
_iterator2.e(err);
|
|
12049
|
+
} finally {
|
|
12050
|
+
_iterator2.f();
|
|
9618
12051
|
}
|
|
9619
|
-
// A string union's items are literals, so there is nothing to look inside.
|
|
9620
12052
|
return false;
|
|
9621
|
-
} else if (schema.type === "boolean" ||
|
|
12053
|
+
} else if (schema.type === "boolean" ||
|
|
12054
|
+
// An enum's values are strings, so there is nothing to look inside.
|
|
12055
|
+
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" ||
|
|
9622
12056
|
// A settings module holds the assistant's configuration, not content, and
|
|
9623
12057
|
// nothing in it is media.
|
|
9624
12058
|
schema.type === "settings") {
|
|
@@ -9897,6 +12331,46 @@ function getFileHash(text) {
|
|
|
9897
12331
|
return hashToRemoteFileHash(getSHA256Hash(new Uint8Array(text)));
|
|
9898
12332
|
}
|
|
9899
12333
|
|
|
12334
|
+
/**
|
|
12335
|
+
* The variant of a discriminated union that a value takes, by its tag.
|
|
12336
|
+
*
|
|
12337
|
+
* A discriminated union is a fork rather than a level: the variant IS the node,
|
|
12338
|
+
* and everything a caller wants to know about that node — its fields, its
|
|
12339
|
+
* `locale` field, the schema to draw it with — is on the variant and not on the
|
|
12340
|
+
* union. Resolving it takes the source, so it cannot be done from the schema
|
|
12341
|
+
* alone, which is why every caller that has only the union ends up needing this.
|
|
12342
|
+
*
|
|
12343
|
+
* `undefined` where the tag matches nothing, rather than a fallback to the first
|
|
12344
|
+
* variant: a value whose tag names no variant is not a member of the union,
|
|
12345
|
+
* validation is already saying so, and reading fields out of the wrong shape
|
|
12346
|
+
* would answer confidently and wrongly.
|
|
12347
|
+
*
|
|
12348
|
+
* `s.enum()` never reaches here — it is a leaf whose values are strings, with no
|
|
12349
|
+
* variants to resolve — so anything that is not a discriminated union answers
|
|
12350
|
+
* `undefined` too.
|
|
12351
|
+
*/
|
|
12352
|
+
function discriminatedUnionBranchOf(schema, tag) {
|
|
12353
|
+
if ((schema === null || schema === void 0 ? void 0 : schema.type) !== "discriminated-union") {
|
|
12354
|
+
return undefined;
|
|
12355
|
+
}
|
|
12356
|
+
var _iterator = _createForOfIteratorHelper(schema.items),
|
|
12357
|
+
_step;
|
|
12358
|
+
try {
|
|
12359
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
12360
|
+
var item = _step.value;
|
|
12361
|
+
var discriminator = item.items[schema.key];
|
|
12362
|
+
if ((discriminator === null || discriminator === void 0 ? void 0 : discriminator.type) === "literal" && discriminator.value === tag) {
|
|
12363
|
+
return item;
|
|
12364
|
+
}
|
|
12365
|
+
}
|
|
12366
|
+
} catch (err) {
|
|
12367
|
+
_iterator.e(err);
|
|
12368
|
+
} finally {
|
|
12369
|
+
_iterator.f();
|
|
12370
|
+
}
|
|
12371
|
+
return undefined;
|
|
12372
|
+
}
|
|
12373
|
+
|
|
9900
12374
|
function deserializeSchema(serialized) {
|
|
9901
12375
|
var schema = deserializeSchemaImpl(serialized);
|
|
9902
12376
|
if (serialized.readonly) {
|
|
@@ -9908,7 +12382,7 @@ function deserializeSchema(serialized) {
|
|
|
9908
12382
|
return schema;
|
|
9909
12383
|
}
|
|
9910
12384
|
function deserializeSchemaImpl(serialized) {
|
|
9911
|
-
var _serialized$options, _serialized$options2, _serialized$render, _serialized$multiline, _serialized$render2, _serialized$render3, _serialized$render4, _serialized$render5, _serialized$render6, _serialized$render7, _serialized$accept, _serialized$directory, _serialized$remote, _serialized$jsonValue, _serialized$
|
|
12385
|
+
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;
|
|
9912
12386
|
switch (serialized.type) {
|
|
9913
12387
|
case "string":
|
|
9914
12388
|
return new StringSchema(_objectSpread2(_objectSpread2({}, serialized.options), {}, {
|
|
@@ -9937,28 +12411,32 @@ function deserializeSchemaImpl(serialized) {
|
|
|
9937
12411
|
key = _ref4[0],
|
|
9938
12412
|
item = _ref4[1];
|
|
9939
12413
|
return [key, deserializeSchema(item)];
|
|
9940
|
-
})), serialized.opt, false, false, serialized.description
|
|
12414
|
+
})), serialized.opt, false, false, serialized.description,
|
|
12415
|
+
// Carried through, or the Studio's validation worker — which only ever
|
|
12416
|
+
// sees the deserialized schema — would run every field's own rules and
|
|
12417
|
+
// none of the section's, so a language declared twice would be reported
|
|
12418
|
+
// by the CLI and silently accepted in the Studio.
|
|
12419
|
+
serialized.section);
|
|
9941
12420
|
case "array":
|
|
9942
12421
|
return new ArraySchema(deserializeSchema(serialized.item), serialized.opt, [], false, false, serialized.description,
|
|
9943
12422
|
// The preview closure cannot survive serialization; the render can.
|
|
9944
12423
|
null, (_serialized$render6 = serialized.render) !== null && _serialized$render6 !== void 0 ? _serialized$render6 : null);
|
|
9945
|
-
case "union":
|
|
9946
|
-
return new
|
|
9947
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9948
|
-
deserializeSchema(serialized.key),
|
|
9949
|
-
// TODO: we do not really need any here - right?
|
|
12424
|
+
case "discriminated-union":
|
|
12425
|
+
return new DiscriminatedUnionSchema(serialized.key,
|
|
9950
12426
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9951
12427
|
serialized.items.map(deserializeSchema),
|
|
9952
12428
|
// TODO: we do not really need any here - right?
|
|
9953
12429
|
serialized.opt, [], false, false, serialized.description, (_serialized$render7 = serialized.render) !== null && _serialized$render7 !== void 0 ? _serialized$render7 : null);
|
|
12430
|
+
case "enum":
|
|
12431
|
+
return new EnumSchema(serialized.values, serialized.opt, [], false, false, serialized.description, (_serialized$render8 = serialized.render) !== null && _serialized$render8 !== void 0 ? _serialized$render8 : null);
|
|
9954
12432
|
case "richtext":
|
|
9955
12433
|
{
|
|
9956
|
-
var _serialized$options3, _serialized$options4, _serialized$options5, _serialized$options6, _serialized$
|
|
12434
|
+
var _serialized$options3, _serialized$options4, _serialized$options5, _serialized$options6, _serialized$render9;
|
|
9957
12435
|
var deserializedOptions = _objectSpread2(_objectSpread2({}, serialized.options || {}), {}, {
|
|
9958
12436
|
a: _typeof((_serialized$options3 = serialized.options) === null || _serialized$options3 === void 0 ? void 0 : _serialized$options3.a) === "object" ? deserializeSchema(serialized.options.a) : (_serialized$options4 = serialized.options) === null || _serialized$options4 === void 0 ? void 0 : _serialized$options4.a,
|
|
9959
12437
|
img: _typeof((_serialized$options5 = serialized.options) === null || _serialized$options5 === void 0 ? void 0 : _serialized$options5.img) === "object" ? deserializeSchema(serialized.options.img) : (_serialized$options6 = serialized.options) === null || _serialized$options6 === void 0 ? void 0 : _serialized$options6.img
|
|
9960
12438
|
});
|
|
9961
|
-
return new RichTextSchema(deserializedOptions, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12439
|
+
return new RichTextSchema(deserializedOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render9 = serialized.render) !== null && _serialized$render9 !== void 0 ? _serialized$render9 : null);
|
|
9962
12440
|
}
|
|
9963
12441
|
case "record":
|
|
9964
12442
|
return new RecordSchema(deserializeSchema(serialized.item), serialized.opt, [], null, serialized.key ? deserializeSchema(serialized.key) : null, serialized.mediaType ? {
|
|
@@ -9969,33 +12447,38 @@ function deserializeSchemaImpl(serialized) {
|
|
|
9969
12447
|
altSchema: serialized.alt ? deserializeSchema(serialized.alt) : undefined
|
|
9970
12448
|
} : undefined, false, false, serialized.description, (_serialized$jsonValue = serialized.jsonValues) !== null && _serialized$jsonValue !== void 0 ? _serialized$jsonValue : false,
|
|
9971
12449
|
// The preview closure cannot survive serialization; the render can.
|
|
9972
|
-
null, (_serialized$
|
|
12450
|
+
null, (_serialized$render0 = serialized.render) !== null && _serialized$render0 !== void 0 ? _serialized$render0 : null, // The external label is static data, so it survives serialization and
|
|
9973
12451
|
// must be carried back: a deserialized schema that forgot it would walk
|
|
9974
12452
|
// an external record as if its entries were local.
|
|
9975
12453
|
(_serialized$external = serialized.external) !== null && _serialized$external !== void 0 ? _serialized$external : null);
|
|
9976
12454
|
case "keyOf":
|
|
9977
|
-
return new KeyOfSchema(serialized.schema, serialized.path, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12455
|
+
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);
|
|
12456
|
+
case "locale":
|
|
12457
|
+
{
|
|
12458
|
+
var _serialized$render10;
|
|
12459
|
+
return new LocaleSchema(serialized.opt, [], false, false, serialized.description, (_serialized$render10 = serialized.render) !== null && _serialized$render10 !== void 0 ? _serialized$render10 : null);
|
|
12460
|
+
}
|
|
9978
12461
|
case "route":
|
|
9979
12462
|
{
|
|
9980
|
-
var _serialized$
|
|
12463
|
+
var _serialized$render11;
|
|
9981
12464
|
var routeOptions = serialized.options ? {
|
|
9982
12465
|
include: serialized.options.include ? new RegExp(serialized.options.include.source, serialized.options.include.flags) : undefined,
|
|
9983
12466
|
exclude: serialized.options.exclude ? new RegExp(serialized.options.exclude.source, serialized.options.exclude.flags) : undefined
|
|
9984
12467
|
} : undefined;
|
|
9985
|
-
return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12468
|
+
return new RouteSchema(routeOptions, serialized.opt, [], false, false, serialized.description, (_serialized$render11 = serialized.render) !== null && _serialized$render11 !== void 0 ? _serialized$render11 : null);
|
|
9986
12469
|
}
|
|
9987
12470
|
case "file":
|
|
9988
|
-
return new FileSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$
|
|
12471
|
+
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);
|
|
9989
12472
|
case "image":
|
|
9990
|
-
return new ImageSchema(serialized.options, serialized.opt, serialized.remote, [], {}, false, false, serialized.description, (_serialized$
|
|
12473
|
+
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);
|
|
9991
12474
|
case "date":
|
|
9992
|
-
return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12475
|
+
return new DateSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render14 = serialized.render) !== null && _serialized$render14 !== void 0 ? _serialized$render14 : null);
|
|
9993
12476
|
case "dateTime":
|
|
9994
|
-
return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12477
|
+
return new DateTimeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render15 = serialized.render) !== null && _serialized$render15 !== void 0 ? _serialized$render15 : null);
|
|
9995
12478
|
case "color":
|
|
9996
|
-
return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12479
|
+
return new ColorSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render16 = serialized.render) !== null && _serialized$render16 !== void 0 ? _serialized$render16 : null);
|
|
9997
12480
|
case "code":
|
|
9998
|
-
return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$
|
|
12481
|
+
return new CodeSchema(serialized.options, serialized.opt, [], false, false, serialized.description, (_serialized$render17 = serialized.render) !== null && _serialized$render17 !== void 0 ? _serialized$render17 : null);
|
|
9999
12482
|
default:
|
|
10000
12483
|
{
|
|
10001
12484
|
var exhaustiveCheck = serialized;
|
|
@@ -10204,10 +12687,11 @@ function previewScope(paths) {
|
|
|
10204
12687
|
* question, and a disagreement between them is a row you can edit in place but
|
|
10205
12688
|
* that "add" navigates away from.
|
|
10206
12689
|
*
|
|
10207
|
-
* A
|
|
10208
|
-
* ANY of its variants does. A page-builder list is
|
|
10209
|
-
* block, block, ...))` and the natural
|
|
10210
|
-
* blocks, one per block type — the union
|
|
12690
|
+
* A discriminated union counts as inline when the union itself declares it OR
|
|
12691
|
+
* when ANY of its variants does. A page-builder list is
|
|
12692
|
+
* `s.array(s.discriminatedUnion("type", block, block, ...))` and the natural
|
|
12693
|
+
* place to write the render is on the blocks, one per block type — the union
|
|
12694
|
+
* is a dispatch, not something the
|
|
10211
12695
|
* author thinks of as the field. `some` rather than `every` because the row
|
|
10212
12696
|
* draws the union's own editor (the tag selector plus the matched variant's
|
|
10213
12697
|
* fields), which handles every variant either way: with `every`, adding one
|
|
@@ -10224,7 +12708,7 @@ function isInlineRender(schema) {
|
|
|
10224
12708
|
if (((_schema$render = schema.render) === null || _schema$render === void 0 ? void 0 : _schema$render.as) === "inline") {
|
|
10225
12709
|
return true;
|
|
10226
12710
|
}
|
|
10227
|
-
if (schema.type === "union") {
|
|
12711
|
+
if (schema.type === "discriminated-union") {
|
|
10228
12712
|
return schema.items.some(function (item) {
|
|
10229
12713
|
var _item$render;
|
|
10230
12714
|
return ((_item$render = item.render) === null || _item$render === void 0 ? void 0 : _item$render.as) === "inline";
|
|
@@ -10661,7 +13145,7 @@ function isPageRouter(routerId) {
|
|
|
10661
13145
|
|
|
10662
13146
|
var corePackageJson = {
|
|
10663
13147
|
name: "@valbuild/core",
|
|
10664
|
-
version: "0.
|
|
13148
|
+
version: "0.127.0",
|
|
10665
13149
|
"private": false,
|
|
10666
13150
|
description: "Val - supercharged hard-coded content",
|
|
10667
13151
|
repository: {
|
|
@@ -10832,4 +13316,4 @@ function tryJsonParse(str) {
|
|
|
10832
13316
|
}
|
|
10833
13317
|
}
|
|
10834
13318
|
|
|
10835
|
-
export {
|
|
13319
|
+
export { DiscriminatedUnionSchema as $, ArraySchema as A, BooleanSchema as B, declaredKeySetOf as C, DEFAULT_CONTENT_HOST as D, missingDeclaredKeys as E, FATAL_ERROR_TYPES as F, GenericSelector as G, discriminatedUnionBranchOf as H, Internal as I, ColorSchema as J, CodeSchema as K, LocaleSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, CODE_LANGUAGES as Q, RecordSchema as R, Schema as S, COLOR_FORMATS as T, DEFAULT_COLOR_FORMAT as U, VAL_EXTENSION as V, DateTimeSchema as W, KeyOfSchema as X, RouteSchema as Y, RichTextSchema as Z, _typeof as _, _slicedToArray as a, EnumSchema as a0, LiteralSchema as a1, deserializeSchema as a2, previewScope as a3, isInlineRender as a4, parseNextJsRoutePattern as a5, parseTanStackRoutePattern as a6, tanStackSegmentsOfRoutePath as a7, validateUrlAgainstPattern as a8, getSourcePathFromRoute as a9, isPageRouter as aa, _createClass as b, _classCallCheck as c, _toConsumableArray as d, DEFAULT_APP_HOST as e, extractValModules as f, computeValModuleShas as g, hasRemoteFileSchema as h, initVal as i, hasMediaSchema as j, DEFAULT_VAL_REMOTE_HOST as k, derefPatch as l, modules as m, StringSchema as n, ImageSchema as o, FileSchema as p, DateSchema as q, SettingsSchema as r, splitModuleFilePathAndModulePath as s, ASSISTANT_SETTINGS_MAX_LENGTH as t, assistantAvailability as u, SETTINGS_MODULE_CONVENTION as v, isRootModuleFilePath as w, resolveSettingsModule as x, localeTagError as y, localeOfValue as z };
|