"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { $keys: function() { return $keys; }, $strict: function() { return $strict; }, $values: function() { return $values; }, and: function() { return and; }, as: function() { return as; }, asError: function() { return asError; }, ascertain: function() { return ascertain; }, compile: function() { return compile; }, formatError: function() { return formatError; }, fromBase64: function() { return fromBase64; }, optional: function() { return optional; }, or: function() { return or; }, tuple: function() { return tuple; } }); class Operator { schemas; constructor(schemas){ this.schemas = schemas; if (schemas.length === 0) { throw new TypeError(`Operation schema ${this.constructor.name} must have at least one element`); } } } const $keys = Symbol.for('@@keys'); const $values = Symbol.for('@@values'); const $strict = Symbol.for('@@strict'); class Or extends Operator { } const or = (...schemas)=>new Or(schemas); class And extends Operator { } const and = (...schemas)=>new And(schemas); class Optional extends Operator { constructor(schema){ super([ schema ]); } } const optional = (schema)=>new Optional(schema); class Tuple extends Operator { } const tuple = (...schemas)=>new Tuple(schemas); const fromBase64 = typeof Buffer === 'undefined' ? (value)=>atob(value) : (value)=>Buffer.from(value, 'base64').toString('utf-8'); const MULTIPLIERS = { ms: 1, s: 1000, m: 60000, h: 3600000, d: 86400000, w: 604800000 }; const asError = (message)=>new TypeError(message); const as = { string: (value)=>{ return typeof value === 'string' ? value : asError(`Invalid value "${value}", expected a string`); }, number: (value)=>{ const result = parseFloat(value); return Number.isNaN(result) ? asError(`Invalid value ${value}, expected a valid number`) : result; }, date: (value)=>{ const result = Date.parse(value); const date = new Date(result); return Number.isNaN(date.valueOf()) ? asError(`Invalid value "${value}", expected a valid date format`) : date; }, time: (value, conversionFactor = 1)=>{ const matches = value?.match(/^(\d*\.?\d*)(ms|s|m|h|d|w)?$/); if (matches) { const [, amount, unit = 'ms'] = matches; return parseInt(`${parseFloat(amount) * MULTIPLIERS[unit] / conversionFactor}`); } return asError(`Invalid value ${value}, expected a valid time format`); }, boolean: (value)=>/^(0|1|true|false|enabled|disabled)$/i.test(value) ? /^(1|true|enabled)$/i.test(value) : asError(`Invalid value ${value}, expected a boolean like`), array: (value, delimiter)=>value?.split?.(delimiter) ?? asError(`Invalid value ${value}, expected an array`), json: (value)=>{ try { return JSON.parse(value); } catch (e) { return asError(`Invalid value ${value}, expected a valid JSON string`); } }, base64: (value)=>{ try { return fromBase64(value); } catch (e) { return asError(`Invalid value ${value}, expected a valid base64 string`); } } }; const formatError = (value, expected, path, subject)=>`Invalid ${subject} ${JSON.stringify(value)} for path ${path}, expected ${expected}.`; class Context { registry = []; varIndex = 0; register(value) { if (!this.registry.includes(value)) { this.registry.push(value); } return this.registry.indexOf(value); } unique(prefix) { return `${prefix}$$${this.varIndex++}`; } } const codeGenCollectErrors = (errorsAlias, code, extra = '')=>`try {${code}} catch (e) {${errorsAlias}.push(e.message);${extra}}`; const codeGenExpectNoErrors = (errorsAlias)=>`if (${errorsAlias}.length !== 0) { throw new TypeError(${errorsAlias}.join('\\n')); }`; const codeGenExpectNonError = (valueAlias, path)=>`if (${valueAlias} instanceof Error) { throw new TypeError(\`\${${valueAlias}.message} for path "${path}".\`); }`; const codeGenExpectNonNullable = (valueAlias, path)=>`if (${valueAlias} === null || ${valueAlias} === undefined) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected non-nullable.\`); }`; const codeGenExpectObject = (valueAlias, path, instanceOf)=>`if (typeof ${valueAlias} !== 'object') { throw new TypeError(\`Invalid type \${typeof ${valueAlias}} for path "${path}", expected an instance of ${instanceOf}\`); }`; const codeGenExpectArray = (valueAlias, path)=>`if (!Array.isArray(${valueAlias})) { throw new TypeError(\`Invalid instance of \${${valueAlias}.constructor?.name} for path "${path}", expected an instance of Array.\`); }`; const codeGen = (schema, context, valuePath, path)=>{ if (schema instanceof And) { const valueAlias = context.unique('v'); const errorsAlias = context.unique('err'); const code = schema.schemas.map((s)=>`try { ${codeGen(s, context, valueAlias, path)} } catch (e) { ${errorsAlias}.push(e.message); }`).join('\n'); return `// And const ${errorsAlias} = []; const ${valueAlias} = ${valuePath}; ${code} ${codeGenExpectNoErrors(errorsAlias)} `; } else if (schema instanceof Or) { const valueAlias = context.unique('v'); const errorsAlias = context.unique('err'); const code = schema.schemas.map((s)=>codeGen(s, context, valueAlias, path)).reduceRight((result, code)=>codeGenCollectErrors(errorsAlias, code, result), codeGenExpectNoErrors(errorsAlias)); return `// Or const ${errorsAlias} = []; const ${valueAlias} = ${valuePath}; ${code} `; } else if (schema instanceof Optional) { const valueAlias = context.unique('v'); return `// Optional const ${valueAlias} = ${valuePath}; if (${valueAlias} !== undefined && ${valueAlias} !== null) { ${codeGen(schema.schemas[0], context, valueAlias, path)} } `; } else if (schema instanceof Tuple) { const valueAlias = context.unique('v'); const errorsAlias = context.unique('err'); const code = [ '// Tuple', `const ${valueAlias} = ${valuePath};`, `const ${errorsAlias} = [];`, codeGenExpectNonNullable(valueAlias, path), codeGenExpectObject(valueAlias, path, 'Array'), codeGenExpectArray(valueAlias, path), `if (${valueAlias}.length > ${schema.schemas.length}) { throw new TypeError(\`Invalid tuple length \${${valueAlias}.length} for path "${path}", expected ${schema.schemas.length}.\`); }`, ...schema.schemas.map((s, idx)=>codeGenCollectErrors(errorsAlias, codeGen(s, context, `${valueAlias}[${idx}]`, `${path}[${idx}]`))), codeGenExpectNoErrors(errorsAlias) ]; return code.join('\n'); } else if (typeof schema === 'function') { const index = context.register(schema); const valueAlias = context.unique('v'); const registryAlias = context.unique('r'); const code = [ `const ${valueAlias} = ${valuePath};`, `const ${registryAlias} = ctx.registry[${index}];`, codeGenExpectNonNullable(valueAlias, path) ]; if (schema !== Error && !(schema?.prototype instanceof Error)) { code.push(codeGenExpectNonError(valueAlias, path)); } code.push(`if (typeof ${valueAlias} === 'object' && !(${valueAlias} instanceof ${registryAlias})) { throw new TypeError(\`Invalid instance of \${${valueAlias}?.constructor?.name} for path "${path}", expected an instance of ${schema?.name}\`); }`, `if (typeof ${valueAlias} !== 'object' && ${valueAlias}?.constructor !== ${registryAlias}) { throw new TypeError(\`Invalid type \${${valueAlias}?.constructor?.name} for path "${path}", expected type ${schema?.name}\`); }`, `if (Number.isNaN(${valueAlias}?.valueOf?.())) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected a valid ${schema?.name}\`); }`); return code.join('\n'); } else if (Array.isArray(schema)) { const valueAlias = context.unique('v'); const code = [ `const ${valueAlias} = ${valuePath};`, codeGenExpectNonNullable(valueAlias, path), codeGenExpectNonError(valueAlias, path), codeGenExpectObject(valueAlias, path, 'Array'), codeGenExpectArray(valueAlias, path) ]; if (schema.length > 0) { const value = context.unique('val'); const key = context.unique('key'); const errorsAlias = context.unique('err'); code.push(`const ${errorsAlias} = [];`); code.push(...schema.map((s)=>`${valueAlias}.forEach((${value},${key}) => { ${codeGenCollectErrors(errorsAlias, codeGen(s, context, value, `${path}[\${${key}}]`))} });`)); code.push(codeGenExpectNoErrors(errorsAlias)); } return code.join('\n'); } else if (typeof schema === 'object' && schema !== null) { if (schema instanceof RegExp) { const valueAlias = context.unique('v'); return ` const ${valueAlias} = ${valuePath}; ${codeGenExpectNonNullable(valueAlias, path)} ${codeGenExpectNonError(valueAlias, path)} if (!${schema.toString()}.test('' + ${valueAlias})) { throw new TypeError(\`Invalid value \${${valueAlias}} for path "${path}", expected to match ${schema.toString()}\`); } `; } else { const valueAlias = context.unique('v'); const code = [ `const ${valueAlias} = ${valuePath};`, codeGenExpectNonNullable(valueAlias, path), codeGenExpectObject(valueAlias, path, 'Object'), codeGenExpectNonError(valueAlias, path) ]; if ($keys in schema) { const keysAlias = context.unique('k'); const errorsAlias = context.unique('err'); const kAlias = context.unique('k'); code.push(` const ${keysAlias} = Object.keys(${valueAlias}); const ${errorsAlias} = []; ${keysAlias}.forEach(${kAlias} => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$keys], context, kAlias, `${path}[\${${kAlias}}]`))} }); ${codeGenExpectNoErrors(errorsAlias)} `); } if ($values in schema) { const vAlias = context.unique('val'); const kAlias = context.unique('k'); const entriesAlias = context.unique('en'); const errorsAlias = context.unique('err'); code.push(` const ${entriesAlias} = Object.entries(${valueAlias}); const ${errorsAlias} = []; ${entriesAlias}.forEach(([${kAlias},${vAlias}]) => { ${codeGenCollectErrors(errorsAlias, codeGen(schema[$values], context, vAlias, `${path}[\${${kAlias}}]`))} }); ${codeGenExpectNoErrors(errorsAlias)} `); } if ($strict in schema && schema[$strict]) { const keysAlias = context.unique('k'); const kAlias = context.unique('k'); const extraAlias = context.unique('ex'); code.push(`const ${keysAlias} = new Set(${JSON.stringify(Object.keys(schema))});`); code.push(`const ${extraAlias} = Object.keys(${valueAlias}).filter(${kAlias} => !${keysAlias}.has(${kAlias}));`); code.push(`if (${extraAlias}.length !== 0) { throw new TypeError(\`Extra properties: \${${extraAlias}}, are not allowed for path "${path}"\`); }`); } code.push(...Object.entries(schema).map(([key, s])=>codeGen(s, context, `${valueAlias}['${key}']`, `${path}.${key}`))); return `${code.join('\n')}`; } } else if (typeof schema === 'symbol') { const index = context.register(schema); const valueAlias = context.unique('v'); const registryAlias = context.unique('r'); return ` const ${valueAlias} = ${valuePath}; const ${registryAlias} = ctx.registry[${index}]; if (typeof ${valueAlias} !== 'symbol') { throw new TypeError(\`Invalid type \${typeof ${valueAlias}} for "path", expected symbol\`); } if (${valueAlias} !== ${registryAlias}) { throw new TypeError(\`Invalid value \${${valueAlias}.toString()} for path "${path}", expected ${schema.toString()}\`); } `; } else if (schema === null || schema === undefined) { const valueAlias = context.unique('v'); return ` const ${valueAlias} = ${valuePath}; if (${valueAlias} !== null && ${valueAlias} !== undefined ) { throw new TypeError(\`Invalid value ${valueAlias} for path "${path}", expected nullable\`); } `; } else { const valueAlias = context.unique('v'); const value = context.unique('val'); return ` const ${valueAlias} = ${valuePath}; const ${value} = ${JSON.stringify(schema)}; ${codeGenExpectNonError(valueAlias, path)} if (typeof ${valueAlias} !== '${typeof schema}') { throw new TypeError(\`Invalid type \${typeof ${valueAlias}} for path "${path}", expected ${typeof schema}\`); } if (${valueAlias} !== ${value}) { throw new TypeError(\`Invalid value ${JSON.stringify(valueAlias)} for path "${path}", expected ${JSON.stringify(schema)}\`); } `; } }; const compile = (schema, rootName)=>{ const context = new Context(); const code = codeGen(schema, context, 'data', rootName); const validator = new Function('ctx', 'data', code); return (data)=>validator(context, data); }; const ascertain = (schema, data, rootName = '[root]')=>{ compile(schema, rootName)(data); }; //# sourceMappingURL=index.cjs.map