// @ts-nocheck /* @flow */ /** * constants */ import { errorMessages } from './errors' import { warnMessages } from './warnings' export const numberFormatKeys = [ 'compactDisplay', 'currency', 'currencyDisplay', 'currencySign', 'localeMatcher', 'notation', 'numberingSystem', 'signDisplay', 'style', 'unit', 'unitDisplay', 'useGrouping', 'minimumIntegerDigits', 'minimumFractionDigits', 'maximumFractionDigits', 'minimumSignificantDigits', 'maximumSignificantDigits' ] export const dateTimeFormatKeys = [ 'dateStyle', 'timeStyle', 'calendar', 'localeMatcher', "hour12", "hourCycle", "timeZone", "formatMatcher", 'weekday', 'era', 'year', 'month', 'day', 'hour', 'minute', 'second', 'timeZoneName', ] /** * utilities */ export function getAllKeys(map:Map):string[] { let keys:string[] = [] map.forEach((_, key) => { keys.push(key) }) return keys } /** * 打印警告信息 * @param {string} msg - 警告信息 * @param {Error} err - 可选的错误对象 */ export function warn(msg : string, code:number = -1) { if(process.env.NODE_ENV !== 'production') { console.warn(`[uvue-i18n] : ${code!=-1?warnMessages.get(code):msg}`) } } /** * 打印错误信息 * @param {string} msg - 错误信息 * @param {Error} err - 可选的错误对象 */ export function error(code: number, msg : string|null = null) { if(process.env.NODE_ENV !== 'production') { console.error(`[uvue-i18n] : ${msg ?? errorMessages.get(code)}`) } } export function isArray(value : any) : boolean { return Array.isArray(value) } /** * 判断一个值是否为对象 * @param {mixed} obj - 需要判断的值 * @returns {boolean} - 如果值为对象,则返回 true,否则返回 false */ export function isObject(obj : any | null) : boolean { return obj != null && typeof obj == 'object' } /** * 判断一个值是否为布尔值 * @param {mixed} val - 需要判断的值 * @returns {boolean} - 如果值为布尔值,则返回 true,否则返回 false */ export function isBoolean(val : any) : boolean { return typeof val == 'boolean' } /** * 判断一个值是否为字符串 * @param {mixed} val - 需要判断的值 * @returns {boolean} - 如果值为字符串,则返回 true,否则返回 false */ export function isString(val : any) : boolean { return typeof val == 'string' } /** * 判断一个值是否为普通对象 * @param {any} obj - 需要判断的值 * @returns {boolean} - 如果值为普通对象,则返回 true,否则返回 false */ export function isPlainObject(obj : any) : boolean { // #ifndef APP-ANDROID || APP-IOS const toString = Object.prototype.toString const OBJECT_STRING : string = '[object Object]' return toString.call(obj) === OBJECT_STRING // #endif // #ifdef APP-ANDROID || APP-IOS return typeof obj == 'object' && obj instanceof UTSJSONObject // #endif } /** * 判断一个值是否为 null 或 undefined * @param {mixed} val - 需要判断的值 * @returns {boolean} - 如果值为 null 或 undefined,则返回 true,否则返回 false */ // #ifndef APP-ANDROID || APP-IOS export function isNull(val : any | null | undefined) : boolean { return val == null || val == undefined } // #endif // #ifdef APP-ANDROID || APP-IOS export function isNull(val : any | null) : boolean { return val == null } // #endif /** * 判断一个值是否为函数 * @param {mixed} val - 需要判断的值 * @returns {boolean} - 如果值为函数,则返回 true,否则返回 false */ export function isFunction(val : any) : boolean { return typeof val == 'function' } /** * 解析参数 * @param {...mixed} args - 输入的参数 * @returns {Object} - 包含 locale 和 params 的对象 */ export function parseArgs(...args : Array) : Map { let locale : string | null = null let params : UTSJSONObject | null = null if (args.length == 1) { if (isObject(args[0]) || isArray(args[0]) ) { params = args[0] //as UTSJSONObject } else if (typeof args[0] == 'string') { locale = args[0] as string } } else if (args.length == 2) { if (typeof args[0] == 'string') { locale = args[0] as string } if (isObject(args[1]) || isArray(args[1])) { params = args[1] //as UTSJSONObject } } if(locale == null || params == null) return new Map() return new Map([ [locale, params] ]) } /** * looseClone 函数用于对一个对象进行浅拷贝。 * 它通过将对象序列化为 JSON 字符串,然后再将其解析回对象来实现这一目的。 * 请注意,这种方法仅适用于可序列化的对象,不适用于包含循环引用或特殊对象(如函数、Date 对象等)的对象。 * * @param {Object} obj - 需要进行浅拷贝的对象。 * @returns {Object} 返回一个新的对象,它是原始对象的浅拷贝。 */ export function looseClone(obj : UTSJSONObject) : UTSJSONObject { return JSON.parse(JSON.stringify(obj)) } /** * remove 函数用于从数组中删除指定的元素。 * 如果成功删除元素,则返回修改后的数组;否则,不返回任何值。 * * @param {Array} arr - 需要操作的数组。 * @param {*} item - 需要删除的元素。 * @returns {Array} 返回修改后的数组,或者不返回任何值。 */ export function remove(arr : Set, item : any) : Set | null { if (arr.delete(item)) { return arr } return null } /** * arrayFrom 函数用于将类数组对象(如 Set 集合)转换为数组。 * * @param {Set} arr - 需要转换的类数组对象。 * @returns {Array} 返回一个新数组,其中包含原类数组对象的所有元素。 */ export function arrayFrom(arr : Set) : Array { const ret : any[] = [] arr.forEach(a => { ret.push(a) }) return ret } /** * includes 函数用于检查数组中是否包含指定的元素。 * * @param {Array} arr - 需要检查的数组。 * @param {*} item - 需要查找的元素。 * @returns {boolean} 如果数组中包含指定元素,则返回 true,否则返回 false。 */ export function includes(arr : Array, item : any) : boolean { return arr.indexOf(item) } /** * hasOwn 函数用于检查对象是否具有指定的属性。 * 与直接使用 `obj.hasOwnProperty` 不同,此函数可以正确处理通过原型链继承的属性。 * * @param {Object|Array} obj - 需要检查的对象或数组。 * @param {string} key - 需要检查的属性名。 * @returns {boolean} 如果对象具有指定的属性,则返回 true,否则返回 false。 */ export function hasOwn(obj : UTSJSONObject, key : string) : boolean { return obj[key] != null } /** * merge 函数用于合并多个对象。 * 它会将源对象的所有可枚举属性值复制到目标对象。 * 如果目标对象和源对象有相同的属性,且它们的属性值都是对象,则会递归地合并这两个属性值。 * * @param {Object} target - 目标对象,将被合并的对象。 * @returns {Object} 返回合并后的新对象。 */ export function merge(...target : UTSJSONObject[]) : UTSJSONObject { return UTSJSONObject.assign(...target) // const output = Object(target) // for (let i = 1; i < arguments.length; i++) { // const source = arguments[i] // if (source !== undefined && source !== null) { // let key // for (key in source) { // if (hasOwn(source, key)) { // if (isObject(source[key])) { // output[key] = merge(output[key], source[key]) // } else { // output[key] = source[key] // } // } // } // } // } // return output } /** * looseEqual 函数用于比较两个值是否宽松相等。 * 宽松相等意味着在比较时会进行类型转换,例如将字符串转换为数字。 * 该函数可以处理对象、数组和其他基本数据类型的值。 * * @param {any} a - 要比较的第一个值。 * @param {any} b - 要比较的第二个值。 * @returns {boolean} 如果两个值宽松相等,则返回 true,否则返回 false。 */ export function looseEqual(a : any, b : any) : boolean { // 如果 a 和 b 严格相等,直接返回 true if (a == b) { return true } // 检查 a 和 b 是否都是对象 const isObjectA : boolean = isObject(a) const isObjectB : boolean = isObject(b) // 如果 a 和 b 都是对象 if (isObjectA && isObjectB) { try { // 检查 a 和 b 是否都是数组 const isArrayA : boolean = Array.isArray(a) const isArrayB : boolean = Array.isArray(b) // 如果 a 和 b 都是数组 if (isArrayA && isArrayB) { // 比较它们的长度是否相等,以及它们的每个元素是否宽松相等 return (a as any[]).length == (b as any[]).length && a.every((e : any, i : number) : boolean => { return looseEqual(e, b[i]) }) } else if (!isArrayA && !isArrayB) { // 如果 a 和 b 都不是数组 // 比较它们的键的数量是否相等,以及对应的键对应的值是否宽松相等 const keysA : Array = UTSJSONObject.keys(a as UTSJSONObject) const keysB : Array = UTSJSONObject.keys(b as UTSJSONObject) return keysA.length == keysB.length && keysA.every((key : string) : boolean => { const valueA = a[key] const valueB = b[key] if(valueA == null || valueB == null) { return false } return looseEqual(valueA, valueB) }) } else { // 如果 a 和 b 类型不同(一个是数组,另一个不是),返回 false return false } } catch (e) { // 如果在比较过程中发生异常,返回 false return false } } else if (!isObjectA && !isObjectB) { // 如果 a 和 b 都不是对象 // 尝试将它们转换为字符串并比较 return `${a}` == `${b}` } else { // 如果 a 和 b 类型不同(一个是对象,另一个不是),返回 false return false } } /** * 对用户输入的原始文本进行 HTML 特殊字符转义,以降低 XSS 攻击的风险。 * @param {string} rawText - 需要转义的原始用户输入文本。 * @returns {string} 返回转义后的文本。 */ function escapeHtml(rawText: string): string { return rawText .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } /** * 从 `parseArgs().params` 返回的所有提供的参数中转义 HTML 标签和特殊符号。 * 此方法对 `params` 对象执行原地操作。 * * @param {any} params - 从 `parseArgs().params` 提供的参数。 * 可能是字符串数组或字符串到任意值的映射。 * @returns {any} 返回被操纵过的 `params` 对象。 */ export function escapeParams(params: UTSJSONObject|null): UTSJSONObject|null { if(params != null) { UTSJSONObject.keys(params).forEach(key => { if(typeof(params[key]) == 'string') { params[key] = escapeHtml(params[key]) } }) } return params }