@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.
Files changed (42) hide show
  1. package/CHANGELOG.md +299 -0
  2. package/dist/declarations/src/index.d.ts +8 -2
  3. package/dist/declarations/src/initSchema.d.ts +62 -15
  4. package/dist/declarations/src/initVal.d.ts +108 -0
  5. package/dist/declarations/src/locale.d.ts +55 -0
  6. package/dist/declarations/src/render.d.ts +5 -4
  7. package/dist/declarations/src/schema/array.d.ts +69 -0
  8. package/dist/declarations/src/schema/boolean.d.ts +44 -0
  9. package/dist/declarations/src/schema/code.d.ts +63 -0
  10. package/dist/declarations/src/schema/color.d.ts +54 -0
  11. package/dist/declarations/src/schema/date.d.ts +64 -2
  12. package/dist/declarations/src/schema/datetime.d.ts +87 -2
  13. package/dist/declarations/src/schema/declaredKeys.d.ts +37 -0
  14. package/dist/declarations/src/schema/discriminatedUnion.d.ts +170 -0
  15. package/dist/declarations/src/schema/discriminatedUnionBranch.d.ts +20 -0
  16. package/dist/declarations/src/schema/enum.d.ts +131 -0
  17. package/dist/declarations/src/schema/file.d.ts +77 -0
  18. package/dist/declarations/src/schema/image.d.ts +102 -0
  19. package/dist/declarations/src/schema/index.d.ts +155 -2
  20. package/dist/declarations/src/schema/keyOf.d.ts +50 -0
  21. package/dist/declarations/src/schema/literal.d.ts +48 -0
  22. package/dist/declarations/src/schema/locale.d.ts +132 -0
  23. package/dist/declarations/src/schema/number.d.ts +58 -0
  24. package/dist/declarations/src/schema/object.d.ts +70 -0
  25. package/dist/declarations/src/schema/record.d.ts +187 -1
  26. package/dist/declarations/src/schema/richtext.d.ts +78 -0
  27. package/dist/declarations/src/schema/route.d.ts +44 -0
  28. package/dist/declarations/src/schema/settings.d.ts +54 -1
  29. package/dist/declarations/src/schema/string.d.ts +99 -0
  30. package/dist/declarations/src/schema/union.d.ts +54 -91
  31. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  32. package/dist/declarations/src/source/settings.d.ts +51 -0
  33. package/dist/{index-915dd675.esm.js → index-5a6e6398.esm.js} +3057 -573
  34. package/dist/{index-daa122af.cjs.dev.js → index-889ac441.cjs.dev.js} +3064 -573
  35. package/dist/{index-a3846321.cjs.prod.js → index-d44deccb.cjs.prod.js} +3064 -573
  36. package/dist/valbuild-core.cjs.dev.js +9 -2
  37. package/dist/valbuild-core.cjs.prod.js +9 -2
  38. package/dist/valbuild-core.esm.js +1 -1
  39. package/package.json +1 -1
  40. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  41. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  42. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -59,10 +59,11 @@ export type FieldRender = InlineRender;
59
59
  * question, and a disagreement between them is a row you can edit in place but
60
60
  * that "add" navigates away from.
61
61
  *
62
- * A tagged union counts as inline when the union itself declares it OR when
63
- * ANY of its variants does. A page-builder list is `s.array(s.union("type",
64
- * block, block, ...))` and the natural place to write the render is on the
65
- * blocks, one per block type — the union is a dispatch, not something the
62
+ * A discriminated union counts as inline when the union itself declares it OR
63
+ * when ANY of its variants does. A page-builder list is
64
+ * `s.array(s.discriminatedUnion("type", block, block, ...))` and the natural
65
+ * place to write the render is on the blocks, one per block type — the union
66
+ * is a dispatch, not something the
66
67
  * author thinks of as the field. `some` rather than `every` because the row
67
68
  * draws the union's own editor (the tag selector plus the matched variant's
68
69
  * fields), which handles every variant either way: with `every`, adding one
