@valbuild/core 0.99.1 → 0.101.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/dist/declarations/src/index.d.ts +15 -0
  2. package/dist/declarations/src/initSchema.d.ts +21 -0
  3. package/dist/declarations/src/initVal.d.ts +2 -0
  4. package/dist/declarations/src/schema/array.d.ts +2 -1
  5. package/dist/declarations/src/schema/boolean.d.ts +2 -1
  6. package/dist/declarations/src/schema/color.d.ts +57 -0
  7. package/dist/declarations/src/schema/colorFormat.d.ts +83 -0
  8. package/dist/declarations/src/schema/date.d.ts +2 -1
  9. package/dist/declarations/src/schema/datetime.d.ts +2 -1
  10. package/dist/declarations/src/schema/file.d.ts +2 -1
  11. package/dist/declarations/src/schema/image.d.ts +2 -1
  12. package/dist/declarations/src/schema/index.d.ts +24 -1
  13. package/dist/declarations/src/schema/keyOf.d.ts +2 -1
  14. package/dist/declarations/src/schema/literal.d.ts +2 -1
  15. package/dist/declarations/src/schema/number.d.ts +2 -1
  16. package/dist/declarations/src/schema/object.d.ts +2 -1
  17. package/dist/declarations/src/schema/record.d.ts +46 -3
  18. package/dist/declarations/src/schema/richtext.d.ts +2 -1
  19. package/dist/declarations/src/schema/route.d.ts +2 -1
  20. package/dist/declarations/src/schema/string.d.ts +2 -1
  21. package/dist/declarations/src/schema/union.d.ts +9 -1
  22. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  23. package/dist/declarations/src/selector/index.d.ts +3 -2
  24. package/dist/declarations/src/source/index.d.ts +3 -2
  25. package/dist/declarations/src/source/json.d.ts +73 -0
  26. package/dist/{index-28d99c34.cjs.prod.js → index-049780fa.cjs.prod.js} +1238 -181
  27. package/dist/{index-b2601ac3.cjs.dev.js → index-3e2d700e.cjs.dev.js} +1238 -181
  28. package/dist/{index-204b5d78.esm.js → index-a18c24c2.esm.js} +1236 -182
  29. package/dist/valbuild-core.cjs.dev.js +4 -1
  30. package/dist/valbuild-core.cjs.prod.js +4 -1
  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
@@ -8,6 +8,7 @@ export type { FileMetadata } from "./schema/file.js";
8
8
  export type { ValModule, SerializedModule, InferValModuleType } from "./module.js";
9
9
  export type { SourceObject, SourcePrimitive, Source } from "./source/index.js";
10
10
  export type { FileSource } from "./source/file.js";
11
+ export type { JsonSource, JsonOf, JsonImportThunk } from "./source/json.js";
11
12
  export type { RemoteSource, RemoteRef } from "./source/remote.js";
12
13
  export { DEFAULT_VAL_REMOTE_HOST } from "./schema/remote.js";
13
14
  export type { RawString } from "./schema/string.js";
@@ -34,11 +35,13 @@ import { getMimeType, mimeTypeToFileExt, filenameToMimeType } from "./mimeType/i
34
35
  import { type ImageMetadata } from "./schema/image.js";
35
36
  import { type FileMetadata } from "./schema/file.js";
36
37
  import { isFile } from "./source/file.js";
38
+ import { isJson, getJsonImport, resolveJsonValues } from "./source/json.js";
37
39
  import { createRemoteRef } from "./source/remote.js";
38
40
  import { getValidationBasis, getValidationHash } from "./remote/validationBasis.js";
39
41
  import { getFileHash, hashToRemoteFileHash } from "./remote/fileHash.js";
40
42
  import { splitRemoteRef } from "./remote/splitRemoteRef.js";
41
43
  import { convertRemoteSource } from "./schema/remote.js";
44
+ import { colorToHex, convertColor, detectColorFormat, formatColor, parseColor } from "./schema/colorFormat.js";
42
45
  export { type SerializedArraySchema, ArraySchema } from "./schema/array.js";
43
46
  export { type SerializedObjectSchema, ObjectSchema } from "./schema/object.js";
