@sinclair/typebox 0.29.6 → 0.30.0-dev-2

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.
@@ -28,10 +28,11 @@ THE SOFTWARE.
28
28
  ---------------------------------------------------------------------------*/
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
30
  exports.TypeCompiler = exports.TypeCompilerTypeGuardError = exports.TypeCompilerDereferenceError = exports.TypeCompilerUnknownTypeError = exports.TypeCheck = void 0;
31
+ const index_1 = require("../system/index");
31
32
  const Types = require("../typebox");
32
- const index_1 = require("../errors/index");
33
- const index_2 = require("../system/index");
34
- const hash_1 = require("../value/hash");
33
+ const ValueErrors = require("../errors/index");
34
+ const ValueHash = require("../value/hash");
35
+ const ValueGuard = require("../value/guard");
35
36
  // -------------------------------------------------------------------
36
37
  // TypeCheck
37
38
  // -------------------------------------------------------------------
@@ -48,7 +49,7 @@ class TypeCheck {
48
49
  }
49
50
  /** Returns an iterator for each error in this value. */
50
51
  Errors(value) {
51
- return index_1.ValueErrors.Errors(this.schema, this.references, value);
52
+ return ValueErrors.Errors(this.schema, this.references, value);
52
53
  }
53
54
  /** Returns true if the value matches the compiled type. */
54
55
  Check(value) {
@@ -128,7 +129,7 @@ var Identifier;
128
129
  Identifier.Encode = Encode;
129
130
  })(Identifier || (Identifier = {}));
130
131
  // -------------------------------------------------------------------
131
- // TypeCompiler
132
+ // Errors
132
133
  // -------------------------------------------------------------------
