This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function paramSchema(schema: Schema) { | |
return function setParamSchemaMetadata( | |
target: Object, | |
propertyKey: string | symbol, | |
parameterIndex: number | |
) { | |
// If no property is given, we assume that we are trying to annotate a constructor parameter | |
propertyKey = | |
typeof propertyKey === "undefined" ? "constructor" : propertyKey; | |
// Collect metadata entries that mark parameters as constrained by a schema |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const personNameSchema = Joi.string().min(3) | |
const personAgeSchema = Joi.number().min(1) | |
const personSchema = Joi.object({ | |
name: personNameSchema, | |
age: personAgeSchema | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@schema(personSchema) | |
class Person { | |
age: number | |
name: string | |
constructor(name: string, age: number) { | |
this.age = age | |
this.name = name | |
} | |
} | |
const p = new Person('Jake', 50) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function schema(schema: Schema) { | |
return function validateArgs(target: any) { | |
// save a reference to the original constructor | |
var original = target; | |
// wrap orginal constructor with validation behaviour | |
var f: any = function(...args) { | |
const instance = new original(...args); | |
const { error } = schema.validate(instance); | |
if (error instanceof Error) { | |
throw error; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Joi = require('@hapi/joi') | |
const personNameSchema = Joi.string().min(3) | |
const personAgeSchema = Joi.number().min(1) | |
const personGroupName = Joi.string().min(3) | |
const personSchema = Joi.object({ | |
name: personNameSchema, | |
age: personAgeSchema | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private buildValidObject(p: ObjectArgumentDescriptor, value: object) { | |
if ((value as ValidObject).__className === 'ValidObject') { | |
return new (p.type as IValidObjectConstructor<typeof p.type>)( | |
'ValidObject', | |
(value as ValidObject).schema, | |
...this.buildValidObjectArguments(value as ValidObject) | |
) | |
} else { | |
// We have a derived class from ValidObject | |
return new (p.type as IDerivedValidObjectConstructor<typeof p.type>)( |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type PrimitiveArgumentDescriptor< | |
T extends Primitive<PrimitiveType> = any | |
> = { | |
__className: 'PrimitiveArgumentDescriptor' | |
type: IPrimitiveConstructor<T> | |
name: string | |
value: PrimitiveType | |
} | |
type ObjectArgumentDescriptor<T extends ValidObject = any> = { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generate Getter and Setter for each property | |
setProperties(...x: AnyArgumentDescriptor[]) { | |
x.forEach(p => { | |
// initialise private property counterpart | |
this[`_${p.name}`] = | |
p.__className === 'ObjectArgumentDescriptor' | |
? p.value | |
: p.__className === 'PrimitiveArgumentDescriptor' | |
? new p.type(p.value) | |
: undefined |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Initialise the Object | |
private _init(...x: AnyArgumentDescriptor[]) { | |
this.params = x.map(arg => | |
arg.__className === 'PrimitiveArgumentDescriptor' | |
? PrimitiveParameterDescriptorFactory(arg.type, arg.name) | |
: ObjectParameterDescriptorFactory(arg.type, arg.name) | |
) | |
this.setProperties(...x) | |
this._value = this.getValidable() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ValidObject { | |
params: AnyParameterDescriptor[] | |
private _value: PrimitiveType | object = {} | |
constructor( | |
public readonly __className: string = 'ValidObject',private schema: Schema,...x: AnyArgumentDescriptor[]) { | |
this._init(...x) | |
const result = this.validate() | |
if (result instanceof Error) { | |
this.handleError(result) | |
} |