@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
|
@@ -108,9 +108,81 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
108
108
|
* sites.
|
|
109
109
|
*/
|
|
110
110
|
externalLabel?: string | null);
|
|
111
|
+
/**
|
|
112
|
+
* Describe this field.
|
|
113
|
+
*
|
|
114
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
115
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
116
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
117
|
+
* assistant and the MCP tools read.
|
|
118
|
+
*
|
|
119
|
+
* Pass `null` to clear a description set earlier.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* const schema = s
|
|
123
|
+
* .record(s.string())
|
|
124
|
+
* .describe("Button labels, keyed by locale");
|
|
125
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
126
|
+
*/
|
|
111
127
|
describe(description: string | null): RecordSchema<T, K, Src>;
|
|
128
|
+
/**
|
|
129
|
+
* Add a custom validation rule to this field.
|
|
130
|
+
*
|
|
131
|
+
* The function is called with the field's value and returns `false` when the
|
|
132
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
133
|
+
* more than once to add more rules — they all run, and every message is
|
|
134
|
+
* reported.
|
|
135
|
+
*
|
|
136
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
137
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
138
|
+
*
|
|
139
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
140
|
+
* before a publish.
|
|
141
|
+
*
|
|
142
|
+
* The function is given the whole record. To validate one entry, put a
|
|
143
|
+
* `.validate(...)` on the ITEM schema instead — that reports the error on
|
|
144
|
+
* the entry's own row, and on a `.jsonValues()` record it does not force
|
|
145
|
+
* every entry to be loaded.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* const schema = s.record(s.string()).validate((val) =>
|
|
149
|
+
* "en" in val ? false : "There has to be an 'en' entry",
|
|
150
|
+
* );
|
|
151
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
152
|
+
*/
|
|
112
153
|
validate(validationFunction: (src: Src) => false | string): RecordSchema<T, K, Src>;
|
|
113
154
|
protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
|
|
155
|
+
/**
|
|
156
|
+
* The check that a record with a DECLARED key set holds every one of them.
|
|
157
|
+
*
|
|
158
|
+
* `s.record(s.locale(), item)` has one entry per language and
|
|
159
|
+
* `s.record(s.union(s.literal("a"), s.literal("b")), item)` has both — the
|
|
160
|
+
* keys are part of the schema either way, so a missing one is a hole in the
|
|
161
|
+
* content rather than content nobody has written yet. TypeScript already
|
|
162
|
+
* demanded both keys of the second; this is the validator catching up, which
|
|
163
|
+
* is why the two now behave the same.
|
|
164
|
+
*
|
|
165
|
+
* Deferred to `resolveSchemaSourceFixes` even for the literal case, where the
|
|
166
|
+
* keys are known right here: a locale record's keys are in another file, and
|
|
167
|
+
* one code path for both is one message, one fix and one thing to be wrong.
|
|
168
|
+
*/
|
|
169
|
+
private getDeclaredKeysValidation;
|
|
170
|
+
/**
|
|
171
|
+
* The key set this record's schema declares, computed once.
|
|
172
|
+
*
|
|
173
|
+
* `declaredKeySetOf` reads a SERIALIZED schema, and serializing the key
|
|
174
|
+
* schema walks it — twice per validate, and once per record instance, for an
|
|
175
|
+
* answer that is a property of the schema and cannot move between them. A
|
|
176
|
+
* schema is built once and validated against many times, so the walk happens
|
|
177
|
+
* on the first question and not on any after it.
|
|
178
|
+
*/
|
|
179
|
+
private declaredKeys;
|
|
180
|
+
private declaredKeySet;
|
|
181
|
+
protected opensLocaleScope(): "field" | "key" | null;
|
|
182
|
+
protected localeScopeChildren(): {
|
|
183
|
+
key: string;
|
|
184
|
+
schema: Schema<SelectorSource>;
|
|
185
|
+
}[];
|
|
114
186
|
private isRemoteUrl;
|
|
115
187
|
/** Marks the validation errors reported at `path` as key errors (in place). */
|
|
116
188
|
private markKeyErrorsAtPath;
|
|
@@ -128,10 +200,55 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
128
200
|
* must come BEFORE `.external()`: afterwards the value is a `Schema`, and
|
|
129
201
|
* there is no `.readonly()` left to call — which is the error the compiler
|
|
130
202
|
* gives, and a clearer one than a runtime throw.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const schema = s.record(s.string()).readonly();
|
|
206
|
+
* export default c.define("/example.val.ts", schema, { en: "Read more" });
|
|
131
207
|
*/
|
|
132
208
|
readonly<B extends boolean = true>(isReadonly?: B): RecordSchema<T, K, Src, B>;
|
|
133
209
|
hidden(isHidden?: boolean): RecordSchema<T, K, Src>;
|
|
210
|
+
/**
|
|
211
|
+
* Turn this record into a page router: its keys are route paths of your
|
|
212
|
+
* application, and they are validated against the router's conventions.
|
|
213
|
+
*
|
|
214
|
+
* `s.router(router, item)` builds the same thing in one call and is what
|
|
215
|
+
* most code should use — this is for adding a router to a record that
|
|
216
|
+
* already exists.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* import { nextAppRouter } from "../val.config";
|
|
220
|
+
* const schema = s
|
|
221
|
+
* .record(s.object({ title: s.string() }))
|
|
222
|
+
* .router(nextAppRouter);
|
|
223
|
+
* export default c.define("/app/[slug]/page.val.ts", schema, {
|
|
224
|
+
* "/a-page-slug": { title: "First Page" },
|
|
225
|
+
* });
|
|
226
|
+
*/
|
|
134
227
|
router(router: ValRouter): RecordSchema<T, K, Src>;
|
|
228
|
+
/**
|
|
229
|
+
* Allow the files in this gallery to be stored on Val's remote content host
|
|
230
|
+
* instead of in your repository.
|
|
231
|
+
*
|
|
232
|
+
* For `s.images()` and `s.files()`, which are records of media. Remote is off
|
|
233
|
+
* until this is called.
|
|
234
|
+
*
|
|
235
|
+
* Each entry is then keyed by its URL on the content host rather than by a
|
|
236
|
+
* path under `/public`. That key is not something to write by hand: upload
|
|
237
|
+
* in the Studio, or add a local path and let `npx val validate --fix`
|
|
238
|
+
* upload it and rewrite the key.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* const schema = s.images({ directory: "/public/val/images" }).remote();
|
|
242
|
+
* export default c.define("/content/images.val.ts", schema, {
|
|
243
|
+
* "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/hero.webp":
|
|
244
|
+
* {
|
|
245
|
+
* width: 1920,
|
|
246
|
+
* height: 1080,
|
|
247
|
+
* mimeType: "image/webp",
|
|
248
|
+
* alt: "Hero image",
|
|
249
|
+
* },
|
|
250
|
+
* });
|
|
251
|
+
*/
|
|
135
252
|
remote(): RecordSchema<T, K, Src>;
|
|
136
253
|
/**
|
|
137
254
|
* Store each entry's value in its own lazily-loaded `*.val.json` file instead
|
|
@@ -146,6 +263,20 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
146
263
|
* nested inside an object/array/record is rejected at startup with a module
|
|
147
264
|
* error, because the single-entry fetch endpoint, the Studio's content
|
|
148
265
|
* substitution and content validation are all root-only.
|
|
266
|
+
*
|
|
267
|
+
* Must come BEFORE `.validate()` and `.preview()`: those are typed against
|
|
268
|
+
* the un-lazy source shape, so a validator or preview declared first cannot
|
|
269
|
+
* be carried over, and declaring one first throws rather than silently
|
|
270
|
+
* dropping it.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* import { nextAppRouter } from "../val.config";
|
|
274
|
+
* const schema = s
|
|
275
|
+
* .router(nextAppRouter, s.object({ title: s.string(), body: s.string() }))
|
|
276
|
+
* .jsonValues();
|
|
277
|
+
* export default c.define("/app/support/[slug]/page.val.ts", schema, {
|
|
278
|
+
* "/support/faq": c.json(() => import("./content/faq.val.json")),
|
|
279
|
+
* });
|
|
149
280
|
*/
|
|
150
281
|
jsonValues(): RecordSchema<T, K, JsonValuesRecordSrc<T, K>>;
|
|
151
282
|
/**
|
|
@@ -166,6 +297,19 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
166
297
|
* nested external record would leave a hole in the middle of a module's
|
|
167
298
|
* source, and the Studio, patching and validation all assume a module's
|
|
168
299
|
* source is complete apart from its entries.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* const schema = s.record(s.object({ title: s.string() })).external("posts");
|
|
303
|
+
* export default c.define("/content/posts.val.ts", schema, c.external());
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* // A read-only external record: `.readonly()` must come FIRST, because
|
|
307
|
+
* // afterwards there is no `.readonly()` left on the type to call.
|
|
308
|
+
* const schema = s
|
|
309
|
+
* .record(s.object({ title: s.string() }))
|
|
310
|
+
* .readonly()
|
|
311
|
+
* .external("posts");
|
|
312
|
+
* export default c.define("/content/posts.val.ts", schema, c.external());
|
|
169
313
|
*/
|
|
170
314
|
external<L extends string>(label: L): RecordSchema<T, K, ExternalRecordSrc<SelectorOfSchema<T>, L, RO>, RO>;
|
|
171
315
|
/**
|
|
@@ -197,6 +341,25 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
197
341
|
* is the item of another container, in search, in references. What its
|
|
198
342
|
* entries show is the ITEM schema's `preview`, not this. Never how the field
|
|
199
343
|
* is edited (that is `render`). See `preview.ts`.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* // The preview of the RECORD, for where it is an item of something else.
|
|
347
|
+
* // What its own rows show is the ITEM schema's preview — see below.
|
|
348
|
+
* const labels = s.record(s.string()).preview(({ val }) => ({
|
|
349
|
+
* title: `${Object.keys(val).length} locales`,
|
|
350
|
+
* }));
|
|
351
|
+
* export default c.define("/example.val.ts", s.array(labels), [
|
|
352
|
+
* { en: "Read more" },
|
|
353
|
+
* ]);
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* // Rows of a record come from the ITEM's preview, not the record's:
|
|
357
|
+
* const author = s
|
|
358
|
+
* .object({ name: s.string(), role: s.string() })
|
|
359
|
+
* .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
|
|
360
|
+
* export default c.define("/example.val.ts", s.record(author), {
|
|
361
|
+
* ada: { name: "Ada", role: "Engineer" },
|
|
362
|
+
* });
|
|
200
363
|
*/
|
|
201
364
|
preview(select: ItemPreviewInput<Src>): RecordSchema<T, K, Src>;
|
|
202
365
|
/**
|
|
@@ -205,9 +368,32 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
205
368
|
* instead of a preview row that navigates to it.
|
|
206
369
|
*
|
|
207
370
|
* Static configuration, not a callback — see `render.ts`.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* const schema = s.array(s.record(s.string()).render({ as: "inline" }));
|
|
374
|
+
* export default c.define("/example.val.ts", schema, [{ en: "Read more" }]);
|
|
208
375
|
*/
|
|
209
376
|
render(input: FieldRender): RecordSchema<T, K, Src>;
|
|
210
377
|
}
|
|
211
|
-
|
|
378
|
+
/**
|
|
379
|
+
* The source of a record, given what its key schema says about its keys.
|
|
380
|
+
*
|
|
381
|
+
* A key schema that ENUMERATES its keys (a union of literals, or `s.locale()`)
|
|
382
|
+
* makes every one of them an entry of the record, and an entry nobody has
|
|
383
|
+
* written yet is `null` rather than absent — so the value type widens by
|
|
384
|
+
* `null`. That is the whole of option F at the type level: a half-translated
|
|
385
|
+
* record is a record with nulls in it, which is data you can count, filter and
|
|
386
|
+
* see in a diff, rather than keys that are simply not there.
|
|
387
|
+
*
|
|
388
|
+
* For a union of literals TypeScript already required every key, since
|
|
389
|
+
* `SelectorOfSchema<K>` is the literal union itself. `s.locale()` is a flavoured
|
|
390
|
+
* string, so it requires nothing here and the requirement is the validator's —
|
|
391
|
+
* deliberately: which languages exist is in the settings module, where the
|
|
392
|
+
* project can change it without a deploy.
|
|
393
|
+
*/
|
|
394
|
+
export type RecordSrcOf<K extends Schema<string>, S extends Schema<SelectorSource>> = K extends {
|
|
395
|
+
__declaresRecordKeys: true;
|
|
396
|
+
} ? Record<SelectorOfSchema<K>, SelectorOfSchema<S> | null> : Record<SelectorOfSchema<K>, SelectorOfSchema<S>>;
|
|
397
|
+
export declare function record<K extends Schema<string>, S extends Schema<SelectorSource>>(key: K, schema: S): RecordSchema<S, K, RecordSrcOf<K, S>>;
|
|
212
398
|
export declare function record<S extends Schema<SelectorSource>>(schema: S): RecordSchema<S, Schema<string>, Record<string, SelectorOfSchema<S>>>;
|
|
213
399
|
export {};
|
|
@@ -31,9 +31,71 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
|
|
|
31
31
|
private readonly renderInput;
|
|
32
32
|
private readonly previewInput;
|
|
33
33
|
constructor(options: O & ValidationOptions, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
|
|
34
|
+
/**
|
|
35
|
+
* Describe this field.
|
|
36
|
+
*
|
|
37
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
38
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
39
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
40
|
+
* assistant and the MCP tools read.
|
|
41
|
+
*
|
|
42
|
+
* Pass `null` to clear a description set earlier.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const schema = s.richtext().describe("The body of the article");
|
|
46
|
+
* export default c.define("/example.val.ts", schema, [
|
|
47
|
+
* { tag: "p", children: ["Hello"] },
|
|
48
|
+
* ]);
|
|
49
|
+
*/
|
|
34
50
|
describe(description: string | null): RichTextSchema<O, Src>;
|
|
51
|
+
/**
|
|
52
|
+
* Validate that the rich text holds at most `max` characters.
|
|
53
|
+
*
|
|
54
|
+
* Counted over the TEXT, not the markup: tags, attributes and the structure
|
|
55
|
+
* of the document do not add to it.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const schema = s.richtext().maxLength(280);
|
|
59
|
+
* export default c.define("/example.val.ts", schema, [
|
|
60
|
+
* { tag: "p", children: ["Hello"] },
|
|
61
|
+
* ]);
|
|
62
|
+
*/
|
|
35
63
|
maxLength(max: number): RichTextSchema<O, Src>;
|
|
64
|
+
/**
|
|
65
|
+
* Validate that the rich text holds at least `min` characters.
|
|
66
|
+
*
|
|
67
|
+
* Counted over the TEXT, not the markup: tags, attributes and the structure
|
|
68
|
+
* of the document do not add to it.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const schema = s.richtext().minLength(20).maxLength(280);
|
|
72
|
+
* export default c.define("/example.val.ts", schema, [
|
|
73
|
+
* { tag: "p", children: ["Long enough to clear the minimum length."] },
|
|
74
|
+
* ]);
|
|
75
|
+
*/
|
|
36
76
|
minLength(min: number): RichTextSchema<O, Src>;
|
|
77
|
+
/**
|
|
78
|
+
* Add a custom validation rule to this field.
|
|
79
|
+
*
|
|
80
|
+
* The function is called with the field's value and returns `false` when the
|
|
81
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
82
|
+
* more than once to add more rules — they all run, and every message is
|
|
83
|
+
* reported.
|
|
84
|
+
*
|
|
85
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
86
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
87
|
+
*
|
|
88
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
89
|
+
* before a publish.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* const schema = s.richtext().validate((val) =>
|
|
93
|
+
* val.length > 0 ? false : "Write something",
|
|
94
|
+
* );
|
|
95
|
+
* export default c.define("/example.val.ts", schema, [
|
|
96
|
+
* { tag: "p", children: ["Hello"] },
|
|
97
|
+
* ]);
|
|
98
|
+
*/
|
|
37
99
|
validate(validationFunction: (src: Src) => false | string): RichTextSchema<O, Src>;
|
|
38
100
|
protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
|
|
39
101
|
private internalValidate;
|
|
@@ -49,12 +111,28 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
|
|
|
49
111
|
* instead of a preview row that navigates to it.
|
|
50
112
|
*
|
|
51
113
|
* Static configuration, not a callback — see `render.ts`.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const schema = s.array(s.richtext().render({ as: "inline" }));
|
|
117
|
+
* export default c.define("/example.val.ts", schema, [
|
|
118
|
+
* [{ tag: "p", children: ["Hello"] }],
|
|
119
|
+
* ]);
|
|
52
120
|
*/
|
|
53
121
|
render(input: FieldRender): RichTextSchema<O, Src>;
|
|
54
122
|
/**
|
|
55
123
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
56
124
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
57
125
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* const schema = s.array(
|
|
129
|
+
* s.richtext().preview(({ val }) => ({
|
|
130
|
+
* title: val.length > 0 ? "Rich text" : "Empty",
|
|
131
|
+
* })),
|
|
132
|
+
* );
|
|
133
|
+
* export default c.define("/example.val.ts", schema, [
|
|
134
|
+
* [{ tag: "p", children: ["Hello"] }],
|
|
135
|
+
* ]);
|
|
58
136
|
*/
|
|
59
137
|
preview(select: ItemPreviewInput<Src>): RichTextSchema<O, Src>;
|
|
60
138
|
protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
|
|
@@ -40,6 +40,20 @@ export declare class RouteSchema<Src extends string | null> extends Schema<Src>
|
|
|
40
40
|
private readonly renderInput;
|
|
41
41
|
private readonly previewInput;
|
|
42
42
|
constructor(options?: RouteOptions | undefined, opt?: boolean, customValidateFunctions?: ((src: Src) => false | string)[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
|
|
43
|
+
/**
|
|
44
|
+
* Describe this field.
|
|
45
|
+
*
|
|
46
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
47
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
48
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
49
|
+
* assistant and the MCP tools read.
|
|
50
|
+
*
|
|
51
|
+
* Pass `null` to clear a description set earlier.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const schema = s.route().describe("Where the button goes");
|
|
55
|
+
* export default c.define("/example.val.ts", schema, "/a-page-slug");
|
|
56
|
+
*/
|
|
43
57
|
describe(description: string | null): RouteSchema<Src>;
|
|
44
58
|
/**
|
|
45
59
|
* Specify a pattern for which routes are allowed.
|
|
@@ -67,6 +81,26 @@ export declare class RouteSchema<Src extends string | null> extends Schema<Src>
|
|
|
67
81
|
* s.route().include(/^\/api\//).exclude(/^\/api\/internal\//) // API routes except internal
|
|
68
82
|
*/
|
|
69
83
|
exclude(pattern: RegExp): RouteSchema<Src>;
|
|
84
|
+
/**
|
|
85
|
+
* Add a custom validation rule to this field.
|
|
86
|
+
*
|
|
87
|
+
* The function is called with the field's value and returns `false` when the
|
|
88
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
89
|
+
* more than once to add more rules — they all run, and every message is
|
|
90
|
+
* reported.
|
|
91
|
+
*
|
|
92
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
93
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
94
|
+
*
|
|
95
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
96
|
+
* before a publish.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* const schema = s.route().validate((val) =>
|
|
100
|
+
* val.endsWith("/") ? "Leave off the trailing slash" : false,
|
|
101
|
+
* );
|
|
102
|
+
* export default c.define("/example.val.ts", schema, "/a-page-slug");
|
|
103
|
+
*/
|
|
70
104
|
validate(validationFunction: (src: Src) => false | string): RouteSchema<Src>;
|
|
71
105
|
protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
|
|
72
106
|
protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
|
|
@@ -80,12 +114,22 @@ export declare class RouteSchema<Src extends string | null> extends Schema<Src>
|
|
|
80
114
|
* instead of a preview row that navigates to it.
|
|
81
115
|
*
|
|
82
116
|
* Static configuration, not a callback — see `render.ts`.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const schema = s.array(s.route().render({ as: "inline" }));
|
|
120
|
+
* export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
|
|
83
121
|
*/
|
|
84
122
|
render(input: FieldRender): RouteSchema<Src>;
|
|
85
123
|
/**
|
|
86
124
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
87
125
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
88
126
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* const schema = s.array(
|
|
130
|
+
* s.route().preview(({ val }) => ({ title: val })),
|
|
131
|
+
* );
|
|
132
|
+
* export default c.define("/example.val.ts", schema, ["/a-page-slug"]);
|
|
89
133
|
*/
|
|
90
134
|
preview(select: ItemPreviewInput<Src>): RouteSchema<Src>;
|
|
91
135
|
protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
|
|
@@ -38,6 +38,19 @@ export type SerializedSettingsSchema = {
|
|
|
38
38
|
readonly?: boolean;
|
|
39
39
|
hidden?: boolean;
|
|
40
40
|
description?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Which of Val's sections this is, where it is one.
|
|
43
|
+
*
|
|
44
|
+
* The name rather than the rule itself, because the rule is a closure and a
|
|
45
|
+
* closure does not survive JSON. Val owns both ends — every section's rules
|
|
46
|
+
* are in {@link sectionValidators} in this file — so the name is enough for
|
|
47
|
+
* {@link deserializeSchema} to put the same rules back, and a Studio that
|
|
48
|
+
* does not recognise the name simply runs none (see `sectionValidate`).
|
|
49
|
+
*
|
|
50
|
+
* Absent on the settings module itself, which is a bag of sections and has no
|
|
51
|
+
* rules of its own.
|
|
52
|
+
*/
|
|
53
|
+
section?: string;
|
|
41
54
|
};
|
|
42
55
|
/**
|
|
43
56
|
* An object whose keys are all optional: absent means unset.
|
|
@@ -58,7 +71,47 @@ export declare class SettingsSchema<Src extends {
|
|
|
58
71
|
private readonly isReadonly;
|
|
59
72
|
private readonly isHidden;
|
|
60
73
|
private readonly description?;
|
|
61
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Which section this is, where Val has rules about it beyond its keys.
|
|
76
|
+
*
|
|
77
|
+
* Not the `validate` the class deliberately does not offer: that one is the
|
|
78
|
+
* schema author's, and `s.settings()` takes no arguments to declare it
|
|
79
|
+
* with. This names a rule Val states about a shape Val owns — no language
|
|
80
|
+
* declared twice in `locales.available` is true of every project, and
|
|
81
|
+
* there is nowhere else it can be said. A single value's rules stay on its
|
|
82
|
+
* own schema; this is for the ones that need to see more than one value,
|
|
83
|
+
* or to report on a row of a list.
|
|
84
|
+
*
|
|
85
|
+
* A NAME rather than the function, so it survives serialization: the schema
|
|
86
|
+
* reaches the Studio's validation worker as JSON, and a closure would be
|
|
87
|
+
* dropped on the way — which is how these rules once went missing there.
|
|
88
|
+
*/
|
|
89
|
+
private readonly section?;
|
|
90
|
+
constructor(items: Record<string, Schema<SelectorSource>>, opt?: boolean, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined,
|
|
91
|
+
/**
|
|
92
|
+
* Which section this is, where Val has rules about it beyond its keys.
|
|
93
|
+
*
|
|
94
|
+
* Not the `validate` the class deliberately does not offer: that one is the
|
|
95
|
+
* schema author's, and `s.settings()` takes no arguments to declare it
|
|
96
|
+
* with. This names a rule Val states about a shape Val owns — no language
|
|
97
|
+
* declared twice in `locales.available` is true of every project, and
|
|
98
|
+
* there is nowhere else it can be said. A single value's rules stay on its
|
|
99
|
+
* own schema; this is for the ones that need to see more than one value,
|
|
100
|
+
* or to report on a row of a list.
|
|
101
|
+
*
|
|
102
|
+
* A NAME rather than the function, so it survives serialization: the schema
|
|
103
|
+
* reaches the Studio's validation worker as JSON, and a closure would be
|
|
104
|
+
* dropped on the way — which is how these rules once went missing there.
|
|
105
|
+
*/
|
|
106
|
+
section?: string | undefined);
|
|
107
|
+
/**
|
|
108
|
+
* This section's rules, or `undefined` where there are none to run.
|
|
109
|
+
*
|
|
110
|
+
* A name this Val does not know means a schema written by a newer one. Its
|
|
111
|
+
* per-field validation still runs; only the section's own rule is missed,
|
|
112
|
+
* which is the mild half of the failure and better than refusing the schema.
|
|
113
|
+
*/
|
|
114
|
+
private sectionValidate;
|
|
62
115
|
protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
|
|
63
116
|
protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
|
|
64
117
|
nullable(): SettingsSchema<Src | null>;
|
|
@@ -66,24 +66,113 @@ export declare class StringSchema<Src extends string | null> extends Schema<Src>
|
|
|
66
66
|
private readonly previewInput;
|
|
67
67
|
private readonly isMultiline;
|
|
68
68
|
constructor(options?: StringOptions | undefined, opt?: boolean, isRaw?: boolean, customValidateFunctions?: ((src: Src) => false | string)[], renderInput?: FieldRender | null, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null, isMultiline?: boolean);
|
|
69
|
+
/**
|
|
70
|
+
* Describe this field.
|
|
71
|
+
*
|
|
72
|
+
* The description is shown next to the field's label in the Val editor, so
|
|
73
|
+
* it is where you say what an editor needs to know but the field name cannot
|
|
74
|
+
* carry. It also travels in the serialized schema, which is what the AI
|
|
75
|
+
* assistant and the MCP tools read.
|
|
76
|
+
*
|
|
77
|
+
* Pass `null` to clear a description set earlier.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const schema = s
|
|
81
|
+
* .string()
|
|
82
|
+
* .describe("Shown in the browser tab and in search results");
|
|
83
|
+
* export default c.define("/example.val.ts", schema, "Hello");
|
|
84
|
+
*/
|
|
69
85
|
describe(description: string | null): StringSchema<Src>;
|
|
70
86
|
/**
|
|
71
87
|
* @deprecated Use `minLength` instead
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const schema = s.string().minLength(2);
|
|
91
|
+
* export default c.define("/example.val.ts", schema, "Hi");
|
|
72
92
|
*/
|
|
73
93
|
min(minLength: number): StringSchema<Src>;
|
|
94
|
+
/**
|
|
95
|
+
* Validate that the string is at least `minLength` characters long.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* const schema = s.string().minLength(2);
|
|
99
|
+
* export default c.define("/example.val.ts", schema, "Hi");
|
|
100
|
+
*/
|
|
74
101
|
minLength(minLength: number): StringSchema<Src>;
|
|
75
102
|
/**
|
|
76
103
|
* @deprecated Use `maxLength` instead
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const schema = s.string().maxLength(60);
|
|
107
|
+
* export default c.define("/example.val.ts", schema, "A title that fits");
|
|
77
108
|
*/
|
|
78
109
|
max(maxLength: number): StringSchema<Src>;
|
|
110
|
+
/**
|
|
111
|
+
* Validate that the string is at most `maxLength` characters long.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const schema = s.string().maxLength(60);
|
|
115
|
+
* export default c.define("/example.val.ts", schema, "A title that fits");
|
|
116
|
+
*/
|
|
79
117
|
maxLength(maxLength: number): StringSchema<Src>;
|
|
118
|
+
/**
|
|
119
|
+
* Validate that the string matches `regexp`.
|
|
120
|
+
*
|
|
121
|
+
* `message` is what the editor is shown when it does not match. Without one
|
|
122
|
+
* the error names the pattern, which is rarely what a non-developer needs.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* const schema = s
|
|
126
|
+
* .string()
|
|
127
|
+
* .regexp(/^[a-z0-9-]+$/, "Lower case letters, digits and dashes only");
|
|
128
|
+
* export default c.define("/example.val.ts", schema, "my-slug");
|
|
129
|
+
*/
|
|
80
130
|
regexp(regexp: RegExp, message?: string): StringSchema<Src>;
|
|
131
|
+
/**
|
|
132
|
+
* Add a custom validation rule to this field.
|
|
133
|
+
*
|
|
134
|
+
* The function is called with the field's value and returns `false` when the
|
|
135
|
+
* value is fine, or a STRING with the message to show when it is not. Call it
|
|
136
|
+
* more than once to add more rules — they all run, and every message is
|
|
137
|
+
* reported.
|
|
138
|
+
*
|
|
139
|
+
* Write the check as a ternary, not as `ok || "message"`: that returns `true`
|
|
140
|
+
* when the value is fine, and `true` is not one of the two answers.
|
|
141
|
+
*
|
|
142
|
+
* Validation runs in the Studio as you type, in `npx val validate` and
|
|
143
|
+
* before a publish.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* const schema = s.string().validate((val) =>
|
|
147
|
+
* val.trim() === val ? false : "Must not start or end with a space",
|
|
148
|
+
* );
|
|
149
|
+
* export default c.define("/example.val.ts", schema, "Hello");
|
|
150
|
+
*/
|
|
81
151
|
validate(validationFunction: (src: Src) => false | string): StringSchema<Src>;
|
|
82
152
|
protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
|
|
83
153
|
protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
|
|
84
154
|
nullable(): StringSchema<Src | null>;
|
|
85
155
|
readonly(isReadonly?: boolean): StringSchema<Src>;
|
|
86
156
|
hidden(isHidden?: boolean): StringSchema<Src>;
|
|
157
|
+
/**
|
|
158
|
+
* Do not stega encode this string.
|
|
159
|
+
*
|
|
160
|
+
* Val normally encodes an invisible pointer back to the source into every
|
|
161
|
+
* string it hands your app, which is what makes click-to-edit work. A raw
|
|
162
|
+
* string is handed over exactly as written — use it wherever the value is
|
|
163
|
+
* not rendered as visible text: a slug, a class name, an `id`, a URL,
|
|
164
|
+
* anything parsed or compared.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* const schema = s.object({
|
|
168
|
+
* title: s.string(),
|
|
169
|
+
* slug: s.string().raw(),
|
|
170
|
+
* });
|
|
171
|
+
* export default c.define("/example.val.ts", schema, {
|
|
172
|
+
* title: "Hello",
|
|
173
|
+
* slug: "hello",
|
|
174
|
+
* });
|
|
175
|
+
*/
|
|
87
176
|
raw(): StringSchema<Src extends null ? RawString | null : RawString>;
|
|
88
177
|
protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
|
|
89
178
|
protected executeSerialize(): SerializedSchema;
|
|
@@ -107,12 +196,22 @@ export declare class StringSchema<Src extends string | null> extends Schema<Src>
|
|
|
107
196
|
*
|
|
108
197
|
* Static configuration, not a callback — see `render.ts`. What a CONTAINER
|
|
109
198
|
* shows for its items is a `preview`, which is a different thing entirely.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* const schema = s.array(s.string().render({ as: "inline" }));
|
|
202
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
110
203
|
*/
|
|
111
204
|
render(input: FieldRender): StringSchema<Src>;
|
|
112
205
|
/**
|
|
113
206
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
114
207
|
* sortable list, a reference dropdown, a search hit. Never how the field
|
|
115
208
|
* itself is edited (that is `render`). See `preview.ts`.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* const schema = s.array(
|
|
212
|
+
* s.string().preview(({ val }) => ({ title: val })),
|
|
213
|
+
* );
|
|
214
|
+
* export default c.define("/example.val.ts", schema, ["First", "Second"]);
|
|
116
215
|
*/
|
|
117
216
|
preview(select: ItemPreviewInput<Src>): StringSchema<Src>;
|
|
118
217
|
protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
|