UNPKG

@sinclair/typebox

Version:

Json Schema Type Builder with Static Type Resolution for TypeScript

475 lines (473 loc) 15.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValueCreateError = void 0; exports.Create = Create; const index_1 = require("../guard/index"); const index_2 = require("../check/index"); const index_3 = require("../clone/index"); const index_4 = require("../deref/index"); const index_5 = require("../../type/template-literal/index"); const index_6 = require("../../type/patterns/index"); const index_7 = require("../../type/registry/index"); const index_8 = require("../../type/symbols/index"); const index_9 = require("../../type/error/index"); // ------------------------------------------------------------------ // Errors // ------------------------------------------------------------------ class ValueCreateError extends index_9.TypeBoxError { constructor(schema, message) { super(message); this.schema = schema; } } exports.ValueCreateError = ValueCreateError; // ------------------------------------------------------------------ // Default // ------------------------------------------------------------------ function FromDefault(value) { return typeof value === 'function' ? value : (0, index_3.Clone)(value); } // ------------------------------------------------------------------ // Create // ------------------------------------------------------------------ function FromAny(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return {}; } } function FromArray(schema, references) { if (schema.uniqueItems === true && !(0, index_1.HasPropertyKey)(schema, 'default')) { throw new ValueCreateError(schema, 'Array with the uniqueItems constraint requires a default value'); } else if ('contains' in schema && !(0, index_1.HasPropertyKey)(schema, 'default')) { throw new ValueCreateError(schema, 'Array with the contains constraint requires a default value'); } else if ('default' in schema) { return FromDefault(schema.default); } else if (schema.minItems !== undefined) { return Array.from({ length: schema.minItems }).map((item) => { return Visit(schema.items, references); }); } else { return []; } } function FromAsyncIterator(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return (async function* () { })(); } } function FromBigInt(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return BigInt(0); } } function FromBoolean(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return false; } } function FromConstructor(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { const value = Visit(schema.returns, references); if (typeof value === 'object' && !Array.isArray(value)) { return class { constructor() { for (const [key, val] of Object.entries(value)) { const self = this; self[key] = val; } } }; } else { return class { }; } } } function FromDate(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.minimumTimestamp !== undefined) { return new Date(schema.minimumTimestamp); } else { return new Date(); } } function FromFunction(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return () => Visit(schema.returns, references); } } function FromInteger(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.minimum !== undefined) { return schema.minimum; } else { return 0; } } function FromIntersect(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { // -------------------------------------------------------------- // Note: The best we can do here is attempt to instance each // sub type and apply through object assign. For non-object // sub types, we just escape the assignment and just return // the value. In the latter case, this is typically going to // be a consequence of an illogical intersection. // -------------------------------------------------------------- const value = schema.allOf.reduce((acc, schema) => { const next = Visit(schema, references); return typeof next === 'object' ? { ...acc, ...next } : next; }, {}); if (!(0, index_2.Check)(schema, references, value)) throw new ValueCreateError(schema, 'Intersect produced invalid value. Consider using a default value.'); return value; } } function FromIterator(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return (function* () { })(); } } function FromLiteral(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return schema.const; } } function FromNever(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { throw new ValueCreateError(schema, 'Never types cannot be created. Consider using a default value.'); } } function FromNot(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { throw new ValueCreateError(schema, 'Not types must have a default value'); } } function FromNull(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return null; } } function FromNumber(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.minimum !== undefined) { return schema.minimum; } else { return 0; } } function FromObject(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { const required = new Set(schema.required); const Acc = {}; for (const [key, subschema] of Object.entries(schema.properties)) { if (!required.has(key)) continue; Acc[key] = Visit(subschema, references); } return Acc; } } function FromPromise(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return Promise.resolve(Visit(schema.item, references)); } } function FromRecord(schema, references) { const [keyPattern, valueSchema] = Object.entries(schema.patternProperties)[0]; if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (!(keyPattern === index_6.PatternStringExact || keyPattern === index_6.PatternNumberExact)) { const propertyKeys = keyPattern.slice(1, keyPattern.length - 1).split('|'); const Acc = {}; for (const key of propertyKeys) Acc[key] = Visit(valueSchema, references); return Acc; } else { return {}; } } function FromRef(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return Visit((0, index_4.Deref)(schema, references), references); } } function FromRegExp(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { throw new ValueCreateError(schema, 'RegExp types cannot be created. Consider using a default value.'); } } function FromString(schema, references) { if (schema.pattern !== undefined) { if (!(0, index_1.HasPropertyKey)(schema, 'default')) { throw new ValueCreateError(schema, 'String types with patterns must specify a default value'); } else { return FromDefault(schema.default); } } else if (schema.format !== undefined) { if (!(0, index_1.HasPropertyKey)(schema, 'default')) { throw new ValueCreateError(schema, 'String types with formats must specify a default value'); } else { return FromDefault(schema.default); } } else { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.minLength !== undefined) { // prettier-ignore return Array.from({ length: schema.minLength }).map(() => ' ').join(''); } else { return ''; } } } function FromSymbol(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if ('value' in schema) { return Symbol.for(schema.value); } else { return Symbol(); } } function FromTemplateLiteral(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } if (!(0, index_5.IsTemplateLiteralFinite)(schema)) throw new ValueCreateError(schema, 'Can only create template literals that produce a finite variants. Consider using a default value.'); const generated = (0, index_5.TemplateLiteralGenerate)(schema); return generated[0]; } function FromThis(schema, references) { if (recursiveDepth++ > recursiveMaxDepth) throw new ValueCreateError(schema, 'Cannot create recursive type as it appears possibly infinite. Consider using a default.'); if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return Visit((0, index_4.Deref)(schema, references), references); } } function FromTuple(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } if (schema.items === undefined) { return []; } else { return Array.from({ length: schema.minItems }).map((_, index) => Visit(schema.items[index], references)); } } function FromUndefined(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return undefined; } } function FromUnion(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.anyOf.length === 0) { throw new Error('ValueCreate.Union: Cannot create Union with zero variants'); } else { return Visit(schema.anyOf[0], references); } } function FromUint8Array(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else if (schema.minByteLength !== undefined) { return new Uint8Array(schema.minByteLength); } else { return new Uint8Array(0); } } function FromUnknown(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return {}; } } function FromVoid(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { return void 0; } } function FromKind(schema, references) { if ((0, index_1.HasPropertyKey)(schema, 'default')) { return FromDefault(schema.default); } else { throw new Error('User defined types must specify a default value'); } } function AddReference(references, schema) { references.push(schema); return references; } function Visit(schema, references) { const references_ = (0, index_1.IsString)(schema.$id) ? AddReference(references, schema) : references; const schema_ = schema; switch (schema_[index_8.Kind]) { case 'Any': return FromAny(schema_, references_); case 'Array': return FromArray(schema_, references_); case 'AsyncIterator': return FromAsyncIterator(schema_, references_); case 'BigInt': return FromBigInt(schema_, references_); case 'Boolean': return FromBoolean(schema_, references_); case 'Constructor': return FromConstructor(schema_, references_); case 'Date': return FromDate(schema_, references_); case 'Function': return FromFunction(schema_, references_); case 'Integer': return FromInteger(schema_, references_); case 'Intersect': return FromIntersect(schema_, references_); case 'Iterator': return FromIterator(schema_, references_); case 'Literal': return FromLiteral(schema_, references_); case 'Never': return FromNever(schema_, references_); case 'Not': return FromNot(schema_, references_); case 'Null': return FromNull(schema_, references_); case 'Number': return FromNumber(schema_, references_); case 'Object': return FromObject(schema_, references_); case 'Promise': return FromPromise(schema_, references_); case 'Record': return FromRecord(schema_, references_); case 'Ref': return FromRef(schema_, references_); case 'RegExp': return FromRegExp(schema_, references_); case 'String': return FromString(schema_, references_); case 'Symbol': return FromSymbol(schema_, references_); case 'TemplateLiteral': return FromTemplateLiteral(schema_, references_); case 'This': return FromThis(schema_, references_); case 'Tuple': return FromTuple(schema_, references_); case 'Undefined': return FromUndefined(schema_, references_); case 'Union': return FromUnion(schema_, references_); case 'Uint8Array': return FromUint8Array(schema_, references_); case 'Unknown': return FromUnknown(schema_, references_); case 'Void': return FromVoid(schema_, references_); default: if (!index_7.TypeRegistry.Has(schema_[index_8.Kind])) throw new ValueCreateError(schema_, 'Unknown type'); return FromKind(schema_, references_); } } // ------------------------------------------------------------------ // State // ------------------------------------------------------------------ const recursiveMaxDepth = 512; let recursiveDepth = 0; /** Creates a value from the given schema */ function Create(...args) { recursiveDepth = 0; return args.length === 2 ? Visit(args[0], args[1]) : Visit(args[0], []); }