@valbuild/core 0.124.0 → 0.126.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/dist/declarations/src/getSourcePathFromRoute.d.ts +12 -3
  3. package/dist/declarations/src/index.d.ts +7 -3
  4. package/dist/declarations/src/initSchema.d.ts +46 -15
  5. package/dist/declarations/src/initVal.d.ts +108 -0
  6. package/dist/declarations/src/render.d.ts +5 -4
  7. package/dist/declarations/src/router.d.ts +45 -0
  8. package/dist/declarations/src/schema/array.d.ts +65 -0
  9. package/dist/declarations/src/schema/boolean.d.ts +44 -0
  10. package/dist/declarations/src/schema/code.d.ts +63 -0
  11. package/dist/declarations/src/schema/color.d.ts +54 -0
  12. package/dist/declarations/src/schema/date.d.ts +64 -2
  13. package/dist/declarations/src/schema/datetime.d.ts +87 -2
  14. package/dist/declarations/src/schema/discriminatedUnion.d.ts +166 -0
  15. package/dist/declarations/src/schema/enum.d.ts +122 -0
  16. package/dist/declarations/src/schema/file.d.ts +77 -0
  17. package/dist/declarations/src/schema/image.d.ts +102 -0
  18. package/dist/declarations/src/schema/index.d.ts +42 -2
  19. package/dist/declarations/src/schema/keyOf.d.ts +50 -0
  20. package/dist/declarations/src/schema/literal.d.ts +46 -0
  21. package/dist/declarations/src/schema/number.d.ts +58 -0
  22. package/dist/declarations/src/schema/object.d.ts +63 -0
  23. package/dist/declarations/src/schema/record.d.ts +136 -0
  24. package/dist/declarations/src/schema/richtext.d.ts +78 -0
  25. package/dist/declarations/src/schema/route.d.ts +44 -0
  26. package/dist/declarations/src/schema/string.d.ts +99 -0
  27. package/dist/declarations/src/schema/union.d.ts +54 -91
  28. package/dist/{index-22a40d42.cjs.prod.js → index-6db78f3c.cjs.prod.js} +2161 -423
  29. package/dist/{index-fcd087bd.cjs.dev.js → index-b41b638f.cjs.dev.js} +2161 -423
  30. package/dist/{index-9c14df37.esm.js → index-cd25c2dc.esm.js} +2155 -423
  31. package/dist/valbuild-core.cjs.dev.js +8 -2
  32. package/dist/valbuild-core.cjs.prod.js +8 -2
  33. package/dist/valbuild-core.esm.js +1 -1
  34. package/package.json +1 -1
  35. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  36. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  37. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -0,0 +1,122 @@
