typesea 0.2.0 → 0.3.1

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 (159) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +104 -41
  3. package/SECURITY.md +52 -0
  4. package/dist/aot/index.d.ts +1 -1
  5. package/dist/aot/index.d.ts.map +1 -1
  6. package/dist/aot/index.js +22 -3
  7. package/dist/builders/composite.d.ts +6 -3
  8. package/dist/builders/composite.d.ts.map +1 -1
  9. package/dist/builders/composite.js +22 -13
  10. package/dist/builders/index.d.ts +6 -5
  11. package/dist/builders/index.d.ts.map +1 -1
  12. package/dist/builders/index.js +5 -4
  13. package/dist/builders/modifier.d.ts +6 -0
  14. package/dist/builders/modifier.d.ts.map +1 -1
  15. package/dist/builders/modifier.js +14 -0
  16. package/dist/builders/object/guard.d.ts +54 -2
  17. package/dist/builders/object/guard.d.ts.map +1 -1
  18. package/dist/builders/object/guard.js +117 -7
  19. package/dist/builders/object/index.d.ts +2 -2
  20. package/dist/builders/object/index.d.ts.map +1 -1
  21. package/dist/builders/object/index.js +1 -1
  22. package/dist/builders/object/schema.d.ts +33 -2
  23. package/dist/builders/object/schema.d.ts.map +1 -1
  24. package/dist/builders/object/schema.js +198 -8
  25. package/dist/builders/object/types.d.ts +15 -0
  26. package/dist/builders/object/types.d.ts.map +1 -1
  27. package/dist/builders/runtime.d.ts +40 -0
  28. package/dist/builders/runtime.d.ts.map +1 -0
  29. package/dist/builders/runtime.js +150 -0
  30. package/dist/builders/scalar.d.ts +20 -1
  31. package/dist/builders/scalar.d.ts.map +1 -1
  32. package/dist/builders/scalar.js +54 -1
  33. package/dist/builders/table.d.ts +31 -5
  34. package/dist/builders/table.d.ts.map +1 -1
  35. package/dist/builders/table.js +31 -5
  36. package/dist/builders/types.d.ts +6 -0
  37. package/dist/builders/types.d.ts.map +1 -1
  38. package/dist/compile/check-composite.d.ts +3 -1
  39. package/dist/compile/check-composite.d.ts.map +1 -1
  40. package/dist/compile/check-composite.js +143 -11
  41. package/dist/compile/check-scalar.d.ts +10 -0
  42. package/dist/compile/check-scalar.d.ts.map +1 -1
  43. package/dist/compile/check-scalar.js +138 -2
  44. package/dist/compile/check.d.ts.map +1 -1
  45. package/dist/compile/check.js +25 -3
  46. package/dist/compile/context.d.ts.map +1 -1
  47. package/dist/compile/context.js +2 -0
  48. package/dist/compile/first.d.ts +26 -0
  49. package/dist/compile/first.d.ts.map +1 -0
  50. package/dist/compile/first.js +850 -0
  51. package/dist/compile/graph-predicate.d.ts.map +1 -1
  52. package/dist/compile/graph-predicate.js +389 -18
  53. package/dist/compile/guard.d.ts +2 -1
  54. package/dist/compile/guard.d.ts.map +1 -1
  55. package/dist/compile/guard.js +54 -8
  56. package/dist/compile/predicate.d.ts.map +1 -1
  57. package/dist/compile/predicate.js +156 -5
  58. package/dist/compile/runtime.d.ts +20 -1
  59. package/dist/compile/runtime.d.ts.map +1 -1
  60. package/dist/compile/runtime.js +31 -0
  61. package/dist/compile/source.d.ts.map +1 -1
  62. package/dist/compile/source.js +27 -3
  63. package/dist/compile/types.d.ts +2 -0
  64. package/dist/compile/types.d.ts.map +1 -1
  65. package/dist/decoder/index.d.ts +60 -0
  66. package/dist/decoder/index.d.ts.map +1 -1
  67. package/dist/decoder/index.js +164 -1
  68. package/dist/evaluate/check-composite.d.ts +52 -2
  69. package/dist/evaluate/check-composite.d.ts.map +1 -1
  70. package/dist/evaluate/check-composite.js +193 -6
  71. package/dist/evaluate/check-scalar.d.ts +9 -0
  72. package/dist/evaluate/check-scalar.d.ts.map +1 -1
  73. package/dist/evaluate/check-scalar.js +92 -3
  74. package/dist/evaluate/check.d.ts.map +1 -1
  75. package/dist/evaluate/check.js +19 -4
  76. package/dist/evaluate/shared.d.ts +19 -0
  77. package/dist/evaluate/shared.d.ts.map +1 -1
  78. package/dist/evaluate/shared.js +35 -0
  79. package/dist/guard/array.d.ts +48 -0
  80. package/dist/guard/array.d.ts.map +1 -0
  81. package/dist/guard/array.js +84 -0
  82. package/dist/guard/base.d.ts +32 -2
  83. package/dist/guard/base.d.ts.map +1 -1
  84. package/dist/guard/base.js +74 -3
  85. package/dist/guard/date.d.ts +34 -0
  86. package/dist/guard/date.d.ts.map +1 -0
  87. package/dist/guard/date.js +60 -0
  88. package/dist/guard/index.d.ts +2 -0
  89. package/dist/guard/index.d.ts.map +1 -1
  90. package/dist/guard/index.js +2 -0
  91. package/dist/guard/number.d.ts +60 -0
  92. package/dist/guard/number.d.ts.map +1 -1
  93. package/dist/guard/number.js +129 -0
  94. package/dist/guard/read.d.ts +53 -1
  95. package/dist/guard/read.d.ts.map +1 -1
  96. package/dist/guard/read.js +102 -0
  97. package/dist/guard/string.d.ts +82 -0
  98. package/dist/guard/string.d.ts.map +1 -1
  99. package/dist/guard/string.js +213 -0
  100. package/dist/guard/types.d.ts +18 -0
  101. package/dist/guard/types.d.ts.map +1 -1
  102. package/dist/index.d.ts +4 -4
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +4 -4
  105. package/dist/ir/builder.d.ts +3 -3
  106. package/dist/ir/builder.d.ts.map +1 -1
  107. package/dist/ir/builder.js +5 -2
  108. package/dist/ir/freeze.js +7 -0
  109. package/dist/ir/types.d.ts +4 -1
  110. package/dist/ir/types.d.ts.map +1 -1
  111. package/dist/ir/validate.d.ts.map +1 -1
  112. package/dist/ir/validate.js +35 -1
  113. package/dist/issue/index.d.ts +1 -1
  114. package/dist/issue/index.d.ts.map +1 -1
  115. package/dist/issue/index.js +4 -0
  116. package/dist/json-schema/emit-composite.d.ts +6 -2
  117. package/dist/json-schema/emit-composite.d.ts.map +1 -1
  118. package/dist/json-schema/emit-composite.js +66 -12
  119. package/dist/json-schema/emit-scalar.d.ts.map +1 -1
  120. package/dist/json-schema/emit-scalar.js +54 -1
  121. package/dist/json-schema/emit.d.ts.map +1 -1
  122. package/dist/json-schema/emit.js +11 -2
  123. package/dist/json-schema/types.d.ts +7 -1
  124. package/dist/json-schema/types.d.ts.map +1 -1
  125. package/dist/kind/index.d.ts +25 -0
  126. package/dist/kind/index.d.ts.map +1 -1
  127. package/dist/kind/index.js +26 -3
  128. package/dist/lower/index.d.ts.map +1 -1
  129. package/dist/lower/index.js +52 -3
  130. package/dist/message/index.d.ts +18 -0
  131. package/dist/message/index.d.ts.map +1 -1
  132. package/dist/message/index.js +67 -0
  133. package/dist/optimize/domain.js +6 -2
  134. package/dist/optimize/map-node.d.ts.map +1 -1
  135. package/dist/optimize/map-node.js +3 -0
  136. package/dist/plan/cache.js +13 -1
  137. package/dist/plan/predicate.d.ts.map +1 -1
  138. package/dist/plan/predicate.js +33 -3
  139. package/dist/plan/schema-predicate.d.ts.map +1 -1
  140. package/dist/plan/schema-predicate.js +267 -8
  141. package/dist/schema/freeze.js +22 -0
  142. package/dist/schema/index.d.ts +2 -2
  143. package/dist/schema/index.d.ts.map +1 -1
  144. package/dist/schema/index.js +1 -1
  145. package/dist/schema/types.d.ts +89 -4
  146. package/dist/schema/types.d.ts.map +1 -1
  147. package/dist/schema/types.js +8 -1
  148. package/dist/schema/undefined.d.ts.map +1 -1
  149. package/dist/schema/undefined.js +5 -0
  150. package/dist/schema/validate.d.ts.map +1 -1
  151. package/dist/schema/validate.js +111 -4
  152. package/docs/api.md +79 -10
  153. package/docs/assets/benchmark-headline.svg +33 -33
  154. package/docs/engine-notes.md +9 -5
  155. package/docs/index.html +1366 -722
  156. package/docs/ko/api.md +383 -0
  157. package/docs/ko/engine-notes.md +156 -0
  158. package/docs/ko/readme.md +404 -0
  159. package/package.json +6 -2
