@valbuild/core 0.125.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 (35) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/declarations/src/index.d.ts +3 -1
  3. package/dist/declarations/src/initSchema.d.ts +46 -15
  4. package/dist/declarations/src/initVal.d.ts +108 -0
  5. package/dist/declarations/src/render.d.ts +5 -4
  6. package/dist/declarations/src/schema/array.d.ts +65 -0
  7. package/dist/declarations/src/schema/boolean.d.ts +44 -0
  8. package/dist/declarations/src/schema/code.d.ts +63 -0
  9. package/dist/declarations/src/schema/color.d.ts +54 -0
  10. package/dist/declarations/src/schema/date.d.ts +64 -2
  11. package/dist/declarations/src/schema/datetime.d.ts +87 -2
  12. package/dist/declarations/src/schema/discriminatedUnion.d.ts +166 -0
  13. package/dist/declarations/src/schema/enum.d.ts +122 -0
  14. package/dist/declarations/src/schema/file.d.ts +77 -0
  15. package/dist/declarations/src/schema/image.d.ts +102 -0
  16. package/dist/declarations/src/schema/index.d.ts +42 -2
  17. package/dist/declarations/src/schema/keyOf.d.ts +50 -0
  18. package/dist/declarations/src/schema/literal.d.ts +46 -0
  19. package/dist/declarations/src/schema/number.d.ts +58 -0
  20. package/dist/declarations/src/schema/object.d.ts +63 -0
  21. package/dist/declarations/src/schema/record.d.ts +136 -0
  22. package/dist/declarations/src/schema/richtext.d.ts +78 -0
  23. package/dist/declarations/src/schema/route.d.ts +44 -0
  24. package/dist/declarations/src/schema/string.d.ts +99 -0
  25. package/dist/declarations/src/schema/union.d.ts +54 -91
  26. package/dist/{index-a3846321.cjs.prod.js → index-6db78f3c.cjs.prod.js} +1953 -449
  27. package/dist/{index-daa122af.cjs.dev.js → index-b41b638f.cjs.dev.js} +1953 -449
  28. package/dist/{index-915dd675.esm.js → index-cd25c2dc.esm.js} +1952 -449
  29. package/dist/valbuild-core.cjs.dev.js +3 -2
  30. package/dist/valbuild-core.cjs.prod.js +3 -2
  31. package/dist/valbuild-core.esm.js +1 -1
  32. package/package.json +1 -1
  33. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  34. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  35. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -50,7 +50,47 @@ export declare class ColorSchema<Src extends string | null> extends Schema<Src>
50
50
  private readonly renderInput;
51
51
  private readonly previewInput;