@@ -38,13 +38,57 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
38
38
  private readonly previewInput;
39
39
  private readonly renderInput;
40
40
  constructor(item: T, opt?: boolean, customValidateFunctions?: ((src: Src) => false | string)[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null, renderInput?: FieldRender | null);
41
+ /**
42
+ * Describe this field.
43
+ *
44
+ * The description is shown next to the field's label in the Val editor, so
45
+ * it is where you say what an editor needs to know but the field name cannot
46
+ * carry. It also travels in the serialized schema, which is what the AI
47
+ * assistant and the MCP tools read.
48
+ *
49
+ * Pass `null` to clear a description set earlier.
50
+ *
51
+ * @example
52
+ * const schema = s
53
+ * .array(s.string())
54
+ * .describe("Bullet points shown under the heading");
55
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
56
+ */
41
57
  describe(description: string | null): ArraySchema<T, Src>;
58
+ /**
59
+ * Add a custom validation rule to this field.
60
+ *
61
+ * The function is called with the field's value and returns `false` when the
62
+ * value is fine, or a STRING with the message to show when it is not. Call it
63
+ * more than once to add more rules — they all run, and every message is
64
+ * reported.
65
+ *
66
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
67
+ * when the value is fine, and `true` is not one of the two answers.
68
+ *
69
+ * Validation runs in the Studio as you type, in `npx val validate` and
70
+ * before a publish.
71
+ *
72
+ * The function is given the whole array. To validate one item, put a
73
+ * `.validate(...)` on the ITEM schema instead — that reports the error on
74
+ * the item's own row.
75
+ *
76
+ * @example
77
+ * const schema = s.array(s.string()).validate((val) =>
78
+ * val.length <= 3 ? false : "At most 3 items",
79
+ * );
80
+ * export default c.define("/example.val.ts", schema, ["First", "Second"]);
81
+ */
42
82
  validate(validationFunction: (src: Src) => false | string): ArraySchema<T, Src>;
43
83
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
44
84
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
45
85
  nullable(): ArraySchema<T, Src | null>;
46
86
  readonly(isReadonly?: boolean): ArraySchema<T, Src>;
47
87
  hidden(isHidden?: boolean): ArraySchema<T, Src>;
88
+ protected localeScopeChildren(): {
89
+ key: string;
90
+ schema: Schema<SelectorSource>;
91
+ }[];
48
92
  protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
49
93
  protected executeSerialize(): SerializedArraySchema;
50
94
  protected executePreview(sourcePath: SourcePath | ModuleFilePath, src: Src, scope?: PreviewScope): ReifiedPreview;
@@ -55,6 +99,25 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
55
99
  * is the item of another container, in search, in references. What its rows
56
100
  * show is the ITEM schema's `preview`, not this. Never how the field is
57
101
  * edited (that is `render`). See `preview.ts`.
102
+ *
103
+ * @example
104
+ * // The preview of the ARRAY, for where it is an item of something else.
105
+ * // What its own rows show is the ITEM schema's preview — see below.
106
+ * const tags = s.array(s.string()).preview(({ val }) => ({
107
+ * title: `${val.length} tags`,
108
+ * }));
109
+ * export default c.define("/example.val.ts", s.record(tags), {
110
+ * "a-post": ["news", "release"],
111
+ * });
112
+ *
113
+ * @example
114
+ * // Rows of an array come from the ITEM's preview, not the array's:
115
+ * const author = s
116
+ * .object({ name: s.string(), role: s.string() })
117
+ * .preview(({ val }) => ({ title: val.name, subtitle: val.role }));
118
+ * export default c.define("/example.val.ts", s.array(author), [
119
+ * { name: "Ada", role: "Engineer" },
120
+ * ]);
58
121
  */
59
122
  preview(select: ItemPreviewInput<Src>): ArraySchema<T, Src>;
60
123
  /**
@@ -63,6 +126,12 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
63
126
  * instead of a preview row that navigates to it.
64
127
  *
65
128
  * Static configuration, not a callback — see `render.ts`.
129
+ *
130
+ * @example
131
+ * const schema = s.record(s.array(s.string()).render({ as: "inline" }));
132
+ * export default c.define("/example.val.ts", schema, {
133
+ * "a-post": ["news", "release"],
134
+ * });
66
135
  */
67
136
  render(input: FieldRender): ArraySchema<T, Src>;
68
137
  }
