tynder
Version:
TypeScript friendly Data validator for JavaScript.
99 lines (82 loc) • 2.8 kB
text/typescript
// Copyright (c) 2020 Shellyl_N and Authors
// license: ISC
// https://github.com/shellyln
import { CustomConstraintInfo } from '../types';
import { dummyTargetObject,
isUnsafeVarNames } from '../lib/protection';
type MapperFn = (data: any, fields: string[]) => any[];
const mapperErrMsg = 'Unsafe symbol name is appeared in unique constraint assertion:';
const normalMapper: MapperFn = (data: any, fields: string[]) => {
const ret: any[] = [];
if (0 < fields.length) {
for (const field of fields) {
if (isUnsafeVarNames(dummyTargetObject, field)) {
throw new Error(`${mapperErrMsg} ${field}`);
}
ret.push(data[field]);
}
} else {
ret.push(data);
}
return ret;
};
const nonNullMapper: MapperFn = (data: any, fields: string[]) => {
const ret: any[] = [];
if (0 < fields.length) {
for (const field of fields) {
if (isUnsafeVarNames(dummyTargetObject, field)) {
throw new Error(`${mapperErrMsg} ${field}`);
}
ret.push(data[field] ?? NaN);
}
} else {
ret.push(data);
}
return ret;
};
const checkerGen = (mapper: MapperFn) => {
return ((data: any, args: any) => {
const errMsg = `evaluateFormula: invalid parameter ${args}`;
if (! Array.isArray(data)) {
throw new Error(errMsg);
}
const fields: string[] = [];
if (typeof args === 'string') {
fields.push(args);
} else if (Array.isArray(args)) {
for (const z of args) {
if (typeof z !== 'string') {
throw new Error(errMsg);
}
}
fields.push(...args);
}
const mapped = data.map(x => mapper(x, fields));
for (let i = 0; i < mapped.length; i++) {
CMP: for (let j = 0; j < mapped.length; j++) {
if (i === j) {
continue;
}
const a = mapped[i];
const b = mapped[j];
for (let k = 0; k < a.length; k++) { // TODO: this is slow! more better checking
if (a[k] !== b[k]) {
continue CMP;
}
}
return false;
}
}
return true;
});
};
export const constraints: Array<[string, CustomConstraintInfo]> = [
['unique', {
kinds: ['repeated', 'sequence'],
check: checkerGen(normalMapper),
}],
['unique-non-null', {
kinds: ['repeated', 'sequence'],
check: checkerGen(nonNullMapper),
}],
];