@decaf-ts/decorator-validation
Version:
simple decorator based validation engine
129 lines • 5.31 kB
JavaScript
import "./Metadata.js";
import { Metadata } from "@decaf-ts/decoration";
import { Model } from "./../model/Model.js";
import { DEFAULT_ERROR_MESSAGES, ValidationKeys, } from "./../validation/Validators/constants.js";
import { ReservedModels } from "./../model/constants.js";
import { ModelRegistryManager } from "./../model/ModelRegistry.js";
Metadata.validationFor = function (model, property, key) {
const meta = Metadata.get(model);
if (!meta)
return undefined;
if (!property)
return meta.validation;
if (!meta.validation)
return undefined;
if (!meta.validation[ValidationKeys.TYPE]) {
const { designTypes } = Metadata.getPropDesignTypes(model, property);
// Adds by default the type validation
// If the designtypes is object, we exclude it. It causes problems with pks.
if (meta.validation[property] &&
designTypes?.length &&
designTypes[0] !== ReservedModels.OBJECT)
meta.validation[property][ValidationKeys.TYPE] = {
customTypes: designTypes,
message: DEFAULT_ERROR_MESSAGES.TYPE,
description: "defines the accepted types for the attribute",
async: false,
};
}
if (!key) {
const validationsForProp = meta.validation[property];
return validationsForProp;
}
const propValidation = meta.validation[property];
if (!propValidation)
return undefined;
return propValidation[key];
}.bind(Metadata);
Metadata.modelName = function (model) {
const constr = Metadata.constr(model);
return constr ? constr.name : model.name;
}.bind(Metadata);
Metadata.validatableProperties = function (model, ...propsToIgnore) {
const metavalidation = Metadata.validationFor(model);
const keys = metavalidation ? Object.keys(metavalidation) : [];
const props = [...new Set([...Model.getAttributes(model), ...keys])];
return props.filter((k) => !propsToIgnore || !propsToIgnore?.includes(k));
}.bind(Metadata);
Metadata.allowedTypes = function (model, prop) {
const designType = Metadata.type(model, prop);
if (!designType)
throw new Error(`No metadata found for property ${String(prop)}`);
const validation = Metadata.validationFor(model, prop);
// TODO: CHeck why some are not iterable
return validation &&
validation[ValidationKeys.TYPE] &&
typeof validation[ValidationKeys.TYPE]?.customTypes[Symbol.iterator] ===
"function"
? [...validation[ValidationKeys.TYPE].customTypes]
: [designType];
}.bind(Metadata);
Metadata.getPropDesignTypes = function (model, prop) {
const metadata = Metadata.get(model);
const designTypeMeta = Metadata.type(model, prop);
const validation = metadata?.[ValidationKeys.REFLECT]?.[prop];
if (!designTypeMeta && (!validation || !validation[ValidationKeys.TYPE]))
return {};
const propTypes = validation && validation[ValidationKeys.TYPE]
? [validation[ValidationKeys.TYPE].customTypes]
: [designTypeMeta];
if (!propTypes?.length)
return {};
const designTypeDec = propTypes[0];
const designType = designTypeDec.class ||
designTypeDec.clazz ||
designTypeDec.customTypes ||
designTypeDec;
const designTypes = (Array.isArray(designType) ? designType : [designType]).map((e) => (e = typeof e === "function" && !e.name ? e() : e));
return { designTypes, designType };
}.bind(Metadata);
Metadata.isModel = function isModel(target) {
try {
if (target instanceof Model)
return true;
const constr = Metadata.constr(target);
if (!constr || constr === target)
return false;
return !!Metadata.modelName(constr);
//
// // return target instanceof Model || !!Metadata.modelName(target as any);
// const modelName = Metadata.modelName(target as any);
// return target instanceof Model || !!Model.get(modelName);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}
catch (e) {
return false;
}
}.bind(Metadata);
Metadata.isPropertyModel = function isPropertyModel(target, attribute) {
const isModel = Metadata.isModel(target[attribute]);
if (isModel)
return true;
const metadata = Metadata.type(target.constructor, attribute);
if (!metadata)
return undefined;
return ModelRegistryManager.getRegistry().get(metadata.name)
? metadata.name
: undefined;
}.bind(Metadata);
Metadata.getAttributes = function getAttributes(model) {
const constructor = model instanceof Model ? model.constructor : model;
const seen = new Set();
const collect = (current) => {
if (!current)
return [];
const resolved = Metadata.constr(current);
const parent = Object.getPrototypeOf(resolved);
const attributes = collect(parent);
const props = Metadata.properties(current) ?? [];
for (const prop of props) {
if (!seen.has(prop)) {
seen.add(prop);
attributes.push(prop);
}
}
return attributes;
};
return collect(constructor);
}.bind(Metadata);
//# sourceMappingURL=overrides.js.map