typia
Version:
Superfast runtime validators with only one line
150 lines (132 loc) • 3.79 kB
text/typescript
import { ClassProperties } from "../../typings/ClassProperties";
import { IJsDocTagInfo } from "./IJsDocTagInfo";
import { IMetadataObjectType } from "./IMetadataObjectType";
import { MetadataProperty } from "./MetadataProperty";
export class MetadataObjectType {
public readonly name: string;
public readonly properties: Array<MetadataProperty>;
public readonly description: string | undefined;
public readonly jsDocTags: IJsDocTagInfo[];
public readonly index: number;
public validated: boolean;
public recursive: boolean;
public nullables: boolean[] = [];
/**
* @internal
*/
public tagged_: boolean = false;
/**
* @internal
*/
private literal_?: boolean;
/* -----------------------------------------------------------
CONSTRUCTORS
----------------------------------------------------------- */
/**
* @hidden
*/
private constructor(
props: Omit<ClassProperties<MetadataObjectType>, "tagged_">,
) {
this.name = props.name;
this.properties = props.properties;
this.description = props.description;
this.jsDocTags = props.jsDocTags;
this.index = props.index;
this.validated = props.validated;
this.recursive = props.recursive;
this.nullables = props.nullables.slice();
this.tagged_ = false;
}
/**
* @internal
*/
public static create(
props: Omit<ClassProperties<MetadataObjectType>, "tagged_">,
) {
return new MetadataObjectType(props);
}
/**
* @internal
*/
public static _From_without_properties(
obj: IMetadataObjectType,
): MetadataObjectType {
return MetadataObjectType.create({
name: obj.name,
properties: [],
description: obj.description,
jsDocTags: obj.jsDocTags,
index: obj.index,
validated: false,
recursive: obj.recursive,
nullables: obj.nullables.slice(),
});
}
public isPlain(level: number = 0): boolean {
return (
this.recursive === false &&
this.properties.length < 10 &&
this.properties.every(
(property) =>
property.key.isSoleLiteral() &&
property.value.size() === 1 &&
property.value.isRequired() === true &&
property.value.nullable === false &&
(property.value.atomics.length === 1 ||
(level < 1 &&
property.value.objects.length === 1 &&
property.value.objects[0]!.type.isPlain(level + 1))),
)
);
}
public isLiteral(): boolean {
return (this.literal_ ??= (() => {
if (this.recursive === true) return false;
return (
this.name === "__type" ||
this.name === "__object" ||
this.name.startsWith("__type.") ||
this.name.startsWith("__object.") ||
this.name.includes("readonly [")
);
})());
}
public toJSON(): IMetadataObjectType {
return {
name: this.name,
properties: this.properties.map((property) => property.toJSON()),
description: this.description,
jsDocTags: this.jsDocTags,
index: this.index,
recursive: this.recursive,
nullables: this.nullables.slice(),
};
}
}
/**
* @internal
*/
export namespace MetadataObjectType {
export const intersects = (
x: MetadataObjectType,
y: MetadataObjectType,
): boolean =>
x.properties.some(
(prop) =>
y.properties.find(
(oppo) => prop.key.getName() === oppo.key.getName(),
) !== undefined,
);
export const covers = (
x: MetadataObjectType,
y: MetadataObjectType,
): boolean =>
x.properties.length >= y.properties.length &&
x.properties.every(
(prop) =>
y.properties.find(
(oppo) => prop.key.getName() === oppo.key.getName(),
) !== undefined,
);
}