@travetto/schema
Advanced tools
Comparing version 0.3.5 to 0.3.6
@@ -8,3 +8,3 @@ import { ControllerRegistry, AppError, ParamConfig, Filter, EndpointDecorator, Response, Request } from '@travetto/rest'; | ||
// tslint:disable:no-invalid-this | ||
(ValidationErrors as any as Class<Error>).prototype.render = function (res: Response) { | ||
(ValidationErrors as Class).prototype.render = function (res: Response) { | ||
res.status(403); | ||
@@ -11,0 +11,0 @@ res.json({ |
@@ -35,4 +35,4 @@ { | ||
}, | ||
"version": "0.3.5", | ||
"gitHead": "1dc2f5764a2286dd9237a906f6aa1b3cc1305800" | ||
"version": "0.3.6", | ||
"gitHead": "b4f46ddcd29fe1e3fafbd1da75cd5530815f6d39" | ||
} |
@@ -72,2 +72,6 @@ import { Class } from '@travetto/registry'; | ||
val = `${val}`; | ||
} else if (type === Date) { | ||
if (typeof val === 'number' || typeof val === 'string') { | ||
val = new Date(val); | ||
} | ||
} | ||
@@ -74,0 +78,0 @@ } |
@@ -1,5 +0,5 @@ | ||
import { DescriableConfig } from '../types'; | ||
import { DescribableConfig } from '../types'; | ||
import { SchemaRegistry } from '../registry'; | ||
export function Describe(config: Partial<DescriableConfig>) { | ||
export function Describe(config: Partial<DescribableConfig>) { | ||
return (target: any, property?: string, descriptor?: PropertyDescriptor) => { | ||
@@ -6,0 +6,0 @@ if (property) { |
@@ -5,3 +5,3 @@ import { SchemaRegistry } from '../registry'; | ||
function prop(obj: { [key: string]: any }) { | ||
function prop<T = any>(obj: { [key: string]: any }) { | ||
return (f: any, p: string) => { | ||
@@ -29,17 +29,17 @@ SchemaRegistry.registerPendingFieldFacet(f.constructor, p, obj); | ||
export const Required = (message?: string) => prop({ required: { active: true, message } }); | ||
export const Enum = (vals: string[] | any, message?: string) => { | ||
export const Enum = ((vals: string[] | any, message?: string) => { | ||
const values = enumKeys(vals); | ||
message = message || `{path} is only allowed to be "${values.join('" or "')}"`; | ||
return prop({ enum: { values, message } }); | ||
}; | ||
export const Trimmed = () => prop({ trim: true }); | ||
export const Match = (re: RegExp, message?: string) => prop({ match: { re, message } }); | ||
return prop<string | number>({ enum: { values, message } }); | ||
}); | ||
export const Trimmed = () => prop<string>({ trim: true }); | ||
export const Match = (re: RegExp, message?: string) => prop<string>({ match: { re, message } }); | ||
export const MinLength = (n: number, message?: string) => prop({ minlength: { n, message } }); | ||
export const MaxLength = (n: number, message?: string) => prop({ maxlength: { n, message } }); | ||
export const Min = (n: number | Date, message?: string) => prop({ min: { n, message } }); | ||
export const Max = (n: number | Date, message?: string) => prop({ max: { n, message } }); | ||
export const Min = <T extends number | Date>(n: T, message?: string) => prop<Date | number>({ min: { n, message } }); | ||
export const Max = <T extends number | Date>(n: T, message?: string) => prop<Date | number>({ max: { n, message } }); | ||
export const Email = (message?: string) => Match(CommonRegExp.email, message); | ||
export const Telephone = (message?: string) => Match(CommonRegExp.telephone, message); | ||
export const Url = (message?: string) => Match(CommonRegExp.url, message); | ||
export const Precision = (precision: number) => prop({ precision }); | ||
export const Precision = (precision: number) => prop<number>({ precision }); | ||
export const Integer = () => Precision(0); | ||
@@ -46,0 +46,0 @@ export const Float = () => Precision(10); |
@@ -7,12 +7,7 @@ /// <reference path="../typings.d.ts" /> | ||
export interface ClassWithSchema<T> extends Class<T> { | ||
from<U>(this: Class<U>, data: U, view?: string): U; | ||
} | ||
export function Schema(auto: boolean = true): ClassDecorator { | ||
return <T>(target: Class<T>): Class<T> => { | ||
const res: ClassWithSchema<T> = target as any; | ||
return (<T>(target: Class<T>): Class<T> => { | ||
SchemaRegistry.getOrCreatePending(target); | ||
return res; | ||
}; | ||
return target; | ||
}) as any; | ||
} | ||
@@ -19,0 +14,0 @@ |
@@ -72,2 +72,28 @@ import { Class } from '@travetto/registry'; | ||
static validateRange(field: FieldConfig, key: 'min' | 'max', value: any) { | ||
const f = field[key]; | ||
if (f) { | ||
if (typeof f.n === 'number') { | ||
if (typeof value !== 'number') { | ||
value = parseInt(value, 10); | ||
} | ||
if (field.type === Date) { | ||
value = new Date(value); | ||
} | ||
if (value < f.n) { | ||
return true; | ||
} | ||
} else { | ||
const date = f.n.getTime(); | ||
if (typeof value === 'string') { | ||
value = Date.parse(value); | ||
} | ||
if (value < date) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
static validateField(field: FieldConfig, value: any, parent: any) { | ||
@@ -79,3 +105,3 @@ const criteria: string[] = []; | ||
(field.type === Number && ((typeof value !== 'number') || Number.isNaN(value))) || | ||
(field.type === Date && (typeof value !== 'number' && !(value instanceof Date))) || | ||
(field.type === Date && !(value instanceof Date)) || | ||
(field.type === Boolean && typeof value !== 'boolean') | ||
@@ -103,38 +129,8 @@ ) { | ||
if (field.min) { | ||
if (typeof field.min.n === 'number') { | ||
if (typeof value !== 'number') { | ||
value = parseInt(value, 10); | ||
} | ||
if (value < field.min.n) { | ||
criteria.push('min'); | ||
} | ||
} else { | ||
const date = field.min.n.getTime(); | ||
if (typeof value === 'string') { | ||
value = Date.parse(value); | ||
} | ||
if (value < date) { | ||
criteria.push('min'); | ||
} | ||
} | ||
if (this.validateRange(field, 'min', value)) { | ||
criteria.push('min'); | ||
} | ||
if (field.max) { | ||
if (typeof field.max.n === 'number') { | ||
if (typeof value !== 'number') { | ||
value = parseInt(value, 10); | ||
} | ||
if (value > field.max.n) { | ||
criteria.push('max'); | ||
} | ||
} else { | ||
const date = field.max.n.getTime(); | ||
if (typeof value === 'string') { | ||
value = Date.parse(value); | ||
} | ||
if (value > date) { | ||
criteria.push('max'); | ||
} | ||
} | ||
if (this.validateRange(field, 'max', value)) { | ||
criteria.push('max'); | ||
} | ||
@@ -141,0 +137,0 @@ |
@@ -10,3 +10,3 @@ import { Class } from '@travetto/registry'; | ||
export interface DescriableConfig { | ||
export interface DescribableConfig { | ||
title?: string; | ||
@@ -25,3 +25,3 @@ description?: string; | ||
export interface ClassConfig extends DescriableConfig { | ||
export interface ClassConfig extends DescribableConfig { | ||
class: Class; | ||
@@ -32,3 +32,3 @@ views: { [key: string]: ViewConfig }; | ||
export interface FieldConfig extends DescriableConfig { | ||
export interface FieldConfig extends DescribableConfig { | ||
owner: any; | ||
@@ -35,0 +35,0 @@ name: string; |
type DeepPartial<T> = { | ||
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P] | ||
[P in keyof T]?: (T[P] extends (number | string | Date | boolean | any[] | undefined) ? (T[P] | undefined) : DeepPartial<T[P]>); | ||
} & { | ||
@@ -7,4 +7,11 @@ [key: string]: any; | ||
type DeepPartialRaw<T> = { | ||
[P in keyof T]?: (T[P] extends (number | string | Date | boolean | any[]) ? | ||
(number | string | Date | boolean | any[] | undefined) : DeepPartialRaw<T[P]>) | ||
}; | ||
declare interface Function { | ||
from<T>(this: { new(...args: any[]): T }, data: Partial<T>, view?: string): T; | ||
from<T>(this: { new(...args: any[]): T }, data: DeepPartial<T> & { [key: string]: any }, view?: string): T; | ||
fromRaw<T>(this: { new(...args: any[]): T }, data: DeepPartialRaw<T> & { [key: string]: any }, view?: string): T; | ||
} |
@@ -12,3 +12,3 @@ const proto = (Function as any)['__proto__']; | ||
before: 'base', // Should be global | ||
action: () => proto.from = from // Register global from | ||
action: () => proto.fromRaw = proto.from = from // Register global from | ||
}; |
47401
21
1083