133
134
  class TypeCompilerUnknownTypeError extends Error {
134
135
  constructor(schema) {
@@ -154,20 +155,8 @@ exports.TypeCompilerTypeGuardError = TypeCompilerTypeGuardError;
154
155
  /** Compiles Types for Runtime Type Checking */
155
156
  var TypeCompiler;
156
157
  (function (TypeCompiler) {
157
- // -------------------------------------------------------------------
158
- // Guards
159
- // -------------------------------------------------------------------
160
- function IsBigInt(value) {
161
- return typeof value === 'bigint';
162
- }
163
- function IsNumber(value) {
164
- return typeof value === 'number' && globalThis.Number.isFinite(value);
165
- }
166
- function IsString(value) {
167
- return typeof value === 'string';
168
- }
169
158
  // ----------------------------------------------------------------------
170
- // SchemaGuards
159
+ // Guards
171
160
  // ----------------------------------------------------------------------
172
161
  function IsAnyOrUnknown(schema) {
173
162
  return schema[Types.Kind] === 'Any' || schema[Types.Kind] === 'Unknown';
@@ -176,95 +165,110 @@ var TypeCompiler;
176
165
  // Polices
177
166
  // -------------------------------------------------------------------
178
167
  function IsExactOptionalProperty(value, key, expression) {
179
- return index_2.TypeSystem.ExactOptionalPropertyTypes ? `('${key}' in ${value} ? ${expression} : true)` : `(${MemberExpression.Encode(value, key)} !== undefined ? ${expression} : true)`;
168
+ return index_1.TypeSystem.ExactOptionalPropertyTypes ? `('${key}' in ${value} ? ${expression} : true)` : `(${MemberExpression.Encode(value, key)} !== undefined ? ${expression} : true)`;
180
169
  }
181
170
  function IsObjectCheck(value) {
182
- return !index_2.TypeSystem.AllowArrayObjects ? `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}))` : `(typeof ${value} === 'object' && ${value} !== null)`;
171
+ return !index_1.TypeSystem.AllowArrayObjects ? `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}))` : `(typeof ${value} === 'object' && ${value} !== null)`;
183
172
  }
184
173
  function IsRecordCheck(value) {
185
- return !index_2.TypeSystem.AllowArrayObjects
174
+ return !index_1.TypeSystem.AllowArrayObjects
186
175
  ? `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}) && !(${value} instanceof Date) && !(${value} instanceof Uint8Array))`
187
176
  : `(typeof ${value} === 'object' && ${value} !== null && !(${value} instanceof Date) && !(${value} instanceof Uint8Array))`;
188
177
  }
189
178
  function IsNumberCheck(value) {
190
- return !index_2.TypeSystem.AllowNaN ? `(typeof ${value} === 'number' && Number.isFinite(${value}))` : `typeof ${value} === 'number'`;
179
+ return !index_1.TypeSystem.AllowNaN ? `(typeof ${value} === 'number' && Number.isFinite(${value}))` : `typeof ${value} === 'number'`;
191
180
  }
192
181
  function IsVoidCheck(value) {
193
- return index_2.TypeSystem.AllowVoidNull ? `(${value} === undefined || ${value} === null)` : `${value} === undefined`;
182
+ return index_1.TypeSystem.AllowVoidNull ? `(${value} === undefined || ${value} === null)` : `${value} === undefined`;
194
183
  }
195
184
  // -------------------------------------------------------------------
196
185
  // Types
197
186
  // -------------------------------------------------------------------
198
- function* Any(schema, references, value) {
187
+ function* TAny(schema, references, value) {
199
188
  yield 'true';
200
189
  }
201
- function* Array(schema, references, value) {
190
+ function* TArray(schema, references, value) {
202
191
  yield `Array.isArray(${value})`;
203
- if (IsNumber(schema.minItems))
192
+ const [parameter, accumulator] = [CreateParameter('value', 'any'), CreateParameter('acc', 'number')];
193
+ if (ValueGuard.IsNumber(schema.minItems))
204
194
  yield `${value}.length >= ${schema.minItems}`;
205
- if (IsNumber(schema.maxItems))
195
+ if (ValueGuard.IsNumber(schema.maxItems))
206
196
  yield `${value}.length <= ${schema.maxItems}`;
207
- if (schema.uniqueItems === true)
208
- yield `((function() { const set = new Set(); for(const element of ${value}) { const hashed = hash(element); if(set.has(hashed)) { return false } else { set.add(hashed) } } return true })())`;
209
- const expression = CreateExpression(schema.items, references, 'value');
210
- const parameter = CreateParameter('value', 'any');
211
- yield `${value}.every((${parameter}) => ${expression})`;
197
+ const elementExpression = CreateExpression(schema.items, references, 'value');
198
+ yield `${value}.every((${parameter}) => ${elementExpression})`;
199
+ if (Types.TypeGuard.TSchema(schema.contains) || ValueGuard.IsNumber(schema.minContains) || ValueGuard.IsNumber(schema.maxContains)) {
200
+ const containsSchema = Types.TypeGuard.TSchema(schema.contains) ? schema.contains : Types.Type.Never();
201
+ const checkExpression = CreateExpression(containsSchema, references, 'value');
202
+ const checkMinContains = ValueGuard.IsNumber(schema.minContains) ? [`(count >= ${schema.minContains})`] : [];
203
+ const checkMaxContains = ValueGuard.IsNumber(schema.maxContains) ? [`(count <= ${schema.maxContains})`] : [];
204
+ const checkCount = `const count = ${value}.reduce((${accumulator}, ${parameter}) => ${checkExpression} ? acc + 1 : acc, 0)`;
205
+ const check = [`(count > 0)`, ...checkMinContains, ...checkMaxContains].join(' && ');
206
+ yield `((${parameter}) => { ${checkCount}; return ${check}})(${value})`;
207
+ }
208
+ if (schema.uniqueItems === true) {
209
+ const check = `const hashed = hash(element); if(set.has(hashed)) { return false } else { set.add(hashed) } } return true`;
210
+ const block = `const set = new Set(); for(const element of value) { ${check} }`;
211
+ yield `((${parameter}) => { ${block} )(${value})`;
212
+ }
212
213
  }
213
- function* BigInt(schema, references, value) {
214
+ function* TAsyncIterator(schema, references, value) {
215
+ yield `(typeof value === 'object' && Symbol.asyncIterator in ${value})`;
216
+ }
217
+ function* TBigInt(schema, references, value) {
214
218
  yield `(typeof ${value} === 'bigint')`;
215
- if (IsBigInt(schema.multipleOf))
219
+ if (ValueGuard.IsBigInt(schema.multipleOf))
216
220
  yield `(${value} % BigInt(${schema.multipleOf})) === 0`;
217
- if (IsBigInt(schema.exclusiveMinimum))
221
+ if (ValueGuard.IsBigInt(schema.exclusiveMinimum))
218
222
  yield `${value} > BigInt(${schema.exclusiveMinimum})`;
219
- if (IsBigInt(schema.exclusiveMaximum))
223
+ if (ValueGuard.IsBigInt(schema.exclusiveMaximum))
220
224
  yield `${value} < BigInt(${schema.exclusiveMaximum})`;
221
- if (IsBigInt(schema.minimum))
225
+ if (ValueGuard.IsBigInt(schema.minimum))
222
226
  yield `${value} >= BigInt(${schema.minimum})`;
223
- if (IsBigInt(schema.maximum))
227
+ if (ValueGuard.IsBigInt(schema.maximum))
224
228
  yield `${value} <= BigInt(${schema.maximum})`;
225
229
  }
226
- function* Boolean(schema, references, value) {
230
+ function* TBoolean(schema, references, value) {
227
231
  yield `(typeof ${value} === 'boolean')`;
228
232
  }
229
- function* Constructor(schema, references, value) {
233
+ function* TConstructor(schema, references, value) {
230
234
  yield* Visit(schema.returns, references, `${value}.prototype`);
231
235
  }
232
- function* Date(schema, references, value) {
236
+ function* TDate(schema, references, value) {
233
237
  yield `(${value} instanceof Date) && Number.isFinite(${value}.getTime())`;
234
- if (IsNumber(schema.exclusiveMinimumTimestamp))
238
+ if (ValueGuard.IsNumber(schema.exclusiveMinimumTimestamp))
235
239
  yield `${value}.getTime() > ${schema.exclusiveMinimumTimestamp}`;
236
- if (IsNumber(schema.exclusiveMaximumTimestamp))
240
+ if (ValueGuard.IsNumber(schema.exclusiveMaximumTimestamp))
237
241
  yield `${value}.getTime() < ${schema.exclusiveMaximumTimestamp}`;
238
- if (IsNumber(schema.minimumTimestamp))
242
+ if (ValueGuard.IsNumber(schema.minimumTimestamp))
239
243
  yield `${value}.getTime() >= ${schema.minimumTimestamp}`;
240
- if (IsNumber(schema.maximumTimestamp))
244
+ if (ValueGuard.IsNumber(schema.maximumTimestamp))
241
245
  yield `${value}.getTime() <= ${schema.maximumTimestamp}`;
242
246
  }
243
- function* Function(schema, references, value) {
247
+ function* TFunction(schema, references, value) {
244
248
  yield `(typeof ${value} === 'function')`;
245
249
  }
246
- function* Integer(schema, references, value) {
250
+ function* TInteger(schema, references, value) {
247
251
  yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`;
248
- if (IsNumber(schema.multipleOf))
252
+ if (ValueGuard.IsNumber(schema.multipleOf))
249
253
  yield `(${value} % ${schema.multipleOf}) === 0`;
250
- if (IsNumber(schema.exclusiveMinimum))
254
+ if (ValueGuard.IsNumber(schema.exclusiveMinimum))
251
255
  yield `${value} > ${schema.exclusiveMinimum}`;
252
- if (IsNumber(schema.exclusiveMaximum))
256
+ if (ValueGuard.IsNumber(schema.exclusiveMaximum))
253
257
  yield `${value} < ${schema.exclusiveMaximum}`;
254
- if (IsNumber(schema.minimum))
258
+ if (ValueGuard.IsNumber(schema.minimum))
255
259
  yield `${value} >= ${schema.minimum}`;
256
- if (IsNumber(schema.maximum))
260
+ if (ValueGuard.IsNumber(schema.maximum))
257
261
  yield `${value} <= ${schema.maximum}`;
258
262
  }
259
- function* Intersect(schema, references, value) {
263
+ function* TIntersect(schema, references, value) {
260
264
  const check1 = schema.allOf.map((schema) => CreateExpression(schema, references, value)).join(' && ');
261
265
  if (schema.unevaluatedProperties === false) {
262
- const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
266
+ const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
263
267
  const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))`;
264
268
  yield `(${check1} && ${check2})`;
265
269
  }
266
270
  else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) {
267
- const keyCheck = PushLocal(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
271
+ const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`);
268
272
  const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})`;
269
273
  yield `(${check1} && ${check2})`;
270
274
  }
@@ -272,7 +276,10 @@ var TypeCompiler;
272
276
  yield `(${check1})`;
273
277
  }
274
278
  }
275
- function* Literal(schema, references, value) {
279
+ function* TIterator(schema, references, value) {
280
+ yield `(typeof value === 'object' && Symbol.iterator in ${value})`;
281
+ }
282
+ function* TLiteral(schema, references, value) {
276
283
  if (typeof schema.const === 'number' || typeof schema.const === 'boolean') {
277
284
  yield `(${value} === ${schema.const})`;
278
285
  }
@@ -280,36 +287,36 @@ var TypeCompiler;
280
287
  yield `(${value} === '${schema.const}')`;
281
288
  }
282
289
  }
283
- function* Never(schema, references, value) {
290
+ function* TNever(schema, references, value) {
284
291
  yield `false`;
285
292
  }
286
- function* Not(schema, references, value) {
293
+ function* TNot(schema, references, value) {
287
294
  const expression = CreateExpression(schema.not, references, value);
288
295
  yield `(!${expression})`;
289
296
  }
290
- function* Null(schema, references, value) {
297
+ function* TNull(schema, references, value) {
291
298
  yield `(${value} === null)`;
292
299
  }
293
- function* Number(schema, references, value) {
300
+ function* TNumber(schema, references, value) {
294
301
  yield IsNumberCheck(value);
295
- if (IsNumber(schema.multipleOf))
302
+ if (ValueGuard.IsNumber(schema.multipleOf))
296
303
  yield `(${value} % ${schema.multipleOf}) === 0`;
297
- if (IsNumber(schema.exclusiveMinimum))
304
+ if (ValueGuard.IsNumber(schema.exclusiveMinimum))
298
305
  yield `${value} > ${schema.exclusiveMinimum}`;
299
- if (IsNumber(schema.exclusiveMaximum))
306
+ if (ValueGuard.IsNumber(schema.exclusiveMaximum))
300
307
  yield `${value} < ${schema.exclusiveMaximum}`;
301
- if (IsNumber(schema.minimum))
308
+ if (ValueGuard.IsNumber(schema.minimum))
302
309
  yield `${value} >= ${schema.minimum}`;
303
- if (IsNumber(schema.maximum))
310
+ if (ValueGuard.IsNumber(schema.maximum))
304
311
  yield `${value} <= ${schema.maximum}`;
305
312
  }
306
- function* Object(schema, references, value) {
313
+ function* TObject(schema, references, value) {
307
314
  yield IsObjectCheck(value);
308
- if (IsNumber(schema.minProperties))
315
+ if (ValueGuard.IsNumber(schema.minProperties))
309
316
  yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`;
310
- if (IsNumber(schema.maxProperties))
317
+ if (ValueGuard.IsNumber(schema.maxProperties))
311
318
  yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`;
312
- const knownKeys = globalThis.Object.getOwnPropertyNames(schema.properties);
319
+ const knownKeys = Object.getOwnPropertyNames(schema.properties);
313
320
  for (const knownKey of knownKeys) {
314
321
  const memberExpression = MemberExpression.Encode(value, knownKey);
315
322
  const property = schema.properties[knownKey];
@@ -338,61 +345,60 @@ var TypeCompiler;
338
345
  yield `(Object.getOwnPropertyNames(${value}).every(key => ${keys}.includes(key) || ${expression}))`;
339
346
  }
340
347
  }
341
- function* Promise(schema, references, value) {
348
+ function* TPromise(schema, references, value) {
342
349
  yield `(typeof value === 'object' && typeof ${value}.then === 'function')`;
343
350
  }
344
- function* Record(schema, references, value) {
351
+ function* TRecord(schema, references, value) {
345
352
  yield IsRecordCheck(value);
346
- if (IsNumber(schema.minProperties))
353
+ if (ValueGuard.IsNumber(schema.minProperties))
347
354
  yield `Object.getOwnPropertyNames(${value}).length >= ${schema.minProperties}`;
348
- if (IsNumber(schema.maxProperties))
355
+ if (ValueGuard.IsNumber(schema.maxProperties))
349
356
  yield `Object.getOwnPropertyNames(${value}).length <= ${schema.maxProperties}`;
350
- const [patternKey, patternSchema] = globalThis.Object.entries(schema.patternProperties)[0];
351
- const local = PushLocal(`new RegExp(/${patternKey}/)`);
357
+ const [patternKey, patternSchema] = Object.entries(schema.patternProperties)[0];
358
+ const variable = CreateVariable(`new RegExp(/${patternKey}/)`);
352
359
  const check1 = CreateExpression(patternSchema, references, 'value');
353
360
  const check2 = Types.TypeGuard.TSchema(schema.additionalProperties) ? CreateExpression(schema.additionalProperties, references, value) : schema.additionalProperties === false ? 'false' : 'true';
354
- const expression = `(${local}.test(key) ? ${check1} : ${check2})`;
361
+ const expression = `(${variable}.test(key) ? ${check1} : ${check2})`;
355
362
  yield `(Object.entries(${value}).every(([key, value]) => ${expression}))`;
356
363
  }
357
- function* Ref(schema, references, value) {
364
+ function* TRef(schema, references, value) {
358
365
  const index = references.findIndex((foreign) => foreign.$id === schema.$ref);
359
366
  if (index === -1)
360
367
  throw new TypeCompilerDereferenceError(schema);
361
368
  const target = references[index];
362
- // Reference: If we have seen this reference before we can just yield and
363
- // return the function call. If this isn't the case we defer to visit to
364
- // generate and set the function for subsequent passes.
369
+ // Reference: If we have seen this reference before we can just yield and return the function call.
370
+ // If this isn't the case we defer to visit to generate and set the function for subsequent passes.
365
371
  if (state.functions.has(schema.$ref))
366
372
  return yield `${CreateFunctionName(schema.$ref)}(${value})`;
367
373
  yield* Visit(target, references, value);
368
374
  }
369
- function* String(schema, references, value) {
375
+ function* TString(schema, references, value) {
370
376
  yield `(typeof ${value} === 'string')`;
371
- if (IsNumber(schema.minLength))
377
+ if (ValueGuard.IsNumber(schema.minLength))
372
378
  yield `${value}.length >= ${schema.minLength}`;
373
- if (IsNumber(schema.maxLength))
379
+ if (ValueGuard.IsNumber(schema.maxLength))
374
380
  yield `${value}.length <= ${schema.maxLength}`;
375
381
  if (schema.pattern !== undefined) {
376
- const local = PushLocal(`${new RegExp(schema.pattern)};`);
377
- yield `${local}.test(${value})`;
382
+ const variable = CreateVariable(`${new RegExp(schema.pattern)};`);
383
+ yield `${variable}.test(${value})`;
378
384
  }
379
385
  if (schema.format !== undefined) {
380
386
  yield `format('${schema.format}', ${value})`;
381
387
  }
382
388
  }
383
- function* Symbol(schema, references, value) {
389
+ function* TSymbol(schema, references, value) {
384
390
  yield `(typeof ${value} === 'symbol')`;
385
391
  }
386
- function* TemplateLiteral(schema, references, value) {
392
+ function* TTemplateLiteral(schema, references, value) {
387
393
  yield `(typeof ${value} === 'string')`;
388
- const local = PushLocal(`${new RegExp(schema.pattern)};`);
389
- yield `${local}.test(${value})`;
394
+ const variable = CreateVariable(`${new RegExp(schema.pattern)};`);
395
+ yield `${variable}.test(${value})`;
390
396
  }
391
- function* This(schema, references, value) {
397
+ function* TThis(schema, references, value) {
392
398
  const func = CreateFunctionName(schema.$ref);
393
399
  yield `${func}(${value})`;
394
400
  }
395
- function* Tuple(schema, references, value) {
401
+ function* TTuple(schema, references, value) {
396
402
  yield `Array.isArray(${value})`;
397
403
  if (schema.items === undefined)
398
404
  return yield `${value}.length === 0`;
@@ -402,112 +408,114 @@ var TypeCompiler;
402
408
  yield `${expression}`;
403
409
  }
404
410
  }
405
- function* Undefined(schema, references, value) {
411
+ function* TUndefined(schema, references, value) {
406
412
  yield `${value} === undefined`;
407
413
  }
408
- function* Union(schema, references, value) {
414
+ function* TUnion(schema, references, value) {
409
415
  const expressions = schema.anyOf.map((schema) => CreateExpression(schema, references, value));
410
416
  yield `(${expressions.join(' || ')})`;
411
417
  }
412
- function* Uint8Array(schema, references, value) {
418
+ function* TUint8Array(schema, references, value) {
413
419
  yield `${value} instanceof Uint8Array`;
414
- if (IsNumber(schema.maxByteLength))
420
+ if (ValueGuard.IsNumber(schema.maxByteLength))
415
421
  yield `(${value}.length <= ${schema.maxByteLength})`;
416
- if (IsNumber(schema.minByteLength))
422
+ if (ValueGuard.IsNumber(schema.minByteLength))
417
423
  yield `(${value}.length >= ${schema.minByteLength})`;
418
424
  }
419
- function* Unknown(schema, references, value) {
425
+ function* TUnknown(schema, references, value) {
420
426
  yield 'true';
421
427
  }
422
- function* Void(schema, references, value) {
428
+ function* TVoid(schema, references, value) {
423
429
  yield IsVoidCheck(value);
424
430
  }
425
- function* UserDefined(schema, references, value) {
426
- const schema_key = `schema_key_${state.customs.size}`;
427
- state.customs.set(schema_key, schema);
428
- yield `custom('${schema[Types.Kind]}', '${schema_key}', ${value})`;
431
+ function* TKind(schema, references, value) {
432
+ yield `kind('${schema[Types.Kind]}', ${value})`;
429
433
  }
430
- function* Visit(schema, references, value, root = false) {
431
- const references_ = IsString(schema.$id) ? [...references, schema] : references;
434
+ function* Visit(schema, references, value, useHoisting = true) {
435
+ const references_ = ValueGuard.IsString(schema.$id) ? [...references, schema] : references;
432
436
  const schema_ = schema;
433
- // Rule: Types with identifiers are hoisted into their own functions.
434
- // The following will generate a function for the schema and yield the
435
- // call to that function. This call is only made if NOT the root type
436
- // which allows the generated function to yield its expression. The
437
- // root argument is only true when making calls via CreateFunction().
438
- // Note there is potential to omit the root argument and conditional
439
- // by refactoring the logic below. Consider for review.
440
- if (IsString(schema.$id)) {
441
- const name = CreateFunctionName(schema.$id);
442
- if (!state.functions.has(schema.$id)) {
443
- state.functions.add(schema.$id);
444
- const body = CreateFunction(name, schema, references, 'value');
445
- PushFunction(body);
437
+ // ----------------------------------------------------------------------------------
438
+ // Hoisting
439
+ // ----------------------------------------------------------------------------------
440
+ if (useHoisting && ValueGuard.IsString(schema.$id)) {
441
+ const functionName = CreateFunctionName(schema.$id);
442
+ if (state.functions.has(functionName)) {
443
+ return yield `${functionName}(${value})`;
444
+ }
445
+ else {
446
+ const functionCode = CreateFunction(functionName, schema, references, 'value', false);
447
+ state.functions.set(functionName, functionCode);
448
+ return yield `${functionName}(${value})`;
446
449
  }
447
- if (!root)
448
- return yield `${name}(${value})`;
449
450
  }
451
+ // ----------------------------------------------------------------------------------
452
+ // Types
453
+ // ----------------------------------------------------------------------------------
450
454
  switch (schema_[Types.Kind]) {
451
455
  case 'Any':
452
- return yield* Any(schema_, references_, value);
456
+ return yield* TAny(schema_, references_, value);
453
457
  case 'Array':
454
- return yield* Array(schema_, references_, value);
458
+ return yield* TArray(schema_, references_, value);
459
+ case 'AsyncIterator':
460
+ return yield* TAsyncIterator(schema_, references_, value);
455
461
  case 'BigInt':
456
- return yield* BigInt(schema_, references_, value);
462
+ return yield* TBigInt(schema_, references_, value);
457
463
  case 'Boolean':
458
- return yield* Boolean(schema_, references_, value);
464
+ return yield* TBoolean(schema_, references_, value);
459
465
  case 'Constructor':
460
- return yield* Constructor(schema_, references_, value);
466
+ return yield* TConstructor(schema_, references_, value);
461
467
  case 'Date':
462
- return yield* Date(schema_, references_, value);
468
+ return yield* TDate(schema_, references_, value);
463
469
  case 'Function':
464
- return yield* Function(schema_, references_, value);
470
+ return yield* TFunction(schema_, references_, value);
465
471
  case 'Integer':
466
- return yield* Integer(schema_, references_, value);
472
+ return yield* TInteger(schema_, references_, value);
467
473
  case 'Intersect':
468
- return yield* Intersect(schema_, references_, value);
474
+ return yield* TIntersect(schema_, references_, value);
475
+ case 'Iterator':
476
+ return yield* TIterator(schema_, references_, value);
469
477
  case 'Literal':
470
- return yield* Literal(schema_, references_, value);
478
+ return yield* TLiteral(schema_, references_, value);
471
479
  case 'Never':
472
- return yield* Never(schema_, references_, value);
480
+ return yield* TNever(schema_, references_, value);
473
481
  case 'Not':
474
- return yield* Not(schema_, references_, value);
482
+ return yield* TNot(schema_, references_, value);
475
483
  case 'Null':
476
- return yield* Null(schema_, references_, value);
484
+ return yield* TNull(schema_, references_, value);
477
485
  case 'Number':
478
- return yield* Number(schema_, references_, value);
486
+ return yield* TNumber(schema_, references_, value);
479
487
  case 'Object':
480
- return yield* Object(schema_, references_, value);
488
+ return yield* TObject(schema_, references_, value);
481
489
  case 'Promise':
482
- return yield* Promise(schema_, references_, value);
490
+ return yield* TPromise(schema_, references_, value);
483
491
  case 'Record':
484
- return yield* Record(schema_, references_, value);
492
+ return yield* TRecord(schema_, references_, value);
485
493
  case 'Ref':
486
- return yield* Ref(schema_, references_, value);
494
+ return yield* TRef(schema_, references_, value);
487
495
  case 'String':
488
- return yield* String(schema_, references_, value);
496
+ return yield* TString(schema_, references_, value);
489
497
  case 'Symbol':
490
- return yield* Symbol(schema_, references_, value);
498
+ return yield* TSymbol(schema_, references_, value);
491
499
  case 'TemplateLiteral':
492
- return yield* TemplateLiteral(schema_, references_, value);
500
+ return yield* TTemplateLiteral(schema_, references_, value);
493
501
  case 'This':
494
- return yield* This(schema_, references_, value);
502
+ return yield* TThis(schema_, references_, value);
495
503
  case 'Tuple':
496
- return yield* Tuple(schema_, references_, value);
504
+ return yield* TTuple(schema_, references_, value);
497
505
  case 'Undefined':
498
- return yield* Undefined(schema_, references_, value);
506
+ return yield* TUndefined(schema_, references_, value);
499
507
  case 'Union':
500
- return yield* Union(schema_, references_, value);
508
+ return yield* TUnion(schema_, references_, value);
501
509
  case 'Uint8Array':
502
- return yield* Uint8Array(schema_, references_, value);
510
+ return yield* TUint8Array(schema_, references_, value);
503
511
  case 'Unknown':
504
- return yield* Unknown(schema_, references_, value);
512
+ return yield* TUnknown(schema_, references_, value);
505
513
  case 'Void':
506
- return yield* Void(schema_, references_, value);
514
+ return yield* TVoid(schema_, references_, value);
507
515
  default:
508
516
  if (!Types.TypeRegistry.Has(schema_[Types.Kind]))
509
517
  throw new TypeCompilerUnknownTypeError(schema);
510
- return yield* UserDefined(schema_, references_, value);
518
+ return yield* TKind(schema_, references_, value);
511
519
  }
512
520
  }
513
521
  // -------------------------------------------------------------------
@@ -516,15 +524,29 @@ var TypeCompiler;
516
524
  // prettier-ignore
517
525
  const state = {
518
526
  language: 'javascript',
519
- variables: new Set(),
520
- functions: new Set(),
521
- customs: new Map(), // custom type data
527
+ functions: new Map(),
528
+ variables: new Map(), // local variables
522
529
  };
530
+ // -------------------------------------------------------------------
531
+ // Compiler Factory
532
+ // -------------------------------------------------------------------
533
+ function CreateExpression(schema, references, value, useHoisting = true) {
534
+ return `(${[...Visit(schema, references, value, useHoisting)].join(' && ')})`;
535
+ }
523
536
  function CreateFunctionName($id) {
524
537
  return `check_${Identifier.Encode($id)}`;
525
538
  }
526
- function CreateExpression(schema, references, value) {
527
- return `(${[...Visit(schema, references, value)].join(' && ')})`;
539
+ function CreateVariable(expression) {
540
+ const variableName = `local_${state.variables.size}`;
541
+ state.variables.set(variableName, `const ${variableName} = ${expression}`);
542
+ return variableName;
543
+ }
544
+ function CreateFunction(name, schema, references, value, useHoisting = true) {
545
+ const [newline, pad] = ['\n', (length) => ''.padStart(length, ' ')];
546
+ const parameter = CreateParameter('value', 'any');
547
+ const returns = CreateReturns('boolean');
548
+ const expression = [...Visit(schema, references, value, useHoisting)].map((expression) => `${pad(4)}${expression}`).join(` &&${newline}`);
549
+ return `function ${name}(${parameter})${returns} {${newline}${pad(2)}return (${newline}${expression}${newline}${pad(2)})\n}`;
528
550
  }
529
551
  function CreateParameter(name, type) {
530
552
  const annotation = state.language === 'typescript' ? `: ${type}` : '';
@@ -533,71 +555,63 @@ var TypeCompiler;
533
555
  function CreateReturns(type) {
534
556
  return state.language === 'typescript' ? `: ${type}` : '';
535
557
  }
536
- function CreateFunction(name, schema, references, value) {
537
- const expression = [...Visit(schema, references, value, true)].map((condition) => ` ${condition}`).join(' &&\n');
538
- const parameter = CreateParameter('value', 'any');
539
- const returns = CreateReturns('boolean');
540
- return `function ${name}(${parameter})${returns} {\n return (\n${expression}\n )\n}`;
541
- }
542
- function PushFunction(functionBody) {
543
- state.variables.add(functionBody);
544
- }
545
- function PushLocal(expression) {
546
- const local = `local_${state.variables.size}`;
547
- state.variables.add(`const ${local} = ${expression}`);
548
- return local;
549
- }
550
- function GetLocals() {
551
- return [...state.variables.values()];
552
- }
553
558
  // -------------------------------------------------------------------
554
559
  // Compile
555
560
  // -------------------------------------------------------------------
556
- function Build(schema, references) {
557
- const check = CreateFunction('check', schema, references, 'value'); // interior visit
558
- const locals = GetLocals();
561
+ function Build(schema, references, options) {
562
+ const functionCode = CreateFunction('check', schema, references, 'value'); // will populate functions and variables
559
563
  const parameter = CreateParameter('value', 'any');
560
564
  const returns = CreateReturns('boolean');
565
+ const functions = [...state.functions.values()];
566
+ const variables = [...state.variables.values()];
561
567
  // prettier-ignore
562
- return IsString(schema.$id) // ensure top level schemas with $id's are hoisted
563
- ? `${locals.join('\n')}\nreturn function check(${parameter})${returns} {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
564
- : `${locals.join('\n')}\nreturn ${check}`;
568
+ const checkFunction = ValueGuard.IsString(schema.$id) // ensure top level schemas with $id's are hoisted
569
+ ? `return function check(${parameter})${returns} {\n return ${CreateFunctionName(schema.$id)}(value)\n}`
570
+ : `return ${functionCode}`;
571
+ return [...variables, ...functions, checkFunction].join('\n');
565
572
  }
566
573
  /** Returns the generated assertion code used to validate this type. */
567
- function Code(schema, references = [], options = { language: 'javascript' }) {
574
+ function Code(...args) {
575
+ const defaults = { language: 'javascript' };
576
+ // prettier-ignore
577
+ const [schema, references, options] = (args.length === 2 && ValueGuard.IsArray(args[1]) ? [args[0], args[1], defaults] :
578
+ args.length === 2 && !ValueGuard.IsArray(args[1]) ? [args[0], [], args[1]] :
579
+ args.length === 3 ? [args[0], args[1], args[2]] :
580
+ args.length === 1 ? [args[0], [], defaults] :
581
+ [null, [], defaults]);
568
582
  // compiler-reset
569
583
  state.language = options.language;
570
584
  state.variables.clear();
571
585
  state.functions.clear();
572
- state.customs.clear();
573
586
  if (!Types.TypeGuard.TSchema(schema))
574
587
  throw new TypeCompilerTypeGuardError(schema);
575
588
  for (const schema of references)
576
589
  if (!Types.TypeGuard.TSchema(schema))
577
590
  throw new TypeCompilerTypeGuardError(schema);
578
- return Build(schema, references);
591
+ return Build(schema, references, options);
579
592
  }
580
593
  TypeCompiler.Code = Code;
581
594
  /** Compiles the given type for runtime type checking. This compiler only accepts known TypeBox types non-inclusive of unsafe types. */
582
595
  function Compile(schema, references = []) {
583
- const code = Code(schema, references, { language: 'javascript' });
584
- const customs = new Map(state.customs);
585
- const compiledFunction = globalThis.Function('custom', 'format', 'hash', code);
586
- const checkFunction = compiledFunction((kind, schema_key, value) => {
587
- if (!Types.TypeRegistry.Has(kind) || !customs.has(schema_key))
596
+ const generatedCode = Code(schema, references, { language: 'javascript' });
597
+ const compiledFunction = globalThis.Function('kind', 'format', 'hash', generatedCode);
598
+ function typeRegistryFunction(kind, value) {
599
+ if (!Types.TypeRegistry.Has(kind))
588
600
  return false;
589
- const schema = customs.get(schema_key);
590
- const func = Types.TypeRegistry.Get(kind);
591
- return func(schema, value);
592
- }, (format, value) => {
601
+ const checkFunc = Types.TypeRegistry.Get(kind);
602
+ return checkFunc(schema, value);
603
+ }
604
+ function formatRegistryFunction(format, value) {
593
605
  if (!Types.FormatRegistry.Has(format))
594
606
  return false;
595
- const func = Types.FormatRegistry.Get(format);
596
- return func(value);
597
- }, (value) => {
598
- return hash_1.ValueHash.Create(value);
599
- });
600
- return new TypeCheck(schema, references, checkFunction, code);
607
+ const checkFunc = Types.FormatRegistry.Get(format);
608
+ return checkFunc(value);
609
+ }
610
+ function valueHashFunction(value) {
611
+ return ValueHash.Hash(value);
612
+ }
613
+ const checkFunction = compiledFunction(typeRegistryFunction, formatRegistryFunction, valueHashFunction);
614
+ return new TypeCheck(schema, references, checkFunction, generatedCode);
601
615
  }
602
616
  TypeCompiler.Compile = Compile;
603
617
  })(TypeCompiler || (exports.TypeCompiler = TypeCompiler = {}));