52
52
  constructor(options?: ColorOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
53
+ /**
54
+ * Describe this field.
55
+ *
56
+ * The description is shown next to the field's label in the Val editor, so
57
+ * it is where you say what an editor needs to know but the field name cannot
58
+ * carry. It also travels in the serialized schema, which is what the AI
59
+ * assistant and the MCP tools read.
60
+ *
61
+ * Pass `null` to clear a description set earlier.
62
+ *
63
+ * @example
64
+ * const schema = s.color().describe("Background of the hero section");
65
+ * export default c.define(
66
+ * "/example.val.ts",
67
+ * schema,
68
+ * "hsl(217.22 91.22% 59.8%)",
69
+ * );
70
+ */
53
71
  describe(description: string | null): ColorSchema<Src>;
72
+ /**
73
+ * Add a custom validation rule to this field.
74
+ *
75
+ * The function is called with the field's value and returns `false` when the
76
+ * value is fine, or a STRING with the message to show when it is not. Call it
77
+ * more than once to add more rules — they all run, and every message is
78
+ * reported.
79
+ *
80
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
81
+ * when the value is fine, and `true` is not one of the two answers.
82
+ *
83
+ * Validation runs in the Studio as you type, in `npx val validate` and
84
+ * before a publish.
85
+ *
86
+ * @example
87
+ * const schema = s
88
+ * .color({ format: "hex" })
89
+ * .validate((val) =>
90
+ * val === val.toLowerCase() ? false : "Write hex in lower case",
91
+ * );
92
+ * export default c.define("/example.val.ts", schema, "#3b82f6");
93
+ */
54
94
  validate(validationFunction: (src: Src) => false | string): ColorSchema<Src>;
55
95
  protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
56
96
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
@@ -64,12 +104,26 @@ export declare class ColorSchema<Src extends string | null> extends Schema<Src>
64
104
  * instead of a preview row that navigates to it.
65
105
  *
66
106
  * Static configuration, not a callback — see `render.ts`.
107
+ *
108
+ * @example
109
+ * const schema = s.array(s.color().render({ as: "inline" }));
110
+ * export default c.define("/example.val.ts", schema, [
111
+ * "hsl(217.22 91.22% 59.8%)",
112
+ * ]);
67
113
  */
68
114
  render(input: FieldRender): ColorSchema<Src>;
69
115
  /**
70
116
  * How this VALUE is shown where a preview of it is needed — a row in a
71
117
  * sortable list, a reference dropdown, a search hit. Never how the field
72
118
  * itself is edited (that is `render`). See `preview.ts`.
119
+ *
120
+ * @example
121
+ * const schema = s.array(
122
+ * s.color().preview(({ val }) => ({ title: val })),
123
+ * );
124
+ * export default c.define("/example.val.ts", schema, [
125
+ * "hsl(217.22 91.22% 59.8%)",
126
+ * ]);
73
127
  */
74
128
  preview(select: ItemPreviewInput<Src>): ColorSchema<Src>;
75
129
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -9,14 +9,14 @@ type DateOptions = {
9
9
  * Validate that the date is this date or after (inclusive).
10
10
  *
11
11
  * @example
12
- * 2021-01-01
12
+ * "2021-01-01"
13
13
  */
14
14
  from?: string;
15
15
  /**
16
16
  * Validate that the date is this date or before (inclusive).
17
17
  *
18
18
  * @example
19
- * 2021-01-01
19
+ * "2021-01-01"
20
20
  */
21
21
  to?: string;
22
22
  };
@@ -43,11 +43,63 @@ export declare class DateSchema<Src extends string | null> extends Schema<Src> {
43
43
  private readonly renderInput;
44
44
  private readonly previewInput;
45
45
  constructor(options?: DateOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
46
+ /**
47
+ * Describe this field.
48
+ *
49
+ * The description is shown next to the field's label in the Val editor, so
50
+ * it is where you say what an editor needs to know but the field name cannot
51
+ * carry. It also travels in the serialized schema, which is what the AI
52
+ * assistant and the MCP tools read.
53
+ *
54
+ * Pass `null` to clear a description set earlier.
55
+ *
56
+ * @example
57
+ * const schema = s.date().describe("First day the campaign is live");
58
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
59
+ */
46
60
  describe(description: string | null): DateSchema<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
+ * const schema = s.date().validate((val) =>
77
+ * val >= "2025-01-01" ? false : "Must be in 2025 or later",
78
+ * );
79
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
80
+ */
47
81
  validate(validationFunction: (src: Src) => false | string): DateSchema<Src>;
48
82
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
49
83
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
84
+ /**
85
+ * Validate that the date is this date or after (inclusive).
86
+ *
87
+ * Written as `YYYY-MM-DD`, the same shape the value has.
88
+ *
89
+ * @example
90
+ * const schema = s.date().from("2025-01-01");
91
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
92
+ */
50
93
  from(from: string): DateSchema<Src>;
94
+ /**
95
+ * Validate that the date is this date or before (inclusive).
96
+ *
97
+ * Written as `YYYY-MM-DD`, the same shape the value has.
98
+ *
99
+ * @example
100
+ * const schema = s.date().from("2025-01-01").to("2025-12-31");
101
+ * export default c.define("/example.val.ts", schema, "2025-06-01");
102
+ */
51
103
  to(to: string): DateSchema<Src>;
52
104
  nullable(): DateSchema<Src | null>;
53
105
  readonly(isReadonly?: boolean): DateSchema<Src>;
@@ -59,12 +111,22 @@ export declare class DateSchema<Src extends string | null> extends Schema<Src> {
59
111
  * instead of a preview row that navigates to it.
60
112
  *
61
113
  * Static configuration, not a callback — see `render.ts`.
114
+ *
115
+ * @example
116
+ * const schema = s.array(s.date().render({ as: "inline" }));
117
+ * export default c.define("/example.val.ts", schema, ["2025-06-01"]);
62
118
  */
63
119
  render(input: FieldRender): DateSchema<Src>;
64
120
  /**
65
121
  * How this VALUE is shown where a preview of it is needed — a row in a
66
122
  * sortable list, a reference dropdown, a search hit. Never how the field
67
123
  * itself is edited (that is `render`). See `preview.ts`.
124
+ *
125
+ * @example
126
+ * const schema = s.array(
127
+ * s.date().preview(({ val }) => ({ title: val })),
128
+ * );
129
+ * export default c.define("/example.val.ts", schema, ["2025-06-01"]);
68
130
  */
69
131
  preview(select: ItemPreviewInput<Src>): DateSchema<Src>;
70
132
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -11,7 +11,7 @@ type DateTimeOptions = {
11
11
  * Accepts any ISO 8601 datetime string parseable by `Date.parse`.
12
12
  *
13
13
  * @example
14
- * 2021-01-01T00:00:00Z
14
+ * "2021-01-01T00:00:00Z"
15
15
  */
16
16
  from?: string;
17
17
  /**
@@ -20,7 +20,7 @@ type DateTimeOptions = {
20
20
  * Accepts any ISO 8601 datetime string parseable by `Date.parse`.
21
21
  *
22
22
  * @example
23
- * 2021-12-31T23:59:59Z
23
+ * "2021-12-31T23:59:59Z"
24
24
  */
25
25
  to?: string;
26
26
  };
@@ -47,11 +47,82 @@ export declare class DateTimeSchema<Src extends string | null> extends Schema<Sr
47
47
  private readonly renderInput;
48
48
  private readonly previewInput;
49
49
  constructor(options?: DateTimeOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
50
+ /**
51
+ * Describe this field.
52
+ *
53
+ * The description is shown next to the field's label in the Val editor, so
54
+ * it is where you say what an editor needs to know but the field name cannot
55
+ * carry. It also travels in the serialized schema, which is what the AI
56
+ * assistant and the MCP tools read.
57
+ *
58
+ * Pass `null` to clear a description set earlier.
59
+ *
60
+ * @example
61
+ * const schema = s.datetime().describe("When the article goes live");
62
+ * export default c.define(
63
+ * "/example.val.ts",
64
+ * schema,
65
+ * "2025-06-01T09:00:00.000Z",
66
+ * );
67
+ */
50
68
  describe(description: string | null): DateTimeSchema<Src>;
69
+ /**
70
+ * Add a custom validation rule to this field.
71
+ *
72
+ * The function is called with the field's value and returns `false` when the
73
+ * value is fine, or a STRING with the message to show when it is not. Call it
74
+ * more than once to add more rules — they all run, and every message is
75
+ * reported.
76
+ *
77
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
78
+ * when the value is fine, and `true` is not one of the two answers.
79
+ *
80
+ * Validation runs in the Studio as you type, in `npx val validate` and
81
+ * before a publish.
82
+ *
83
+ * @example
84
+ * const schema = s.datetime().validate((val) =>
85
+ * val.endsWith("Z") ? false : "Must be in UTC",
86
+ * );
87
+ * export default c.define(
88
+ * "/example.val.ts",
89
+ * schema,
90
+ * "2025-06-01T09:00:00.000Z",
91
+ * );
92
+ */
51
93
  validate(validationFunction: (src: Src) => false | string): DateTimeSchema<Src>;
52
94
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
53
95
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
96
+ /**
97
+ * Validate that the datetime is this datetime or after (inclusive).
98
+ *
99
+ * Any ISO 8601 datetime string `Date.parse` understands.
100
+ *
101
+ * @example
102
+ * const schema = s.datetime().from("2025-01-01T00:00:00Z");
103
+ * export default c.define(
104
+ * "/example.val.ts",
105
+ * schema,
106
+ * "2025-06-01T09:00:00.000Z",
107
+ * );
108
+ */
54
109
  from(from: string): DateTimeSchema<Src>;
110
+ /**
111
+ * Validate that the datetime is this datetime or before (inclusive).
112
+ *
113
+ * Any ISO 8601 datetime string `Date.parse` understands.
114
+ *
115
+ * @example
116
+ * const schema = s
117
+ * .datetime()
118
+ * .from("2025-01-01T00:00:00Z")
119
+ * .to("2025-12-31T23:59:59Z");
120
+ * export default c.define(
121
+ * "/example.val.ts",
122
+ * schema,
123
+ * "2025-06-01T09:00:00.000Z",
124
+ * );
125
+ */
55
126
  to(to: string): DateTimeSchema<Src>;
56
127
  nullable(): DateTimeSchema<Src | null>;
57
128
  readonly(isReadonly?: boolean): DateTimeSchema<Src>;
@@ -63,12 +134,26 @@ export declare class DateTimeSchema<Src extends string | null> extends Schema<Sr
63
134
  * instead of a preview row that navigates to it.
64
135
  *
65
136
  * Static configuration, not a callback — see `render.ts`.
137
+ *
138
+ * @example
139
+ * const schema = s.array(s.datetime().render({ as: "inline" }));
140
+ * export default c.define("/example.val.ts", schema, [
141
+ * "2025-06-01T09:00:00.000Z",
142
+ * ]);
66
143
  */
67
144
  render(input: FieldRender): DateTimeSchema<Src>;
68
145
  /**
69
146
  * How this VALUE is shown where a preview of it is needed — a row in a
70
147
  * sortable list, a reference dropdown, a search hit. Never how the field
71
148
  * itself is edited (that is `render`). See `preview.ts`.
149
+ *
150
+ * @example
151
+ * const schema = s.array(
152
+ * s.datetime().preview(({ val }) => ({ title: val })),
153
+ * );
154
+ * export default c.define("/example.val.ts", schema, [
155
+ * "2025-06-01T09:00:00.000Z",
156
+ * ]);
72
157
  */
73
158
  preview(select: ItemPreviewInput<Src>): DateTimeSchema<Src>;
74
159
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -0,0 +1,166 @@
1
+ import { CustomValidateFunction, Schema, SchemaAssertResult } from "./index.js";
2
+ import { ItemPreviewInput, PreviewItem, ReifiedPreview, PreviewScope } from "../preview.js";
3
+ import { FieldRender } from "../render.js";
4
+ import { SelectorSource } from "../selector/index.js";
5
+ import { SourceObject } from "../source/index.js";
6
+ import { ModuleFilePath, SourcePath } from "../val/index.js";
7
+ import { SerializedObjectSchema } from "./object.js";
8
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
9
+ export type SerializedDiscriminatedUnionSchema = {
10
+ type: "discriminated-union";
11
+ /** Static layout config, carried whole in the serialized schema — see `render.ts`. */
12
+ render?: FieldRender;
13
+ /** Set when this schema declares a `preview`. The closure itself cannot serialize. */
14
+ preview?: true;
15
+ /** The name of the field every variant tags itself with. */
16
+ key: string;
17
+ items: SerializedObjectSchema[];
18
+ opt: boolean;
19
+ customValidate?: boolean;
20
+ readonly?: boolean;
21
+ hidden?: boolean;
22
+ description?: string;
23
+ };
24
+ /** The variant objects a discriminated union on `Key` may be built from. */
25
+ export type DiscriminatedUnionItem<Key extends string> = Schema<SourceObject & {
26
+ [k in Key]: string;
27
+ }>;
28
+ /**
29
+ * At least one variant, so a union with none cannot be written.
30
+ *
31
+ * Everything downstream reads the first one where it needs any — `emptyOf`
32
+ * takes `items[0]` for the value a new entry starts as — and a union with
33
+ * nothing to select is not a thing an author means. `s.enum` says the same
34
+ * about its values.
35
+ */
36
+ export type DiscriminatedUnionItems<Key extends string> = [
37
+ DiscriminatedUnionItem<Key>,
38
+ ...DiscriminatedUnionItem<Key>[]
39
+ ];
40
+ /** The source type a discriminated union over `T` accepts. */
41
+ export type DiscriminatedUnionSourceOf<Key extends string, T extends DiscriminatedUnionItem<Key>[]> = T extends Schema<infer S>[] ? S extends SelectorSource ? S : never : never;
42
+ /**
43
+ * One of several object shapes, told apart by a tag field.
44
+ *
45
+ * Every variant is an object with `key` set to a distinct `s.literal(...)`, and
46
+ * the value of that field decides which variant a value is. Unlike
47
+ * {@link EnumSchema} this is a CONTAINER: the variant's fields are the fields
48
+ * being edited, and everything that walks the schema tree has to descend
49
+ * through the matching variant.
50
+ */
51
+ export declare class DiscriminatedUnionSchema<Key extends string, T extends DiscriminatedUnionItem<Key>[], Src extends DiscriminatedUnionSourceOf<Key, T> | null> extends Schema<Src> {
52
+ private readonly key;
53
+ private readonly items;
54
+ private readonly opt;
55
+ private readonly customValidateFunctions;
56
+ private readonly isReadonly;
57
+ private readonly isHidden;
58
+ private readonly description?;
59
+ private readonly renderInput;
60
+ private readonly previewInput;
61
+ constructor(key: Key, items: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
62
+ /**
63
+ * Describe this field.
64
+ *
65
+ * The description is shown next to the field's label in the Val editor, so it is
66
+ * where you say what an editor needs to know but the field name cannot carry. It
67
+ * also travels in the serialized schema, which is what the AI assistant and the
68
+ * MCP tools read.
69
+ *
70
+ * Pass `null` to clear a description set earlier.
71
+ *
72
+ * @example
73
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
74
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
75
+ * const schema = s
76
+ * .discriminatedUnion("type", hero, text)
77
+ * .describe("What this section of the page is");
78
+ * export default c.define("/example.val.ts", schema, {
79
+ * type: "hero",
80
+ * title: "Hello",
81
+ * });
82
+ */
83
+ describe(description: string | null): DiscriminatedUnionSchema<Key, T, 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
+ * Validation runs in the Studio as you type, in `npx val validate` and before a
93
+ * publish.
94
+ *
95
+ * The function is given the whole value, whichever variant it took. A rule
96
+ * that only concerns one variant belongs on that variant's object schema.
97
+ *
98
+ * @example
99
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
100
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
101
+ * const schema = s
102
+ * .discriminatedUnion("type", hero, text)
103
+ * .validate((val) =>
104
+ * val.type === "hero" && !val.title ? "A hero needs a title" : false,
105
+ * );
106
+ * export default c.define("/example.val.ts", schema, {
107
+ * type: "hero",
108
+ * title: "Hello",
109
+ * });
110
+ */
111
+ validate(validationFunction: (src: Src) => false | string): DiscriminatedUnionSchema<Key, T, Src>;
112
+ protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
113
+ protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
114
+ nullable(): DiscriminatedUnionSchema<Key, T, Src | null>;
115
+ readonly(isReadonly?: boolean): DiscriminatedUnionSchema<Key, T, Src>;
116
+ hidden(isHidden?: boolean): DiscriminatedUnionSchema<Key, T, Src>;
117
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
118
+ /**
119
+ * The variant schema a value takes. `null` when the value matches none of
120
+ * them — a structural error `executeValidate` already reports.
121
+ */
122
+ private matchedVariant;
123
+ /**
124
+ * How this field is laid out in the editor when it is the item of an array
125
+ * or record: `{ as: "inline" }` renders the field itself inside each row,
126
+ * instead of a preview row that navigates to it.
127
+ *
128
+ * Static configuration, not a callback — see `render.ts`.
129
+ *
130
+ * @example
131
+ * // A page builder: the row draws the tag selector and the matched
132
+ * // variant's fields.
133
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
134
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
135
+ * const block = s.discriminatedUnion("type", hero, text).render({ as: "inline" });
136
+ * export default c.define("/example.val.ts", s.array(block), [
137
+ * { type: "hero", title: "Hello" },
138
+ * ]);
139
+ */
140
+ render(input: FieldRender): DiscriminatedUnionSchema<Key, T, Src>;
141
+ /**
142
+ * How this VALUE is shown where a preview of it is needed — a row in a
143
+ * sortable list, a reference dropdown, a search hit. Never how the field
144
+ * itself is edited (that is `render`). See `preview.ts`.
145
+ *
146
+ * Without one of its own, a discriminated union previews as the VARIANT the
147
+ * value takes — declare `preview` on the member objects and the union
148
+ * dispatches.
149
+ *
150
+ * @example
151
+ * const hero = s.object({ type: s.literal("hero"), title: s.string() });
152
+ * const text = s.object({ type: s.literal("text"), body: s.string() });
153
+ * const block = s
154
+ * .discriminatedUnion("type", hero, text)
155
+ * .preview(({ val }) => ({ title: val.type }));
156
+ * export default c.define("/example.val.ts", s.array(block), [
157
+ * { type: "hero", title: "Hello" },
158
+ * ]);
159
+ */
160
+ preview(select: ItemPreviewInput<Src>): DiscriminatedUnionSchema<Key, T, Src>;
161
+ protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
162
+ protected declaresItemPreview(): boolean;
163
+ protected executeSerialize(): SerializedDiscriminatedUnionSchema;
164
+ protected executePreview(sourcePath: SourcePath | ModuleFilePath, src: Src, scope?: PreviewScope): ReifiedPreview;
165
+ }
166
+ export declare const discriminatedUnion: <Key extends string, T extends DiscriminatedUnionItems<Key>>(key: Key, ...objects: T) => DiscriminatedUnionSchema<Key, T, DiscriminatedUnionSourceOf<Key, T>>;
@@ -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>;