dilswer
Version:
Blazingly fast data validation library with TypeScript integration.
945 lines (942 loc) • 32.8 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/validation-algorithms/compile-fast-validator.ts
var compile_fast_validator_exports = {};
__export(compile_fast_validator_exports, {
compile: () => compile
});
module.exports = __toCommonJS(compile_fast_validator_exports);
var import_approximate_complexity = require("./approximate-complexity.cjs");
var KNOWN_GLOBAL_CLASSES = /* @__PURE__ */ new Map([
[Map, "Map"],
[Set, "Set"],
[RegExp, "RegExp"],
[Date, "Date"],
[Error, "Error"],
[EvalError, "EvalError"],
[RangeError, "RangeError"],
[ReferenceError, "ReferenceError"],
[SyntaxError, "SyntaxError"],
[TypeError, "TypeError"],
[URIError, "URIError"],
[AggregateError, "AggregateError"],
[Array, "Array"],
[Object, "Object"],
[WeakMap, "WeakMap"],
[WeakSet, "WeakSet"],
[Function, "Function"],
[String, "String"],
[Number, "Number"],
[Boolean, "Boolean"],
[Int8Array, "Int8Array"],
[Uint8Array, "Uint8Array"],
[Uint8ClampedArray, "Uint8ClampedArray"],
[Int16Array, "Int16Array"],
[Uint16Array, "Uint16Array"],
[Int32Array, "Int32Array"],
[Uint32Array, "Uint32Array"],
[Float32Array, "Float32Array"],
[Float64Array, "Float64Array"],
[BigInt64Array, "BigInt64Array"],
[BigUint64Array, "BigUint64Array"],
[ArrayBuffer, "ArrayBuffer"],
[DataView, "DataView"],
[Promise, "Promise"]
]);
if (typeof SharedArrayBuffer !== "undefined") {
KNOWN_GLOBAL_CLASSES.set(SharedArrayBuffer, "SharedArrayBuffer");
}
var propertyAccessor = (propertyName) => {
if (propertyName.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/)) {
return `.${propertyName}`;
}
return `[${JSON.stringify(propertyName)}]`;
};
var ConditionBuilder = class {
constructor(type) {
__publicField(this, "type", type);
__publicField(this, "conditions", []);
}
add(condition) {
this.conditions.push(condition);
return this;
}
build() {
if (this.conditions.length === 0) {
return "true";
}
if (this.conditions.length === 1) {
const c = this.conditions[0];
return typeof c === "string" ? c : c.build();
}
const separator = this.type === "||" ? " || " : " && ";
return "(" + this.conditions.map((c) => typeof c === "string" ? c : c.build()).join(separator) + ")";
}
};
var $dependency = (depName) => `_$getDependency(${JSON.stringify(depName)})`;
var $condition = (type) => new ConditionBuilder(type);
var $type = (varname, type) => {
return `typeof ${varname} === "${type}"`;
};
var _serialize = (value) => {
return JSON.stringify(value);
};
var $defineFn = (fnName, argName, body) => {
return {
declaration: `const ${fnName} = (${argName}) => ${body};`,
$invokeWith(varname) {
return `${fnName}(${varname})`;
}
};
};
var $defineRegexp = (name, regexp) => {
return {
declaration: `const ${name} = new RegExp(${JSON.stringify(
regexp.source
)}, ${JSON.stringify(regexp.flags)});`,
$test(varname) {
return `${name}.test(${varname})`;
}
};
};
var $lte = (name, value) => {
return `${name} <= ${value}`;
};
var $gte = (name, value) => {
return `${name} >= ${value}`;
};
var $equal = (varname, value) => {
return `${varname} === ${_serialize(value)}`;
};
var $notEqual = (varname, value) => {
return `${varname} !== ${_serialize(value)}`;
};
var $isArray = (varname) => {
return `Array.isArray(${varname})`;
};
var $isObject = (varname) => {
return $condition("&&").add($type(varname, "object")).add($notEqual(varname, null));
};
var $isSet = (varname) => {
return $equal(`${varname}[Symbol.toStringTag]`, "Set");
};
var $isInteger = (varname) => {
return `Number.isInteger(${varname})`;
};
var $notNaN = (varname) => {
return `${varname} === ${varname}`;
};
var $has = (varname, key) => {
return `${_serialize(key)} in ${varname}`;
};
var $ternary = (condition) => {
return {
then(thenValue) {
return {
else(elseValue) {
return `(${typeof condition === "string" ? condition : condition.build()} ? ${thenValue} : ${elseValue})`;
}
};
}
};
};
var $length = (varname, is, than) => {
switch (is) {
case "==":
return `${varname}.length === ${than}`;
case ">":
return `${varname}.length > ${than}`;
case "<":
return `${varname}.length < ${than}`;
case ">=":
return `${varname}.length >= ${than}`;
case "<=":
return `${varname}.length <= ${than}`;
}
};
var $every = (generator, varname, predicate, startIndex) => {
let inline = generator.shouldInline();
if (inline) {
const iVar = generator.getUniqueVarName();
return `(() => { for (let ${iVar} = ${startIndex != null ? startIndex : 0}; ${iVar} < ${varname}.length; ${iVar}++) { if (!(${predicate(`${varname}[${iVar}]`, iVar)})) { return false; } }return true; })()`;
}
generator.includes.every = true;
const elemName = generator.getUniqueVarName();
const indexName = generator.getUniqueVarName();
if (startIndex != null) {
return `_$every(${varname}, (${elemName}, ${indexName}) => ${predicate(elemName, indexName)}, ${startIndex})`;
}
return `_$every(${varname}, (${elemName}, ${indexName}) => ${predicate(elemName, indexName)})`;
};
var $everySome = (generator, varname, everyPredicate, somePredicate, startIdx) => {
let inline = generator.shouldInline();
if (inline) {
const satisfied = generator.getUniqueVarName("someSatisfied");
const iVar = generator.getUniqueVarName();
return `(() => { let ${satisfied} = false; for (let ${iVar} = ${startIdx != null ? startIdx : 0}; ${iVar} < ${varname}.length; ${iVar}++) { if (!(${everyPredicate(`${varname}[${iVar}]`, iVar)})) { return false; } if(!${satisfied}) { ${satisfied} = ${somePredicate(`${varname}[${iVar}]`, iVar)}; } } return ${satisfied}; })()`;
}
generator.includes.everySome = true;
const elemName1 = generator.getUniqueVarName();
const indexName1 = generator.getUniqueVarName();
const elemName2 = generator.getUniqueVarName();
const indexName2 = generator.getUniqueVarName();
if (startIdx != null) {
return `_$everySome(${varname}, (${elemName1}, ${indexName1}) => ${everyPredicate(elemName1, indexName1)}, (${elemName2}, ${indexName2}) => ${somePredicate(elemName2, indexName2)}, ${startIdx})`;
}
return `_$everySome(${varname}, (${elemName1}, ${indexName1}) => ${everyPredicate(elemName1, indexName1)}, (${elemName2}, ${indexName2}) => ${somePredicate(elemName2, indexName2)})`;
};
var $everyObjectValue = (generator, varname, predicate) => {
let inline = generator.shouldInline();
if (inline) {
const iVar = generator.getUniqueVarName();
return `(() => { for (let ${iVar} in ${varname}) { if (!(${predicate(`${varname}[${iVar}]`)})) { return false; } }return true; })()`;
}
generator.includes.everyObjectValue = true;
const elemName = generator.getUniqueVarName();
return `_$everyObjectValue(${varname}, (${elemName}) => ${predicate(elemName)})`;
};
var $everyInSet = (generator, varname, predicate) => {
let inline = generator.shouldInline();
if (inline) {
const item = generator.getUniqueVarName();
return `(() => { for (let ${item} of ${varname}) { if (!(${predicate(item)})) { return false; } }return true; })()`;
}
generator.includes.everyInSet = true;
const elemName = generator.getUniqueVarName();
return `_$everyInSet(${varname}, (${elemName}) => ${predicate(elemName)})`;
};
var $charCode = (varname, is) => {
if (Array.isArray(is)) {
return `${varname}.charCodeAt(0) >= ${is[0]} && ${varname}.charCodeAt(0) <= ${is[1]}`;
}
return `${varname}.charCodeAt(0) === ${is}`;
};
var $charCount = (generator, varname, char, is, expected) => {
let inline = generator.shouldInline();
if (inline) {
const counter = generator.getUniqueVarName("count");
const iVar = generator.getUniqueVarName();
return `(() => { let ${counter} = 0; for (let ${iVar} = 0; ${iVar} < ${varname}.length; ${iVar}++) { if (${varname}[${iVar}] === ${JSON.stringify(char)}) { ${counter}++; } }return ${counter}; })() ${is} ${expected}`;
}
generator.includes.charCount = true;
return `_$countChar(${varname}, ${JSON.stringify(char)}) ${is} ${expected}`;
};
var $instanceof = (generator, varname, constructor) => {
if (KNOWN_GLOBAL_CLASSES.has(constructor)) {
return `(${varname} instanceof ${KNOWN_GLOBAL_CLASSES.get(constructor)})`;
}
const name = generator.getUniqueVarName();
generator.addDependency(name, constructor);
return `(${varname} instanceof ${$dependency(name)})`;
};
var ValidateGenerator = class {
constructor(t, get$validate) {
__publicField(this, "t", t);
__publicField(this, "get$validate", get$validate);
__publicField(this, "_memo_complexity", null);
}
approxComplexity() {
if (this._memo_complexity != null) {
return this._memo_complexity;
}
return this._memo_complexity = (0, import_approximate_complexity.approximateComplexity)(this.t);
}
originalSchema() {
return this.t;
}
isAlwaysTrue() {
return false;
}
$buildValidate(varname) {
const validate = this.get$validate(varname, this);
if (typeof validate === "string") {
return validate;
}
return validate.build();
}
};
var TruthyGenerator = class {
constructor(t) {
__publicField(this, "t", t);
}
approxComplexity() {
return 0;
}
originalSchema() {
return this.t;
}
isAlwaysTrue() {
return true;
}
$buildValidate() {
return "true";
}
};
var DataTypeValidatorVisitor = class {
constructor(opts) {
__publicField(this, "opts", opts);
__publicField(this, "depth", 0);
__publicField(this, "includes", {
every: false,
everySome: false,
everyObjectValue: false,
everyInSet: false,
charCount: false,
recursive: false,
custom: false,
instanceof: false
});
__publicField(this, "circValidationFnNames", /* @__PURE__ */ new Map());
__publicField(this, "_counter1", 0);
__publicField(this, "_counter2", 0);
__publicField(this, "_counter3", 0);
__publicField(this, "knownTypes", /* @__PURE__ */ new Map());
__publicField(this, "outerDeclarations", []);
__publicField(this, "innerDeclarations", []);
__publicField(this, "dependencies", []);
}
shouldInline() {
if (this.opts && this.opts.inlineHelpers != null) {
return this.opts.inlineHelpers;
}
return this.depth > 5 && this.depth <= 12;
}
canSkipPropertyCheck(t) {
if (t.kind === "simple") {
switch (t.simpleType) {
case "null":
case "unknown":
case "undefined":
return false;
}
return true;
}
return t.kind === "dictionary" || t.kind === "record";
}
sortChildren(children) {
return children.slice().sort(
(a, b) => {
const ac = "_isRecordOfVisitChild" in a ? a.child : a;
const bc = "_isRecordOfVisitChild" in b ? b.child : b;
const aSchema = ac.originalSchema();
const bSchema = bc.originalSchema();
const aKind = aSchema.kind;
const bKind = bSchema.kind;
const aCustom = aKind === "custom";
const bCustom = bKind === "custom";
if (aCustom !== bCustom && (aCustom || bCustom)) {
return aCustom ? 1 : -1;
}
const aMaybeDiscriminator = aKind === "literal" || aKind === "enumMember" || aKind === "stringMatching" || aKind === "union" && aSchema.oneOf.every(
(t) => t.kind === "literal" || t.kind === "enumMember" || t.kind === "stringMatching"
);
const bMaybeDiscriminator = bKind === "literal" || bKind === "enumMember" || bKind === "stringMatching" || bKind === "union" && bSchema.oneOf.every(
(t) => t.kind === "literal" || t.kind === "enumMember" || t.kind === "stringMatching"
);
if (aMaybeDiscriminator !== bMaybeDiscriminator && (aMaybeDiscriminator || bMaybeDiscriminator)) {
return aMaybeDiscriminator ? -1 : 1;
}
const aCplx = ac.approxComplexity();
const bCplx = bc.approxComplexity();
return aCplx - bCplx;
}
);
}
addDeclaration(type, inlined) {
if (type === "inner") {
this.innerDeclarations.push(inlined);
} else {
this.outerDeclarations.push(inlined);
}
return this;
}
addDependency(name, value) {
this.dependencies.push([name, value]);
return this;
}
getUniqueStringForType(type) {
if (this.knownTypes.has(type)) {
return this.knownTypes.get(type);
}
const name = `_$t${++this._counter3}`;
this.knownTypes.set(type, name);
return name;
}
getUniqueVarName(name) {
if (name) {
return `_$a${++this._counter1}_${name}`;
}
return `_$a${++this._counter1}`;
}
getUniqueFnName() {
return `_$v${++this._counter2}`;
}
visitPrimitive(type) {
switch (type.simpleType) {
case "boolean":
return new ValidateGenerator(
type,
(varname) => $type(varname, "boolean")
);
case "integer":
return new ValidateGenerator(type, (varname) => {
const cond = $condition("&&").add($type(varname, "number")).add($isInteger(varname));
if (type.options.max != null) {
cond.add($lte(varname, type.options.max));
}
if (type.options.min != null) {
cond.add($gte(varname, type.options.min));
}
return cond;
});
case "null":
return new ValidateGenerator(type, (varname) => $equal(varname, null));
case "number":
return new ValidateGenerator(type, (varname) => {
let cond = $condition("&&").add($type(varname, "number")).add($notNaN(varname));
if (type.options.max != null) {
cond = cond.add($lte(varname, type.options.max));
}
if (type.options.min != null) {
cond = cond.add($gte(varname, type.options.min));
}
return cond;
});
case "string":
return new ValidateGenerator(type, (varname) => {
const cond = $condition("&&").add($type(varname, "string"));
if (type.options.max != null) {
cond.add($length(varname, "<=", type.options.max));
}
if (type.options.min != null) {
cond.add($length(varname, ">=", type.options.min));
}
return cond;
});
case "stringinteger":
if (type.options.negative === false && type.options.positive === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$ternary($charCode(varname, 45 /* Minus */)).then($every(
this,
varname,
(char) => $charCode(char, 48 /* Zero */),
1
// start from the second char
)).else($every(
this,
varname,
(char) => $charCode(char, 48 /* Zero */)
))
));
}
if (type.options.negative === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$everySome(
this,
varname,
(char) => $charCode(char, [48 /* Zero */, 57 /* Nine */]),
// each char must be a digit
(char) => $charCode(char, [49 /* One */, 57 /* Nine */])
// at least one char must be a non-zero digit
)
));
}
if (type.options.positive === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add($charCode(varname, 45 /* Minus */)).add(
$everySome(
this,
varname,
(char) => $charCode(char, [48 /* Zero */, 57 /* Nine */]),
// each char must be a digit
(char) => $charCode(char, [49 /* One */, 57 /* Nine */]),
// at least one char must be a non-zero digit
1
// start from the second char
)
));
}
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$ternary($charCode(varname, 45 /* Minus */)).then($every(
this,
varname,
(char) => $charCode(char, [48 /* Zero */, 57 /* Nine */]),
1
// start from the second char
)).else($every(
this,
varname,
(char) => $charCode(char, [48 /* Zero */, 57 /* Nine */])
))
));
case "stringnumeral":
if (type.options.negative === false && type.options.positive === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$ternary($charCode(varname, 45 /* Minus */)).then(
$every(
this,
varname,
(char) => $condition("||").add($charCode(char, 48 /* Zero */)).add($charCode(char, 46 /* Dot */)).build(),
1
// start from the second char
)
).else(
$every(
this,
varname,
(char) => $condition("||").add($charCode(char, 48 /* Zero */)).add($charCode(char, 46 /* Dot */)).build()
)
)
).add($charCount(this, varname, ".", "<", 2)));
}
if (type.options.negative === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$everySome(
this,
varname,
(char) => $condition("||").add($charCode(char, [48 /* Zero */, 57 /* Nine */])).add($charCode(char, 46 /* Dot */)).build(),
(char) => $charCode(char, [49 /* One */, 57 /* Nine */])
)
).add($charCount(this, varname, ".", "<", 2)));
}
if (type.options.positive === false) {
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add($charCode(varname, 45 /* Minus */)).add(
$everySome(
this,
varname,
(char) => $condition("||").add($charCode(char, [48 /* Zero */, 57 /* Nine */])).add($charCode(char, 46 /* Dot */)).build(),
(char) => $charCode(char, [49 /* One */, 57 /* Nine */]),
1
)
).add($charCount(this, varname, ".", "<", 2)));
}
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add($length(varname, ">", 0)).add(
$ternary($charCode(varname, 45 /* Minus */)).then($every(
this,
varname,
(char) => $condition("||").add($charCode(char, [48 /* Zero */, 57 /* Nine */])).add($charCode(char, 46 /* Dot */)).build(),
1
)).else($every(
this,
varname,
(char) => $condition("||").add($charCode(char, [48 /* Zero */, 57 /* Nine */])).add($charCode(char, 46 /* Dot */)).build()
))
).add($charCount(this, varname, ".", "<", 2)));
case "function":
return new ValidateGenerator(
type,
(varname) => $type(varname, "function")
);
case "symbol":
return new ValidateGenerator(
type,
(varname) => $type(varname, "symbol")
);
case "undefined":
return new ValidateGenerator(
type,
(varname) => $type(varname, "undefined")
);
case "unknown":
return new TruthyGenerator(type);
}
}
visitArrayOf(type, children) {
if (children && children.length > 0) {
const oneof = this.visitOneOf(type["union"], children);
return new ValidateGenerator(type, (varname) => {
return $condition("&&").add($isArray(varname)).add($every(this, varname, (elem) => oneof.$buildValidate(elem)));
});
}
return new ValidateGenerator(type, (varname) => $isArray(varname));
}
visitTuple(type, children) {
return new ValidateGenerator(type, (varname) => {
const cond = $condition("&&").add($isArray(varname)).add($length(varname, "==", type.tuple.length));
if (children && children.length > 0) {
for (const [index, c] of children.entries()) {
cond.add(c.$buildValidate(`${varname}[${index}]`));
}
}
return cond;
});
}
visitRecordOf(type, children = []) {
children = this.sortChildren(children);
const getRecordConditions = (varName) => {
const cond = $isObject(varName);
if (children && children.length > 0) {
for (const c of children) {
const accessor = propertyAccessor(c.propertyName);
const nextName = `${varName}${accessor}`;
if (c.required === true) {
if (this.canSkipPropertyCheck(c.child.originalSchema())) {
if (c.child.isAlwaysTrue()) {
cond.add($has(varName, c.propertyName));
} else {
cond.add(c.child.$buildValidate(nextName));
}
} else {
cond.add($has(varName, c.propertyName));
if (!c.child.isAlwaysTrue()) {
cond.add(c.child.$buildValidate(nextName));
}
}
} else {
if (!c.child.isAlwaysTrue()) {
cond.add(
$ternary($notEqual(nextName, void 0)).then(c.child.$buildValidate(nextName)).else("true")
);
}
}
}
}
return cond;
};
return new ValidateGenerator(type, (varname) => {
if (varname.split(/\[|\./).length > 2) {
const fnName = this.getUniqueFnName();
const argName = this.getUniqueVarName();
const validateFn = $defineFn(
fnName,
argName,
getRecordConditions(argName).build()
);
this.addDeclaration("inner", validateFn.declaration);
return validateFn.$invokeWith(varname);
} else {
return getRecordConditions(varname);
}
});
}
visitDict(type, children) {
if (children && children.length > 0) {
const oneof = this.visitOneOf(type["union"], children);
return new ValidateGenerator(
type,
(varname) => $isObject(varname).add(
$everyObjectValue(
this,
varname,
(elem) => oneof.$buildValidate(elem)
)
)
);
} else {
return new ValidateGenerator(
type,
(varname) => $isObject(varname)
);
}
}
visitSetOf(type, children = []) {
children = this.sortChildren(children);
const getBaseSetConditions = (varName) => {
return $isObject(varName).add($isSet(varName));
};
if (children && children.length > 0) {
const oneof = this.visitOneOf(type["union"], children);
return new ValidateGenerator(
type,
(varname) => getBaseSetConditions(varname).add(
$everyInSet(this, varname, (elem) => oneof.$buildValidate(elem))
)
);
}
return new ValidateGenerator(
type,
(varname) => getBaseSetConditions(varname)
);
}
visitOneOf(type, children) {
children = this.sortChildren(children);
return new ValidateGenerator(type, (varname) => {
const cond = $condition("||");
for (const c of children) {
cond.add(c.$buildValidate(varname));
}
return cond;
});
}
visitAllOf(type, children) {
return new ValidateGenerator(type, (varname) => {
const cond = $condition("&&");
for (const c of children) {
cond.add(c.$buildValidate(varname));
}
return cond;
});
}
visitLiteral(type) {
return new ValidateGenerator(
type,
(varname) => $equal(varname, type.literal)
);
}
visitEnum(type) {
const enumKeys = Object.keys(type.enumInstance).filter(
(key) => Number.isNaN(Number(key))
);
return new ValidateGenerator(type, (varname) => {
const cond = $condition("||");
for (const key of enumKeys) {
const member = type.enumInstance[key];
cond.add($equal(varname, member));
}
return cond;
});
}
visitEnumMember(type) {
return new ValidateGenerator(
type,
(varname) => $equal(varname, type.enumMember)
);
}
visitInstanceOf(type) {
if (!KNOWN_GLOBAL_CLASSES.has(type.instanceOf)) {
this.includes.instanceof = true;
}
return new ValidateGenerator(type, (varname) => $condition("&&").add($instanceof(this, varname, type.instanceOf)));
}
visitCustom(type) {
this.includes.custom = true;
const customDepName = this.getUniqueVarName();
this.addDependency(customDepName, type.custom);
return new ValidateGenerator(
type,
(varname) => `${$dependency(customDepName)}(${varname})`
);
}
visitStringMatching(type) {
const regexp = $defineRegexp(this.getUniqueVarName(), type.pattern);
this.addDeclaration("outer", regexp.declaration);
return new ValidateGenerator(type, (varname) => $condition("&&").add($type(varname, "string")).add(regexp.$test(varname)));
}
visitRecursive(circular, children) {
const [childSchema] = children;
const child = circular.type;
if (this.circValidationFnNames.has(child)) {
const validatorFnName = this.circValidationFnNames.get(child);
const argName = this.getUniqueVarName();
const typeUniqueName = this.getUniqueStringForType(child);
const validateFn = $defineFn(
validatorFnName,
argName,
$ternary(
`_$wasRecursivelyValidated(${_serialize(typeUniqueName)}, ${argName})`
).then("true").else(childSchema.$buildValidate(argName))
);
this.includes.recursive = true;
this.addDeclaration("inner", validateFn.declaration);
return new ValidateGenerator(
circular,
(varname) => validateFn.$invokeWith(varname)
);
}
return childSchema;
}
visitRecursiveRef(type) {
const referencedType = type._getReferencedType();
if (this.circValidationFnNames.has(referencedType)) {
const validatorFnName2 = this.circValidationFnNames.get(referencedType);
return new ValidateGenerator(
type,
(varname) => `${validatorFnName2}(${varname})`
);
}
const validatorFnName = this.getUniqueFnName();
this.circValidationFnNames.set(referencedType, validatorFnName);
return new ValidateGenerator(
type,
(varname) => `${validatorFnName}(${varname})`
);
}
visit(type, children, depth) {
if (depth > this.depth) {
this.depth = depth;
}
switch (type.kind) {
case "simple":
return this.visitPrimitive(type);
case "array":
return this.visitArrayOf(type, children);
case "tuple":
return this.visitTuple(type, children);
case "record":
return this.visitRecordOf(type, children);
case "dictionary":
return this.visitDict(type, children);
case "set":
return this.visitSetOf(type, children);
case "union":
return this.visitOneOf(type, children);
case "intersection":
return this.visitAllOf(type, children);
case "literal":
return this.visitLiteral(type);
case "enumUnion":
return this.visitEnum(type);
case "enumMember":
return this.visitEnumMember(type);
case "instanceOf":
return this.visitInstanceOf(type);
case "custom":
return this.visitCustom(type);
case "stringMatching":
return this.visitStringMatching(type);
case "circular":
return this.visitRecursive(type, children);
case "circularRef":
return this.visitRecursiveRef(type);
}
}
};
var e = eval;
var recursiveTracker = (
/* js */
`
const _$validatedRecursiveValues = new Map();
function _$wasRecursivelyValidated(_$tn, _$d) {
let _$set = _$validatedRecursiveValues.get(_$tn);
if (!_$set) {
_$set = new Set([_$d]);
_$validatedRecursiveValues.set(_$tn, _$set);
return false;
}
if (_$set.has(_$d)) {
return true;
}
_$set.add(_$d);
return false;
};
`.trim()
);
var compile = (dataType, options) => {
const visitor = new DataTypeValidatorVisitor(options);
const generator = dataType._acceptVisitor(visitor);
const validation = generator.$buildValidate("data");
const outerDeclarations = [];
const innerDeclarations = [];
if (visitor.includes.every) {
outerDeclarations.push("const _$every = " + _$every.toString());
}
if (visitor.includes.everySome) {
outerDeclarations.push("const _$everySome = " + _$everySome.toString());
}
if (visitor.includes.everyInSet) {
outerDeclarations.push("const _$everyInSet = " + _$everyInSet.toString());
}
if (visitor.includes.everyObjectValue) {
outerDeclarations.push(
"const _$everyObjectValue = " + _$everyObjectValue.toString()
);
}
if (visitor.includes.charCount) {
outerDeclarations.push("const _$countChar = " + _$countChar.toString());
}
if (visitor.outerDeclarations) {
outerDeclarations.push(...visitor.outerDeclarations);
}
if (visitor.includes.recursive) {
innerDeclarations.push(recursiveTracker);
}
if (visitor.innerDeclarations) {
innerDeclarations.push(...visitor.innerDeclarations);
}
const validatorStr = `(_$getDependency) => {
${outerDeclarations.join("\n ")}
return function validate(data) {
${innerDeclarations.join("\n ")}
return ${validation};
}
}`;
const deps = new Map(visitor.dependencies);
const _$getDependency = (name) => {
return deps.get(name);
};
const evaluatedCode = e(validatorStr);
const validator = evaluatedCode(_$getDependency);
const { includes } = visitor;
validator.asString = (name = "validate") => {
if (includes.custom) {
throw new Error(
"Validators with Custom type validation cannot be compiled to standalone code"
);
}
if (includes.instanceof) {
throw new Error(
"Validators with InstanceOf type validation cannot be compiled to standalone code"
);
}
return [
...outerDeclarations,
`function ${name}(data) {
${innerDeclarations.join("\n ")}
return ${validation}
}`
].join("\n");
};
return validator;
};
function _$every(_$arr, _$predicate, _$start = 0) {
for (let _$i = _$start; _$i < _$arr.length; _$i++) {
if (!_$predicate(_$arr[_$i], _$i)) {
return false;
}
}
return true;
}
function _$everySome(_$arr, _$everyPredicate, _$somePredicate, _$start = 0) {
let _$someSatisfied = false;
for (let _$i = _$start; _$i < _$arr.length; _$i++) {
if (!_$everyPredicate(_$arr[_$i], _$i)) {
return false;
}
if (!_$someSatisfied) {
_$someSatisfied = _$somePredicate(_$arr[_$i], _$i);
}
}
return _$someSatisfied;
}
function _$everyInSet(_$set, _$predicate) {
for (let _$item of _$set) {
if (!_$predicate(_$item)) {
return false;
}
}
return true;
}
function _$everyObjectValue(_$obj, _$predicate) {
for (let _$key in _$obj) {
if (!_$predicate(_$obj[_$key])) {
return false;
}
}
return true;
}
function _$countChar(_$str, _$char) {
let _$count = 0;
for (let _$i = 0; _$i < _$str.length; _$i++) {
if (_$str[_$i] === _$char) {
_$count++;
}
}
return _$count;
}