@valbuild/core 0.15.0 → 0.17.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 (133) hide show
  1. package/ROADMAP.md +106 -0
  2. package/dist/declarations/src/ValApi.d.ts +26 -0
  3. package/dist/declarations/src/expr/eval.d.ts +1 -1
  4. package/dist/declarations/src/future/fetchVal.d.ts +5 -0
  5. package/dist/declarations/src/index.d.ts +38 -9
  6. package/dist/declarations/src/initSchema.d.ts +2 -10
  7. package/dist/declarations/src/initVal.d.ts +3 -21
  8. package/dist/declarations/src/module.d.ts +2 -14
  9. package/dist/declarations/src/patch/index.d.ts +1 -1
  10. package/dist/declarations/src/patch/util.d.ts +2 -0
  11. package/dist/declarations/src/schema/array.d.ts +3 -2
  12. package/dist/declarations/src/schema/boolean.d.ts +3 -2
  13. package/dist/declarations/src/schema/image.d.ts +4 -3
  14. package/dist/declarations/src/schema/index.d.ts +8 -7
  15. package/dist/declarations/src/schema/keyOf.d.ts +23 -0
  16. package/dist/declarations/src/schema/literal.d.ts +3 -2
  17. package/dist/declarations/src/schema/number.d.ts +3 -2
  18. package/dist/declarations/src/schema/object.d.ts +3 -2
  19. package/dist/declarations/src/schema/record.d.ts +19 -0
  20. package/dist/declarations/src/schema/richtext.d.ts +3 -2
  21. package/dist/declarations/src/schema/string.d.ts +3 -2
  22. package/dist/declarations/src/schema/union.d.ts +4 -2
  23. package/dist/declarations/src/schema/validation/ValidationError.d.ts +14 -0
  24. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +2 -0
  25. package/dist/declarations/src/selector/SelectorProxy.d.ts +7 -0
  26. package/dist/declarations/src/selector/array.d.ts +2 -13
  27. package/dist/declarations/src/selector/file.d.ts +1 -4
  28. package/dist/declarations/src/selector/future/array.d.ts +17 -0
  29. package/dist/declarations/src/selector/future/boolean.d.ts +2 -0
  30. package/dist/declarations/src/selector/future/file.d.ts +9 -0
  31. package/dist/declarations/src/selector/{i18n.d.ts → future/i18n.d.ts} +2 -2
  32. package/dist/declarations/src/selector/future/index.d.ts +81 -0
  33. package/dist/declarations/src/selector/future/number.d.ts +2 -0
  34. package/dist/declarations/src/selector/future/object.d.ts +10 -0
  35. package/dist/declarations/src/selector/future/primitive.d.ts +9 -0
  36. package/dist/declarations/src/selector/{remote.d.ts → future/remote.d.ts} +1 -1
  37. package/dist/declarations/src/selector/future/string.d.ts +2 -0
  38. package/dist/declarations/src/selector/index.d.ts +5 -32
  39. package/dist/declarations/src/selector/object.d.ts +2 -9
  40. package/dist/declarations/src/selector/primitive.d.ts +3 -9
  41. package/dist/declarations/src/source/{i18n.d.ts → future/i18n.d.ts} +2 -2
  42. package/dist/declarations/src/source/{remote.d.ts → future/remote.d.ts} +3 -3
  43. package/dist/declarations/src/source/index.d.ts +4 -3
  44. package/dist/declarations/src/val/index.d.ts +2 -2
  45. package/dist/index-369caccf.esm.js +550 -0
  46. package/dist/{index-06df0a5b.esm.js → index-3e3e839e.esm.js} +190 -555
  47. package/dist/{index-9663f28a.cjs.dev.js → index-486c7fbf.cjs.dev.js} +224 -617
  48. package/dist/{index-b2270f8f.cjs.prod.js → index-601a7d73.cjs.prod.js} +224 -617
  49. package/dist/index-8706c87e.cjs.prod.js +582 -0
  50. package/dist/index-a6e642dd.cjs.dev.js +582 -0
  51. package/dist/ops-0d09f8ee.cjs.prod.js +684 -0
  52. package/dist/ops-23a5abb2.esm.js +671 -0
  53. package/dist/ops-f3015423.cjs.dev.js +684 -0
  54. package/dist/valbuild-core.cjs.dev.js +640 -633
  55. package/dist/valbuild-core.cjs.prod.js +640 -633
  56. package/dist/valbuild-core.esm.js +578 -572
  57. package/expr/dist/valbuild-core-expr.cjs.dev.js +8 -8
  58. package/expr/dist/valbuild-core-expr.cjs.prod.js +8 -8
  59. package/expr/dist/valbuild-core-expr.esm.js +2 -2
  60. package/package.json +2 -2
  61. package/patch/dist/valbuild-core-patch.cjs.dev.js +32 -23
  62. package/patch/dist/valbuild-core-patch.cjs.prod.js +32 -23
  63. package/patch/dist/valbuild-core-patch.esm.js +12 -4
  64. package/src/ValApi.ts +85 -0
  65. package/src/expr/eval.test.ts +2 -2
  66. package/src/expr/eval.ts +2 -2
  67. package/src/expr/repl.ts +2 -2
  68. package/src/{fetchVal.test.ts → future/fetchVal.test.ts} +57 -57
  69. package/src/{fetchVal.ts → future/fetchVal.ts} +17 -22
  70. package/src/index.ts +51 -14
  71. package/src/initSchema.ts +11 -12
  72. package/src/initVal.ts +42 -52
  73. package/src/module.test.ts +40 -40
  74. package/src/module.ts +53 -43
  75. package/src/patch/deref.test.ts +1 -1
  76. package/src/patch/deref.ts +1 -1
  77. package/src/patch/index.ts +1 -0
  78. package/src/patch/json.test.ts +0 -1
  79. package/src/patch/util.ts +7 -0
  80. package/src/schema/array.ts +45 -4
  81. package/src/schema/boolean.ts +14 -3
  82. package/src/schema/{i18n.ts → future/i18n.ts} +15 -11
  83. package/src/schema/{oneOf.ts → future/oneOf.ts} +21 -18
  84. package/src/schema/image.ts +66 -6
  85. package/src/schema/index.ts +37 -13
  86. package/src/schema/keyOf.ts +167 -0
  87. package/src/schema/literal.ts +24 -3
  88. package/src/schema/number.ts +14 -3
  89. package/src/schema/object.ts +50 -7
  90. package/src/schema/record.ts +103 -0
  91. package/src/schema/richtext.ts +63 -3
  92. package/src/schema/string.ts +14 -3
  93. package/src/schema/union.ts +4 -3
  94. package/src/schema/validation/ValidationError.ts +16 -0
  95. package/src/schema/validation/ValidationFix.ts +6 -0
  96. package/src/schema/validation.test.ts +291 -0
  97. package/src/selector/SelectorProxy.ts +16 -16
  98. package/src/selector/array.ts +2 -26
  99. package/src/selector/file.ts +1 -9
  100. package/src/selector/{ExprProxy.test.ts → future/ExprProxy.test.ts} +2 -2
  101. package/src/selector/{ExprProxy.ts → future/ExprProxy.ts} +9 -2
  102. package/src/selector/{SelectorProxy.test.ts → future/SelectorProxy.test.ts} +4 -4
  103. package/src/selector/future/SelectorProxy.ts +238 -0
  104. package/src/selector/future/array.ts +37 -0
  105. package/src/selector/future/boolean.ts +4 -0
  106. package/src/selector/future/file.ts +14 -0
  107. package/src/selector/{i18n.ts → future/i18n.ts} +2 -2
  108. package/src/selector/future/index.ts +165 -0
  109. package/src/selector/future/number.ts +4 -0
  110. package/src/selector/future/object.ts +22 -0
  111. package/src/selector/future/primitive.ts +17 -0
  112. package/src/selector/{remote.ts → future/remote.ts} +1 -1
  113. package/src/selector/{selector.test.ts → future/selector.test.ts} +8 -28
  114. package/src/selector/{selectorOf.ts → future/selectorOf.ts} +1 -1
  115. package/src/selector/future/string.ts +4 -0
  116. package/src/selector/index.ts +4 -46
  117. package/src/selector/object.ts +2 -19
  118. package/src/selector/primitive.ts +3 -16
  119. package/src/source/{i18n.ts → future/i18n.ts} +2 -2
  120. package/src/source/{remote.ts → future/remote.ts} +3 -3
  121. package/src/source/index.ts +3 -2
  122. package/src/val/array.ts +1 -1
  123. package/src/val/index.ts +2 -2
  124. package/src/val/object.ts +1 -1
  125. package/dist/createClass-012eebbf.esm.js +0 -109
  126. package/dist/createClass-a436dbfe.cjs.dev.js +0 -116
  127. package/dist/createClass-de7426aa.cjs.prod.js +0 -116
  128. package/dist/declarations/src/fetchVal.d.ts +0 -5
  129. package/dist/declarations/src/schema/i18n.d.ts +0 -21
  130. package/dist/declarations/src/schema/oneOf.d.ts +0 -22
  131. package/dist/ops-6fae92a1.esm.js +0 -12
  132. package/dist/ops-87cdbafc.cjs.dev.js +0 -14
  133. package/dist/ops-ae4d1bc2.cjs.prod.js +0 -14