@@ -24,7 +24,41 @@ export declare class BooleanSchema<Src extends boolean | null> extends Schema<Sr
24
24
  private readonly renderInput;
25
25
  private readonly previewInput;
26
26
  constructor(opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
27
+ /**
28
+ * Describe this field.
29
+ *
30
+ * The description is shown next to the field's label in the Val editor, so
31
+ * it is where you say what an editor needs to know but the field name cannot
32
+ * carry. It also travels in the serialized schema, which is what the AI
33
+ * assistant and the MCP tools read.
34
+ *
35
+ * Pass `null` to clear a description set earlier.
36
+ *
37
+ * @example
38
+ * const schema = s.boolean().describe("Show this item in the main menu");
39
+ * export default c.define("/example.val.ts", schema, true);
40
+ */
27
41
  describe(description: string | null): BooleanSchema<Src>;
42
+ /**
43
+ * Add a custom validation rule to this field.
44
+ *
45
+ * The function is called with the field's value and returns `false` when the
46
+ * value is fine, or a STRING with the message to show when it is not. Call it
47
+ * more than once to add more rules — they all run, and every message is
48
+ * reported.
49
+ *
50
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
51
+ * when the value is fine, and `true` is not one of the two answers.
52
+ *
53
+ * Validation runs in the Studio as you type, in `npx val validate` and
54
+ * before a publish.
55
+ *
56
+ * @example
57
+ * const schema = s.boolean().validate((val) =>
58
+ * val === true ? false : "This has to be on for now",
59
+ * );
60
+ * export default c.define("/example.val.ts", schema, true);
61
+ */
28
62
  validate(validationFunction: (src: Src) => false | string): BooleanSchema<Src>;
29
63
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
30
64
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
@@ -38,12 +72,22 @@ export declare class BooleanSchema<Src extends boolean | null> extends Schema<Sr
38
72
  * instead of a preview row that navigates to it.
39
73
  *
40
74
  * Static configuration, not a callback — see `render.ts`.
75
+ *
76
+ * @example
77
+ * const schema = s.array(s.boolean().render({ as: "inline" }));
78
+ * export default c.define("/example.val.ts", schema, [true, false]);
41
79
  */
42
80
  render(input: FieldRender): BooleanSchema<Src>;
43
81
  /**
44
82
  * How this VALUE is shown where a preview of it is needed — a row in a
45
83
  * sortable list, a reference dropdown, a search hit. Never how the field
46
84
  * itself is edited (that is `render`). See `preview.ts`.
85
+ *
86
+ * @example
87
+ * const schema = s.array(
88
+ * s.boolean().preview(({ val }) => ({ title: val ? "On" : "Off" })),
89
+ * );
90
+ * export default c.define("/example.val.ts", schema, [true, false]);
47
91
  */
48
92
  preview(select: ItemPreviewInput<Src>): BooleanSchema<Src>;
49
93
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -55,7 +55,52 @@ export declare class CodeSchema<Src extends string | null> extends Schema<Src> {
55
55
  private readonly renderInput;
56
56
  private readonly previewInput;
57
57
  constructor(options?: CodeOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
58
+ /**
59
+ * Describe this field.
60
+ *
61
+ * The description is shown next to the field's label in the Val editor, so
62
+ * it is where you say what an editor needs to know but the field name cannot
63
+ * carry. It also travels in the serialized schema, which is what the AI
64
+ * assistant and the MCP tools read.
65
+ *
66
+ * Pass `null` to clear a description set earlier.
67
+ *
68
+ * @example
69
+ * const schema = s
70
+ * .code({ language: "css" })
71
+ * .describe("Injected into the page head — keep it small");
72
+ * export default c.define(
73
+ * "/example.val.ts",
74
+ * schema,
75
+ * ".hero { color: red; }",
76
+ * );
77
+ */
58
78
  describe(description: string | null): CodeSchema<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
+ * @example
94
+ * const schema = s.code({ language: "json" }).validate((val) => {
95
+ * try {
96
+ * JSON.parse(val);
97
+ * return false;
98
+ * } catch {
99
+ * return "Must be valid JSON";
100
+ * }
101
+ * });
102
+ * export default c.define("/example.val.ts", schema, '{ "a": 1 }');
103
+ */
59
104
  validate(validationFunction: (src: Src) => false | string): CodeSchema<Src>;
60
105
  protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
61
106
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
@@ -69,12 +114,30 @@ export declare class CodeSchema<Src extends string | null> extends Schema<Src> {
69
114
  * instead of a preview row that navigates to it.
70
115
  *
71
116
  * Static configuration, not a callback — see `render.ts`.
117
+ *
118
+ * @example
119
+ * const schema = s.array(
120
+ * s.code({ language: "css" }).render({ as: "inline" }),
121
+ * );
122
+ * export default c.define("/example.val.ts", schema, [
123
+ * ".hero { color: red; }",
124
+ * ]);
72
125
  */
73
126
  render(input: FieldRender): CodeSchema<Src>;
74
127
  /**
75
128
  * How this VALUE is shown where a preview of it is needed — a row in a
76
129
  * sortable list, a reference dropdown, a search hit. Never how the field
77
130
  * itself is edited (that is `render`). See `preview.ts`.
131
+ *
132
+ * @example
133
+ * const schema = s.array(
134
+ * s.code({ language: "css" }).preview(({ val }) => ({
135
+ * title: val.split("\n")[0],
136
+ * })),
137
+ * );
138
+ * export default c.define("/example.val.ts", schema, [
139
+ * ".hero { color: red; }",
140
+ * ]);
78
141
  */
79
142
  preview(select: ItemPreviewInput<Src>): CodeSchema<Src>;
80
143
  protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
@@ -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,37 @@
1
+ import { SerializedSchema } from "./index.js";
2
+ /**
3
+ * The keys a record is REQUIRED to hold, where its key schema says what they are.
4
+ *
5
+ * Most records have an open key set — `s.record(s.string(), item)` holds
6
+ * whatever anyone adds — and this returns `null` for those. A record keyed by
7
+ * something that enumerates its values is different in kind: the keys are part
8
+ * of the schema, so a missing one is a hole in the content rather than content
9
+ * nobody has written yet.
10
+ *
11
+ * Two key schemas enumerate. A union of literals does it locally, so its keys
12
+ * are here. `s.locale()` does it in the settings module, which is another file
13
+ * and so cannot be read from a serialized schema — that case says only which
14
+ * kind it is, and is resolved against `locales.available` by
15
+ * `resolveSchemaSourceFixes`, the same crossing `keyOf` and `route` make.
16
+ */
17
+ export type DeclaredKeySet = {
18
+ kind: "literals";
19
+ keys: string[];
20
+ } | {
21
+ kind: "locale";
22
+ };
23
+ /**
24
+ * What `key` requires a record to hold, or `null` where it requires nothing.
25
+ *
26
+ * Works from the SERIALIZED schema so that the Studio, the validation worker
27
+ * and the server all answer this the same way — none of them has the schema
28
+ * instance, and `SchemaStore` deliberately holds serialized schemas only.
29
+ */
30
+ export declare function declaredKeySetOf(key: SerializedSchema | undefined): DeclaredKeySet | null;
31
+ /**
32
+ * The declared keys a record is missing, in the order the schema declares them.
33
+ *
34
+ * Declaration order rather than the source's: this is read as "what is left to
35
+ * write", and the answer should not reshuffle itself as entries are added.
36
+ */
37
+ export declare function missingDeclaredKeys(declared: readonly string[], present: readonly string[]): string[];