@@ -8,7 +8,7 @@ import { BaseGuard, TypeSeaAssertionError } from "../guard/index.js";
8
8
  import { finalizeIssueArray } from "../issue/index.js";
9
9
  import { err, ok } from "../result/index.js";
10
10
  import { freezeSchema, isSchemaValue } from "../schema/index.js";
11
- import { makeDynamicCheck, makeDynamicIssueCheck, strictKeys } from "./runtime.js";
11
+ import { makeDynamicCheck, makeDynamicFirstIssueCheck, makeDynamicIssueCheck, strictKeys } from "./runtime.js";
12
12
  import { emitCompiledSourceBundle } from "./source.js";
13
13
  const trustedCollectors = new WeakSet();
14
14
  const trustedCheckResults = new WeakSet();
@@ -24,7 +24,8 @@ export class CompiledBaseGuard extends BaseGuard {
24
24
  #collect;
25
25
  #trustedCollector;
26
26
  #checkResult;
27
- constructor(schema, test, collect, source, trustedCollector = false, checkResult) {
27
+ #checkFirstResult;
28
+ constructor(schema, test, collect, source, trustedCollector = false, checkResult, checkFirstResult) {
28
29
  if (typeof test !== "function") {
29
30
  throw new TypeError("compiled guard test must be a function");
30
31
  }
@@ -42,9 +43,15 @@ export class CompiledBaseGuard extends BaseGuard {
42
43
  trustedCheckResults.has(checkResult)
43
44
  ? checkResult
44
45
  : undefined;
46
+ this.#checkFirstResult = checkFirstResult !== undefined &&
47
+ trustedCheckResults.has(checkFirstResult)
48
+ ? checkFirstResult
49
+ : undefined;
45
50
  defineReadonlyProperty(this, "source", source, true);
46
- if (trustedPredicates.has(test) && this.#checkResult !== undefined) {
47
- defineTrustedHotMethods(this, test, this.#checkResult);
51
+ if (trustedPredicates.has(test) &&
52
+ this.#checkResult !== undefined &&
53
+ this.#checkFirstResult !== undefined) {
54
+ defineTrustedHotMethods(this, test, this.#checkResult, this.#checkFirstResult);
48
55
  }
49
56
  Object.freeze(this);
50
57
  }
@@ -57,6 +64,12 @@ export class CompiledBaseGuard extends BaseGuard {
57
64
  }
58
65
  return runCompiledCheck(this.#collect, this.#trustedCollector, value);
59
66
  }
67
+ checkFirst(value) {
68
+ if (this.#checkFirstResult !== undefined) {
69
+ return this.#checkFirstResult(value);
70
+ }
71
+ return runCompiledCheckFirst(this.#collect, this.#trustedCollector, value);
72
+ }
60
73
  assert(value) {
61
74
  const result = this.#checkResult === undefined
62
75
  ? runCompiledCheck(this.#collect, this.#trustedCollector, value)
@@ -78,19 +91,21 @@ export function compile(guard, options) {
78
91
  const bundle = emitCompiledSourceBundle(schema, name, mode);
79
92
  // compile() intentionally emits source so V8 can optimize the validator body.
80
93
  // eslint-disable-next-line @typescript-eslint/no-implied-eval
81
- const factory = new Function("l", "r", "k", "u", "d", "m", "sk", bundle.source);
94
+ const factory = new Function("l", "r", "k", "u", "d", "m", "mf", "sk", bundle.source);
82
95
  const dynamicCheck = makeDynamicCheck(bundle.dynamicSchemas);
83
- const runtime = factory(bundle.literals, bundle.regexps, bundle.keysets, bundle.strings, dynamicCheck, makeDynamicIssueCheck(bundle.dynamicSchemas), strictKeys);
96
+ const dynamicFirstIssueCheck = makeDynamicFirstIssueCheck(bundle.dynamicSchemas);
97
+ const runtime = factory(bundle.literals, bundle.regexps, bundle.keysets, bundle.strings, dynamicCheck, makeDynamicIssueCheck(bundle.dynamicSchemas), dynamicFirstIssueCheck, strictKeys);
84
98
  trustedPredicates.add(runtime.is);
85
99
  trustedCollectors.add(runtime.check);
86
100
  trustedCheckResults.add(runtime.result);
87
- return new CompiledBaseGuard(schema, runtime.is, runtime.check, bundle.source, true, runtime.result);
101
+ trustedCheckResults.add(runtime.first);
102
+ return new CompiledBaseGuard(schema, runtime.is, runtime.check, bundle.source, true, runtime.result, runtime.first);
88
103
  }
89
104
  /**
90
105
  * @brief Execute define trusted hot methods.
91
106
  * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
92
107
  */
93
- function defineTrustedHotMethods(guard, test, checkResult) {
108
+ function defineTrustedHotMethods(guard, test, checkResult, checkFirstResult) {
94
109
  const self = guard;
95
110
  /*
96
111
  * Compiled guards receive own methods after construction. The closure over
@@ -133,6 +148,17 @@ function defineTrustedHotMethods(guard, test, checkResult) {
133
148
  throw new TypeSeaAssertionError(result.error);
134
149
  }
135
150
  }, false);
151
+ defineReadonlyProperty(guard, "checkFirst",
152
+ /**
153
+ * @brief Execute compiled trusted checkFirst.
154
+ * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
155
+ */
156
+ function compiledTrustedCheckFirst(value) {
157
+ if (this !== self) {
158
+ throw new TypeError("compiled guard method receiver is invalid");
159
+ }
160
+ return checkFirstResult(value);
161
+ }, false);
136
162
  }
137
163
  /**
138
164
  * @brief Normalize the guard input for runtime compilation.
@@ -203,6 +229,26 @@ function runCompiledCheck(collect, trustedCollector, value) {
203
229
  }
204
230
  return err(issues);
205
231
  }
232
+ /**
233
+ * @brief Convert a generated collector result into a one-issue public Result.
234
+ * @details This fallback is used only for manually constructed compiled guards.
235
+ * Trusted codegen normally installs a dedicated first-result function.
236
+ * @param collect Generated collector function.
237
+ * @param trustedCollector Whether the collector came from TypeSea codegen.
238
+ * @param value Candidate runtime value.
239
+ * @returns Success result or a frozen failure carrying at most one issue.
240
+ */
241
+ function runCompiledCheckFirst(collect, trustedCollector, value) {
242
+ const result = runCompiledCheck(collect, trustedCollector, value);
243
+ if (result.ok || result.error.length <= 1) {
244
+ return result;
245
+ }
246
+ const first = result.error[0];
247
+ if (first === undefined) {
248
+ return ok(value);
249
+ }
250
+ return err(Object.freeze([first]));
251
+ }
206
252
  /**
207
253
  * @brief Execute define readonly property.
208
254
  * @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
@@ -1 +1 @@
1
- {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../../src/compile/predicate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAIH,KAAK,MAAM,EACd,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAkBzE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU1D;AA4BD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,MAAM,CAuDR;AAyUD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACrB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,MAAM,CAYR"}
1
+ {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../../src/compile/predicate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAYH,KAAK,MAAM,EACd,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAkBzE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU1D;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,MAAM,CAiER;AAucD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACrB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,GACrB,MAAM,CAYR"}
@@ -4,8 +4,8 @@
4
4
  * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
5
5
  * stable across runtime and AOT emission.
6
6
  */
7
- import { NumberCheckTag, ObjectModeTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
8
- import { UUID_PATTERN } from "../schema/index.js";
7
+ import { ArrayCheckTag, DateCheckTag, NumberCheckTag, ObjectModeTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
8
+ import { EMAIL_PATTERN, IPV4_PATTERN, IPV6_PATTERN, ISO_DATETIME_PATTERN, ISO_DATE_PATTERN, ULID_PATTERN, URL_PATTERN, UUID_PATTERN } from "../schema/index.js";
9
9
  import { pushLiteral, pushRegex, pushSchema, stringRef } from "./context.js";
10
10
  /**
11
11
  * @brief emit function.
@@ -65,11 +65,19 @@ export function emitFunctions(context) {
65
65
  function emitBody(schema, value, context) {
66
66
  switch (schema.tag) {
67
67
  case SchemaTag.Array:
68
- return emitArrayBody(schema.item, value, context);
68
+ return emitArrayBody(schema, value, context);
69
69
  case SchemaTag.Tuple:
70
+ if (schema.rest !== undefined) {
71
+ return `return d(${String(pushSchema(context, schema))},${value});`;
72
+ }
70
73
  return emitTupleBody(schema.items, value, context);
71
74
  case SchemaTag.Record:
72
75
  return emitRecordBody(schema.value, value, context);
76
+ case SchemaTag.Map:
77
+ case SchemaTag.Set:
78
+ case SchemaTag.InstanceOf:
79
+ case SchemaTag.Property:
80
+ return `return d(${String(pushSchema(context, schema))},${value});`;
73
81
  case SchemaTag.Object:
74
82
  return emitObjectBody(schema, value, context);
75
83
  case SchemaTag.DiscriminatedUnion:
@@ -97,6 +105,8 @@ export function emitExpression(schema, value, context) {
97
105
  return emitString(schema, value, context);
98
106
  case SchemaTag.Number:
99
107
  return emitNumber(schema, value);
108
+ case SchemaTag.Date:
109
+ return emitDate(schema, value);
100
110
  case SchemaTag.BigInt:
101
111
  return `(typeof ${value}==="bigint")`;
102
112
  case SchemaTag.Symbol:
@@ -112,9 +122,17 @@ export function emitExpression(schema, value, context) {
112
122
  */
113
123
  return `${emitFunction(schema, context)}(${value})`;
114
124
  case SchemaTag.Tuple:
125
+ if (schema.rest !== undefined) {
126
+ return `d(${String(pushSchema(context, schema))},${value})`;
127
+ }
115
128
  return `${emitFunction(schema, context)}(${value})`;
116
129
  case SchemaTag.Record:
117
130
  return `${emitFunction(schema, context)}(${value})`;
131
+ case SchemaTag.Map:
132
+ case SchemaTag.Set:
133
+ case SchemaTag.InstanceOf:
134
+ case SchemaTag.Property:
135
+ return `d(${String(pushSchema(context, schema))},${value})`;
118
136
  case SchemaTag.Object:
119
137
  return `${emitFunction(schema, context)}(${value})`;
120
138
  case SchemaTag.Union:
@@ -139,6 +157,34 @@ export function emitExpression(schema, value, context) {
139
157
  return `d(${String(pushSchema(context, schema))},${value})`;
140
158
  }
141
159
  }
160
+ /**
161
+ * @brief Emit a Date predicate expression.
162
+ * @param schema Date schema with normalized checks.
163
+ * @param value Generated expression for the candidate value.
164
+ * @returns JavaScript expression that accepts valid Date objects within bounds.
165
+ */
166
+ function emitDate(schema, value) {
167
+ const checks = schema.checks;
168
+ const parts = [
169
+ `(${value} instanceof Date)`,
170
+ `dg(${value})`
171
+ ];
172
+ for (let index = 0; index < checks.length; index += 1) {
173
+ const check = checks[index];
174
+ if (check === undefined) {
175
+ continue;
176
+ }
177
+ switch (check.tag) {
178
+ case DateCheckTag.Min:
179
+ parts.push(`dt(${value})>=${String(check.value)}`);
180
+ break;
181
+ case DateCheckTag.Max:
182
+ parts.push(`dt(${value})<=${String(check.value)}`);
183
+ break;
184
+ }
185
+ }
186
+ return `(${parts.join("&&")})`;
187
+ }
142
188
  /**
143
189
  * @brief emit array body.
144
190
  * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
@@ -148,7 +194,8 @@ export function emitExpression(schema, value, context) {
148
194
  * @param context Shared code-generation context.
149
195
  * @returns JavaScript source for an array predicate body.
150
196
  */
151
- function emitArrayBody(item, value, context) {
197
+ function emitArrayBody(schema, value, context) {
198
+ const item = schema.item;
152
199
  const itemFunction = emitFunction(item, context);
153
200
  /*
154
201
  * Descriptor reads block accessor-backed slots without executing getters.
@@ -157,6 +204,7 @@ function emitArrayBody(item, value, context) {
157
204
  */
158
205
  return [
159
206
  `if(!Array.isArray(${value}))return false;`,
207
+ emitArrayLengthBody(value, schema.checks),
160
208
  `for(let i=0;i<${value}.length;i+=1){`,
161
209
  `const d=gp(${value},i);`,
162
210
  `if(d!==undefined&&!h.call(d,"value"))return false;`,
@@ -165,6 +213,34 @@ function emitArrayBody(item, value, context) {
165
213
  "return true;"
166
214
  ].join("");
167
215
  }
216
+ /**
217
+ * @brief Emit array length checks for direct predicate bodies.
218
+ * @param value Generated expression for the candidate array.
219
+ * @param checks Normalized array length checks.
220
+ * @returns Straight-line early-return checks, or an empty string.
221
+ */
222
+ function emitArrayLengthBody(value, checks) {
223
+ if (checks.length === 0) {
224
+ return "";
225
+ }
226
+ const chunks = [];
227
+ for (let index = 0; index < checks.length; index += 1) {
228
+ const check = checks[index];
229
+ if (check === undefined) {
230
+ chunks.push("return false;");
231
+ continue;
232
+ }
233
+ switch (check.tag) {
234
+ case ArrayCheckTag.Min:
235
+ chunks.push(`if(${value}.length<${String(check.value)})return false;`);
236
+ break;
237
+ case ArrayCheckTag.Max:
238
+ chunks.push(`if(${value}.length>${String(check.value)})return false;`);
239
+ break;
240
+ }
241
+ }
242
+ return chunks.join("");
243
+ }
168
244
  /**
169
245
  * @brief emit record body.
170
246
  * @details Generated-source helpers keep the side-table ABI and JavaScript source shape
@@ -251,9 +327,34 @@ function emitObjectBody(schema, value, context) {
251
327
  chunks.push(`if(${descriptor}===undefined||!h.call(${descriptor},"value"))return false;`, `const ${itemValue}=${descriptor}.value;`, `if(!${emitExpression(entry.schema, itemValue, context)})return false;`);
252
328
  }
253
329
  }
330
+ chunks.push(emitObjectCatchallBody(schema, value, context));
254
331
  chunks.push("return true;");
255
332
  return chunks.join("");
256
333
  }
334
+ /**
335
+ * @brief Emit catchall checks for undeclared object keys.
336
+ * @param schema Object schema with optional catchall.
337
+ * @param value Generated expression for the object value.
338
+ * @param context Shared code-generation context.
339
+ * @returns Generated source that validates extra own keys.
340
+ */
341
+ function emitObjectCatchallBody(schema, value, context) {
342
+ if (schema.catchall === undefined) {
343
+ return "";
344
+ }
345
+ const keys = schema.keys;
346
+ const membership = keyMembershipExpression("key", keys, context);
347
+ return [
348
+ `const cx=Reflect.ownKeys(${value});`,
349
+ "for(let ci=0;ci<cx.length;ci+=1){",
350
+ "const key=cx[ci];",
351
+ `if(typeof key==="string"&&${membership})continue;`,
352
+ `const cd=gp(${value},key);`,
353
+ "if(cd===undefined||!h.call(cd,\"value\"))return false;",
354
+ `if(!${emitExpression(schema.catchall, "cd.value", context)})return false;`,
355
+ "}"
356
+ ].join("");
357
+ }
257
358
  /**
258
359
  * @brief emit strict object key body.
259
360
  * @details Emits a low-allocation known-key check specialized for one object shape.
@@ -263,7 +364,7 @@ function emitObjectBody(schema, value, context) {
263
364
  * @returns Generated strict-key prelude, or an empty string for passthrough objects.
264
365
  */
265
366
  function emitStrictObjectKeyBody(schema, value, context) {
266
- if (schema.mode !== ObjectModeTag.Strict) {
367
+ if (schema.mode !== ObjectModeTag.Strict || schema.catchall !== undefined) {
267
368
  return "";
268
369
  }
269
370
  const entries = schema.entries;
@@ -347,6 +448,27 @@ function emitString(schema, value, context) {
347
448
  case StringCheckTag.Uuid:
348
449
  parts.push(emitRegex(value, UUID_PATTERN, context));
349
450
  break;
451
+ case StringCheckTag.Email:
452
+ parts.push(emitRegex(value, EMAIL_PATTERN, context));
453
+ break;
454
+ case StringCheckTag.Url:
455
+ parts.push(emitRegex(value, URL_PATTERN, context));
456
+ break;
457
+ case StringCheckTag.IsoDate:
458
+ parts.push(emitRegex(value, ISO_DATE_PATTERN, context));
459
+ break;
460
+ case StringCheckTag.IsoDateTime:
461
+ parts.push(emitRegex(value, ISO_DATETIME_PATTERN, context));
462
+ break;
463
+ case StringCheckTag.Ulid:
464
+ parts.push(emitRegex(value, ULID_PATTERN, context));
465
+ break;
466
+ case StringCheckTag.Ipv4:
467
+ parts.push(emitRegex(value, IPV4_PATTERN, context));
468
+ break;
469
+ case StringCheckTag.Ipv6:
470
+ parts.push(emitRegex(value, IPV6_PATTERN, context));
471
+ break;
350
472
  }
351
473
  }
352
474
  return `(${parts.join("&&")})`;
@@ -386,6 +508,15 @@ function emitNumber(schema, value) {
386
508
  case NumberCheckTag.Lte:
387
509
  parts.push(`(${value}<=${String(check.value)})`);
388
510
  break;
511
+ case NumberCheckTag.Gt:
512
+ parts.push(`(${value}>${String(check.value)})`);
513
+ break;
514
+ case NumberCheckTag.Lt:
515
+ parts.push(`(${value}<${String(check.value)})`);
516
+ break;
517
+ case NumberCheckTag.MultipleOf:
518
+ parts.push(`(${value}%${String(check.value)}===0)`);
519
+ break;
389
520
  }
390
521
  }
391
522
  return `(${parts.join("&&")})`;
@@ -441,3 +572,23 @@ function emitRegex(value, regex, context) {
441
572
  const access = `r[${String(index)}]`;
442
573
  return `((${access}.lastIndex=0),${access}.test(${value}))`;
443
574
  }
575
+ /**
576
+ * @brief Emit a side-table backed key membership expression.
577
+ * @param key Generated expression containing the candidate property key.
578
+ * @param keys Known object shape keys.
579
+ * @param context Shared code-generation context.
580
+ * @returns JavaScript expression that is true for known string keys.
581
+ */
582
+ function keyMembershipExpression(key, keys, context) {
583
+ if (keys.length === 0) {
584
+ return "false";
585
+ }
586
+ const parts = new Array(keys.length);
587
+ for (let index = 0; index < keys.length; index += 1) {
588
+ const value = keys[index];
589
+ parts[index] = value === undefined
590
+ ? "false"
591
+ : `${key}===${stringRef(context, value)}`;
592
+ }
593
+ return `(${parts.join("||")})`;
594
+ }
@@ -57,6 +57,16 @@ export type DynamicCheck = (schemaIndex: number, value: unknown) => boolean;
57
57
  * @param issues Mutable issue buffer owned by the caller.
58
58
  */
59
59
  export type DynamicIssueCheck = (schemaIndex: number, value: unknown, path: readonly PathSegment[], issues: Issue[]) => void;
60
+ /**
61
+ * @brief First-fault fallback for non-lowered schema fragments.
62
+ * @details Opaque lazy and refine schemas use the interpreter for correctness,
63
+ * then return only the first nested issue under the generated path prefix.
64
+ * @param schemaIndex Slot in the side table supplied to the factory.
65
+ * @param value Candidate value for that schema.
66
+ * @param path Path prefix owned by the generated collector.
67
+ * @returns First nested issue, or undefined when the fallback accepts the value.
68
+ */
69
+ export type DynamicFirstIssueCheck = (schemaIndex: number, value: unknown, path: readonly PathSegment[]) => Issue | undefined;
60
70
  /**
61
71
  * @brief Runtime helper for strict-object excess key validation.
62
72
  * @details Code generation can choose safe or fast property access strategies,
@@ -76,6 +86,7 @@ export interface RuntimeBundle {
76
86
  readonly is: BooleanPredicate;
77
87
  readonly check: IssueCollectorRoot;
78
88
  readonly result: CheckResultRoot;
89
+ readonly first: CheckResultRoot;
79
90
  }
80
91
  /**
81
92
  * @brief Factory signature consumed by `new Function` compiled modules.
@@ -91,7 +102,7 @@ export interface RuntimeBundle {
91
102
  * @param strictKeys Shared strict-object excess key helper.
92
103
  * @returns Runtime bundle exposed by the compiled guard.
93
104
  */
94
- export type IsFactory = (literals: readonly LiteralValue[], regexps: readonly RegExp[], keysets: readonly (readonly string[])[], strings: readonly string[], dynamicCheck: DynamicCheck, dynamicIssueCheck: DynamicIssueCheck, strictKeys: StrictKeysCheck) => RuntimeBundle;
105
+ export type IsFactory = (literals: readonly LiteralValue[], regexps: readonly RegExp[], keysets: readonly (readonly string[])[], strings: readonly string[], dynamicCheck: DynamicCheck, dynamicIssueCheck: DynamicIssueCheck, dynamicFirstIssueCheck: DynamicFirstIssueCheck, strictKeys: StrictKeysCheck) => RuntimeBundle;
95
106
  /**
96
107
  * @brief Build the boolean fallback table reader for generated validators.
97
108
  * @details Missing table slots fail closed. That preserves the security
@@ -110,6 +121,14 @@ export declare function makeDynamicCheck(schemas: readonly Schema[]): DynamicChe
110
121
  * @returns Issue fallback callback used by emitted collectors.
111
122
  */
112
123
  export declare function makeDynamicIssueCheck(schemas: readonly Schema[]): DynamicIssueCheck;
124
+ /**
125
+ * @brief Build the first-fault fallback table reader for generated validators.
126
+ * @details This path is entered only for opaque schema fragments that codegen
127
+ * cannot inline. The nested interpreter result is re-rooted once and returned.
128
+ * @param schemas Schema side table captured by the compiled guard.
129
+ * @returns First-issue fallback callback used by emitted collectors.
130
+ */
131
+ export declare function makeDynamicFirstIssueCheck(schemas: readonly Schema[]): DynamicFirstIssueCheck;
113
132
  /**
114
133
  * @brief Safe strict-object key membership helper for generated validators.
115
134
  * @details The default compiled mode uses Reflect.ownKeys so symbol and
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/compile/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC5B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,MAAM,EAAE,KAAK,EAAE,KACd,IAAI,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAC1B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,KACtB,OAAO,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,SAAS,GAAG,CACpB,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACvC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,YAAY,EAAE,YAAY,EAC1B,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,eAAe,KAC1B,aAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAKzE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,SAAS,MAAM,EAAE,GAC3B,iBAAiB,CA8BnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACtB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,GACxB,OAAO,CAYT"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/compile/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC5B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,MAAM,EAAE,KAAK,EAAE,KACd,IAAI,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,WAAW,EAAE,KAC3B,KAAK,GAAG,SAAS,CAAC;AAEvB;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAC1B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,KACtB,OAAO,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,SAAS,GAAG,CACpB,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACvC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,YAAY,EAAE,YAAY,EAC1B,iBAAiB,EAAE,iBAAiB,EACpC,sBAAsB,EAAE,sBAAsB,EAC9C,UAAU,EAAE,eAAe,KAC1B,aAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAKzE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,SAAS,MAAM,EAAE,GAC3B,iBAAiB,CA8BnB;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACtC,OAAO,EAAE,SAAS,MAAM,EAAE,GAC3B,sBAAsB,CA2BxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACtB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,GACxB,OAAO,CAYT"}
@@ -58,6 +58,37 @@ export function makeDynamicIssueCheck(schemas) {
58
58
  }
59
59
  };
60
60
  }
61
+ /**
62
+ * @brief Build the first-fault fallback table reader for generated validators.
63
+ * @details This path is entered only for opaque schema fragments that codegen
64
+ * cannot inline. The nested interpreter result is re-rooted once and returned.
65
+ * @param schemas Schema side table captured by the compiled guard.
66
+ * @returns First-issue fallback callback used by emitted collectors.
67
+ */
68
+ export function makeDynamicFirstIssueCheck(schemas) {
69
+ return (schemaIndex, value, path) => {
70
+ const schema = schemas[schemaIndex];
71
+ if (schema === undefined) {
72
+ return undefined;
73
+ }
74
+ const result = checkSchema(schema, value);
75
+ if (result.ok) {
76
+ return undefined;
77
+ }
78
+ const issue = result.error[0];
79
+ if (issue === undefined) {
80
+ return undefined;
81
+ }
82
+ const nestedPath = Object.freeze(path.concat(issue.path));
83
+ return Object.freeze({
84
+ path: nestedPath,
85
+ code: issue.code,
86
+ expected: issue.expected,
87
+ actual: issue.actual,
88
+ message: issue.message
89
+ });
90
+ };
91
+ }
61
92
  /**
62
93
  * @brief Safe strict-object key membership helper for generated validators.
63
94
  * @details The default compiled mode uses Reflect.ownKeys so symbol and
@@ -1 +1 @@
1
- {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/compile/source.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKjD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAoB,GAC3B,oBAAoB,CA+CtB"}
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/compile/source.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAMjD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAoB,GAC3B,oBAAoB,CAsDtB"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { emitCheckFunction, emitCheckFunctions } from "./check.js";
8
8
  import { createEmitContext } from "./context.js";
9
+ import { emitFirstFunction, emitFirstFunctions } from "./first.js";
9
10
  import { emitGraphFunction, emitGraphFunctions } from "./graph-predicate.js";
10
11
  import { safeFunctionName } from "./names.js";
11
12
  /**
@@ -27,25 +28,32 @@ export function emitCompiledSourceBundle(schema, name, mode = "safe") {
27
28
  */
28
29
  const root = emitGraphFunction(schema, context, directRoot ? functionName : undefined);
29
30
  const checkRoot = emitCheckFunction(schema, context);
31
+ const firstRoot = emitFirstFunction(schema, context);
30
32
  const checkFunctionName = `${functionName}_check`;
31
33
  const resultFunctionName = `${functionName}_result`;
34
+ const firstFunctionName = `${functionName}_first`;
32
35
  const isProperty = directRoot
33
36
  ? `is:${root}`
34
37
  : `is:function ${functionName}(x){return ${root}(x);}`;
35
38
  const graphFunctions = emitGraphFunctions(context);
36
39
  const checkFunctions = emitCheckFunctions(context);
40
+ const firstFunctions = emitFirstFunctions(context);
37
41
  const rootPathIsFrozen = canReuseFrozenRootPath(checkFunctions);
42
+ const firstPathIsFrozen = canReuseFrozenRootPath(firstFunctions);
38
43
  const rootPath = rootPathIsFrozen ? "z" : "[]";
44
+ const firstPath = firstPathIsFrozen ? "z" : "[]";
39
45
  /*
40
46
  * Boolean is() owns the hot path; check()/result() first reuse it so valid
41
47
  * data avoids diagnostic allocation. Only failing inputs enter the check tree.
42
48
  */
43
49
  const issueCollector = `check:function ${checkFunctionName}(x){if(${root}(x))return;const s=[];${checkRoot}(x,${rootPath},s);return s;}`;
44
50
  const resultCollector = `result:function ${resultFunctionName}(x){if(${root}(x))return ${emitSuccessResult(mode, "x")};const s=[];${checkRoot}(x,${rootPath},s);return Object.freeze({ok:false,error:Object.freeze(s)});}`;
51
+ const firstCollector = `first:function ${firstFunctionName}(x){if(${root}(x))return ${emitSuccessResult(mode, "x")};const e=${firstRoot}(x,${firstPath});if(e===undefined)return ${emitSuccessResult(mode, "x")};return Object.freeze({ok:false,error:Object.freeze([e])});}`;
45
52
  const body = [
46
53
  graphFunctions,
47
54
  checkFunctions,
48
- `return {${isProperty},${issueCollector},${resultCollector}};`
55
+ firstFunctions,
56
+ `return {${isProperty},${issueCollector},${resultCollector},${firstCollector}};`
49
57
  ].join("");
50
58
  const source = [
51
59
  "\"use strict\";",
@@ -112,6 +120,7 @@ function isFactoryParameterName(name) {
112
120
  case "u":
113
121
  case "d":
114
122
  case "m":
123
+ case "mf":
115
124
  case "sk":
116
125
  case "w":
117
126
  return true;
@@ -164,15 +173,16 @@ function emitHelperPrelude(body, rootPathIsFrozen) {
164
173
  pushHelper(chunks, needed, "hd", "const hd=function(v,k){if(!ph(v))return false;const d=gp(v,k);return d!==undefined&&h.call(d,\"value\");};");
165
174
  pushHelper(chunks, needed, "fn", "const fn=function(v){return typeof v===\"number\"&&Number.isFinite(v);};");
166
175
  pushHelper(chunks, needed, "nc", "const nc=function(x,y,gte){return typeof x===\"number\"&&typeof y===\"number\"&&(gte?x>=y:x<=y);};");
176
+ pushHelper(chunks, needed, "dg", "const __tg=Date.prototype.getTime;const dg=function(v){return v instanceof Date&&Number.isFinite(__tg.call(v));};const dt=function(v){return __tg.call(v);};");
167
177
  pushHelper(chunks, needed, "sb", "const sb=function(v,b,min){return typeof v===\"string\"&&(min?v.length>=b:v.length<=b);};");
168
178
  pushHelper(chunks, needed, "rx", "const rx=function(v,re){if(typeof v!==\"string\")return false;re.lastIndex=0;const ok=re.test(v);re.lastIndex=0;return ok;};");
169
179
  pushHelper(chunks, needed, "ai", "const ai=function(k,n){if(k.length===0||k===\"length\")return false;const i=Number(k);return Number.isInteger(i)&&i>=0&&i<=4294967294&&i<n&&String(i)===k;};");
170
- pushHelper(chunks, needed, "ea", "const ea=function(v,f){if(!Array.isArray(v))return false;for(let i=0;i<v.length;i+=1){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;if(!f(d===undefined?undefined:d.value))return false;}return true;};");
180
+ pushHelper(chunks, needed, "ea", "const ea=function(v,f){if(!Array.isArray(v))return false;for(let i=0;i<v.length;i+=1){const d=gp(v,i);if(!f(d===undefined?undefined:d.value))return false;}return true;};");
171
181
  pushHelper(chunks, needed, "eu", "const eu=function(v,f){if(!Array.isArray(v))return false;const xs=Object.getOwnPropertyNames(v);for(let i=0;i<xs.length;i+=1){const k=xs[i];if(!ai(k,v.length))continue;const d=gp(v,k);if(d!==undefined&&!h.call(d,\"value\"))return false;if(d!==undefined&&!f(d.value))return false;}return true;};");
172
182
  pushHelper(chunks, needed, "ev", "const ev=function(v,i,f){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;return f(d===undefined?undefined:d.value);};");
173
183
  pushHelper(chunks, needed, "er", "const er=function(v,f){if(!o(v))return false;for(const key in v){if(!h.call(v,key))continue;const d=gp(v,key);if(d===undefined||!h.call(d,\"value\")||!f(d.value))return false;}return true;};");
174
184
  pushHelper(chunks, needed, "dj", "const dj=function(v,key,ks){if(!o(v))return false;const d=g(v,key);if(d===undefined||typeof d.value!==\"string\")return false;const i=ks.indexOf(d.value);return i>=0&&arguments[i+3](v);};");
175
- pushHelper(chunks, needed, "a", "const a=function(v){if(v===null)return \"null\";if(Array.isArray(v))return \"array\";if(typeof v===\"bigint\")return \"bigint\";if(typeof v===\"symbol\")return \"symbol\";if(typeof v===\"number\"&&Number.isNaN(v))return \"nan\";return typeof v;};");
185
+ pushHelper(chunks, needed, "a", "const a=function(v){if(v===null)return \"null\";if(Array.isArray(v))return \"array\";if(v instanceof Date)return \"date\";if(v instanceof Map)return \"map\";if(v instanceof Set)return \"set\";if(typeof v===\"bigint\")return \"bigint\";if(typeof v===\"symbol\")return \"symbol\";if(typeof v===\"number\"&&Number.isNaN(v))return \"nan\";return typeof v;};");
176
186
  pushHelper(chunks, needed, "le", "const le=function(v){if(v===null)return \"null\";if(v===undefined)return \"undefined\";if(typeof v===\"string\")return JSON.stringify(v);if(typeof v===\"number\"&&Object.is(v,-0))return \"-0\";if(typeof v===\"symbol\")return String(v);return String(v);};");
177
187
  pushHelper(chunks, needed, "w", "const w=function(){const x=new Array(u.length);for(let i=0;i<u.length;i+=1)x[i]=Object.freeze([u[i]]);return x;}();");
178
188
  pushHelper(chunks, needed, "q", rootPathIsFrozen
@@ -187,6 +197,10 @@ function emitHelperPrelude(body, rootPathIsFrozen) {
187
197
  pushHelper(chunks, needed, "q2", rootPathIsFrozen
188
198
  ? "const q2=function(s,p,a,b,c,e,x){s.push(Object.freeze({path:Object.freeze([a,b]),code:c,expected:e,actual:x,message:undefined}));};"
189
199
  : "const q2=function(s,p,a,b,c,e,x){const n=p.length;const y=n===0?[a,b]:p.slice();if(n!==0){y.push(a);y.push(b);}Object.freeze(y);s.push(Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined}));};");
200
+ pushHelper(chunks, needed, "fq", "const fq=function(p,c,e,x){const y=p.length===0?z:Object.freeze(p.slice());return Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined});};");
201
+ pushHelper(chunks, needed, "fq1", "const fq1=function(p,k,c,e,x){const n=p.length;const y=n===0?[k]:p.slice();if(n!==0)y.push(k);Object.freeze(y);return Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined});};");
202
+ pushHelper(chunks, needed, "fq1s", "const fq1s=function(p,i,c,e,x){if(p.length===0)return Object.freeze({path:w[i],code:c,expected:e,actual:x,message:undefined});const y=p.slice();y.push(u[i]);Object.freeze(y);return Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined});};");
203
+ pushHelper(chunks, needed, "fq2", "const fq2=function(p,a,b,c,e,x){const n=p.length;const y=n===0?[a,b]:p.slice();if(n!==0){y.push(a);y.push(b);}Object.freeze(y);return Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined});};");
190
204
  return chunks.join("");
191
205
  }
192
206
  /**
@@ -281,8 +295,12 @@ function closeHelperDependencies(needed) {
281
295
  changed = addDependencies(needed, "ev", ["gp", "h"]) || changed;
282
296
  changed = addDependencies(needed, "er", ["o", "gp", "h"]) || changed;
283
297
  changed = addDependencies(needed, "dj", ["o", "g"]) || changed;
298
+ changed = addDependencies(needed, "dt", ["dg"]) || changed;
284
299
  changed = addDependencies(needed, "q", ["z"]) || changed;
285
300
  changed = addDependencies(needed, "q1s", ["w"]) || changed;
301
+ changed = addDependencies(needed, "fq", ["z"]) || changed;
302
+ changed = addDependencies(needed, "fq1", ["z"]) || changed;
303
+ changed = addDependencies(needed, "fq1s", ["w"]) || changed;
286
304
  }
287
305
  }
288
306
  /**
@@ -328,6 +346,8 @@ function isRuntimeHelperName(name) {
328
346
  case "hd":
329
347
  case "fn":
330
348
  case "nc":
349
+ case "dg":
350
+ case "dt":
331
351
  case "sb":
332
352
  case "rx":
333
353
  case "ai":
@@ -343,6 +363,10 @@ function isRuntimeHelperName(name) {
343
363
  case "q1":
344
364
  case "q1s":
345
365
  case "q2":
366
+ case "fq":
367
+ case "fq1":
368
+ case "fq1s":
369
+ case "fq2":
346
370
  return true;
347
371
  default:
348
372
  return false;
@@ -22,6 +22,8 @@ export interface EmitContext {
22
22
  readonly functionNames: Map<Schema, string>;
23
23
  readonly checkFunctions: FunctionSource[];
24
24
  readonly checkFunctionNames: Map<Schema, string>;
25
+ readonly firstFunctions: FunctionSource[];
26
+ readonly firstFunctionNames: Map<Schema, string>;
25
27
  readonly stringIndexes: Map<string, number>;
26
28
  }
27
29
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/compile/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAC1B,MAAM,EACN,SAAS,SAAS,QAAQ,GAAG,UAAU,CACzC,SAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;CAC1C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/compile/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,cAAc,EAAE,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAC1B,MAAM,EACN,SAAS,SAAS,QAAQ,GAAG,UAAU,CACzC,SAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;CAC1C"}