vtils
Version:
一个面向业务的 JavaScript/TypeScript 实用程序库。
396 lines (373 loc) • 12 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import { assign, castArray, cloneDeepFast, findIndex, get, includes, isArray, pick, set, toArray, toPlainObject, values } from "../utils/index.js";
import { VaeError } from "./VaeError.js";
import { VaeLocale } from "./VaeLocale.js";
import { VaeSchemaParseContext } from "./VaeSchemaParseContext.js";
import { VaeSchemaReachContext } from "./VaeSchemaReachContext.js";
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export var VaeSchema = /*#__PURE__*/function () {
function VaeSchema(options) {
this._options = void 0;
this._options = _extends({}, options, {
processors: options.processors || []
});
}
/**
* 选项
*/
var _proto = VaeSchema.prototype;
/**
* 设置元信息
*/
_proto.meta = function meta(metadata) {
this._options.metadata = metadata;
return this;
}
/**
* 新增检测
*/;
_proto.check = function check(payload) {
var index = payload.tag ? findIndex(this._options.processors, function (item) {
return typeof item === 'object' && item.tag === payload.tag;
}) : -1;
if (index !== -1) {
this._options.processors[index] = payload;
} else {
this._options.processors.push(payload);
}
return this;
}
/**
* 新增转换
*/;
_proto.transform = function transform(payload) {
this._options.processors.push(payload);
return this;
}
/**
* 设置标签
*/;
_proto.label = function label(_label) {
this._options.label = _label;
return this;
}
/**
* 设置默认值
*/;
_proto.default = function _default(value) {
this._options.default = value;
return this;
}
/**
* 设为必填
*/;
_proto.required = function required(message) {
if (message === void 0) {
message = VaeLocale.base.required;
}
this._options.required = true;
this._options.requiredMessage = message;
return this;
}
/**
* 设为可选
*/;
_proto.optional = function optional() {
this._options.required = false;
this._options.requiredMessage = undefined;
return this;
}
/**
* 设置枚举
*/;
_proto.enum = function _enum(value, message) {
if (message === void 0) {
message = VaeLocale.base.enum;
}
var enumValues = isArray(value) ? value : values(value);
return this.check({
fn: function fn(v) {
return includes(enumValues, v);
},
message: message,
messageParams: {
enum: enumValues
},
tag: 'enum'
});
}
/**
* 自定义检测
*/;
_proto.custom = function custom(fn, messageOrOptions) {
var _messageOrOptions$pat;
if (!messageOrOptions || typeof messageOrOptions !== 'object') {
messageOrOptions = {
message: messageOrOptions
};
}
var message = messageOrOptions.message || VaeLocale.base.custom;
// @ts-ignore
var path = (_messageOrOptions$pat = messageOrOptions.path) == null ? void 0 : _messageOrOptions$pat.split('.');
var tag = messageOrOptions.tag && "custom_" + messageOrOptions.tag;
return this.check({
fn: fn,
message: message,
path: path,
tag: tag
});
}
/**
* 在运行时动态修改模式
*/;
_proto.runtime = function runtime(fn) {
this._options.runtime = fn;
return this;
}
/**
* 克隆
*/;
_proto.clone = function clone() {
// https://stackoverflow.com/a/44782052
var newSchema = assign(Object.create(Object.getPrototypeOf(this)), this);
newSchema._options = cloneDeepFast(newSchema._options, function (v) {
return v instanceof VaeSchema;
});
newSchema._options.processors.forEach(function (item) {
if (typeof item === 'object' && item.fn instanceof VaeSchema) {
item.fn = item.fn.clone();
}
});
return newSchema;
}
/**
* 获取给定多个路径的模式
*/;
_proto.reach = function reach(path, ctx, curPath) {
var _ctx, _curPath;
var paths = castArray(path);
var isRoot = !ctx;
ctx = (_ctx = ctx) != null ? _ctx : new VaeSchemaReachContext();
curPath = (_curPath = curPath) != null ? _curPath : [];
var currentDotPath = curPath.join('.');
if (paths.includes(currentDotPath)) {
ctx.addSchema(currentDotPath, this);
}
for (var i = 0; i < this._options.processors.length; i++) {
var processor = this._options.processors[i];
if (typeof processor === 'object') {
if (processor.fn instanceof VaeSchema) {
var fullPath = [].concat(curPath, processor.path || []);
if (this._options.type === 'array' && processor.tag === 'element') {
processor.fn.reach(paths, ctx, [].concat(fullPath, [0]));
} else {
processor.fn.reach(paths, ctx, fullPath);
}
}
}
}
if (!isRoot) {
return;
}
var res = ctx.schemas.reduce(function (res, item) {
res[item.path] = item.schema;
return res;
}, {});
return typeof path === 'string' ? res[path] : res;
}
/**
* 解析数据并返回解析结果
*/;
_proto.parse = function parse(data, options) {
var _options$ctx, _options, _options$curPath, _options2, _schema$_options$obje;
// 字符串 trim
if (this._options.stringTrim && this._options.type === 'string' && typeof data === 'string') {
data = data.trim();
}
var dataIsNil = data == null || this._options.type === 'string' && !this._options.stringEmptyable && data === '';
// 默认值
if (dataIsNil && this._options.default != null) {
data = typeof this._options.default === 'function' ? this._options.default() : this._options.default;
dataIsNil = data == null || this._options.type === 'string' && !this._options.stringEmptyable && data === '';
}
// 非必填
if (dataIsNil && !this._options.required) {
return {
success: true,
data: data
};
}
// 运行时
// eslint-disable-next-line @typescript-eslint/no-this-alias
var schema = this;
if (this._options.runtime) {
schema = this.clone();
this._options.runtime({
// @ts-expect-error
value: data,
schema: schema
});
}
var processors = schema._options.processors.slice();
// 必填规则始终前置
if (schema._options.required) {
processors.unshift({
fn: function fn() {
return !dataIsNil;
},
message: schema._options.requiredMessage
});
}
// 2024.1.31: 自行决定位置,不再强制移到最后,以满足类似先格式化元素再去重等需求
// 对于数组,将 element 的验证移到最后
// if (schema._options.type === 'array') {
// moveToBottom(
// processors,
// processors.findIndex(
// item => typeof item === 'object' && item.tag === 'element',
// ),
// )
// }
var ctx = (_options$ctx = (_options = options) == null ? void 0 : _options.ctx) != null ? _options$ctx : new VaeSchemaParseContext();
var curPath = (_options$curPath = (_options2 = options) == null ? void 0 : _options2.curPath) != null ? _options$curPath : [];
options = options || {};
options.ctx = ctx;
options.curPath = curPath;
for (var i = 0; i < processors.length; i++) {
var processor = processors[i];
if (typeof processor === 'object') {
// eslint-disable-next-line prefer-const
var fn = processor.fn,
message = processor.message,
messageParams = processor.messageParams,
_processor$path = processor.path,
_path = _processor$path === void 0 ? [] : _processor$path,
tag = processor.tag;
var fullPath = [].concat(curPath, _path);
if (fn instanceof VaeSchema) {
var pathData = _path.length ? get(data, _path) : data;
if (schema._options.type === 'array' && tag === 'element') {
if (pathData) {
for (var j = 0; j < pathData.length; j++) {
var item = pathData[j];
var res = fn.parse(item, _extends({}, options, {
curPath: [].concat(fullPath, [j])
}));
if (res.success) {
set(data, [].concat(_path, [j]), res.data);
} else {
if (options.abortEarly) {
return {
success: false,
issues: ctx.issues,
message: ctx.issues[0].message
};
}
}
}
}
} else {
var _res = fn.parse(pathData, _extends({}, options, {
curPath: fullPath
}));
if (_res.success) {
if (_path.length) {
set(data, _path, _res.data);
} else {
data = _res.data;
}
} else {
if (options.abortEarly) {
return {
success: false,
issues: ctx.issues,
message: ctx.issues[0].message
};
}
}
}
} else {
var fnRes = void 0;
var fnErr = void 0;
try {
fnRes = fn(
// @ts-expect-error
data);
} catch (err) {
fnErr = err;
}
if (fnErr != null) {
fnRes = false;
message = fnErr instanceof Error ? fnErr.message : String(fnErr);
}
if (fnRes === false) {
if (options.cast) {
data = dataIsNil ? data : schema._options.type === 'string' ? String(data) : schema._options.type === 'number' ? Number(data) : schema._options.type === 'boolean' ? Boolean(data) : schema._options.type === 'date' ? new Date(data) : schema._options.type === 'array' ? toArray(data) : schema._options.type === 'object' ? toPlainObject(data) : null;
} else {
ctx.addIssue({
path: fullPath,
message: typeof message === 'function' ? message({
path: fullPath,
params: messageParams || {},
value: data,
label: schema._options.label
}) : message
});
if (options.abortEarly) {
return {
success: false,
issues: ctx.issues,
message: ctx.issues[0].message
};
}
}
break;
}
}
} else {
// @ts-expect-error
data = processor(data);
}
}
if (ctx.issues.length) {
return {
success: false,
issues: ctx.issues,
message: ctx.issues[0].message
};
}
return {
success: true,
data: !options.preserveUnknownKeys && schema._options.type === 'object' && (_schema$_options$obje = schema._options.objectKeys) != null && _schema$_options$obje.length ? pick(data, schema._options.objectKeys) : data
};
}
/**
* 解析数据,当解析失败时抛出错误,当解析成功时返回结果
*/;
_proto.parseOrThrow = function parseOrThrow(data, options) {
var res = this.parse(data, options);
if (res.success) {
return res.data;
}
throw new VaeError(res.issues);
}
/**
* 根据当前模式强制转换给定数据
*/;
_proto.cast = function cast(data, options) {
var res = this.parse(data, {
cast: true,
preserveUnknownKeys: options == null ? void 0 : options.preserveUnknownKeys
});
// @ts-ignore
return res.data;
};
_createClass(VaeSchema, [{
key: "options",
get: function get() {
return this._options;
}
}]);
return VaeSchema;
}();