UNPKG

vtils

Version:

一个面向业务的 JavaScript/TypeScript 实用程序库。

396 lines (373 loc) 12 kB
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; }();