UNPKG

succulent

Version:

Powerful and easy runtime type checking

489 lines (461 loc) 12.9 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/filters/length.ts function hasLength(length) { return (x) => x.length === length; } function minLength(length) { return (x) => x.length >= length; } function maxLength(length) { return (x) => x.length <= length; } function nonEmpty(x) { return x.length > 0; } // src/filters/matches.ts function matches(expression) { return function(t) { return expression.test(t); }; } // src/filters/range.ts function inRange(min, max) { return (x) => min <= x && x <= max; } // src/base/errorMessages.ts var errorMessages_exports = {}; __export(errorMessages_exports, { invalidProperty: () => invalidProperty, invalidValue: () => invalidValue }); // src/base/toDisplayKey.ts function toDisplayKey(x) { switch (typeof x) { case "string": return x; default: return `[${String(x)}]`; } } // src/base/toDisplayString.ts function toDisplayString(x) { switch (typeof x) { case "bigint": return `${x}n`; case "string": return `"${x}"`; default: return String(x); } } // src/base/errorMessages.ts function invalidProperty(key, schema) { const displayKey = toDisplayKey(key); const typeName = Schema.displayName(schema); return `Expected property ${displayKey} to have type ${typeName}`; } function invalidValue(value, schema) { const displayValue = toDisplayString(value); const typeName = Schema.displayName(schema); return `Expected ${typeName}, got ${displayValue}`; } // src/base/indent.ts function indent(str, level = 2) { const indentation = typeof level === "number" ? " ".repeat(level) : level; return str.split("\n").map((line) => `${indentation}${line}`).join("\n"); } // src/base/trace.ts function trace(message, error) { if (error instanceof Error) { return `${message} ${indent(error.message)}`; } return message; } // src/base/keyReporter.ts function keyReporter(check2, onError) { const errorTraces = []; const report = (...args) => { try { check2(...args); } catch (error) { errorTraces.push(trace(onError(...args), error)); } }; const resolve = () => { if (errorTraces.length > 0) { throw new TypeError(errorTraces.join("\n")); } return true; }; return [report, resolve]; } // src/schema.ts var Schema = class { static check(base, x) { if (base instanceof Schema) { return base.check(x); } return new Schema(base).check(x); } static is(base, x, ref) { try { Schema.check(base, x); return true; } catch (error) { if (ref && error instanceof Error) ref.error = error; return false; } } static displayName(base) { return Schema.from(base).displayName; } static every(base, predicate) { return Array.from(Schema.from(base)).every(predicate); } static from(base) { if (base instanceof Schema) { return base; } return new Schema(base); } [Symbol.iterator] = function* () { }; _check; displayName = "(unknown)"; constructor(base, options = {}) { const { displayName, iter } = options; if (base instanceof Schema) { this._check = base._check; this.displayName = displayName || base.displayName; this[Symbol.iterator] = iter ?? base[Symbol.iterator]; return; } if (typeof base === "function") { this._check = base; if (displayName) this.displayName = displayName; if (iter) this[Symbol.iterator] = iter; return; } this._check = (x) => Object.is(x, base); this.displayName = displayName || toDisplayString(base); this[Symbol.iterator] = iter ?? function* () { yield base; }; } check(x) { let ok; try { ok = this._check(x); } catch (error) { throw new TypeError(trace(errorMessages_exports.invalidValue(x, this), error)); } if (!ok) { throw new TypeError(errorMessages_exports.invalidValue(x, this)); } return true; } that(...filters) { return new Schema((x) => this.check(x) && filters.every((filter) => filter(x))); } toString() { return this.displayName; } }; // src/operators/check.ts function check(x, schema) { if (!Schema.check(schema, x)) { throw new Error("check returned false instead of throwing, which is bad"); } } var guard = check; // src/operators/is.ts function is(x, schema, ref) { return Schema.is(schema, x, ref); } // src/operators/iterables.ts function oneOf(x) { return new Schema((t) => { for (const value of x) { if (Object.is(t, value)) { return true; } } return false; }); } // src/operators/logic.ts function union(...schemas) { return new Schema((t) => schemas.some((schema) => is(t, schema)), { displayName: `(${schemas.map((schema) => Schema.from(schema).displayName).join(" | ")})`, *iter() { for (const schema of schemas) yield* Schema.from(schema); } }); } function or(x, y) { return new Schema((t) => is(t, x) || is(t, y), { displayName: `(${Schema.displayName(x)} | ${Schema.displayName(y)})`, *iter() { yield* Schema.from(x); yield* Schema.from(y); } }); } function and(x, y) { return new Schema((t) => is(t, x) && is(t, y), { displayName: `(${Schema.displayName(x)} & ${Schema.displayName(y)})` }); } // src/types/array.ts function $Array(base) { const itemSchema = Schema.from(base); const baseDisplayName = itemSchema.displayName; return new Schema((t) => { if (!Array.isArray(t)) { return false; } for (const each of t) { itemSchema.check(each); } return true; }, { displayName: baseDisplayName.includes(" ") ? `${baseDisplayName}[]` : `Array<${baseDisplayName}>` }); } // src/types/collections.ts function $Map(keySchemaBase, valueSchemaBase) { const keySchema = Schema.from(keySchemaBase); const valueSchema = Schema.from(valueSchemaBase); const keyTypeName = keySchema.displayName; const valueTypeName = valueSchema.displayName; return new Schema((x) => { if (!(x instanceof Map)) { return false; } for (const [key, value] of x) { keySchema.check(key); valueSchema.check(value); } return true; }, { displayName: `Map<${keyTypeName}, ${valueTypeName}>` }); } function $Set(schemaBase) { const schema = Schema.from(schemaBase); return new Schema((x) => { if (!(x instanceof Set)) { return false; } for (const key of x) { schema.check(key); } return true; }, { displayName: `Set<${schema.displayName}>` }); } // src/types/misc.ts function $instanceof(t) { return new Schema((x) => x instanceof t, { displayName: t.name }); } var a = $instanceof; function $literal(t) { return new Schema(t); } var $falsy = new Schema((x) => !x, { displayName: "falsy" }); var $nullish = new Schema((x) => x == null, { displayName: "nullish" }); function $optional(base) { const schema = Schema.from(base); return new Schema((x) => Schema.is(schema, x) || Schema.is($undefined, x), { displayName: `${schema.displayName}?` }); } function $maybe(base) { const schema = Schema.from(base); return new Schema((x) => Schema.is(schema, x) || Schema.is($nullish, x), { displayName: `maybe ${schema.displayName}` }); } var $any = new Schema((x) => true, { displayName: "any" }); var $never = new Schema((x) => false, { displayName: "never" }); var $Date = $instanceof(Date); var $Error = $instanceof(Error); var $RegExp = $instanceof(RegExp); var $URL = $instanceof(URL); var $ArrayBuffer = $instanceof(ArrayBuffer); var $ArrayBufferView = new Schema((x) => ArrayBuffer.isView(x), { displayName: "ArrayBufferView" }); var $Int8Array = $instanceof(Int8Array); var $Int16Array = $instanceof(Int16Array); var $Int32Array = $instanceof(Int32Array); var $BigInt64Array = $instanceof(BigInt64Array); var $Uint8Array = $instanceof(Uint8Array); var $Uint8ClampedArray = $instanceof(Uint8ClampedArray); var $Uint16Array = $instanceof(Uint16Array); var $Uint32Array = $instanceof(Uint32Array); var $BigUint64Array = $instanceof(BigUint64Array); var $Float32Array = $instanceof(Float32Array); var $Float64Array = $instanceof(Float64Array); // src/types/constants.ts var $boolean = new Schema((x) => typeof x === "boolean", { displayName: "boolean" }); var $NaN = new Schema((x) => x !== x, { displayName: "NaN" }); var $false = $literal(false); var $true = $literal(true); var $undefined = $literal(void 0); var $null = $literal(null); // src/types/enum.ts function isEnumMemberName(x, enumObject) { return x in enumObject && typeof enumObject[enumObject[x]] !== "number"; } function enumKeys(enumObject) { return Object.keys(enumObject).filter((key) => isEnumMemberName(key, enumObject)); } function $enum(enumObject, options = {}) { const keys = enumKeys(enumObject); const values = new Set(keys.map((key) => enumObject[key])); return new Schema((x) => values.has(x), { displayName: options.displayName ?? `enum { ${keys.join(", ")} }`, *iter() { yield* values; } }); } // src/types/number.ts var $number = new Schema((x) => typeof x === "number" && x === x, { displayName: "number" }); var $int = new Schema((x) => Number.isInteger(x), { displayName: "int" }); var $finite = new Schema((x) => Number.isFinite(x), { displayName: "finite" }); var $bigint = new Schema((x) => typeof x === "bigint", { displayName: "bigint" }); // src/types/object.ts function hasOwn(target, prop) { if (!{}.hasOwnProperty.call(target, prop)) { throw null; } return true; } var toDisplayKeyValue = ([key, valueSchema]) => `${toDisplayKey(key)}: ${Schema.displayName(valueSchema)}`; var $object = new Schema((x) => typeof x === "object" && x != null, { displayName: "object" }); function $interface(template) { return new Schema((x) => { const [report, resolve] = keyReporter((key) => Schema.check(template[key], x[key]), (key) => errorMessages_exports.invalidProperty(key, template[key])); return $object.check(x) && (Reflect.ownKeys(template).forEach(report), resolve()); }, { displayName: `{${Reflect.ownKeys(template).map((key) => [key, template[key]]).map(toDisplayKeyValue).join(", ")}}` }); } function $Exact(template) { return new Schema((x) => { const [reportUnknown, resolveUnknown] = keyReporter((key) => hasOwn(template, key), (key) => `Unexpected property ${toDisplayKey(key)}`); const [reportKnown, resolveKnown] = keyReporter((key) => Schema.check(template[key], x[key]), (key) => errorMessages_exports.invalidProperty(key, template[key])); return $object.check(x) && (Reflect.ownKeys(x).forEach(reportUnknown), resolveUnknown()) && (Reflect.ownKeys(template).forEach(reportKnown), resolveKnown()); }, { displayName: `{|${Reflect.ownKeys(template).map((key) => [key, template[key]]).map(toDisplayKeyValue).join(", ")}|}` }); } // src/types/record.ts function $Record(keySchemaBase, valueSchemaBase) { const keySchema = Schema.from(keySchemaBase); const valueSchema = Schema.from(valueSchemaBase); return new Schema((x) => typeof x === "object" && x != null && Schema.every(keySchema, (key) => ({}).hasOwnProperty.call(x, key)) && Object.entries(x).every(([key, value]) => Schema.is(keySchema, key) ? Schema.is(valueSchema, value) : true), { displayName: `Record<${keySchema.displayName}, ${valueSchema.displayName}>` }); } // src/types/string.ts var $string = new Schema((x) => typeof x === "string", { displayName: "string" }); // src/types/symbol.ts var $symbol = new Schema((x) => typeof x === "symbol", { displayName: "symbol" }); // src/types/tuple.ts function $Tuple(...schemas) { return new Schema((t) => Array.isArray(t) && t.length === schemas.length && schemas.every((schema, i) => Schema.check(schema, t[i])), { displayName: `[${schemas.map((schema) => Schema.displayName(schema)).join(", ")}]` }); } // src/ref.ts function createErrorRef() { return { error: null }; } export { $Array, $ArrayBuffer, $ArrayBufferView, $BigInt64Array, $BigUint64Array, $Date, $Error, $Exact, $Float32Array, $Float64Array, $Int16Array, $Int32Array, $Int8Array, $Map, $NaN, $Record, $RegExp, $Set, $Tuple, $URL, $Uint16Array, $Uint32Array, $Uint8Array, $Uint8ClampedArray, $any, $bigint, $boolean, $enum, $false, $falsy, $finite, $instanceof, $int, $interface, $literal, $maybe, $never, $null, $nullish, $number, $object, $optional, $string, $symbol, $true, $undefined, Schema, a, and, check, createErrorRef, guard, hasLength, inRange, is, matches, maxLength, minLength, nonEmpty, oneOf, or, union }; //# sourceMappingURL=index.mjs.map