UNPKG

sunmao-sdk

Version:

榫卯-开箱即用赋能-sdk

407 lines (365 loc) 11.1 kB
/** * Created by Tw93 on 2018-09-26. * 常见功能函数 */ // 克隆对象 export function clone(data) { try { return JSON.parse(JSON.stringify(data)); } catch (e) { return data; } } // 做一个url的弱判断,就判断有没有 “//” export function isUrl(string) { const protocolRE = /^(?:\w+:)?\/\/(\S+)$/; // const domainRE = /^[^\s\.]+\.\S{2,}$/; if (typeof string !== "string") return false; return protocolRE.test(string); } // '3' => true, 3 => true, undefined => false export function isLooselyNumber(num) { if (typeof num === "number") return true; if (typeof num === "string") { return !Number.isNaN(Number(num)); } return false; } export function isCssLength(str) { if (typeof str !== "string") return false; return str.match(/^([0-9])*(%|px|rem|em)$/i); } // 深度对比 export function isDeepEqual(param1, param2) { if (param1 === undefined && param2 === undefined) return true; else if (param1 === undefined || param2 === undefined) return false; if (param1 === null && param2 === null) return true; else if (param1 === null || param2 === null) return false; else if (param1.constructor !== param2.constructor) return false; if (param1.constructor === Array) { if (param1.length !== param2.length) return false; for (let i = 0; i < param1.length; i++) { if (param1[i].constructor === Array || param1[i].constructor === Object) { if (!isDeepEqual(param1[i], param2[i])) return false; } else if (param1[i] !== param2[i]) return false; } } else if (param1.constructor === Object) { if (Object.keys(param1).length !== Object.keys(param2).length) return false; for (let i = 0; i < Object.keys(param1).length; i++) { const key = Object.keys(param1)[i]; if ( param1[key] && typeof param1[key] !== "number" && (param1[key].constructor === Array || param1[key].constructor === Object) ) { if (!isDeepEqual(param1[key], param2[key])) return false; } else if (param1[key] !== param2[key]) return false; } } else if (param1.constructor === String || param1.constructor === Number) { return param1 === param2; } return true; } // fusion 的时间 format export function getFormatForFusion(format) { let dateFormat; switch (format) { case "date": dateFormat = "YYYY-MM-DD"; break; case "time": dateFormat = "HH:mm:ss"; break; case "dateTime": dateFormat = "YYYY-MM-DD HH:mm:ss"; break; case "year": dateFormat = "YYYY"; break; case "quarter": dateFormat = "YYYY-[Q]Q"; break; case "month": dateFormat = "YYYY-MM"; break; case "week": dateFormat = "YYYY-W[*]"; break; default: dateFormat = "YYYY-MM-DD"; if (format && typeof format === "string") { dateFormat = format; } } return dateFormat; } // 时间组件 export function getFormat(format) { let dateFormat; switch (format) { case "date": // dateFormat = 'YYYY-MM-DD'; dateFormat = undefined; break; case "time": dateFormat = "HH:mm:ss"; break; case "dateTime": // dateFormat = 'YYYY-MM-DD HH:mm:ss'; dateFormat = undefined; break; case "year": // dateFormat = 'YYYY'; dateFormat = undefined; break; case "quarter": dateFormat = "YYYY-[Q]Q"; break; case "month": dateFormat = "YYYY-MM"; break; case "week": dateFormat = "YYYY-W[*]"; break; default: dateFormat = "YYYY-MM-DD"; if (format && typeof format === "string") { dateFormat = format; } } return dateFormat; } export function hasRepeat(list) { return list.find( (x, i, self) => i !== self.findIndex(y => JSON.stringify(x) === JSON.stringify(y)) ); } // ----------------- schema 相关 // 合并propsSchema和UISchema。由于两者的逻辑相关性,合并为一个大schema能简化内部处理 export function combineSchema(propsSchema, uiSchema) { const propList = getChildren(propsSchema); const newList = propList.map(p => { const { name } = p; const { type, enum: options, properties, items } = p.schema; const isObj = type === "object" && properties; const isArr = type === "array" && items && !options; // enum + array 代表的多选框,没有sub const ui = name && uiSchema[p.name]; if (!ui) { return p; } // 如果是list,递归合并items if (isArr) { const newItems = combineSchema(items, ui.items || {}); return { ...p, schema: { ...p.schema, ...ui, items: newItems } }; } // object递归合并整个schema if (isObj) { const newSchema = combineSchema(p.schema, ui); return { ...p, schema: newSchema }; } return { ...p, schema: { ...p.schema, ...ui } }; }); const newObj = {}; newList.forEach(s => { newObj[s.name] = s.schema; }); const topLevelUi = {}; Object.keys(uiSchema).forEach(key => { if (typeof key === "string" && key.substring(0, 3) === "ui:") { topLevelUi[key] = uiSchema[key]; } }); if (isEmpty(newObj)) { return { ...propsSchema, ...topLevelUi }; } return { ...propsSchema, ...topLevelUi, properties: newObj }; } function isEmpty(obj) { return Object.keys(obj).length === 0; } // 获得propsSchema的children function getChildren(schema) { const { // object properties, // array items, type } = schema; if (!properties && !items) { return []; } let schemaSubs = {}; if (type === "object") { schemaSubs = properties; } if (type === "array") { schemaSubs = items; } return Object.keys(schemaSubs).map(name => ({ schema: schemaSubs[name], name })); } // 合并多个schema树,比如一个schema的树节点是另一个schema export function combine() {} export const isValidVariableName = param => /^[a-zA-Z]+$/g.test(param); // 去掉所有的window上的api,出现用户在这段逻辑里报错了。 // export function safeEval(code) { // let safeContextStr = ''; // if (typeof window !== 'undefined') { // const windowContextAttr = Object.getOwnPropertyNames(window).filter( // isValidVariableName // ); // for (let i = 0, len = windowContextAttr.length; i < len; i++) { // safeContextStr += `var ${windowContextAttr[i]} = undefined;`; // } // } // return Function(`${safeContextStr} "use strict"; ${code}`)(); // } export function safeEval(code) { return Function(`"use strict"; ${code}`)(); } // 代替eval的函数 export const parseString = string => safeEval(`return (${string})`); // 解析函数字符串值 export const evaluateString = (string, formData, rootValue) => safeEval(` const rootValue =${JSON.stringify(rootValue)}; const formData = ${JSON.stringify(formData)}; return (${string}) `); // 判断schema的值是是否是“函数” // JSON无法使用函数值的参数,所以使用"{{...}}"来标记为函数,也可使用@标记,不推荐。 export function isFunction(func) { if (typeof func === "function") { return true; } if (typeof func === "string" && func.substring(0, 1) === "@") { return func.substring(1); } if ( typeof func === "string" && func.substring(0, 2) === "{{" && func.substring(func.length - 2, func.length) === "}}" ) { return func.substring(2, func.length - 2); } return false; } // 判断schema中是否有属性值是函数表达式 // TODO: 这个util,没有考虑schema是array的情况,不过目前没有被用到 export function isFunctionSchema(schema) { return Object.keys(schema).some(key => { if (typeof schema[key] === "function") { return true; } else if (typeof schema[key] === "string") { return isFunction(schema[key]); } else if (typeof schema[key] === "object") { return isFunctionSchema(schema[key]); } else { return false; } }); } function stringContains(str, text) { return str.indexOf(text) > -1; } export const isNumber = a => !Number.isNaN(Number(a)); export const isObj = a => stringContains(Object.prototype.toString.call(a), "Object"); // 函数表达式转换成值 export const convertValue = (item, formData, rootValue) => { if (typeof item === "function") { return item(formData, rootValue); } else if (typeof item === "string" && isFunction(item) !== false) { const _item = isFunction(item); try { return evaluateString(_item, formData, rootValue); } catch (error) { console.error(error.message); console.error(`happen at ${item}`); return item; } } return item; }; // getValueByKey(formData, 'a.b.c') export function baseGet(object, path) { path = castPath(path, object); let index = 0; const length = path.length; while (object != null && index < length) { object = object[toKey(path[index++])]; } return index && index == length ? object : undefined; } function castPath(value, object) { if (Array.isArray(value)) { return value; } return isKey(value, object) ? [value] : value.match(/([^\.\[\]"']+)/g); } function toKey(value) { if (typeof value === "string") { return value; } const result = `${value}`; return result == "0" && 1 / value == -INFINITY ? "-0" : result; } const reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/; const reIsPlainProp = /^\w*$/; function isKey(value, object) { if (Array.isArray(value)) { return false; } const type = typeof value; if (type === "number" || type === "boolean" || value == null) { return true; } return ( reIsPlainProp.test(value) || !reIsDeepProp.test(value) || (object != null && value in Object(object)) ); } // 将schema内所有的 {{ ... }} 转换为正常函数,我们试着一次性在外部做好这件事,而不是在内部每次去计算,优化性能 export function funcfySchema(schema) { let _schema = clone(schema); if (isObj(_schema)) { Object.keys(_schema).forEach(key => { _schema[key] = funcfySchema(_schema[key]); }); } else if (Array.isArray(_schema)) { _schema = _schema.map(item => funcfySchema(item)); } else { const funcBody = isFunction(schema); if (typeof funcBody === "string") { try { _schema = new Function("formData", "rootValue", `return ${funcBody}`); } catch (error) { console.error("funcfySchema", error); } } } return _schema; } export const getEnum = schema => { if (!schema) return undefined; const itemEnum = schema && schema.items && schema.items.enum; const schemaEnum = schema && schema.enum; return itemEnum ? itemEnum : schemaEnum; }; export const getArray = (arr, defaultValue = []) => { if (Array.isArray(arr)) return arr; return defaultValue; }; export const isEmail = value => { const regex = "^[.a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$"; if (value && new RegExp(regex).test(value)) { return true; } return false; };