package/src/module.ts CHANGED
@@ -4,16 +4,15 @@ import {
4
4
  GenericSelector,
5
5
  SelectorOf,
6
6
  SelectorSource,
7
- SourceOrExpr,
7
+ GetSource,
8
+ GetSchema,
9
+ Path,
8
10
  } from "./selector";
9
- import { Source, SourceArray } from "./source";
10
- import { newSelectorProxy } from "./selector/SelectorProxy";
11
+ import { Source } from "./source";
11
12
  import { ModuleId, ModulePath, SourcePath } from "./val";
12
13
  import { Expr } from "./expr";
13
14
  import { ArraySchema, SerializedArraySchema } from "./schema/array";
14
- import { I18nSchema, SerializedI18nSchema } from "./schema/i18n";
15
15
  import { UnionSchema, SerializedUnionSchema } from "./schema/union";
16
- import { OneOfSchema, SerializedOneOfSchema } from "./schema/oneOf";
17
16
  import { Json } from "./Json";
18
17
  import { RichTextSchema, SerializedRichTextSchema } from "./schema/richtext";
19
18
  import {
@@ -43,11 +42,15 @@ export function content<T extends Schema<SelectorSource>>(
43
42
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
44
43
  source: SchemaTypeOf<T>
45
44
  ): ValModule<SchemaTypeOf<T>> {
46
- return newSelectorProxy(source, id as SourcePath, schema);
45
+ return {
46
+ [GetSource]: source,
47
+ [GetSchema]: schema,
48
+ [Path]: id as SourcePath,
49
+ } as unknown as ValModule<SchemaTypeOf<T>>;
47
50
  }
48
51
 
49
- export function getRawSource(valModule: ValModule<SelectorSource>): Source {
50
- const sourceOrExpr = valModule[SourceOrExpr];
52
+ export function getSource(valModule: ValModule<SelectorSource>): Source {
53
+ const sourceOrExpr = valModule[GetSource];
51
54
  if (sourceOrExpr instanceof Expr) {
52
55
  throw Error("Cannot get raw source of an Expr");
53
56
  }
@@ -100,14 +103,14 @@ function isArraySchema(
100
103
  );
101
104
  }
102
105
 
103
- function isI18nSchema(
104
- schema: Schema<SelectorSource> | SerializedSchema
105
- ): schema is I18nSchema<readonly string[]> | SerializedI18nSchema {
106
- return (
107
- schema instanceof I18nSchema ||
108
- (typeof schema === "object" && "type" in schema && schema.type === "i18n")
109
- );
110
- }
106
+ // function isI18nSchema(
107
+ // schema: Schema<SelectorSource> | SerializedSchema
108
+ // ): schema is I18nSchema<readonly string[]> | SerializedI18nSchema {
109
+ // return (
110
+ // schema instanceof I18nSchema ||
111
+ // (typeof schema === "object" && "type" in schema && schema.type === "i18n")
112
+ // );
113
+ // }
111
114
 
112
115
  function isUnionSchema(
113
116
  schema: Schema<SelectorSource> | SerializedSchema
@@ -144,15 +147,14 @@ function isImageSchema(
144
147
  );
145
148
  }
146
149
 
147
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
148
- function isOneOfSchema(
149
- schema: Schema<SelectorSource> | SerializedSchema
150
- ): schema is OneOfSchema<GenericSelector<SourceArray>> | SerializedOneOfSchema {
151
- return (
152
- schema instanceof OneOfSchema ||
153
- (typeof schema === "object" && "type" in schema && schema.type === "oneOf")
154
- );
155
- }
150
+ // function isOneOfSchema(
151
+ // schema: Schema<SelectorSource> | SerializedSchema
152
+ // ): schema is OneOfSchema<GenericSelector<SourceArray>> | SerializedOneOfSchema {
153
+ // return (
154
+ // schema instanceof OneOfSchema ||
155
+ // (typeof schema === "object" && "type" in schema && schema.type === "oneOf")
156
+ // );
157
+ // }
156
158
 
157
159
  export function resolvePath(
158
160
  path: ModulePath,
@@ -204,23 +206,23 @@ export function resolvePath(
204
206
  }
205
207
  resolvedSource = resolvedSource[part];
206
208
  resolvedSchema = resolvedSchema.items[part];
207
- } else if (isI18nSchema(resolvedSchema)) {
208
- if (!resolvedSchema.locales.includes(part)) {
209
- throw Error(
210
- `Invalid path: i18n schema ${resolvedSchema} supports locales ${resolvedSchema.locales.join(
211
- ", "
212
- )}, but found: ${part}`
213
- );
214
- }
215
- if (!Object.keys(resolvedSource).includes(part)) {
216
- throw Error(
217
- `Schema type error: expected source to be type of i18n with locale ${part}, but got ${JSON.stringify(
218
- Object.keys(resolvedSource)
219
- )}`
220
- );
221
- }
222
- resolvedSource = resolvedSource[part];
223
- resolvedSchema = resolvedSchema.item;
209
+ // } else if (isI18nSchema(resolvedSchema)) {
210
+ // if (!resolvedSchema.locales.includes(part)) {
211
+ // throw Error(
212
+ // `Invalid path: i18n schema ${resolvedSchema} supports locales ${resolvedSchema.locales.join(
213
+ // ", "
214
+ // )}, but found: ${part}`
215
+ // );
216
+ // }
217
+ // if (!Object.keys(resolvedSource).includes(part)) {
218
+ // throw Error(
219
+ // `Schema type error: expected source to be type of i18n with locale ${part}, but got ${JSON.stringify(
220
+ // Object.keys(resolvedSource)
221
+ // )}`
222
+ // );
223
+ // }
224
+ // resolvedSource = resolvedSource[part];
225
+ // resolvedSchema = resolvedSchema.item;
224
226
  } else if (isImageSchema(resolvedSchema)) {
225
227
  return {
226
228
  path: origParts
@@ -270,7 +272,15 @@ export function resolvePath(
270
272
  throw Error(`Invalid path: ${parts.join(".")} is not a valid path`);
271
273
  }
272
274
  return {
273
- path,
275
+ path: origParts
276
+ .map((p) => {
277
+ if (!Number.isNaN(Number(p))) {
278
+ return p;
279
+ } else {
280
+ return JSON.stringify(p);
281
+ }
282
+ })
283
+ .join("."), // TODO: create a function generate path from parts (not sure if this always works)
274
284
  schema: resolvedSchema,
275
285
  source: resolvedSource,
276
286
  };
@@ -1,6 +1,6 @@
1
1
  import { file } from "../source/file";
2
2
  import { result } from "../fp";
3
- import { remote } from "../source/remote";
3
+ import { remote } from "../source/future/remote";
4
4
  import { derefPatch, DerefPatchResult } from "./deref";
5
5
  import { JSONOps } from "./json";
6
6
  import { PatchError } from "./ops";
@@ -1,6 +1,6 @@
1
1
  import { FILE_REF_PROP, isFile } from "../source/file";
2
2
  import { result } from "../fp";
3
- import { isRemote, REMOTE_REF_PROP } from "../source/remote";
3
+ import { isRemote, REMOTE_REF_PROP } from "../source/future/remote";
4
4
  import { Ops, PatchError } from "./ops";
5
5
  import { Patch } from "./patch";
6
6
 
@@ -8,4 +8,5 @@ export {
8
8
  deepEqual,
9
9
  deepClone,
10
10
  parseAndValidateArrayIndex,
11
+ sourceToPatchPath,
11
12
  } from "./util";
@@ -1,4 +1,3 @@
1
- import { describe, test, expect } from "@jest/globals";
2
1
  import { JSONOps } from "./json";
3
2
  import * as result from "../fp/result";
4
3
  import { PatchError, JSONValue } from "./ops";
package/src/patch/util.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { array, result } from "../fp";
2
2
  import { PatchError, ReadonlyJSONValue, ToMutable } from "./ops";
3
+ import { splitModuleIdAndModulePath } from "../module";
4
+ import { SourcePath } from "../val";
3
5
 
4
6
  export function isNotRoot(path: string[]): path is array.NonEmptyArray<string> {
5
7
  return array.isNonEmpty(path);
@@ -65,3 +67,8 @@ export function parseAndValidateArrayIndex(
65
67
  }
66
68
  return result.ok(Number(value));
67
69
  }
70
+
71
+ export function sourceToPatchPath(sourcePath: SourcePath) {
72
+ const [, modulePath] = splitModuleIdAndModulePath(sourcePath);
73
+ return modulePath.split(".").map((p) => JSON.parse(p).toString());
74
+ }
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { Schema, SchemaTypeOf, SerializedSchema } from ".";
3
3
  import { SelectorSource } from "../selector";
4
+ import { createValPathOfItem } from "../selector/SelectorProxy";
4
5
  import { SourcePath } from "../val";
6
+ import { ValidationErrors } from "./validation/ValidationError";
5
7
 
6
8
  export type SerializedArraySchema = {
7
9
  type: "array";
@@ -16,11 +18,46 @@ export class ArraySchema<T extends Schema<SelectorSource>> extends Schema<
16
18
  super();
17
19
  }
18
20
 
19
- validate(src: SchemaTypeOf<T>[]): false | Record<SourcePath, string[]> {
20
- throw new Error("Method not implemented.");
21
+ validate(path: SourcePath, src: SchemaTypeOf<T>[]): ValidationErrors {
22
+ let error: ValidationErrors = false;
23
+
24
+ if (this.opt && (src === null || src === undefined)) {
25
+ return false;
26
+ }
27
+
28
+ if (typeof src !== "object" || !Array.isArray(src)) {
29
+ return {
30
+ [path]: [{ message: `Expected 'array', got '${typeof src}'` }],
31
+ } as ValidationErrors;
32
+ }
33
+ src.forEach((i, idx) => {
34
+ const subPath = createValPathOfItem(path, idx);
35
+ if (!subPath) {
36
+ error = this.appendValidationError(
37
+ error,
38
+ path,
39
+ `Internal error: could not create path at ${
40
+ !path && typeof path === "string" ? "<empty string>" : path
41
+ } at index ${idx}`, // Should! never happen
42
+ src
43
+ );
44
+ } else {
45
+ const subError = this.item.validate(subPath, i);
46
+ if (subError && error) {
47
+ error = {
48
+ ...subError,
49
+ ...error,
50
+ };
51
+ } else if (subError) {
52
+ error = subError;
53
+ }
54
+ }
55
+ });
56
+
57
+ return error;
21
58
  }
22
59
 
23
- match(src: SchemaTypeOf<T>[]): boolean {
60
+ assert(src: SchemaTypeOf<T>[]): boolean {
24
61
  if (this.opt && (src === null || src === undefined)) {
25
62
  return true;
26
63
  }
@@ -28,7 +65,11 @@ export class ArraySchema<T extends Schema<SelectorSource>> extends Schema<
28
65
  return false;
29
66
  }
30
67
 
31
- // TODO: checks all items
68
+ for (const item of src) {
69
+ if (!this.item.assert(item)) {
70
+ return false;
71
+ }
72
+ }
32
73
  return typeof src === "object" && Array.isArray(src);
33
74
  }
34
75
 
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { Schema, SerializedSchema } from ".";
3
3
  import { SourcePath } from "../val";
4
+ import { ValidationErrors } from "./validation/ValidationError";
4
5
 
5
6
  export type SerializedBooleanSchema = {
6
7
  type: "boolean";
@@ -11,11 +12,21 @@ export class BooleanSchema<Src extends boolean | null> extends Schema<Src> {
11
12
  constructor(readonly opt: boolean = false) {
12
13
  super();
13
14
  }
14
- validate(src: Src): false | Record<SourcePath, string[]> {
15
- throw new Error("Method not implemented.");
15
+ validate(path: SourcePath, src: Src): ValidationErrors {
16
+ if (this.opt && (src === null || src === undefined)) {
17
+ return false;
18
+ }
19
+ if (typeof src !== "boolean") {
20
+ return {
21
+ [path]: [
22
+ { message: `Expected 'boolean', got '${typeof src}'`, value: src },
23
+ ],
24
+ } as ValidationErrors;
25
+ }
26
+ return false;
16
27
  }
17
28
 
18
- match(src: Src): boolean {
29
+ assert(src: Src): boolean {
19
30
  if (this.opt && (src === null || src === undefined)) {
20
31
  return true;
21
32
  }
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import { Schema, SchemaTypeOf, SerializedSchema } from ".";
3
- import { I18nCompatibleSource, I18nSource } from "../source/i18n";
4
- import { SourcePath } from "../val";
2
+ import { Schema, SchemaTypeOf, SerializedSchema } from "..";
3
+ import { I18nCompatibleSource, I18nSource } from "../../source/future/i18n";
4
+ import { SourcePath } from "../../val";
5
+ import { ValidationErrors } from "../validation/ValidationError";
5
6
 
6
7
  export type SerializedI18nSchema = {
7
8
  type: "i18n";
@@ -22,12 +23,13 @@ export class I18nSchema<Locales extends readonly string[]> extends Schema<
22
23
  }
23
24
 
24
25
  validate(
26
+ path: SourcePath,
25
27
  src: I18nSource<Locales, SchemaTypeOf<Schema<I18nCompatibleSource>>>
26
- ): false | Record<SourcePath, string[]> {
28
+ ): ValidationErrors {
27
29
  throw new Error("Method not implemented.");
28
30
  }
29
31
 
30
- match(
32
+ assert(
31
33
  src: I18nSource<Locales, SchemaTypeOf<Schema<I18nCompatibleSource>>>
32
34
  ): boolean {
33
35
  throw new Error("Method not implemented.");
@@ -41,12 +43,14 @@ export class I18nSchema<Locales extends readonly string[]> extends Schema<
41
43
  }
42
44
 
43
45
  serialize(): SerializedSchema {
44
- return {
45
- type: "i18n",
46
- item: this.item.serialize(),
47
- locales: this.locales,
48
- opt: this.opt,
49
- };
46
+ throw new Error("Method not implemented.");
47
+
48
+ // return {
49
+ // type: "i18n",
50
+ // item: this.item.serialize(),
51
+ // locales: this.locales,
52
+ // opt: this.opt,
53
+ // };
50
54
  }
51
55
  }
52
56
 
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import { Schema, SerializedSchema } from ".";
3
- import { ValModuleBrand } from "../module";
4
- import { GenericSelector } from "../selector";
5
- import { Source, SourceArray } from "../source";
6
- import { getValPath, SourcePath } from "../val";
2
+ import { Schema, SerializedSchema } from "..";
3
+ import { ValModuleBrand } from "../../module";
4
+ import { GenericSelector } from "../../selector/future";
5
+ import { Source, SourceArray } from "../../source";
6
+ import { SourcePath } from "../../val";
7
+ import { ValidationErrors } from "../validation/ValidationError";
7
8
 
8
9
  export type SerializedOneOfSchema = {
9
10
  type: "oneOf";
@@ -26,10 +27,10 @@ export class OneOfSchema<
26
27
  constructor(readonly selector: Sel, readonly opt: boolean = false) {
27
28
  super();
28
29
  }
29
- validate(src: OneOfSelector<Sel>): false | Record<SourcePath, string[]> {
30
+ validate(path: SourcePath, src: OneOfSelector<Sel>): ValidationErrors {
30
31
  throw new Error("Method not implemented.");
31
32
  }
32
- match(src: OneOfSelector<Sel>): boolean {
33
+ assert(src: OneOfSelector<Sel>): boolean {
33
34
  throw new Error("Method not implemented.");
34
35
  }
35
36
  optional(): Schema<OneOfSelector<Sel> | null> {
@@ -37,17 +38,19 @@ export class OneOfSchema<
37
38
  }
38
39
 
39
40
  serialize(): SerializedSchema {
40
- const path = getValPath(this.selector);
41
- if (!path) {
42
- throw new Error(
43
- "Cannot serialize oneOf schema with empty selector. Make sure a Val module is used."
44
- );
45
- }
46
- return {
47
- type: "oneOf",
48
- selector: path,
49
- opt: this.opt,
50
- };
41
+ throw new Error("Method not implemented.");
42
+
43
+ // const path = getValPath(this.selector);
44
+ // if (!path) {
45
+ // throw new Error(
46
+ // "Cannot serialize oneOf schema with empty selector. Make sure a Val module is used."
47
+ // );
48
+ // }
49
+ // return {
50
+ // type: "oneOf",
51
+ // selector: path,
52
+ // opt: this.opt,
53
+ // };
51
54
  }
52
55
  }
53
56
 
@@ -1,7 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { Schema, SerializedSchema } from ".";
3
+ import { VAL_EXTENSION } from "../source";
3
4
  import { FileSource, FILE_REF_PROP } from "../source/file";
4
5
  import { SourcePath } from "../val";
6
+ import { ValidationErrors } from "./validation/ValidationError";
5
7
 
6
8
  export type ImageOptions = {
7
9
  ext: ["jpg"] | ["webp"];
@@ -29,13 +31,71 @@ export class ImageSchema<
29
31
  super();
30
32
  }
31
33
 
32
- validate(src: Src): false | Record<SourcePath, string[]> {
33
- throw new Error("Method not implemented.");
34
+ validate(path: SourcePath, src: Src): ValidationErrors {
35
+ if (this.opt && (src === null || src === undefined)) {
36
+ return false;
37
+ }
38
+ if (src === null || src === undefined) {
39
+ return {
40
+ [path]: [
41
+ {
42
+ message: `Non-optional image was null or undefined.`,
43
+ value: src,
44
+ },
45
+ ],
46
+ } as ValidationErrors;
47
+ }
48
+ if (typeof src[FILE_REF_PROP] !== "string") {
49
+ return {
50
+ [path]: [
51
+ {
52
+ message: `Image did not have a file reference string. Got: ${typeof src[
53
+ FILE_REF_PROP
54
+ ]}`,
55
+ value: src,
56
+ },
57
+ ],
58
+ } as ValidationErrors;
59
+ }
60
+
61
+ if (src[VAL_EXTENSION] !== "file") {
62
+ return {
63
+ [path]: [
64
+ {
65
+ message: `Image did not have the valid file extension type. Got: ${src[VAL_EXTENSION]}`,
66
+ value: src,
67
+ },
68
+ ],
69
+ } as ValidationErrors;
70
+ }
71
+ if (src.metadata) {
72
+ return {
73
+ [path]: [
74
+ {
75
+ message: `Found metadata, but it could not be validated. Image metadata must be an object with the required props: width (positive number), height (positive number) and sha256 (string of length 64 of the base16 hash).`, // These validation errors will have to be picked up by logic outside of this package and revalidated. Reasons: 1) we have to read files to verify the metadata, which is handled differently in different runtimes (Browser, QuickJS, Node.js); 2) we want to keep this package dependency free.
76
+ value: src,
77
+ fixes: ["image:replace-metadata"],
78
+ },
79
+ ],
80
+ } as ValidationErrors;
81
+ }
82
+
83
+ return {
84
+ [path]: [
85
+ {
86
+ message: `Could not validate Image metadata.`,
87
+ value: src,
88
+ fixes: ["image:add-metadata"],
89
+ },
90
+ ],
91
+ } as ValidationErrors;
34
92
  }
35
93
 
36
- match(src: Src): boolean {
37
- // TODO:
38
- return true;
94
+ assert(src: Src): boolean {
95
+ if (this.opt && (src === null || src === undefined)) {
96
+ return true;
97
+ }
98
+ return src?.[FILE_REF_PROP] === "image" && src?.[VAL_EXTENSION] === "file";
39
99
  }
40
100
 
41
101
  optional(): Schema<Src | null> {
@@ -57,7 +117,7 @@ export const image = (
57
117
  return new ImageSchema(options);
58
118
  };
59
119
 
60
- export const convertImageSource = (
120
+ export const convertFileSource = (
61
121
  src: FileSource<ImageMetadata>
62
122
  ): { url: string; metadata?: ImageMetadata } => {
63
123
  // TODO: /public should be configurable
@@ -1,41 +1,65 @@
1
1
  import { SelectorSource } from "../selector";
2
- import { RemoteCompatibleSource, RemoteSource } from "../source/remote";
2
+ // import { RemoteCompatibleSource, RemoteSource } from "../source/remote";
3
3
  import { SourcePath } from "../val";
4
4
  import { SerializedArraySchema } from "./array";
5
5
  import { SerializedBooleanSchema } from "./boolean";
6
- import { SerializedI18nSchema } from "./i18n";
7
6
  import { SerializedImageSchema } from "./image";
7
+ import { SerializedKeyOfSchema } from "./keyOf";
8
8
  import { SerializedLiteralSchema } from "./literal";
9
9
  import { SerializedNumberSchema } from "./number";
10
10
  import { SerializedObjectSchema } from "./object";
11
- import { SerializedOneOfSchema } from "./oneOf";
11
+ import { SerializedRecordSchema } from "./record";
12
12
  import { SerializedRichTextSchema } from "./richtext";
13
13
  import { SerializedStringSchema } from "./string";
14
14
  import { SerializedUnionSchema } from "./union";
15
+ import { ValidationErrors } from "./validation/ValidationError";
16
+ // import { SerializedI18nSchema } from "./future/i18n";
17
+ // import { SerializedOneOfSchema } from "./future/oneOf";
15
18
 
16
19
  export type SerializedSchema =
20
+ // | SerializedOneOfSchema
21
+ // | SerializedI18nSchema
17
22
  | SerializedStringSchema
18
23
  | SerializedLiteralSchema
19
24
  | SerializedBooleanSchema
20
25
  | SerializedNumberSchema
21
26
  | SerializedObjectSchema
22
- | SerializedOneOfSchema
23
27
  | SerializedArraySchema
24
28
  | SerializedUnionSchema
25
29
  | SerializedRichTextSchema
26
- | SerializedImageSchema
27
- | SerializedI18nSchema;
30
+ | SerializedRecordSchema
31
+ | SerializedKeyOfSchema
32
+ | SerializedImageSchema;
28
33
 
29
34
  export abstract class Schema<Src extends SelectorSource> {
30
- abstract validate(src: Src): false | Record<SourcePath, string[]>;
31
- abstract match(src: Src): boolean; // TODO: false | Record<SourcePath, string[]>;
35
+ abstract validate(path: SourcePath, src: Src): ValidationErrors;
36
+ abstract assert(src: Src): boolean; // TODO: false | Record<SourcePath, string[]>;
32
37
  abstract optional(): Schema<Src | null>;
33
38
  abstract serialize(): SerializedSchema;
34
- remote(): Src extends RemoteCompatibleSource
35
- ? Schema<RemoteSource<Src>>
36
- : never {
37
- // TODO: Schema<never, "Cannot create remote schema from non-remote source.">
38
- throw new Error("You need Val Ultra to use .remote()");
39
+ // remote(): Src extends RemoteCompatibleSource
40
+ // ? Schema<RemoteSource<Src>>
41
+ // : never {
42
+ // // TODO: Schema<never, "Cannot create remote schema from non-remote source.">
43
+ // throw new Error("You need Val Ultra to use .remote()");
44
+ // }
45
+
46
+ /** MUTATES! since internal and perf sensitive */
47
+ protected appendValidationError(
48
+ current: ValidationErrors,
49
+ path: SourcePath,
50
+ message: string,
51
+ value?: unknown
52
+ ): ValidationErrors {
53
+ if (current) {
54
+ if (current[path]) {
55
+ current[path].push({ message, value });
56
+ } else {
57
+ current[path] = [{ message, value }];
58
+ }
59
+ return current;
60
+ } else {
61
+ return { [path]: [{ message, value }] } as ValidationErrors;
62
+ }
39
63
  }
40
64
  }
41
65