1
+ import { CustomValidateFunction, Schema, SchemaAssertResult } from "./index.js";
2
+ import { ItemPreviewInput, PreviewItem, ReifiedPreview } from "../preview.js";
3
+ import { FieldRender } from "../render.js";
4
+ import { SourcePath } from "../val/index.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
+ export type SerializedEnumSchema = {
7
+ type: "enum";
8
+ /** Static layout config, carried whole in the serialized schema — see `render.ts`. */
9
+ render?: FieldRender;
10
+ /** Set when this schema declares a `preview`. The closure itself cannot serialize. */
11
+ preview?: true;
12
+ /**
13
+ * Every value this field may take, in declaration order — which is the order
14
+ * the editor's dropdown offers them in.
15
+ */
16
+ values: string[];
17
+ opt: boolean;
18
+ customValidate?: boolean;
19
+ readonly?: boolean;
20
+ hidden?: boolean;
21
+ description?: string;
22
+ };
23
+ /**
24
+ * One of a fixed set of strings.
25
+ *
26
+ * The values are the schema — there are no member schemas to descend into, so
27
+ * this is a LEAF, like `s.string()` with a closed domain. That is the whole
28
+ * difference from {@link DiscriminatedUnionSchema}, and the reason the two are
29
+ * separate: everything that walks a schema tree has to recurse into a
30
+ * discriminated union's variants and must not try to recurse into these.
31
+ */
32
+ export declare class EnumSchema<Src extends string | null> extends Schema<Src> {
33
+ private readonly values;
34
+ private readonly opt;
35
+ private readonly customValidateFunctions;
36
+ private readonly isReadonly;
37
+ private readonly isHidden;
38
+ private readonly description?;
39
+ private readonly renderInput;
40
+ private readonly previewInput;
41
+ constructor(values: readonly string[], opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
42
+ /**
43
+ * Describe this field.
44
+ *
45
+ * The description is shown next to the field's label in the Val editor, so it is
46
+ * where you say what an editor needs to know but the field name cannot carry. It
47
+ * also travels in the serialized schema, which is what the AI assistant and the
48
+ * MCP tools read.
49
+ *
50
+ * Pass `null` to clear a description set earlier.
51
+ *
52
+ * @example
53
+ * const schema = s
54
+ * .enum("draft", "published")
55
+ * .describe("Only published pages are built");
56
+ * export default c.define("/example.val.ts", schema, "draft");
57
+ */
58
+ describe(description: string | null): EnumSchema<Src>;
59
+ /**
60
+ * Add a custom validation rule to this field.
61
+ *
62
+ * The function is called with the field's value and returns `false` when the
63
+ * value is fine, or a STRING with the message to show when it is not. Call it
64
+ * more than once to add more rules — they all run, and every message is
65
+ * reported.
66
+ *
67
+ * Validation runs in the Studio as you type, in `npx val validate` and before a
68
+ * publish.
69
+ *
70
+ * @example
71
+ * const schema = s
72
+ * .enum("draft", "published")
73
+ * .validate((val) =>
74
+ * val === "published" ? "Publishing is frozen this week" : false,
75
+ * );
76
+ * export default c.define("/example.val.ts", schema, "draft");
77
+ */
78
+ validate(validationFunction: (src: Src) => false | string): EnumSchema<Src>;
79
+ protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
80
+ protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
81
+ nullable(): EnumSchema<Src | null>;
82
+ readonly(isReadonly?: boolean): EnumSchema<Src>;
83
+ hidden(isHidden?: boolean): EnumSchema<Src>;
84
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
85
+ /**
86
+ * How this field is laid out in the editor when it is the item of an array
87
+ * or record: `{ as: "inline" }` renders the field itself inside each row,
88
+ * instead of a preview row that navigates to it.
89
+ *
90
+ * Static configuration, not a callback — see `render.ts`.
91
+ *
92
+ * @example
93
+ * const schema = s.array(
94
+ * s.enum("draft", "published").render({ as: "inline" }),
95
+ * );
96
+ * export default c.define("/example.val.ts", schema, ["draft"]);
97
+ */
98
+ render(input: FieldRender): EnumSchema<Src>;
99
+ /**
100
+ * How this VALUE is shown where a preview of it is needed — a row in a
101
+ * sortable list, a reference dropdown, a search hit. Never how the field
102
+ * itself is edited (that is `render`). See `preview.ts`.
103
+ *
104
+ * @example
105
+ * const schema = s.array(
106
+ * s.enum("draft", "published").preview(({ val }) => ({ title: val })),
107
+ * );
108
+ * export default c.define("/example.val.ts", schema, ["draft"]);
109
+ */
110
+ preview(select: ItemPreviewInput<Src>): EnumSchema<Src>;
111
+ protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
112
+ protected declaresItemPreview(): boolean;
113
+ protected executeSerialize(): SerializedEnumSchema;
114
+ protected executePreview(): ReifiedPreview;
115
+ }
116
+ /**
117
+ * Define a string that must be one of a fixed set of values.
118
+ *
119
+ * Named `enumSchema` rather than `enum` because `enum` is a reserved word and
120
+ * cannot be a binding name; it is exposed as `s.enum`.
121
+ */
122
+ export declare const enumSchema: <T extends string>(...values: [T, ...T[]]) => EnumSchema<T>;
@@ -37,8 +37,71 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
37
37
  private readonly renderInput;
38
38
  private readonly previewInput;
39
39
  constructor(options?: FileOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, FilesEntryMetadata>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
40
+ /**
41
+ * Describe this field.
42
+ *
43
+ * The description is shown next to the field's label in the Val editor, so
44
+ * it is where you say what an editor needs to know but the field name cannot
45
+ * carry. It also travels in the serialized schema, which is what the AI
46
+ * assistant and the MCP tools read.
47
+ *
48
+ * Pass `null` to clear a description set earlier.
49
+ *
50
+ * @example
51
+ * const schema = s.file().describe("The PDF offered for download");
52
+ * export default c.define("/example.val.ts", schema, {
53
+ * path: "/public/val/example.pdf",
54
+ * mimeType: "application/pdf",
55
+ * });
56
+ */
40
57
  describe(description: string | null): FileSchema<Src>;
58
+ /**
59
+ * Store the file on Val's remote content host instead of in your repository.
60
+ *
61
+ * The bytes still go into the patch store when the file is uploaded — the
62
+ * push to the remote host happens at publish. What changes is where the
63
+ * published file lives: `path` becomes a remote URL rather than a path under
64
+ * `/public`, so the repository does not grow with every upload.
65
+ *
66
+ * The `path` of a remote file is a URL on the content host, and it is not
67
+ * something to write by hand: upload the file in the Studio, or write a
68
+ * local path and let `npx val validate --fix` upload it and rewrite the
69
+ * `path` to the ref below.
70
+ *
71
+ * @example
72
+ * const schema = s.file({ accept: "application/pdf" }).remote();
73
+ * export default c.define("/example.val.ts", schema, {
74
+ * path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/example.pdf",
75
+ * mimeType: "application/pdf",
76
+ * });
77
+ */
41
78
  remote(): FileSchema<Src>;
79
+ /**
80
+ * Add a custom validation rule to this field.
81
+ *
82
+ * The function is called with the field's value and returns `false` when the
83
+ * value is fine, or a STRING with the message to show when it is not. Call it
84
+ * more than once to add more rules — they all run, and every message is
85
+ * reported.
86
+ *
87
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
88
+ * when the value is fine, and `true` is not one of the two answers.
89
+ *
90
+ * Validation runs in the Studio as you type, in `npx val validate` and
91
+ * before a publish.
92
+ *
93
+ * The second argument carries the `path` of the field being validated, for
94
+ * when the message needs to say where the problem is.
95
+ *
96
+ * @example
97
+ * const schema = s.file().validate((val) =>
98
+ * val.path.endsWith(".pdf") ? false : "Must be a PDF",
99
+ * );
100
+ * export default c.define("/example.val.ts", schema, {
101
+ * path: "/public/val/example.pdf",
102
+ * mimeType: "application/pdf",
103
+ * });
104
+ */
42
105
  validate(validationFunction: CustomValidateFunction<Src>): FileSchema<Src>;
43
106
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
44
107
  /**
@@ -57,12 +120,26 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
57
120
  * instead of a preview row that navigates to it.
58
121
  *
59
122
  * Static configuration, not a callback — see `render.ts`.
123
+ *
124
+ * @example
125
+ * const schema = s.array(s.file().render({ as: "inline" }));
126
+ * export default c.define("/example.val.ts", schema, [
127
+ * { path: "/public/val/example.pdf", mimeType: "application/pdf" },
128
+ * ]);
60
129
  */
61
130
  render(input: FieldRender): FileSchema<Src>;
62
131
  /**
63
132
  * How this VALUE is shown where a preview of it is needed — a row in a
64
133
  * sortable list, a reference dropdown, a search hit. Never how the field
65
134
  * itself is edited (that is `render`). See `preview.ts`.
135
+ *
136
+ * @example
137
+ * const schema = s.array(
138
+ * s.file().preview(({ val }) => ({ title: val.path })),
139
+ * );
140
+ * export default c.define("/example.val.ts", schema, [
141
+ * { path: "/public/val/example.pdf", mimeType: "application/pdf" },
142
+ * ]);
66
143
  */
67
144
  preview(select: ItemPreviewInput<Src>): FileSchema<Src>;
68
145
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -82,8 +82,82 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
82
82
  private readonly renderInput;
83
83
  private readonly previewInput;
84
84
  constructor(options?: ImageOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, ImagesEntryMetadata>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
85
+ /**
86
+ * Describe this field.
87
+ *
88
+ * The description is shown next to the field's label in the Val editor, so
89
+ * it is where you say what an editor needs to know but the field name cannot
90
+ * carry. It also travels in the serialized schema, which is what the AI
91
+ * assistant and the MCP tools read.
92
+ *
93
+ * Pass `null` to clear a description set earlier.
94
+ *
95
+ * @example
96
+ * const schema = s
97
+ * .image()
98
+ * .describe("Shown at the top of the page, 16:9 works best");
99
+ * export default c.define("/example.val.ts", schema, {
100
+ * path: "/public/val/example.png",
101
+ * width: 100,
102
+ * height: 100,
103
+ * mimeType: "image/png",
104
+ * });
105
+ */
85
106
  describe(description: string | null): ImageSchema<Src>;
107
+ /**
108
+ * Store the image on Val's remote content host instead of in your repository.
109
+ *
110
+ * The bytes still go into the patch store when the image is uploaded — the
111
+ * push to the remote host happens at publish. What changes is where the
112
+ * published image lives: `path` becomes a remote URL rather than a path
113
+ * under `/public`, so the repository does not grow with every upload.
114
+ *
115
+ * The `path` of a remote image is a URL on the content host, and it is not
116
+ * something to write by hand: upload the image in the Studio, or write a
117
+ * local path and let `npx val validate --fix` upload it and rewrite the
118
+ * `path` to the ref below.
119
+ *
120
+ * @example
121
+ * const schema = s
122
+ * .image({ accept: "image/webp", directory: "/public/val/images" })
123
+ * .remote();
124
+ * export default c.define("/example.val.ts", schema, {
125
+ * 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",
126
+ * width: 100,
127
+ * height: 100,
128
+ * mimeType: "image/webp",
129
+ * });
130
+ */
86
131
  remote(): ImageSchema<Src>;
132
+ /**
133
+ * Add a custom validation rule to this field.
134
+ *
135
+ * The function is called with the field's value and returns `false` when the
136
+ * value is fine, or a STRING with the message to show when it is not. Call it
137
+ * more than once to add more rules — they all run, and every message is
138
+ * reported.
139
+ *
140
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
141
+ * when the value is fine, and `true` is not one of the two answers.
142
+ *
143
+ * Validation runs in the Studio as you type, in `npx val validate` and
144
+ * before a publish.
145
+ *
146
+ * The second argument carries the `path` of the field being validated, for
147
+ * when the message needs to say where the problem is.
148
+ *
149
+ * @example
150
+ * const schema = s.image().validate((val) =>
151
+ * val.alt ? false : "Every image needs alt text",
152
+ * );
153
+ * export default c.define("/example.val.ts", schema, {
154
+ * path: "/public/val/example.png",
155
+ * width: 100,
156
+ * height: 100,
157
+ * mimeType: "image/png",
158
+ * alt: "An example",
159
+ * });
160
+ */
87
161
  validate(validationFunction: CustomValidateFunction<Src>): ImageSchema<Src>;
88
162
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
89
163
  /**
@@ -102,12 +176,40 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
102
176
  * instead of a preview row that navigates to it.
103
177
  *
104
178
  * Static configuration, not a callback — see `render.ts`.
179
+ *
180
+ * @example
181
+ * const schema = s.array(s.image().render({ as: "inline" }));
182
+ * export default c.define("/example.val.ts", schema, [
183
+ * {
184
+ * path: "/public/val/example.png",
185
+ * width: 100,
186
+ * height: 100,
187
+ * mimeType: "image/png",
188
+ * },
189
+ * ]);
105
190
  */
106
191
  render(input: FieldRender): ImageSchema<Src>;
107
192
  /**
108
193
  * How this VALUE is shown where a preview of it is needed — a row in a
109
194
  * sortable list, a reference dropdown, a search hit. Never how the field
110
195
  * itself is edited (that is `render`). See `preview.ts`.
196
+ *
197
+ * @example
198
+ * const schema = s.array(
199
+ * s.image().preview(({ val }) => ({
200
+ * title: val.alt ?? "Image",
201
+ * image: val,
202
+ * })),
203
+ * );
204
+ * export default c.define("/example.val.ts", schema, [
205
+ * {
206
+ * path: "/public/val/example.png",
207
+ * width: 100,
208
+ * height: 100,
209
+ * mimeType: "image/png",
210
+ * alt: "An example",
211
+ * },
212
+ * ]);
111
213
  */
112
214
  preview(select: ItemPreviewInput<Src>): ImageSchema<Src>;
113
215
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -11,7 +11,8 @@ import { SerializedObjectSchema } from "./object.js";
11
11
  import { SerializedRecordSchema } from "./record.js";
12
12
  import { SerializedRichTextSchema } from "./richtext.js";
13
13
  import { RawString, SerializedStringSchema } from "./string.js";
14
- import { SerializedUnionSchema } from "./union.js";
14
+ import { SerializedDiscriminatedUnionSchema } from "./discriminatedUnion.js";
15
+ import { SerializedEnumSchema } from "./enum.js";
15
16
  import { SerializedCodeSchema } from "./code.js";
16
17
  import { SerializedColorSchema } from "./color.js";
17
18
  import { SerializedDateSchema } from "./date.js";
@@ -22,7 +23,7 @@ import { ValidationError, ValidationErrors } from "./validation/ValidationError.
22
23
  import { FileSource } from "../source/media.js";
23
24
  import { GenericRichTextSourceNode, RichTextSource } from "../source/richtext.js";
24
25
  import { ReifiedPreview, PreviewScope, PreviewItem } from "../preview.js";
25
- export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedUnionSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedColorSchema | SerializedCodeSchema | SerializedRouteSchema | SerializedSettingsSchema | SerializedImageSchema;
26
+ export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedDiscriminatedUnionSchema | SerializedEnumSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedColorSchema | SerializedCodeSchema | SerializedRouteSchema | SerializedSettingsSchema | SerializedImageSchema;
26
27
  type Primitives = number | string | boolean | null | FileSource;
27
28
  export type AssertError = {
28
29
  message: string;
@@ -92,6 +93,25 @@ export declare abstract class Schema<Src extends SelectorSource> {
92
93
  * For example, if you have an object schema, you must assert each key / value pair manually.
93
94
  */
94
95
  protected abstract executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
96
+ /**
97
+ * Allow `null` as a value for this field.
98
+ *
99
+ * The editor gets a way to clear the field, and the type of the source
100
+ * widens to include `null` — so consuming code has to handle it.
101
+ *
102
+ * Declare `.validate(...)` AFTER `.nullable()`: on most schema types a
103
+ * validator added before it is not carried over.
104
+ *
105
+ * @example
106
+ * const schema = s.object({
107
+ * title: s.string(),
108
+ * subtitle: s.string().nullable(),
109
+ * });
110
+ * export default c.define("/example.val.ts", schema, {
111
+ * title: "Hello",
112
+ * subtitle: null,
113
+ * });
114
+ */
95
115
  abstract nullable(): Schema<Src | null>;
96
116
  /**
97
117
  * Mark this field as read-only in the Val editor.
@@ -102,6 +122,16 @@ export declare abstract class Schema<Src extends SelectorSource> {
102
122
  * The flag defaults to `true`, so `.readonly()` and `.readonly(true)` are the
103
123
  * same thing. `.readonly(false)` leaves the field editable, which is what a
104
124
  * schema is anyway - pass it when the decision comes from a variable.
125
+ *
126
+ * @example
127
+ * const schema = s.object({
128
+ * id: s.string().readonly(),
129
+ * title: s.string(),
130
+ * });
131
+ * export default c.define("/example.val.ts", schema, {
132
+ * id: "generated-by-the-build",
133
+ * title: "Hello",
134
+ * });
105
135
  */
106
136
  abstract readonly(isReadonly?: boolean): Schema<Src>;
107
137
  /**
@@ -113,6 +143,16 @@ export declare abstract class Schema<Src extends SelectorSource> {
113
143
  * The flag defaults to `true`, so `.hidden()` and `.hidden(true)` are the
114
144
  * same thing. `.hidden(false)` leaves the field visible, which is what a
115
145
  * schema is anyway - pass it when the decision comes from a variable.
146
+ *
147
+ * @example
148
+ * const schema = s.object({
149
+ * title: s.string(),
150
+ * internalNotes: s.string().hidden(),
151
+ * });
152
+ * export default c.define("/example.val.ts", schema, {
153
+ * title: "Hello",
154
+ * internalNotes: "Not shown in the editor",
155
+ * });
116
156
  */
117
157
  abstract hidden(isHidden?: boolean): Schema<Src>;
118
158
  protected abstract executeSerialize(): SerializedSchema;
@@ -42,7 +42,45 @@ export declare class KeyOfSchema<Sel extends GenericSelector<SourceObject>, Src
42
42
  private readonly renderInput;
43
43
  private readonly previewInput;
44
44
  constructor(schema?: SerializedRefSchema | undefined, sourcePath?: SourcePath | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
45
+ /**
46
+ * Describe this field.
47
+ *
48
+ * The description is shown next to the field's label in the Val editor, so
49
+ * it is where you say what an editor needs to know but the field name cannot
50
+ * carry. It also travels in the serialized schema, which is what the AI
51
+ * assistant and the MCP tools read.
52
+ *
53
+ * Pass `null` to clear a description set earlier.
54
+ *
55
+ * @example
56
+ * import authorsVal from "./authors.val"; // a record module
57
+ * const schema = s.keyOf(authorsVal).describe("Who wrote this post");
58
+ * export default c.define("/example.val.ts", schema, "ada");
59
+ */
45
60
  describe(description: string | null): KeyOfSchema<Sel, Src>;
61
+ /**
62
+ * Add a custom validation rule to this field.
63
+ *
64
+ * The function is called with the field's value and returns `false` when the
65
+ * value is fine, or a STRING with the message to show when it is not. Call it
66
+ * more than once to add more rules — they all run, and every message is
67
+ * reported.
68
+ *
69
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
70
+ * when the value is fine, and `true` is not one of the two answers.
71
+ *
72
+ * Validation runs in the Studio as you type, in `npx val validate` and
73
+ * before a publish.
74
+ *
75
+ * @example
76
+ * import authorsVal from "./authors.val"; // a record module
77
+ * const schema = s
78
+ * .keyOf(authorsVal)
79
+ * .validate((val) =>
80
+ * val === "placeholder" ? "Pick a real author" : false,
81
+ * );
82
+ * export default c.define("/example.val.ts", schema, "ada");
83
+ */
46
84
  validate(validationFunction: (src: Src) => false | string): KeyOfSchema<Sel, Src>;
47
85
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
48
86
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
@@ -56,12 +94,24 @@ export declare class KeyOfSchema<Sel extends GenericSelector<SourceObject>, Src
56
94
  * instead of a preview row that navigates to it.
57
95
  *
58
96
  * Static configuration, not a callback — see `render.ts`.
97
+ *
98
+ * @example
99
+ * import authorsVal from "./authors.val"; // a record module
100
+ * const schema = s.array(s.keyOf(authorsVal).render({ as: "inline" }));
101
+ * export default c.define("/example.val.ts", schema, ["ada"]);
59
102
  */
60
103
  render(input: FieldRender): KeyOfSchema<Sel, Src>;
61
104
  /**
62
105
  * How this VALUE is shown where a preview of it is needed — a row in a
63
106
  * sortable list, a reference dropdown, a search hit. Never how the field
64
107
  * itself is edited (that is `render`). See `preview.ts`.
108
+ *
109
+ * @example
110
+ * import authorsVal from "./authors.val"; // a record module
111
+ * const schema = s.array(
112
+ * s.keyOf(authorsVal).preview(({ val }) => ({ title: val })),
113
+ * );
114
+ * export default c.define("/example.val.ts", schema, ["ada"]);
65
115
  */
66
116
  preview(select: ItemPreviewInput<Src>): KeyOfSchema<Sel, Src>;
67
117
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -26,7 +26,43 @@ export declare class LiteralSchema<Src extends string | null> extends Schema<Src
26
26
  private readonly renderInput;
27
27
  private readonly previewInput;
28
28
  constructor(value: string, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
29
+ /**
30
+ * Describe this field.
31
+ *
32
+ * The description is shown next to the field's label in the Val editor, so
33
+ * it is where you say what an editor needs to know but the field name cannot
34
+ * carry. It also travels in the serialized schema, which is what the AI
35
+ * assistant and the MCP tools read.
36
+ *
37
+ * Pass `null` to clear a description set earlier.
38
+ *
39
+ * @example
40
+ * const schema = s
41
+ * .literal("hero")
42
+ * .describe("The block type — it identifies the variant");
43
+ * export default c.define("/example.val.ts", schema, "hero");
44
+ */
29
45
  describe(description: string | null): LiteralSchema<Src>;
46
+ /**
47
+ * Add a custom validation rule to this field.
48
+ *
49
+ * The function is called with the field's value and returns `false` when the
50
+ * value is fine, or a STRING with the message to show when it is not. Call it
51
+ * more than once to add more rules — they all run, and every message is
52
+ * reported.
53
+ *
54
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
55
+ * when the value is fine, and `true` is not one of the two answers.
56
+ *
57
+ * Validation runs in the Studio as you type, in `npx val validate` and
58
+ * before a publish.
59
+ *
60
+ * @example
61
+ * const schema = s.literal("hero").validate((val) =>
62
+ * val === "hero" ? false : "Unknown block type",
63
+ * );
64
+ * export default c.define("/example.val.ts", schema, "hero");
65
+ */
30
66
  validate(validationFunction: (src: Src) => false | string): LiteralSchema<Src>;
31
67
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
32
68
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
@@ -40,12 +76,22 @@ export declare class LiteralSchema<Src extends string | null> extends Schema<Src
40
76
  * instead of a preview row that navigates to it.
41
77
  *
42
78
  * Static configuration, not a callback — see `render.ts`.
79
+ *
80
+ * @example
81
+ * const schema = s.array(s.literal("hero").render({ as: "inline" }));
82
+ * export default c.define("/example.val.ts", schema, ["hero"]);
43
83
  */
44
84
  render(input: FieldRender): LiteralSchema<Src>;
45
85
  /**
46
86
  * How this VALUE is shown where a preview of it is needed — a row in a
47
87
  * sortable list, a reference dropdown, a search hit. Never how the field
48
88
  * itself is edited (that is `render`). See `preview.ts`.
89
+ *
90
+ * @example
91
+ * const schema = s.array(
92
+ * s.literal("hero").preview(({ val }) => ({ title: val })),
93
+ * );
94
+ * export default c.define("/example.val.ts", schema, ["hero"]);
49
95
  */
50
96
  preview(select: ItemPreviewInput<Src>): LiteralSchema<Src>;
51
97
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -30,14 +30,62 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
30
30
  private readonly renderInput;
31
31
  private readonly previewInput;
32
32
  constructor(options?: NumberOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
33
+ /**
34
+ * Describe this field.
35
+ *
36
+ * The description is shown next to the field's label in the Val editor, so
37
+ * it is where you say what an editor needs to know but the field name cannot
38
+ * carry. It also travels in the serialized schema, which is what the AI
39
+ * assistant and the MCP tools read.
40
+ *
41
+ * Pass `null` to clear a description set earlier.
42
+ *
43
+ * @example
44
+ * const schema = s.number().describe("How many columns the grid uses");
45
+ * export default c.define("/example.val.ts", schema, 3);
46
+ */
33
47
  describe(description: string | null): NumberSchema<Src>;
48
+ /**
49
+ * Add a custom validation rule to this field.
50
+ *
51
+ * The function is called with the field's value and returns `false` when the
52
+ * value is fine, or a STRING with the message to show when it is not. Call it
53
+ * more than once to add more rules — they all run, and every message is
54
+ * reported.
55
+ *
56
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
57
+ * when the value is fine, and `true` is not one of the two answers.
58
+ *
59
+ * Validation runs in the Studio as you type, in `npx val validate` and
60
+ * before a publish.
61
+ *
62
+ * @example
63
+ * const schema = s.number().validate((val) =>
64
+ * Number.isInteger(val) ? false : "Must be a whole number",
65
+ * );
66
+ * export default c.define("/example.val.ts", schema, 3);
67
+ */
34
68
  validate(validationFunction: (src: Src) => false | string): NumberSchema<Src>;
35
69
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
36
70
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
37
71
  nullable(): NumberSchema<Src | null>;
38
72
  readonly(isReadonly?: boolean): NumberSchema<Src>;
39
73
  hidden(isHidden?: boolean): NumberSchema<Src>;
74
+ /**
75
+ * Validate that the number is at most `max` (inclusive).
76
+ *
77
+ * @example
78
+ * const schema = s.number().max(4);
79
+ * export default c.define("/example.val.ts", schema, 3);
80
+ */
40
81
  max(max: number): NumberSchema<Src>;
82
+ /**
83
+ * Validate that the number is at least `min` (inclusive).
84
+ *
85
+ * @example
86
+ * const schema = s.number().min(1).max(4);
87
+ * export default c.define("/example.val.ts", schema, 3);
88
+ */
41
89
  min(min: number): NumberSchema<Src>;
42
90
  protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
43
91
  /**
@@ -46,12 +94,22 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
46
94
  * instead of a preview row that navigates to it.
47
95
  *
48
96
  * Static configuration, not a callback — see `render.ts`.
97
+ *
98
+ * @example
99
+ * const schema = s.array(s.number().render({ as: "inline" }));
100
+ * export default c.define("/example.val.ts", schema, [1, 2]);
49
101
  */
50
102
  render(input: FieldRender): NumberSchema<Src>;
51
103
  /**
52
104
  * How this VALUE is shown where a preview of it is needed — a row in a
53
105
  * sortable list, a reference dropdown, a search hit. Never how the field
54
106
  * itself is edited (that is `render`). See `preview.ts`.
107
+ *
108
+ * @example
109
+ * const schema = s.array(
110
+ * s.number().preview(({ val }) => ({ title: String(val) })),
111
+ * );
112
+ * export default c.define("/example.val.ts", schema, [1, 2]);
55
113
  */
56
114
  preview(select: ItemPreviewInput<Src>): NumberSchema<Src>;
57
115
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;