@chewbank/typea
Version:
JS数据验证、转换递归器
299 lines (298 loc) • 9.67 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const type_js_1 = require("./type.js");
const symbol_js_1 = require("./symbol.js");
const common_js_1 = require("./common.js");
const { toString } = Object.prototype;
const ignore = [undefined, null, ''];
class Parser {
/**
*
* @param {*} express 验证表达式
* @param {String} mode 验证模式
*/
constructor(express, origin, mode) {
this.express = express;
this.origin = origin;
this.mode = mode;
}
/**
* 递归验证器
* @param {*} express 验证表达式
* @param {*} data 待验证数据
* @param {String, Number} key 数据索引
*/
recursion(express, data, key) {
// 选项值为对象
if (typeof express === 'object') {
return this.object(express, data, key);
}
// 选项值为JS基础类型构造函数或symbol,symbol表示自定义类型
else if (type_js_1.default.get(express)) {
if (ignore.includes(data)) {
// 严格模式下,禁止空值
if (this.mode === 'strict') {
return { error: "值不允许为空" };
}
return {};
}
const { error, data: subData } = type_js_1.default.get(express).type(data);
if (error) {
return { error: `值${error}` };
}
else {
return { data: subData };
}
}
// 选项值为严格匹配的精确值类型
else if (data === express) {
return { data };
}
// 精确值匹配失败
else {
return { error: `值必须为${express}` };
}
}
/**
* 对象结构
* @param {*} express
* @param {object} data
* @param {*} key
*/
object(express, data, key) {
// express为验证表达式
if (express.type) {
return this.expression(express, data, key);
}
// express为数组结构
else if (Array.isArray(express)) {
return this.array(express, data, key);
}
// express为对象结构
else {
if (typeof data !== 'object') {
// 宽松模式下,跳过空值
if (this.mode === 'loose') {
if (ignore.includes(data))
return {};
}
return { error: `值必须为Object类型` };
}
const dataObj = {};
for (const sKey in express) {
const { error, data: subData } = this.recursion(express[sKey], data[sKey], sKey);
if (error) {
// 非根节点
if (key) {
return { error: `.${sKey}${error}` };
}
else {
return { error: `${sKey}${error}` };
}
}
else if (subData !== undefined) {
dataObj[sKey] = subData;
}
}
return { data: dataObj };
}
}
/**
* 数组结构
* @param {*} express
* @param {*} data
* @param {*} key
*/
array(express, data, key) {
if (!Array.isArray(data)) {
// 宽松模式下,跳过空值
if (this.mode === 'loose') {
if (ignore.includes(data))
return {};
}
return { error: `${key}必须为数组类型` };
}
let itemKey = 0;
const dataArray = [];
// express为单数时采用通用匹配
if (express.length === 1) {
const [option] = express;
for (const itemData of data) {
// 子集递归验证
const { error, data: subData } = this.recursion(option, itemData, itemKey);
if (error) {
return { "error": `[${itemKey}]${error}` };
}
else if (subData !== undefined) {
dataArray.push(subData);
}
itemKey++;
}
}
// express为复数时采用精确匹配
else {
for (const option of express) {
const itemData = data[itemKey];
// 子集递归验证
const { error, data: subData } = this.recursion(option, itemData, itemKey);
if (error) {
return { "error": `[${itemKey}]${error}` };
}
else if (subData !== undefined) {
dataArray.push(subData);
}
itemKey++;
}
}
return { data: dataArray };
}
/**
* 验证表达式
* @param {*} express
* @param {*} data
* @param {*} key
*/
expression(express, data, key) {
// 空值处理
if ((express.ignore || ignore).includes(data)) {
// 默认值
if (express.default) {
data = express.default;
}
// 禁止空值
else if (express.allowNull === false) {
return { error: `值不允许为空` };
}
// 允许空值
else if (express.allowNull === true) {
return { data };
}
// 严格模式下,禁止空值
else if (this.mode === 'strict') {
return { error: `值不允许为空` };
}
else {
return { data };
}
}
const type = type_js_1.default.get(express.type);
// type为内置数据类型
if (type) {
for (const name in express) {
const method = type[name];
if (method) {
const option = express[name];
const { error, data: subData } = method(data, option, this.origin);
if (error) {
return { error: `${error}` };
}
data = subData;
}
}
return { data };
}
// 不支持的数据类型
else {
return { error: `${key}参数配置错误,不支持${express.type}类型` };
}
}
}
/**
* 验证器
* @param {*} express 验证表达式
* @param {*} origin 数据源
* @param {object} extend 导出数据扩展函数集合
* @param {string} mode 验证模式(仅供内部使用)
*/
function validator(express, origin, extend, mode) {
const parser = new Parser(express, origin, mode);
if (toString.call(express) === '[object Object]') {
const root = {};
for (const name in express) {
const { error, data } = parser.recursion(express[name], origin[name], name);
if (error) {
return { error: `${name}${error}` };
}
else if (data !== undefined) {
root[name] = data;
}
}
if (extend) {
// 后置数据扩展函数,基于已验证的数据构建新的数据结构
for (const name in extend) {
let value = extend[name];
if (typeof value === 'function') {
value = value(root);
}
root[name] = value;
}
}
return { data: root };
}
else {
return parser.recursion(express, origin, '');
}
}
/**
* @param {*} express 验证表达式
*/
function typea(express) {
return {
/**
* 常规模式,allowNull值为true时强制验证
* @param {object} extend 数据扩展选项
*/
verify(data, extend) {
return validator(express, data, extend, undefined);
},
/**
* 严格模式
* 禁止所有空值,有值验证,无值报错
* @param {object} extend 数据扩展选项
*/
strictVerify(data, extend) {
return validator(express, data, extend, 'strict');
},
/**
* 宽松模式
* 忽略所有空值,有值验证,无值跳过,忽略allowNull属性
* @param {object} extend 数据扩展选项
*/
looseVerify(data, extend) {
return validator(express, data, extend, 'loose');
}
};
}
typea.types = symbol_js_1.default;
/**
* 自定义数据类型扩展方法
* @param {Function, Symbol, String} type 数据类型
* @param {Object} options 扩展选项
* @param {Object.Function} options 扩展方法
*/
typea.use = function (type, options = {}) {
if (!type)
return;
const value = type_js_1.default.get(type);
// 通过Symbol定位,扩展已有数据类型
if (value) {
Object.assign(value, options);
}
// 通过String定位,扩展已有数据类型或创建新类型
else if (typeof type === 'string') {
// 扩展已有Symbol类型
if (symbol_js_1.default[type]) {
const symbol = symbol_js_1.default[type];
const value = type_js_1.default.get(symbol);
Object.assign(value, options);
}
// 创建新类型
else {
Object.assign(options, common_js_1.default);
const symbol = Symbol(type);
symbol_js_1.default[type] = symbol;
type_js_1.default.set(symbol, options);
}
}
};
exports.default = typea;