44
47
  export { type SerializedRecordSchema, RecordSchema } from "./schema/record.js";
@@ -48,6 +51,8 @@ export { type SerializedBooleanSchema, BooleanSchema } from "./schema/boolean.js
48
51
  export { type SerializedImageSchema, ImageSchema } from "./schema/image.js";
49
52
  export { type SerializedFileSchema, FileSchema } from "./schema/file.js";
50
53
  export { type SerializedDateSchema, DateSchema } from "./schema/date.js";
54
+ export { type SerializedColorSchema, type ColorOptions, ColorSchema, } from "./schema/color.js";
55
+ export { type ColorFormat, type ParsedColor, COLOR_FORMATS, DEFAULT_COLOR_FORMAT, } from "./schema/colorFormat.js";
51
56
  export { type SerializedDateTimeSchema, DateTimeSchema, } from "./schema/datetime.js";
52
57
  export { type SerializedKeyOfSchema, KeyOfSchema } from "./schema/keyOf.js";
53
58
  export { type SerializedRouteSchema, RouteSchema } from "./schema/route.js";
@@ -77,6 +82,13 @@ declare const Internal: {
77
82
  joinModuleFilePathAndModulePath: typeof joinModuleFilePathAndModulePath;
78
83
  nextAppRouter: import("./router.js").ValRouter;
79
84
  externalPageRouter: import("./router.js").ValRouter;
85
+ color: {
86
+ parseColor: typeof parseColor;
87
+ formatColor: typeof formatColor;
88
+ convertColor: typeof convertColor;
89
+ detectColorFormat: typeof detectColorFormat;
90
+ colorToHex: typeof colorToHex;
91
+ };
80
92
  remote: {
81
93
  createRemoteRef: typeof createRemoteRef;
82
94
  getValidationBasis: typeof getValidationBasis;
@@ -88,6 +100,9 @@ declare const Internal: {
88
100
  validate: (val: ValModule<SelectorSource>, path: SourcePath, src: unknown) => import("./schema/validation/ValidationError.js").ValidationErrors | undefined;
89
101
  isVal: typeof isVal;
90
102
  isFile: typeof isFile;
103
+ isJson: typeof isJson;
104
+ getJsonImport: typeof getJsonImport;
105
+ resolveJsonValues: typeof resolveJsonValues;
91
106
  createValPathOfItem: typeof createValPathOfItem;
92
107
  getSHA256Hash: (bits: Uint8Array) => string;
93
108
  initSchema: typeof initSchema;
@@ -13,6 +13,7 @@ import { file } from "./schema/file.js";
13
13
  import { files } from "./schema/files.js";
14
14
  import { date } from "./schema/date.js";
15
15
  import { datetime } from "./schema/datetime.js";
16
+ import { color } from "./schema/color.js";
16
17
  import { route } from "./schema/route.js";
17
18
  import { router } from "./schema/router.js";
18
19
  import { images } from "./schema/images.js";
@@ -173,6 +174,25 @@ export type InitSchema = {
173
174
  *
174
175
  */
175
176
  readonly datetime: typeof datetime;
177
+ /**
178
+ * Define a color.
179
+ *
180
+ * Stored as a CSS color string, so it can be used directly in `style`
181
+ * attributes or set as a CSS custom property.
182
+ *
183
+ * The notation is decided by the `format` option, which defaults to `"hsl"`.
184
+ * Set `alpha: true` to allow transparency.
185
+ *
186
+ * @example
187
+ * const schema = s.color();
188
+ * export default c.define("/example.val.ts", schema, "hsl(217.22 91.22% 59.8%)");
189
+ *
190
+ * @example
191
+ * const schema = s.color({ format: "hex" });
192
+ * export default c.define("/example.val.ts", schema, "#3b82f6");
193
+ *
194
+ */
195
+ readonly color: typeof color;
176
196
  /**
177
197
  * Define a string that references a route path in your application.
178
198
  *
@@ -283,6 +303,7 @@ export declare function initSchema(): {
283
303
  }>, import("./schema/index.js").Schema<string>, Record<string, import("./schema/files.js").FilesEntryMetadata>>;
284
304
  date: (options?: Record<string, never>) => import("./schema/date.js").DateSchema<import("./schema/string.js").RawString>;
285
305
  datetime: (options?: Record<string, never>) => import("./schema/datetime.js").DateTimeSchema<import("./schema/string.js").RawString>;
306
+ color: (options?: import("./schema/color.js").ColorOptions) => import("./schema/color.js").ColorSchema<import("./schema/string.js").RawString>;
286
307
  route: <T extends string>(options?: Record<string, never>) => import("./schema/route.js").RouteSchema<T>;
287
308
  router: typeof router;
288
309
  images: <Accept extends `image/${string}`>(options?: import("./schema/images.js").ImagesOptions<Accept>) => import("./schema/record.js").RecordSchema<import("./schema/object.js").ObjectSchema<{
@@ -3,12 +3,14 @@ import { InitSchema } from "./initSchema.js";
3
3
  import { getValPath as getPath } from "./val/index.js";
4
4
  import { initFile } from "./source/file.js";
5
5
  import { initImage } from "./source/image.js";
6
+ import { json } from "./source/json.js";
6
7
  import { initRemote } from "./source/remote.js";
7
8
  export type ContentConstructor = {
8
9
  define: typeof define;
9
10
  file: ReturnType<typeof initFile>;
10
11
  image: ReturnType<typeof initImage>;
11
12
  remote: ReturnType<typeof initRemote>;
13
+ json: typeof json;
12
14
  };
13
15
  export type ValConstructor = {
14
16
  unstable_getPath: typeof getPath;
@@ -3,7 +3,7 @@ import { RenderSelector, ReifiedRender } from "../render.js";
3
3
  import { SelectorSource } from "../selector/index.js";
4
4
  import { ImageSource } from "../source/image.js";
5
5
  import { ModuleFilePath, SourcePath } from "../val/index.js";
6
- import { ValidationErrors } from "./validation/ValidationError.js";
6
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
7
7
  export type SerializedArraySchema = {
8
8
  type: "array";
9
9
  item: SerializedSchema;
@@ -39,6 +39,7 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
39
39
  nullable(): ArraySchema<T, Src | null>;
40
40
  readonly(): ArraySchema<T, Src>;
41
41
  hidden(): ArraySchema<T, Src>;
42
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
42
43
  protected executeSerialize(): SerializedArraySchema;
43
44
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
44
45
  render(input: ArrayRenderInput<T>): ArraySchema<T, Src>;
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  export type SerializedBooleanSchema = {
6
6
  type: "boolean";
7
7
  opt: boolean;
@@ -24,6 +24,7 @@ export declare class BooleanSchema<Src extends boolean | null> extends Schema<Sr
24
24
  nullable(): BooleanSchema<Src | null>;
25
25
  readonly(): BooleanSchema<Src>;
26
26
  hidden(): BooleanSchema<Src>;
27
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
27
28
  protected executeSerialize(): SerializedSchema;
28
29
  protected executeRender(): ReifiedRender;
29
30
  }
@@ -0,0 +1,57 @@
1
+ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
+ import { ReifiedRender } from "../render.js";
3
+ import { SourcePath } from "../val/index.js";
4
+ import { ColorFormat } from "./colorFormat.js";
5
+ import { RawString } from "./string.js";
6
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
7
+ export type { ColorFormat } from "./colorFormat.js";
8
+ export type ColorOptions = {
9
+ /**
10
+ * The CSS notation the color is stored in.
11
+ *
12
+ * Defaults to `"hsl"`.
13
+ *
14
+ * @example
15
+ * "hex" // #3b82f6
16
+ * "rgb" // rgb(59 130 246)
17
+ * "hsl" // hsl(217.22 91.22% 59.8%)
18
+ * "oklch" // oklch(0.6231 0.188 259.81)
19
+ */
20
+ format?: ColorFormat;
21
+ /**
22
+ * Allow an alpha channel (transparency).
23
+ *
24
+ * Defaults to `false`: a color with an alpha channel is a validation error
25
+ * unless this is enabled.
26
+ */
27
+ alpha?: boolean;
28
+ };
29
+ export type SerializedColorSchema = {
30
+ type: "color";
31
+ options?: ColorOptions;
32
+ opt: boolean;
33
+ customValidate?: boolean;
34
+ readonly?: boolean;
35
+ hidden?: boolean;
36
+ description?: string;
37
+ };
38
+ export declare class ColorSchema<Src extends string | null> extends Schema<Src> {
39
+ private readonly options?;
40
+ private readonly opt;
41
+ private readonly customValidateFunctions;
42
+ private readonly isReadonly;
43
+ private readonly isHidden;
44
+ private readonly description?;
45
+ constructor(options?: ColorOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined);
46
+ describe(description: string | null): ColorSchema<Src>;
47
+ validate(validationFunction: (src: Src) => false | string): ColorSchema<Src>;
48
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
49
+ protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
50
+ protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
51
+ nullable(): ColorSchema<Src | null>;
52
+ readonly(): ColorSchema<Src>;
53
+ hidden(): ColorSchema<Src>;
54
+ protected executeSerialize(): SerializedSchema;
55
+ protected executeRender(): ReifiedRender;
56
+ }
57
+ export declare const color: (options?: ColorOptions) => ColorSchema<RawString>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Parsing / formatting of the CSS color strings stored by `s.color()`.
3
+ *
4
+ * Colors are stored as plain CSS strings so that they can be used directly in
5
+ * `style` attributes and CSS custom properties. The schema decides which family
6
+ * (`hex`, `rgb`, `hsl` or `oklch`) the string is written in, this module does
7
+ * the conversion between them.
8
+ *
9
+ * All colors are sRGB: `oklch` is only used as an output notation, so any
10
+ * `oklch` value that falls outside the sRGB gamut is clipped when converted
11
+ * back to the other formats.
12
+ */
13
+ export declare const COLOR_FORMATS: readonly ["hex", "rgb", "hsl", "oklch"];
14
+ export type ColorFormat = (typeof COLOR_FORMATS)[number];
15
+ export declare const DEFAULT_COLOR_FORMAT: ColorFormat;
16
+ /**
17
+ * A color, normalized to sRGB.
18
+ *
19
+ * `r`, `g` and `b` are 0-255 (not rounded), `a` is 0-1.
20
+ */
21
+ export type ParsedColor = {
22
+ r: number;
23
+ g: number;
24
+ b: number;
25
+ a: number;
26
+ };
27
+ /**
28
+ * Which color notation a string uses, or `null` if it is not a notation we
29
+ * recognize. This looks at the syntax only: `detectColorFormat` says nothing
30
+ * about whether the value actually parses (`hsl(nope)` is still `"hsl"`).
31
+ */
32
+ export declare function detectColorFormat(value: string): ColorFormat | null;
33
+ /**
34
+ * Parses a CSS color string into sRGB channels.
35
+ *
36
+ * Accepts hex (3, 4, 6 and 8 digits), `rgb()` / `rgba()`, `hsl()` / `hsla()`
37
+ * and `oklch()`, in both the legacy comma and the modern space syntax. Returns
38
+ * `null` if the value is not a color we can parse - notably: named colors
39
+ * (`red`), `color()`, `lab()` and `color-mix()` are not supported.
40
+ */
41
+ export declare function parseColor(value: string): ParsedColor | null;
42
+ export declare function rgbToHsl(r: number, g: number, b: number): {
43
+ h: number;
44
+ s: number;
45
+ l: number;
46
+ };
47
+ export declare function hslToRgb(h: number, s: number, l: number): {
48
+ r: number;
49
+ g: number;
50
+ b: number;
51
+ };
52
+ /**
53
+ * sRGB to Oklch, using Björn Ottosson's Oklab matrices.
54
+ */
55
+ export declare function rgbToOklch(r: number, g: number, b: number): {
56
+ l: number;
57
+ c: number;
58
+ h: number;
59
+ };
60
+ /**
61
+ * Oklch to sRGB. Out of gamut colors are clipped per channel.
62
+ */
63
+ export declare function oklchToRgb(l: number, c: number, h: number): {
64
+ r: number;
65
+ g: number;
66
+ b: number;
67
+ };
68
+ /**
69
+ * Serializes a color to the canonical string of the given format.
70
+ *
71
+ * The modern, space separated CSS syntax is used for the color functions
72
+ * (`rgb(255 0 0 / 0.5)`). Alpha is only included when it is not fully opaque.
73
+ */
74
+ export declare function formatColor(color: ParsedColor, format: ColorFormat): string;
75
+ /**
76
+ * Converts a color string to the canonical string of the given format, or
77
+ * `null` if the input cannot be parsed.
78
+ */
79
+ export declare function convertColor(value: string, format: ColorFormat): string | null;
80
+ /**
81
+ * `#rrggbb`, which is what `<input type="color">` uses as its value.
82
+ */
83
+ export declare function colorToHex(color: ParsedColor): string;
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
4
  import { RawString } from "./string.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type DateOptions = {
7
7
  /**
8
8
  * Validate that the date is this date or after (inclusive).
@@ -45,6 +45,7 @@ export declare class DateSchema<Src extends string | null> extends Schema<Src> {
45
45
  nullable(): DateSchema<Src | null>;
46
46
  readonly(): DateSchema<Src>;
47
47
  hidden(): DateSchema<Src>;
48
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
48
49
  protected executeSerialize(): SerializedSchema;
49
50
  protected executeRender(): ReifiedRender;
50
51
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
4
  import { RawString } from "./string.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type DateTimeOptions = {
7
7
  /**
8
8
  * Validate that the datetime is this datetime or after (inclusive).
@@ -49,6 +49,7 @@ export declare class DateTimeSchema<Src extends string | null> extends Schema<Sr
49
49
  nullable(): DateTimeSchema<Src | null>;
50
50
  readonly(): DateTimeSchema<Src>;
51
51
  hidden(): DateTimeSchema<Src>;
52
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
52
53
  protected executeSerialize(): SerializedSchema;
53
54
  protected executeRender(): ReifiedRender;
54
55
  }
@@ -2,7 +2,7 @@ import { Json } from "../Json.js";
2
2
  import { FileSource } from "../source/file.js";
3
3
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
4
4
  import { ModulePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  import { RemoteSource, ValModule } from "../index.js";
7
7
  import { ReifiedRender } from "../render.js";
8
8
  import { FilesEntryMetadata } from "./files.js";
@@ -41,6 +41,7 @@ export declare class FileSchema<Src extends FileSource<FileMetadata | undefined>
41
41
  nullable(): FileSchema<Src | null>;
42
42
  readonly(): FileSchema<Src>;
43
43
  hidden(): FileSchema<Src>;
44
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
44
45
  protected executeSerialize(): SerializedSchema;
45
46
  protected executeRender(): ReifiedRender;
46
47
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { FileSource } from "../source/file.js";
3
3
  import { ImageSource } from "../source/image.js";
4
4
  import { ModulePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  import { ValModule } from "../index.js";
7
7
  import { RemoteSource } from "../source/remote.js";
8
8
  import { ReifiedRender } from "../render.js";
@@ -52,6 +52,7 @@ export declare class ImageSchema<Src extends FileSource<ImageMetadata | undefine
52
52
  nullable(): ImageSchema<Src | null>;
53
53
  readonly(): ImageSchema<Src>;
54
54
  hidden(): ImageSchema<Src>;
55
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
55
56
  protected executeSerialize(): SerializedSchema;
56
57
  protected executeRender(): ReifiedRender;
57
58
  }
@@ -12,6 +12,7 @@ import { SerializedRecordSchema } from "./record.js";
12
12
  import { SerializedRichTextSchema } from "./richtext.js";
13
13
  import { RawString, SerializedStringSchema } from "./string.js";
14
14
  import { SerializedUnionSchema } from "./union.js";
15
+ import { SerializedColorSchema } from "./color.js";
15
16
  import { SerializedDateSchema } from "./date.js";
16
17
  import { SerializedDateTimeSchema } from "./datetime.js";
17
18
  import { SerializedRouteSchema } from "./route.js";
@@ -19,7 +20,7 @@ import { ValidationError, ValidationErrors } from "./validation/ValidationError.
19
20
  import { FileSource } from "../source/file.js";
20
21
  import { GenericRichTextSourceNode, RichTextSource } from "../source/richtext.js";
21
22
  import { ReifiedRender } from "../render.js";
22
- export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedUnionSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedRouteSchema | SerializedImageSchema;
23
+ export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedUnionSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedColorSchema | SerializedRouteSchema | SerializedImageSchema;
23
24
  type Primitives = number | string | boolean | null | FileSource;
24
25
  export type AssertError = {
25
26
  message: string;
@@ -48,6 +49,28 @@ export type CustomValidateFunction<Src extends SelectorSource> = (src: Src, ctx:
48
49
  export declare abstract class Schema<Src extends SelectorSource> {
49
50
  /** Validate the value of source content */
50
51
  protected abstract executeValidate(path: SourcePath, src: Src): ValidationErrors;
52
+ /**
53
+ * Runs the custom validate functions declared on THIS node (not its children)
54
+ * against `src`.
55
+ *
56
+ * Abstract because every schema class holds its validators in its own
57
+ * `private readonly customValidateFunctions`, which no base implementation can
58
+ * reach — and a base implementation returning `[]` would let a class that
59
+ * forgot to implement this silently skip its user's validators. A compile error
60
+ * is the better failure.
61
+ *
62
+ * `src` stays a PARAMETER (as in {@link executeValidate}) rather than the
63
+ * functions being returned: `CustomValidateFunction<Src>` puts `Src` in a
64
+ * parameter position, so returning them would make `Schema<Src>` invariant and
65
+ * break every `Schema<Source>` → `Schema<SelectorSource>` assignment in the
66
+ * codebase.
67
+ *
68
+ * Deliberately independent of `executeValidate`: the Studio gets its structural
69
+ * errors from a worker, which holds a DESERIALIZED schema where user functions
70
+ * cannot survive, and then executes the custom validators on the main thread
71
+ * against the real instance. Structural errors publish first; these merge in.
72
+ */
73
+ protected abstract executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
51
74
  protected executeCustomValidateFunctions(src: Src, customValidateFunctions: CustomValidateFunction<Src>[], ctx: {
52
75
  path: SourcePath;
53
76
  }): ValidationError[];
@@ -3,7 +3,7 @@ import { ValModuleBrand } from "../module.js";
3
3
  import { GenericSelector } from "../selector/index.js";
4
4
  import { Source, SourceObject } from "../source/index.js";
5
5
  import { SourcePath } from "../val/index.js";
6
- import { ValidationErrors } from "./validation/ValidationError.js";
6
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
7
7
  import { RawString } from "./string.js";
8
8
  import { ReifiedRender } from "../render.js";
9
9
  export type SerializedKeyOfSchema = {
@@ -42,6 +42,7 @@ export declare class KeyOfSchema<Sel extends GenericSelector<SourceObject>, Src
42
42
  nullable(): KeyOfSchema<Sel, Src | null>;
43
43
  readonly(): KeyOfSchema<Sel, Src>;
44
44
  hidden(): KeyOfSchema<Sel, Src>;
45
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
45
46
  protected executeSerialize(): SerializedSchema;
46
47
  protected executeRender(): ReifiedRender;
47
48
  }
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  export type SerializedLiteralSchema = {
6
6
  type: "literal";
7
7
  value: string;
@@ -26,6 +26,7 @@ export declare class LiteralSchema<Src extends string | null> extends Schema<Src
26
26
  nullable(): LiteralSchema<Src | null>;
27
27
  readonly(): LiteralSchema<Src>;
28
28
  hidden(): LiteralSchema<Src>;
29
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
29
30
  protected executeSerialize(): SerializedSchema;
30
31
  protected executeRender(): ReifiedRender;
31
32
  }
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type NumberOptions = {
6
6
  max?: number;
7
7
  min?: number;
@@ -32,6 +32,7 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
32
32
  hidden(): NumberSchema<Src>;
33
33
  max(max: number): NumberSchema<Src>;
34
34
  min(min: number): NumberSchema<Src>;
35
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
35
36
  protected executeSerialize(): SerializedSchema;
36
37
  protected executeRender(): ReifiedRender;
37
38
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SelectorOfSchema, S
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SelectorSource } from "../selector/index.js";
4
4
  import { ModuleFilePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  export type SerializedObjectSchema = {
7
7
  type: "object";
8
8
  items: Record<string, SerializedSchema>;
@@ -50,6 +50,7 @@ export declare class ObjectSchema<Props extends ObjectSchemaProps, Src extends O
50
50
  nullable(): ObjectSchema<Props, Src | null>;
51
51
  readonly(): ObjectSchema<Props, Src>;
52
52
  hidden(): ObjectSchema<Props, Src>;
53
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
53
54
  protected executeSerialize(): SerializedSchema;
54
55
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
55
56
  }
@@ -3,10 +3,11 @@ import { RenderSelector, ReifiedRender } from "../render.js";
3
3
  import { ValRouter } from "../router.js";
4
4
  import { SelectorSource } from "../selector/index.js";
5
5
  import { ImageSource } from "../source/image.js";
6
+ import { JsonOf, JsonSource } from "../source/json.js";
6
7
  import { RemoteSource } from "../source/remote.js";
7
8
  import { ModuleFilePath, SourcePath } from "../val/index.js";
8
9
  import { ImageMetadata } from "./image.js";
9
- import { ValidationErrors } from "./validation/ValidationError.js";
10
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
10
11
  type MediaOptions = {
11
12
  type: "files" | "images";
12
13
  accept: string;
@@ -26,10 +27,25 @@ export type SerializedRecordSchema = {
26
27
  directory?: string;
27
28
  remote?: boolean;
28
29
  alt?: SerializedSchema;
30
+ jsonValues?: boolean;
29
31
  readonly?: boolean;
30
32
  hidden?: boolean;
31
33
  description?: string;
32
34
  };
35
+ /**
36
+ * The source type of a `.jsonValues()` record: every entry value is EITHER a
37
+ * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
38
+ * {@link JsonOf}) item type, OR the item value written inline.
39
+ *
40
+ * Inline values are accepted by the TYPE on purpose: hand-authoring an entry
41
+ * directly in the `.val.ts` (or copying one in from a non-jsonValues record) is
42
+ * the natural first thing to write, and a type error there is a dead end — the
43
+ * author cannot see what to write instead. Validation reports the inline entry
44
+ * (`jsonValues:extract-entry`) and `val validate --fix` moves it into its own
45
+ * `*.val.json`, so the mistake is caught and repaired instead of blocking
46
+ * authoring.
47
+ */
48
+ export type JsonValuesRecordSrc<T extends Schema<SelectorSource>, K extends Schema<string>> = Record<SelectorOfSchema<K>, JsonSource<JsonOf<SelectorOfSchema<T>>> | SelectorOfSchema<T>>;
33
49
  type RecordRenderInput<T extends Schema<SelectorSource>> = {
34
50
  layout: "list";
35
51
  select: (input: {
@@ -41,7 +57,7 @@ type RecordRenderInput<T extends Schema<SelectorSource>> = {
41
57
  image?: ImageSource | RemoteSource<ImageMetadata> | null;
42
58
  };
43
59
  };
44
- export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Schema<string>, Src extends Record<SelectorOfSchema<K>, SelectorOfSchema<T>> | null> extends Schema<Src> {
60
+ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Schema<string>, Src extends Record<SelectorOfSchema<K>, SelectorOfSchema<T>> | JsonValuesRecordSrc<T, K> | null> extends Schema<Src> {
45
61
  private readonly item;
46
62
  private readonly opt;
47
63
  private readonly customValidateFunctions;
@@ -51,8 +67,12 @@ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Sc
51
67
  private readonly isReadonly;
52
68
  private readonly isHidden;
53
69
  private readonly description?;
70
+ /** When true, entry values are lazily loaded {@link JsonSource} thunks. */
71
+ private readonly isJsonValues;
54
72
  private readonly renderInput;
55
- constructor(item: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], currentRouter?: ValRouter | null, keySchema?: Schema<string> | null, mediaOptions?: MediaOptions | undefined, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: RecordRenderInput<T> | null);
73
+ constructor(item: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], currentRouter?: ValRouter | null, keySchema?: Schema<string> | null, mediaOptions?: MediaOptions | undefined, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined,
74
+ /** When true, entry values are lazily loaded {@link JsonSource} thunks. */
75
+ isJsonValues?: boolean, renderInput?: RecordRenderInput<T> | null);
56
76
  describe(description: string | null): RecordSchema<T, K, Src>;
57
77
  validate(validationFunction: (src: Src) => false | string): RecordSchema<T, K, Src>;
58
78
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
@@ -68,8 +88,31 @@ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Sc
68
88
  hidden(): RecordSchema<T, K, Src>;
69
89
  router(router: ValRouter): RecordSchema<T, K, Src>;
70
90
  remote(): RecordSchema<T, K, Src>;
91
+ /**
92
+ * Store each entry's value in its own lazily-loaded `*.val.json` file instead
93
+ * of inlining it in the `.val.ts` module. Entry values become
94
+ * {@link JsonSource} thunks (`c.json(() => import("./entry.val.json"))`),
95
+ * which lets the runtime, the Studio and validation work one entry at a time
96
+ * so a record/router can scale to many thousands of entries.
97
+ *
98
+ * Not supported on image/file galleries (`s.images()` / `s.files()`).
99
+ *
100
+ * Only supported on a module's ROOT record/router — a `.jsonValues()` record
101
+ * nested inside an object/array/record is rejected at startup with a module
102
+ * error, because the single-entry fetch endpoint, the Studio's content
103
+ * substitution and content validation are all root-only.
104
+ */
105
+ jsonValues(): RecordSchema<T, K, JsonValuesRecordSrc<T, K>>;
71
106
  private getRouterValidations;
107
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
72
108
  protected executeSerialize(): SerializedRecordSchema;
109
+ /**
110
+ * Validate the loaded content of a single `.jsonValues()` entry against the
111
+ * item schema. The server calls this once it has loaded the backing
112
+ * `*.val.json` for an entry (the deep validation that `executeValidate`
113
+ * defers).
114
+ */
115
+ validateJsonEntryContent(path: SourcePath, content: SelectorSource): ValidationErrors;
73
116
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
74
117
  render(input: {
75
118
  as: "list";
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { RichTextSource, RichTextOptions, SerializedRichTextOptions } from "../source/richtext.js";
4
4
  import { SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type ValidationOptions = {
7
7
  maxLength?: number;
8
8
  minLength?: number;
@@ -35,6 +35,7 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
35
35
  nullable(): RichTextSchema<O, Src | null>;
36
36
  readonly(): RichTextSchema<O, Src>;
37
37
  hidden(): RichTextSchema<O, Src>;
38
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
38
39
  protected executeSerialize(): SerializedSchema;
39
40
  protected executeRender(): ReifiedRender;
40
41
  }
@@ -1,7 +1,7 @@
1
1
  import { Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { SourcePath } from "../val/index.js";
3
3
  import { ReifiedRender } from "../render.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type RouteOptions = {
6
6
  include?: RegExp;
7
7
  exclude?: RegExp;
@@ -66,6 +66,7 @@ export declare class RouteSchema<Src extends string | null> extends Schema<Src>
66
66
  nullable(): RouteSchema<Src | null>;
67
67
  readonly(): RouteSchema<Src>;
68
68
  hidden(): RouteSchema<Src>;
69
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
69
70
  protected executeSerialize(): SerializedSchema;
70
71
  protected executeRender(): ReifiedRender;
71
72
  }
@@ -1,7 +1,7 @@
1
1
  import { Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { CodeLanguage, ReifiedRender } from "../render.js";
3
3
  import { ModuleFilePath, SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type StringOptions = {
6
6
  maxLength?: number;
7
7
  minLength?: number;
@@ -65,6 +65,7 @@ export declare class StringSchema<Src extends string | null> extends Schema<Src>
65
65
  readonly(): StringSchema<Src>;
66
66
  hidden(): StringSchema<Src>;
67
67
  raw(): StringSchema<Src extends null ? RawString | null : RawString>;
68
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
68
69
  protected executeSerialize(): SerializedSchema;
69
70
  render(input: {
70
71
  as: "textarea";