typia
Version:
Superfast runtime validators with only one line
290 lines (287 loc) • 9.44 kB
JavaScript
import ts from 'typescript';
import { Metadata } from '../schemas/metadata/Metadata.mjs';
import { MetadataConstant } from '../schemas/metadata/MetadataConstant.mjs';
import { MetadataObject } from '../schemas/metadata/MetadataObject.mjs';
import { explore_metadata } from './internal/metadata/explore_metadata.mjs';
import { iterate_metadata_collection } from './internal/metadata/iterate_metadata_collection.mjs';
import { iterate_metadata_sort } from './internal/metadata/iterate_metadata_sort.mjs';
import { ExpressionFactory } from './ExpressionFactory.mjs';
var MetadataFactory;
(function (MetadataFactory) {
MetadataFactory.analyze = (props) => {
const errors = [];
const metadata = explore_metadata({
...props,
errors,
explore: {
top: true,
object: null,
property: null,
parameter: null,
nested: null,
aliased: false,
escaped: false,
output: false,
},
intersected: false,
});
iterate_metadata_collection({
errors,
collection: props.collection,
});
iterate_metadata_sort({
collection: props.collection,
metadata: metadata,
});
if (props.options.validate)
errors.push(...MetadataFactory.validate({
transformer: props.transformer,
options: props.options,
functor: props.options.validate,
metadata,
}));
return errors.length
? {
success: false,
errors,
}
: {
success: true,
data: metadata,
};
};
/** @internal */
MetadataFactory.soleLiteral = (value) => {
const meta = Metadata.initialize();
meta.constants.push(MetadataConstant.from({
values: [
{
value,
tags: [],
},
],
type: "string",
}));
return meta;
};
MetadataFactory.validate = (props) => {
const visitor = {
functor: props.functor,
errors: [],
objects: new Set(),
arrays: new Set(),
tuples: new Set(),
aliases: new Set(),
functions: new Set(),
};
validateMeta({
...props,
visitor,
explore: {
object: null,
property: null,
parameter: null,
nested: null,
top: true,
aliased: false,
escaped: false,
output: false,
},
});
return visitor.errors;
};
const validateMeta = (props) => {
const result = [];
for (const atomic of props.metadata.atomics)
for (const row of atomic.tags)
for (const tag of row.filter((t) => t.validate !== undefined && t.predicate === undefined))
try {
tag.predicate = ExpressionFactory.transpile({
script: tag.validate,
});
}
catch {
result.push(`Unable to transpile type tag script: ${JSON.stringify(tag.validate)}`);
tag.predicate = () => ts.factory.createTrue();
}
result.push(...props.visitor.functor(props.metadata, props.explore));
if (result.length)
props.visitor.errors.push({
name: props.metadata.getName(),
explore: { ...props.explore },
messages: [...new Set(result)],
});
for (const alias of props.metadata.aliases)
validateAlias({
...props,
alias: alias.type,
});
for (const array of props.metadata.arrays)
validateArray({
...props,
array: array.type,
});
for (const tuple of props.metadata.tuples)
validateTuple({
...props,
tuple: tuple.type,
});
for (const object of props.metadata.objects)
validateObject({
...props,
object: object.type,
});
for (const func of props.metadata.functions)
validateFunction({
...props,
function: func,
});
for (const set of props.metadata.sets)
validateMeta({
...props,
metadata: set.value,
});
for (const map of props.metadata.maps) {
validateMeta({
...props,
metadata: map.key,
});
validateMeta({
...props,
metadata: map.value,
});
}
if (props.options.escape === true && props.metadata.escaped !== null)
validateMeta({
...props,
metadata: props.metadata.escaped.returns,
explore: {
...props.explore,
escaped: true,
},
});
};
const validateAlias = (props) => {
if (props.visitor.aliases.has(props.alias))
return;
props.visitor.aliases.add(props.alias);
validateMeta({
...props,
metadata: props.alias.value,
explore: {
...props.explore,
nested: props.alias,
aliased: true,
},
});
};
const validateArray = (props) => {
if (props.visitor.arrays.has(props.array))
return;
props.visitor.arrays.add(props.array);
validateMeta({
...props,
metadata: props.array.value,
explore: {
...props.explore,
nested: props.array,
top: false,
},
});
};
const validateTuple = (props) => {
if (props.visitor.tuples.has(props.tuple))
return;
props.visitor.tuples.add(props.tuple);
for (const elem of props.tuple.elements)
validateMeta({
...props,
metadata: elem,
explore: {
...props.explore,
nested: props.tuple,
top: false,
},
});
};
const validateObject = (props) => {
if (props.visitor.objects.has(props.object))
return;
props.visitor.objects.add(props.object);
if (props.options.validate) {
const explore = {
object: props.object,
top: false,
property: null,
parameter: null,
nested: null,
aliased: false,
escaped: false,
output: false,
};
const errors = props.options.validate(Metadata.create({
...Metadata.initialize(),
objects: [
MetadataObject.create({
type: props.object,
tags: [],
}),
],
}), explore);
if (errors.length)
props.visitor.errors.push({
name: props.object.name,
explore,
messages: [...new Set(errors)],
});
}
for (const property of props.object.properties)
validateMeta({
...props,
metadata: property.value,
explore: {
object: props.object,
property: property.key.isSoleLiteral()
? property.key.getSoleLiteral()
: {},
parameter: null,
nested: null,
top: false,
aliased: false,
escaped: false,
output: false,
},
});
};
const validateFunction = (props) => {
if (props.visitor.functions.has(props.function))
return;
props.visitor.functions.add(props.function);
for (const param of props.function.parameters)
validateMeta({
...props,
metadata: param.type,
explore: {
...props.explore,
parameter: param.name,
nested: null,
top: false,
output: false,
},
});
if (props.function.output)
validateMeta({
...props,
metadata: props.function.output,
explore: {
...props.explore,
parameter: null,
nested: null,
top: false,
output: true,
},
});
};
})(MetadataFactory || (MetadataFactory = {}));
export { MetadataFactory };
//# sourceMappingURL=MetadataFactory.mjs.map