typia
Version:
Superfast runtime validators with only one line
153 lines (150 loc) • 5.48 kB
JavaScript
import ts from 'typescript';
import { MetadataProperty } from '../../../schemas/metadata/MetadataProperty.mjs';
import { Writable } from '../../../typings/Writable.mjs';
import { ArrayUtil } from '../../../utils/ArrayUtil.mjs';
import { CommentFactory } from '../../CommentFactory.mjs';
import { MetadataHelper } from './MetadataHelper.mjs';
import { explore_metadata } from './explore_metadata.mjs';
const emplace_metadata_object = (props) => {
// EMPLACE OBJECT
const [obj, newbie] = props.collection.emplace(props.checker, props.type);
ArrayUtil.add(obj.nullables, props.metadata.nullable, (elem) => elem === props.metadata.nullable);
if (newbie === false)
return obj;
// PREPARE ASSETS
const isClass = props.type.isClass();
const isProperty = significant(!!props.options.functional);
const pred = isClass
? (node) => {
const capsuled = node
.getChildren()
.some((c) => c
.getChildren()
.some((n) => n.kind === ts.SyntaxKind.PrivateKeyword ||
n.kind === ts.SyntaxKind.ProtectedKeyword));
return capsuled === false && isProperty(node);
}
: (node) => isProperty(node);
const insert = (props) => {
// COMMENTS AND TAGS
const description = props.symbol
? (CommentFactory.description(props.symbol) ?? null)
: null;
const jsDocTags = (props.symbol?.getJsDocTags() ?? []).filter(props.filter ?? (() => true));
// THE PROPERTY
const property = MetadataProperty.create({
key: props.key,
value: props.value,
description,
jsDocTags,
});
obj.properties.push(property);
return property;
};
//----
// REGULAR PROPERTIES
//----
for (const symbol of props.type.getApparentProperties()) {
// CHECK INTERNAL TAG
if ((symbol.getJsDocTags(props.checker) ?? []).find((tag) => tag.name === "internal") !== undefined)
continue;
// CHECK NODE IS A FORMAL PROPERTY
const [node, type] = (() => {
const node = symbol.getDeclarations()?.[0];
const type = node
? props.checker.getTypeOfSymbolAtLocation(symbol, node)
: props.checker.getTypeOfPropertyOfType(props.type, symbol.name);
return [node, type];
})();
if ((node && pred(node) === false) || type === undefined)
continue;
// GET EXACT TYPE
const key = MetadataHelper.literal_to_metadata(symbol.name);
const value = explore_metadata({
...props,
type,
explore: {
top: false,
object: obj,
property: symbol.name,
parameter: null,
nested: null,
aliased: false,
escaped: false,
output: false,
},
intersected: false,
});
Writable(value).optional = (symbol.flags & ts.SymbolFlags.Optional) !== 0;
insert({
key,
value,
symbol,
});
}
//----
// DYNAMIC PROPERTIES
//----
for (const index of props.checker.getIndexInfosOfType(props.type)) {
// GET EXACT TYPE
const analyzer = (type) => (property) => explore_metadata({
...props,
type,
explore: {
top: false,
object: obj,
property,
parameter: null,
nested: null,
aliased: false,
escaped: false,
output: false,
},
intersected: false,
});
const key = analyzer(index.keyType)(null);
const value = analyzer(index.type)({});
if (key.atomics.length +
key.constants.map((c) => c.values.length).reduce((a, b) => a + b, 0) +
key.templates.length +
key.natives.filter((native) => native.name === "Boolean" ||
native.name === "BigInt" ||
native.name === "Number" ||
native.name === "String").length !==
key.size())
props.errors.push({
name: key.getName(),
explore: {
top: false,
object: obj,
property: "[key]",
parameter: null,
nested: null,
aliased: false,
escaped: false,
output: false,
},
messages: [],
});
// INSERT WITH REQUIRED CONFIGURATION
insert({
key,
value,
symbol: index.declaration?.parent
? props.checker.getSymbolAtLocation(index.declaration.parent)
: undefined,
filter: (doc) => doc.name !== "default",
});
}
return obj;
};
const significant = (functional) => functional
? (node) => !ts.isAccessor(node)
: (node) => ts.isParameter(node) ||
ts.isPropertyDeclaration(node) ||
ts.isPropertyAssignment(node) ||
ts.isPropertySignature(node) ||
ts.isTypeLiteralNode(node) ||
ts.isShorthandPropertyAssignment(node);
export { emplace_metadata_object };
//# sourceMappingURL=emplace_metadata_object.mjs.map