UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

227 lines 8.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TypeBuilder = void 0; const tslib_1 = require("tslib"); const schema = tslib_1.__importStar(require("../schema")); const classes = tslib_1.__importStar(require("./classes")); const { s } = schema; class TypeBuilder { constructor(system) { this.system = system; // --------------------------------------------------------------- shorthands this.or = (...types) => this.Or(...types); this.undefined = () => this.undef; this.null = () => this.nil; this.boolean = () => this.bool; this.number = () => this.num; this.string = () => this.str; this.binary = () => this.bin; this.con = (value, options) => this.Const(value, options); this.literal = this.con; this.array = (type, options) => this.Array((type ?? this.any), options); this.tuple = (...types) => this.Tuple(types); /** * Creates an object type with the specified properties. This is a shorthand for * `t.Object(t.prop(key, value), ...)`. * * Importantly, this method does not allow to specify object field order, * so the order of properties in the resulting type is not guaranteed. * * Example: * * ```ts * t.object({ * id: t.str, * name: t.string(), * age: t.num, * verified: t.bool, * }); * ``` * * @param record A mapping of property names to types. * @returns An object type. */ this.object = (record) => { const keys = []; for (const [key, value] of Object.entries(record)) keys.push(this.Key(key, value)); return new classes.ObjType(keys).sys(this.system); }; /** * Creates a type that represents a value that may be present or absent. The * value is `undefined` if absent. This is a shorthand for `t.Or(type, t.undef)`. */ this.maybe = (type) => this.Or(type, this.undef); /** * Creates a union type from a list of values. This is a shorthand for * `t.Or(t.Const(value1), t.Const(value2), ...)`. For example, the below * are equivalent: * * ```ts * t.enum('red', 'green', 'blue'); * t.Or(t.Const('red'), t.Const('green'), t.Const('blue')); * ``` * * @param values The values to include in the union. * @returns A union type representing the values. */ this.enum = (...values) => this.Or(...values.map((type) => this.Const(type))); } // -------------------------------------------------------------- empty types get any() { return this.Any(); } get undef() { return this.Const(undefined); } get nil() { return this.Const(null); } get bool() { return this.Boolean(); } get num() { return this.Number(); } get str() { return this.String(); } get bin() { return this.Binary(this.any); } get arr() { return this.Array(this.any); } get obj() { return this.Object(); } get map() { return this.Map(this.any); } get fn() { return this.Function(this.undef, this.undef); } get fn$() { return this.Function$(this.undef, this.undef); } // --------------------------------------------------- base node constructors Any(options) { return new classes.AnyType(s.Any(options)).sys(this.system); } Const(value, options) { return new classes.ConType(schema.s.Const(value, options)).sys(this.system); } Boolean(options) { return new classes.BoolType(s.Boolean(options)).sys(this.system); } Number(options) { return new classes.NumType(s.Number(options)).sys(this.system); } String(options) { return new classes.StrType(s.String(options)).sys(this.system); } Binary(type, options = {}) { return new classes.BinType(type, options).sys(this.system); } Array(type, options) { return new classes.ArrType(type, void 0, void 0, options).sys(this.system); } Tuple(head, item, tail, options) { return new classes.ArrType(item, head, tail, options).sys(this.system); } Object(...keys) { return new classes.ObjType(keys).sys(this.system); } Key(key, value) { return new classes.KeyType(key, value).sys(this.system); } KeyOpt(key, value) { return new classes.KeyOptType(key, value).sys(this.system); } Map(val, key, options) { return new classes.MapType(val, key, options).sys(this.system); } Or(...types) { return new classes.OrType(types).sys(this.system); } Ref(ref) { return new classes.RefType(ref).sys(this.system); } Function(req, res, options) { return new classes.FnType(req, res, options).sys(this.system); } Function$(req, res, options) { return new classes.FnRxType(req, res, options).sys(this.system); } import(node) { switch (node.kind) { case 'any': return this.Any(node); case 'bool': return this.Boolean(node); case 'num': return this.Number(node); case 'str': return this.String(node); case 'bin': return this.Binary(this.import(node.type), node); case 'arr': { const { head, type, tail, ...rest } = node; return this.Tuple(head ? head.map((h) => this.import(h)) : void 0, type ? this.import(type) : void 0, tail ? tail.map((t) => this.import(t)) : void 0, rest); } case 'obj': { const fields = node.keys.map((f) => f.optional ? this.KeyOpt(f.key, this.import(f.value)).options(f) : this.Key(f.key, this.import(f.value)).options(f)); return this.Object(...fields).options(node); } case 'key': return node.optional ? this.KeyOpt(node.key, this.import(node.value)).options(node) : this.Key(node.key, this.import(node.value)).options(node); case 'map': return this.Map(this.import(node.value), node.key ? this.import(node.key) : undefined, node); case 'con': return this.Const(node.value).options(node); case 'or': return this.Or(...node.types.map((t) => this.import(t))).options(node); case 'ref': return this.Ref(node.ref).options(node); case 'fn': return this.Function(this.import(node.req), this.import(node.res)).options(node); case 'fn$': return this.Function$(this.import(node.req), this.import(node.res)).options(node); } throw new Error(`UNKNOWN_NODE [${node.kind}]`); } from(value) { switch (typeof value) { case 'undefined': return this.undef; case 'boolean': return this.bool; case 'number': return this.num; case 'string': return this.str; case 'object': if (value === null) return this.nil; if (Array.isArray(value)) { if (value.length === 0) return this.arr; const getType = (v) => this.from(v) + ''; const allElementsOfTheSameType = value.every((v) => getType(v) === getType(value[0])); this.Array(this.from(value[0])); return allElementsOfTheSameType ? this.Array(this.from(value[0])) : this.tuple(...value.map((v) => this.from(v))); } return this.Object(...Object.entries(value).map(([key, value]) => this.Key(key, this.from(value)))); default: return this.any; } } } exports.TypeBuilder = TypeBuilder; //# sourceMappingURL=TypeBuilder.js.map