-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
So working with strings within TS is weird, here's a sample what we can achieve there:
var validator = require('fluent-validator');
var validation = validator()
.validate(this.Data, x => <TestPersonModel>x.LastName).isUppercase().isAlpha()
.validate(this.Data, x => <TestPersonModel>x.SSN).isNotEmpty().and.matches("\\d{3}-\\d{2}-\\d{4}").and.isLength(11)
;
// custom message
validation.validate(this.Data, x => <TestPersonModel>x.FirstName).passes(x => x == "Abc", "Must be Abc");
validation.validate(this.Data, x => <TestPersonModel>x.Age).passes(x => validator().isGreaterOrEql(x, 18), "Must be at least 18yrs old.");
var errors = validation.getErrors();
Fortunately it's easy to extend/override fluent-validator default behavior and export it under a different node module. The code to override and to work like above is below. Also worth to notice that it does not break existing code, so might be worth to consider to add it to the library itself (not a big deal to compile it down to JS).
'use strict';
/*
SAMPLE:
var validator = require("fluent-validation-extension");
var errors = validator().validate(m, x => x.Name).isAlpha().getErrors();
*/
var fluentValidator = require('fluent-validator');
module.exports = function(value) {
var inst = fluentValidator();
return patchValidator(inst);
};
var originalValidate;
function patchValidator(validatorInst)
{
originalValidate = validatorInst.validate;
validatorInst.validate = extendedValidate.bind(null);
return validatorInst;
}
// NOTE: see fluent-ts-validator for the original selector code
function extendedValidate<T, TProperty>(obj: T, expression: (instance: T) => TProperty) : any
{
if (expression) {
let propertySelector = getPropertySelector(expression);
let value = getValue(obj, propertySelector)
return originalValidate(value).param(propertySelector);
}
return originalValidate(obj);
}
var memberNamesExtractor = new RegExp("return (.*);?\\b");
var memberNamesExtractorArrowFunctions = new RegExp("=>(.*)");
function getPropertySelector<TResult>(name: (x?: TResult) => any) {
let match = memberNamesExtractor.exec(name + "") || memberNamesExtractorArrowFunctions.exec(name + "");
if (match == null)
throw new Error("The function does not contain a statement matching 'return variableName;'");
let expression = match[1].toString();
let firstDotIndex = expression.indexOf('.');
let propertySelector = expression.substring(firstDotIndex + 1);
return propertySelector;
}
function getValue(obj: any, propertySelector: string) : any
{
/*
// NOTE: simple solution with prop1.prop2...propN - no support for arrays...
var memberNames = propertySelector.split('.')
var value = obj;
for (let member of memberNames) {
value = value[member]
}
*/
// NOTE: the don't do way
// value = eval("obj." + propertySelector);
// NOTE: alternative way to eval()
let value = new Function('obj', "return obj." + propertySelector)(obj);
return value;
}
Metadata
Metadata
Assignees
Labels
No labels