express-cargo
Version:
express middleware for class-based request parsing
153 lines (152 loc) • 7.84 kB
JavaScript
import { ValidatorRule } from './types';
import { CargoClassMetadata } from './metadata';
function addValidator(target, propertyKey, rule) {
const classMeta = new CargoClassMetadata(target);
const fieldMeta = classMeta.getFieldMetadata(propertyKey);
fieldMeta.addValidator(rule);
classMeta.setFieldMetadata(propertyKey, fieldMeta);
}
export function Min(minimum, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'min', (input)=>typeof input === 'number' && input >= minimum, message || `${String(propertyKey)} must be >= ${minimum}`));
};
}
export function Max(maximum, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'max', (input)=>typeof input === 'number' && input <= maximum, message || `${String(propertyKey)} must be <= ${maximum}`));
};
}
export function Prefix(prefixText, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'prefix', (val)=>typeof val === 'string' && val.startsWith(prefixText), message || `${String(propertyKey)} must start with ${prefixText}`));
};
}
export function Suffix(suffixText, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'suffix', (val)=>typeof val === 'string' && val.endsWith(suffixText), message || `${String(propertyKey)} must end with ${suffixText}`));
};
}
export function Equal(value, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'equal', (val)=>val === value, message || `${String(propertyKey)} must be equal to ${value}`));
};
}
export function NotEqual(value, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'notEqual', (val)=>val !== value, message || `${String(propertyKey)} must not be equal to ${value}`));
};
}
export function Range(min, max, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'range', (value)=>typeof value === 'number' && value >= min && value <= max, message || `${String(propertyKey)} must be between ${min} and ${max}`));
};
}
export function IsFalse(message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'isFalse', (val)=>val === false, message || `${String(propertyKey)} must be false`));
};
}
export function IsTrue(message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'isTrue', (val)=>val === true, message || `${String(propertyKey)} must be true`));
};
}
export function Length(value, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'length', (val)=>typeof val === 'string' && val.length === value, message || `${String(propertyKey)} must be ${value} characters`));
};
}
export function MaxLength(max, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'maxLength', (val)=>typeof val === 'string' && val.length <= max, message || `${String(propertyKey)} must not exceed ${max} characters`));
};
}
export function MinLength(min, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'minLength', (val)=>typeof val === 'string' && val.length >= min, message || `${String(propertyKey)} must be at least ${min} characters`));
};
}
/**
* 속성 값이 주어진 값들 중 하나인지 확인합니다.
* @param options 허용되는 값의 배열.
*/ export function OneOf(options, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'oneOf', (value)=>options.includes(value), message || `${String(propertyKey)} must be one of ${options.join(', ')}`));
};
}
export function Validate(validateFn, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'validate', validateFn, message || `${String(propertyKey)} did not pass the provided validation rule.`));
};
}
export function Regexp(pattern, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'regexp', (value)=>typeof value === 'string' && pattern.test(value), message || `${String(propertyKey)} does not match pattern ${pattern}`));
};
}
export function Email(message) {
return (target, propertyKey)=>{
const DEFAULT_EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'email', (value)=>typeof value === 'string' && DEFAULT_EMAIL_PATTERN.test(value), message || `${String(propertyKey)} should be email format`));
};
}
const ALPHA_PATTERN = /^[a-zA-Z]+$/;
export function Alpha(message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'alpha', (value)=>typeof value === 'string' && ALPHA_PATTERN.test(value), message || `${String(propertyKey)} should be alphabetic`));
};
}
const uuidPatterns = {
all: /^[0-9a-f]{8}-[0-9a-f]{4}-[1345][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
v1: /^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
v3: /^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
v4: /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
v5: /^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
};
export function Uuid(version, message) {
let regex;
let versionLabel;
const v = version ? version.replace('v', '') : 'all';
switch(v){
case '1':
regex = uuidPatterns.v1;
versionLabel = 'v1';
break;
case '3':
regex = uuidPatterns.v3;
versionLabel = 'v3';
break;
case '4':
regex = uuidPatterns.v4;
versionLabel = 'v4';
break;
case '5':
regex = uuidPatterns.v5;
versionLabel = 'v5';
break;
default:
regex = uuidPatterns.all;
versionLabel = 'v1, v3, v4, or v5';
}
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'uuid', (value)=>typeof value === 'string' && regex.test(value), message || `${String(propertyKey)} must be a valid UUID format (${versionLabel})`));
};
}
export function Alphanumeric(message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'alphanumeric', (value)=>typeof value === 'string' && /^[a-zA-Z0-9]+$/.test(value), message || `${String(propertyKey)} should be alphanumeric`));
};
}
export function With(fieldName, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'with', (value, instance)=>!(!!value && !instance?.[fieldName]), message || `${String(propertyKey)} requires ${fieldName}`));
};
}
export function Without(fieldName, message) {
return (target, propertyKey)=>{
addValidator(target, propertyKey, new ValidatorRule(propertyKey, 'without', (value, instance)=>{
if (!instance) return false;
return !(!!value && !!instance?.[fieldName]);
}, message || `${String(propertyKey)} cannot exist with ${fieldName}`));
};
}