sculp-js 1.6.1 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/lib/cjs/array.js +2 -2
- package/lib/cjs/async.js +2 -2
- package/lib/cjs/base64.js +2 -2
- package/lib/cjs/clipboard.js +2 -2
- package/lib/cjs/cookie.js +2 -2
- package/lib/cjs/date.js +2 -2
- package/lib/cjs/dom.js +2 -2
- package/lib/cjs/download.js +2 -2
- package/lib/cjs/easing.js +2 -2
- package/lib/cjs/file.js +2 -2
- package/lib/cjs/func.js +2 -2
- package/lib/cjs/index.js +26 -3
- package/lib/cjs/math.js +2 -2
- package/lib/cjs/number.js +2 -2
- package/lib/cjs/object.js +67 -20
- package/lib/cjs/path.js +2 -2
- package/lib/cjs/qs.js +2 -2
- package/lib/cjs/random.js +2 -2
- package/lib/cjs/string.js +3 -3
- package/lib/cjs/tooltip.js +2 -2
- package/lib/cjs/tree.js +10 -8
- package/lib/cjs/type.js +8 -8
- package/lib/cjs/unique.js +2 -2
- package/lib/cjs/url.js +2 -2
- package/lib/cjs/validator.js +147 -0
- package/lib/cjs/variable.js +118 -0
- package/lib/cjs/watermark.js +2 -2
- package/lib/cjs/we-decode.js +4 -4
- package/lib/es/array.js +2 -2
- package/lib/es/async.js +2 -2
- package/lib/es/base64.js +2 -2
- package/lib/es/clipboard.js +2 -2
- package/lib/es/cookie.js +2 -2
- package/lib/es/date.js +2 -2
- package/lib/es/dom.js +2 -2
- package/lib/es/download.js +2 -2
- package/lib/es/easing.js +2 -2
- package/lib/es/file.js +2 -2
- package/lib/es/func.js +2 -2
- package/lib/es/index.js +5 -3
- package/lib/es/math.js +2 -2
- package/lib/es/number.js +2 -2
- package/lib/es/object.js +67 -20
- package/lib/es/path.js +2 -2
- package/lib/es/qs.js +2 -2
- package/lib/es/random.js +2 -2
- package/lib/es/string.js +3 -3
- package/lib/es/tooltip.js +2 -2
- package/lib/es/tree.js +10 -8
- package/lib/es/type.js +8 -8
- package/lib/es/unique.js +2 -2
- package/lib/es/url.js +2 -2
- package/lib/es/validator.js +130 -0
- package/lib/es/variable.js +112 -0
- package/lib/es/watermark.js +2 -2
- package/lib/es/we-decode.js +4 -4
- package/lib/index.d.ts +154 -16
- package/lib/umd/index.js +327 -33
- package/package.json +1 -1
package/lib/umd/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.
|
|
3
|
-
* (c) 2023-
|
|
2
|
+
* sculp-js v1.7.0
|
|
3
|
+
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
/**
|
|
157
157
|
* 判断一个字符串是否为有效的 JSON, 若有效则返回有效的JSON对象,否则false
|
|
158
158
|
* @param {string} str
|
|
159
|
-
* @
|
|
159
|
+
* @returns {Object | boolean}
|
|
160
160
|
*/
|
|
161
161
|
function isJsonString(str) {
|
|
162
162
|
try {
|
|
@@ -181,19 +181,19 @@
|
|
|
181
181
|
* @returns {boolean} Returns `true` if `value` is empty, else `false`.
|
|
182
182
|
* @example
|
|
183
183
|
*
|
|
184
|
-
*
|
|
184
|
+
* isEmpty(null);
|
|
185
185
|
* // => true
|
|
186
186
|
*
|
|
187
|
-
*
|
|
187
|
+
* isEmpty(true);
|
|
188
188
|
* // => true
|
|
189
189
|
*
|
|
190
|
-
*
|
|
190
|
+
* isEmpty(1);
|
|
191
191
|
* // => true
|
|
192
192
|
*
|
|
193
|
-
*
|
|
193
|
+
* isEmpty([1, 2, 3]);
|
|
194
194
|
* // => false
|
|
195
195
|
*
|
|
196
|
-
*
|
|
196
|
+
* isEmpty({ 'a': 1 });
|
|
197
197
|
* // => false
|
|
198
198
|
*/
|
|
199
199
|
function isEmpty(value) {
|
|
@@ -424,26 +424,73 @@
|
|
|
424
424
|
}
|
|
425
425
|
/**
|
|
426
426
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
427
|
-
* @param {
|
|
427
|
+
* @param {T} source
|
|
428
428
|
* @param {WeakMap} map
|
|
429
|
-
* @returns {
|
|
429
|
+
* @returns {T}
|
|
430
430
|
*/
|
|
431
|
-
function cloneDeep(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
431
|
+
function cloneDeep(source, map = new WeakMap()) {
|
|
432
|
+
// 处理原始类型(非对象/数组)和 null/undefined
|
|
433
|
+
if (source === null || typeof source !== 'object') {
|
|
434
|
+
return source;
|
|
435
|
+
}
|
|
436
|
+
// 处理循环引用
|
|
437
|
+
if (map.has(source)) {
|
|
438
|
+
return map.get(source);
|
|
439
|
+
}
|
|
440
|
+
// 处理 Date 类型
|
|
441
|
+
if (source instanceof Date) {
|
|
442
|
+
const copy = new Date(source.getTime());
|
|
443
|
+
map.set(source, copy);
|
|
444
|
+
return copy;
|
|
445
|
+
}
|
|
446
|
+
// 处理 RegExp 类型
|
|
447
|
+
if (source instanceof RegExp) {
|
|
448
|
+
const copy = new RegExp(source.source, source.flags);
|
|
449
|
+
map.set(source, copy);
|
|
450
|
+
return copy;
|
|
451
|
+
}
|
|
452
|
+
// 处理数组类型
|
|
453
|
+
if (Array.isArray(source)) {
|
|
454
|
+
const copy = [];
|
|
455
|
+
map.set(source, copy);
|
|
456
|
+
for (const item of source) {
|
|
457
|
+
copy.push(cloneDeep(item, map));
|
|
458
|
+
}
|
|
459
|
+
return copy;
|
|
460
|
+
}
|
|
461
|
+
// 处理 Map 类型
|
|
462
|
+
if (source instanceof Map) {
|
|
463
|
+
const copy = new Map();
|
|
464
|
+
map.set(source, copy);
|
|
465
|
+
source.forEach((value, key) => {
|
|
466
|
+
copy.set(cloneDeep(key, map), cloneDeep(value, map));
|
|
467
|
+
});
|
|
468
|
+
return copy;
|
|
469
|
+
}
|
|
470
|
+
// 处理 Set 类型
|
|
471
|
+
if (source instanceof Set) {
|
|
472
|
+
const copy = new Set();
|
|
473
|
+
map.set(source, copy);
|
|
474
|
+
source.forEach(value => {
|
|
475
|
+
copy.add(cloneDeep(value, map));
|
|
476
|
+
});
|
|
477
|
+
return copy;
|
|
478
|
+
}
|
|
479
|
+
// 处理 ArrayBuffer 类型
|
|
480
|
+
if (source instanceof ArrayBuffer) {
|
|
481
|
+
const copy = new ArrayBuffer(source.byteLength);
|
|
482
|
+
new Uint8Array(copy).set(new Uint8Array(source));
|
|
483
|
+
map.set(source, copy);
|
|
484
|
+
return copy;
|
|
438
485
|
}
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
map.set(
|
|
442
|
-
for (const key of Reflect.ownKeys(
|
|
443
|
-
const value =
|
|
444
|
-
|
|
486
|
+
// 处理普通对象(包括原型链继承)
|
|
487
|
+
const copy = Object.create(Object.getPrototypeOf(source));
|
|
488
|
+
map.set(source, copy);
|
|
489
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
490
|
+
const value = source[key];
|
|
491
|
+
copy[key] = cloneDeep(value, map);
|
|
445
492
|
}
|
|
446
|
-
return
|
|
493
|
+
return copy;
|
|
447
494
|
}
|
|
448
495
|
|
|
449
496
|
/**
|
|
@@ -565,7 +612,7 @@
|
|
|
565
612
|
/**
|
|
566
613
|
* 解析URL查询参数
|
|
567
614
|
* @param {string} searchStr
|
|
568
|
-
* @
|
|
615
|
+
* @returns {Record<string, string | string[]>}
|
|
569
616
|
*/
|
|
570
617
|
function parseQueryParams(searchStr = location.search) {
|
|
571
618
|
const queryObj = {};
|
|
@@ -1369,7 +1416,7 @@
|
|
|
1369
1416
|
/**
|
|
1370
1417
|
* 字符串编码成Base64 (适用于任何环境,包括小程序)
|
|
1371
1418
|
* @param {string} string
|
|
1372
|
-
* @
|
|
1419
|
+
* @returns {string}
|
|
1373
1420
|
*/
|
|
1374
1421
|
function weBtoa(string) {
|
|
1375
1422
|
// 同window.btoa: 字符串编码成Base64
|
|
@@ -1391,7 +1438,7 @@
|
|
|
1391
1438
|
/**
|
|
1392
1439
|
* Base64解码为原始字符串(适用于任何环境,包括小程序)
|
|
1393
1440
|
* @param {string} string
|
|
1394
|
-
* @
|
|
1441
|
+
* @returns {string}
|
|
1395
1442
|
*/
|
|
1396
1443
|
function weAtob(string) {
|
|
1397
1444
|
// 同window.atob: Base64解码为原始字符串
|
|
@@ -2196,7 +2243,7 @@
|
|
|
2196
2243
|
* @param {boolean} isReverse 是否反向遍历
|
|
2197
2244
|
* @returns {any[]} 新的一棵树
|
|
2198
2245
|
*/
|
|
2199
|
-
function
|
|
2246
|
+
function mapDeep(tree, iterator, children = 'children', isReverse = false) {
|
|
2200
2247
|
let isBreak = false;
|
|
2201
2248
|
const newTree = [];
|
|
2202
2249
|
const walk = (arr, parent, newTree, level = 0) => {
|
|
@@ -2213,7 +2260,7 @@
|
|
|
2213
2260
|
else if (re === true) {
|
|
2214
2261
|
continue;
|
|
2215
2262
|
}
|
|
2216
|
-
newTree.push(re);
|
|
2263
|
+
newTree.push(objectOmit(re, [children]));
|
|
2217
2264
|
// @ts-ignore
|
|
2218
2265
|
if (arr[i] && Array.isArray(arr[i][children])) {
|
|
2219
2266
|
newTree[newTree.length - 1][children] = [];
|
|
@@ -2239,7 +2286,7 @@
|
|
|
2239
2286
|
else if (re === true) {
|
|
2240
2287
|
continue;
|
|
2241
2288
|
}
|
|
2242
|
-
newTree.push(re);
|
|
2289
|
+
newTree.push(objectOmit(re, [children]));
|
|
2243
2290
|
// @ts-ignore
|
|
2244
2291
|
if (arr[i] && Array.isArray(arr[i][children])) {
|
|
2245
2292
|
newTree[newTree.length - 1][children] = [];
|
|
@@ -2402,7 +2449,7 @@
|
|
|
2402
2449
|
* 树形结构转扁平化
|
|
2403
2450
|
* @param {any} treeList
|
|
2404
2451
|
* @param {IFieldOptions} options
|
|
2405
|
-
* @
|
|
2452
|
+
* @returns {*}
|
|
2406
2453
|
*/
|
|
2407
2454
|
function flatTree(treeList, options = defaultFieldOptions) {
|
|
2408
2455
|
const { childField, keyField, pidField } = options;
|
|
@@ -2428,7 +2475,7 @@
|
|
|
2428
2475
|
* @param {any[]} nodes
|
|
2429
2476
|
* @param {string} query
|
|
2430
2477
|
* @param {ISearchTreeOpts} options
|
|
2431
|
-
* @
|
|
2478
|
+
* @returns {any[]}
|
|
2432
2479
|
*/
|
|
2433
2480
|
function fuzzySearchTree(nodes, query, options = defaultSearchTreeOptions) {
|
|
2434
2481
|
const result = [];
|
|
@@ -2594,12 +2641,244 @@
|
|
|
2594
2641
|
return !isNullOrUnDef(getGlobal('btoa')) ? getGlobal('btoa')(binaryString) : weBtoa(binaryString);
|
|
2595
2642
|
}
|
|
2596
2643
|
|
|
2644
|
+
// 邮箱
|
|
2645
|
+
const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
2646
|
+
/**
|
|
2647
|
+
* 判断字符串是否为邮箱格式,不对邮箱真实性做验证,如域名是否正确等
|
|
2648
|
+
* @param {string} value
|
|
2649
|
+
* @returns {boolean}
|
|
2650
|
+
*/
|
|
2651
|
+
const isEmail = (value) => EMAIL_REGEX.test(value);
|
|
2652
|
+
// 手机号码 (中国大陆)
|
|
2653
|
+
// reference: https://www.runoob.com/regexp/regexp-syntax.html (?: 是非捕获元之一)
|
|
2654
|
+
const PHONE_REGEX = /^(?:(?:\+|00)86)?1\d{10}$/;
|
|
2655
|
+
/**
|
|
2656
|
+
* 判断字符串是否为宽松手机格式,即首位为 1 的 11 位数字都属于手机号
|
|
2657
|
+
* @param {string} value
|
|
2658
|
+
* @returns {boolean}
|
|
2659
|
+
*/
|
|
2660
|
+
const isPhone = (value) => PHONE_REGEX.test(value);
|
|
2661
|
+
// 身份证号码
|
|
2662
|
+
// http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/
|
|
2663
|
+
// ["北京市", "天津市", "河北省", "山西省", "内蒙古自治区",
|
|
2664
|
+
// "辽宁省", "吉林省", "黑龙江省",
|
|
2665
|
+
// "上海市", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省",
|
|
2666
|
+
// "河南省", "湖北省", "湖南省", "广东省", "广西壮族自治区", "海南省",
|
|
2667
|
+
// "重庆市", "四川省", "贵州省", "云南省", "西藏自治区",
|
|
2668
|
+
// "陕西省", "甘肃省", "青海省","宁夏回族自治区", "新疆维吾尔自治区",
|
|
2669
|
+
// "台湾省",
|
|
2670
|
+
// "香港特别行政区", "澳门特别行政区"]
|
|
2671
|
+
// ["11", "12", "13", "14", "15",
|
|
2672
|
+
// "21", "22", "23",
|
|
2673
|
+
// "31", "32", "33", "34", "35", "36", "37",
|
|
2674
|
+
// "41", "42", "43", "44", "45", "46",
|
|
2675
|
+
// "50", "51", "52", "53", "54",
|
|
2676
|
+
// "61", "62", "63", "64", "65",
|
|
2677
|
+
// "71",
|
|
2678
|
+
// "81", "82"]
|
|
2679
|
+
// 91 国外
|
|
2680
|
+
const IDNO_RE = /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|7[1]|8[1-2]|9[1])\d{4}(18|19|20)\d{2}[01]\d[0123]\d{4}[\dxX]$/;
|
|
2681
|
+
/**
|
|
2682
|
+
* 判断字符串是否为身份证号码格式
|
|
2683
|
+
* @param {string} value
|
|
2684
|
+
* @returns {boolean}
|
|
2685
|
+
*/
|
|
2686
|
+
const isIdNo = (value) => {
|
|
2687
|
+
const isSameFormat = IDNO_RE.test(value);
|
|
2688
|
+
if (!isSameFormat)
|
|
2689
|
+
return false;
|
|
2690
|
+
const year = Number(value.slice(6, 10));
|
|
2691
|
+
const month = Number(value.slice(10, 12));
|
|
2692
|
+
const date = Number(value.slice(12, 14));
|
|
2693
|
+
const d = new Date(year, month - 1, date);
|
|
2694
|
+
const isSameDate = d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === date;
|
|
2695
|
+
if (!isSameDate)
|
|
2696
|
+
return false;
|
|
2697
|
+
// 将身份证号码前面的17位数分别乘以不同的系数;
|
|
2698
|
+
// 从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2
|
|
2699
|
+
// 将这17位数字和系数相乘的结果相加;
|
|
2700
|
+
// 用加出来和除以11,看余数是多少;
|
|
2701
|
+
// 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字;
|
|
2702
|
+
// 其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2
|
|
2703
|
+
// 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。
|
|
2704
|
+
const coefficientList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
2705
|
+
const residueList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
2706
|
+
let sum = 0;
|
|
2707
|
+
for (let start = 0; start < 17; start++) {
|
|
2708
|
+
sum += Number(value.slice(start, start + 1)) * coefficientList[start];
|
|
2709
|
+
}
|
|
2710
|
+
return residueList[sum % 11] === value.slice(-1);
|
|
2711
|
+
};
|
|
2712
|
+
const URL_REGEX = /^(https?|ftp):\/\/([^\s/$.?#].[^\s]*)$/i;
|
|
2713
|
+
const HTTP_URL_REGEX = /^https?:\/\/([^\s/$.?#].[^\s]*)$/i;
|
|
2714
|
+
/**
|
|
2715
|
+
* 判断字符串是否为 url 格式,支持 http、https、ftp 协议,支持域名或者 ipV4
|
|
2716
|
+
* @param {string} value
|
|
2717
|
+
* @returns {boolean}
|
|
2718
|
+
*/
|
|
2719
|
+
const isUrl = (url, includeFtp = false) => {
|
|
2720
|
+
const regex = includeFtp ? URL_REGEX : HTTP_URL_REGEX;
|
|
2721
|
+
return regex.test(url);
|
|
2722
|
+
};
|
|
2723
|
+
// ipv4
|
|
2724
|
+
const IPV4_REGEX = /^(?:(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/;
|
|
2725
|
+
// ipv6
|
|
2726
|
+
const IPV6_REGEX = /^(([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}|([\da-fA-F]{1,4}:){1,7}:|([\da-fA-F]{1,4}:){1,6}:[\da-fA-F]{1,4}|([\da-fA-F]{1,4}:){1,5}(:[\da-fA-F]{1,4}){1,2}|([\da-fA-F]{1,4}:){1,4}(:[\da-fA-F]{1,4}){1,3}|([\da-fA-F]{1,4}:){1,3}(:[\da-fA-F]{1,4}){1,4}|([\da-fA-F]{1,4}:){1,2}(:[\da-fA-F]{1,4}){1,5}|[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,6})|:((:[\da-fA-F]{1,4}){1,7}|:)|fe80:(:[\da-fA-F]{0,4}){0,4}%[\da-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d)|([\da-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?\d)?\d)\.){3}(25[0-5]|(2[0-4]|1?\d)?\d))$/i;
|
|
2727
|
+
/**
|
|
2728
|
+
* 判断字符串是否为 IPV4 格式,不对 ip 真实性做验证
|
|
2729
|
+
* @param {string} value
|
|
2730
|
+
* @returns {boolean}
|
|
2731
|
+
*/
|
|
2732
|
+
const isIpV4 = (value) => IPV4_REGEX.test(value);
|
|
2733
|
+
/**
|
|
2734
|
+
* 判断字符串是否为 IPV6 格式,不对 ip 真实性做验证
|
|
2735
|
+
* @param {string} value
|
|
2736
|
+
* @returns {boolean}
|
|
2737
|
+
*/
|
|
2738
|
+
const isIpV6 = (value) => IPV6_REGEX.test(value);
|
|
2739
|
+
const INTEGER_RE = /^(-?[1-9]\d*|0)$/;
|
|
2740
|
+
/**
|
|
2741
|
+
* 判断字符串是否为整数(自然数),即 ...,-3,-2,-1,0,1,2,3,...
|
|
2742
|
+
* @param {string} value
|
|
2743
|
+
* @returns {boolean}
|
|
2744
|
+
*/
|
|
2745
|
+
const isInteger = (value) => INTEGER_RE.test(value);
|
|
2746
|
+
const FLOAT_RE = /^-?([1-9]\d*|0)\.\d*[1-9]$/;
|
|
2747
|
+
/**
|
|
2748
|
+
* 判断字符串是否为浮点数,即必须有小数点的有理数
|
|
2749
|
+
* @param {string} value
|
|
2750
|
+
* @returns {boolean}
|
|
2751
|
+
*/
|
|
2752
|
+
const isFloat = (value) => FLOAT_RE.test(value);
|
|
2753
|
+
/**
|
|
2754
|
+
* 判断字符串是否为正确数值,包括整数和浮点数
|
|
2755
|
+
* @param {string} value
|
|
2756
|
+
* @returns {boolean}
|
|
2757
|
+
*/
|
|
2758
|
+
const isNumerical = (value) => isInteger(value) || isFloat(value);
|
|
2759
|
+
const DIGIT_RE = /^\d+$/;
|
|
2760
|
+
/**
|
|
2761
|
+
* 判断字符串是否为数字,例如六位数字短信验证码(093031)
|
|
2762
|
+
* @param {string} value
|
|
2763
|
+
* @returns {boolean}
|
|
2764
|
+
*/
|
|
2765
|
+
const isDigit = (value) => DIGIT_RE.test(value);
|
|
2766
|
+
|
|
2767
|
+
/**
|
|
2768
|
+
* 去除字符串中重复字符
|
|
2769
|
+
* @param {string} str
|
|
2770
|
+
* @returns string
|
|
2771
|
+
* @example
|
|
2772
|
+
*
|
|
2773
|
+
* uniqueSymbol('1a1bac');
|
|
2774
|
+
* // => '1abc'
|
|
2775
|
+
*/
|
|
2776
|
+
function uniqueSymbol(str) {
|
|
2777
|
+
return [...new Set(str.trim().split(''))].join('');
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* 转义所有特殊字符
|
|
2781
|
+
* @param {string} str 原字符串
|
|
2782
|
+
* reference: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_expressions
|
|
2783
|
+
* @returns string
|
|
2784
|
+
*/
|
|
2785
|
+
function escapeRegExp(str) {
|
|
2786
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); //$&表示整个被匹配的字符串
|
|
2787
|
+
}
|
|
2788
|
+
/**
|
|
2789
|
+
* 根据左右匹配符号生产解析变量(自动删除变量内的空白)
|
|
2790
|
+
* @param {string} leftMatchSymbol
|
|
2791
|
+
* @param {string} rightMatchSymbol
|
|
2792
|
+
* @returns RegExp
|
|
2793
|
+
*/
|
|
2794
|
+
function parseVariableRegExp(leftMatchSymbol, rightMatchSymbol) {
|
|
2795
|
+
return new RegExp(`${escapeRegExp(leftMatchSymbol.trim())}\\s*([^${escapeRegExp(uniqueSymbol(leftMatchSymbol))}${escapeRegExp(uniqueSymbol(rightMatchSymbol))}\\s]*)\\s*${rightMatchSymbol.trim()}`, 'g');
|
|
2796
|
+
}
|
|
2797
|
+
/**
|
|
2798
|
+
* 解析字符串的插值变量
|
|
2799
|
+
* @param {string} str 字符串
|
|
2800
|
+
* @param {string} leftMatchSymbol 变量左侧匹配符号,默认:{
|
|
2801
|
+
* @param {string} rightMatchSymbol 变量右侧匹配符号,默认:}
|
|
2802
|
+
* @returns string[]
|
|
2803
|
+
* @example
|
|
2804
|
+
*
|
|
2805
|
+
* default match symbol {} same as /{\s*([^{}\s]*)\s*}/g
|
|
2806
|
+
*/
|
|
2807
|
+
function parseVarFromString(str, leftMatchSymbol = '{', rightMatchSymbol = '}') {
|
|
2808
|
+
return Array.from(str.matchAll(parseVariableRegExp(leftMatchSymbol, rightMatchSymbol))).map(el => el?.[1]);
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* 替换字符串中的插值变量
|
|
2812
|
+
* @param {string} sourceStr
|
|
2813
|
+
* @param {Record<string, any>} targetObj
|
|
2814
|
+
* @param {string} leftMatchSymbol 变量左侧匹配符号,默认:{
|
|
2815
|
+
* @param {string} rightMatchSymbol 变量右侧匹配符号,默认:}
|
|
2816
|
+
* @returns string
|
|
2817
|
+
*/
|
|
2818
|
+
function replaceVarFromString(sourceStr, targetObj, leftMatchSymbol = '{', rightMatchSymbol = '}') {
|
|
2819
|
+
return sourceStr.replace(new RegExp(parseVariableRegExp(leftMatchSymbol, rightMatchSymbol)), function (m, p1) {
|
|
2820
|
+
return objectHas(targetObj, p1) ? targetObj[p1] : m;
|
|
2821
|
+
});
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* 在指定作用域中执行代码
|
|
2825
|
+
* @param {string} code 要执行的代码(需包含 return 语句或表达式)
|
|
2826
|
+
* @param {Object} scope 作用域对象(键值对形式的变量环境)
|
|
2827
|
+
* @returns 代码执行结果
|
|
2828
|
+
*
|
|
2829
|
+
* @example
|
|
2830
|
+
* // 测试用例 1: 基本变量访问
|
|
2831
|
+
* executeInScope("return a + b;", { a: 1, b: 2 });
|
|
2832
|
+
* // 3
|
|
2833
|
+
*
|
|
2834
|
+
* // 测试用例 2: 支持复杂表达式和运算
|
|
2835
|
+
* executeInScope(
|
|
2836
|
+
* "return Array.from({ length: 3 }, (_, i) => base + i);",
|
|
2837
|
+
* { base: 100 }
|
|
2838
|
+
* );
|
|
2839
|
+
* // [100, 101, 102]
|
|
2840
|
+
*
|
|
2841
|
+
* // 支持外传函数作用域执行
|
|
2842
|
+
* const scope = {
|
|
2843
|
+
* $: {
|
|
2844
|
+
* fun: {
|
|
2845
|
+
* time: {
|
|
2846
|
+
* now: function () {
|
|
2847
|
+
* return new Date();
|
|
2848
|
+
* },
|
|
2849
|
+
* },
|
|
2850
|
+
* },
|
|
2851
|
+
* },
|
|
2852
|
+
* };
|
|
2853
|
+
* executeInScope("return $.fun.time.now()", scope)
|
|
2854
|
+
*/
|
|
2855
|
+
function executeInScope(code, scope = {}) {
|
|
2856
|
+
// 提取作用域对象的键和值
|
|
2857
|
+
const keys = Object.keys(scope);
|
|
2858
|
+
const values = keys.map(key => scope[key]);
|
|
2859
|
+
try {
|
|
2860
|
+
// 动态创建函数,将作用域的键作为参数,代码作为函数体
|
|
2861
|
+
const func = new Function(...keys, `return (() => { ${code} })()`);
|
|
2862
|
+
// 调用函数并传入作用域的值
|
|
2863
|
+
return func(...values);
|
|
2864
|
+
}
|
|
2865
|
+
catch (error) {
|
|
2866
|
+
throw new Error(`代码执行失败: ${error.message}`);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
exports.EMAIL_REGEX = EMAIL_REGEX;
|
|
2597
2871
|
exports.HEX_POOL = HEX_POOL;
|
|
2872
|
+
exports.HTTP_URL_REGEX = HTTP_URL_REGEX;
|
|
2873
|
+
exports.IPV4_REGEX = IPV4_REGEX;
|
|
2874
|
+
exports.IPV6_REGEX = IPV6_REGEX;
|
|
2875
|
+
exports.PHONE_REGEX = PHONE_REGEX;
|
|
2598
2876
|
exports.STRING_ARABIC_NUMERALS = STRING_ARABIC_NUMERALS;
|
|
2599
2877
|
exports.STRING_LOWERCASE_ALPHA = STRING_LOWERCASE_ALPHA;
|
|
2600
2878
|
exports.STRING_POOL = STRING_POOL;
|
|
2601
2879
|
exports.STRING_UPPERCASE_ALPHA = STRING_UPPERCASE_ALPHA;
|
|
2602
2880
|
exports.UNIQUE_NUMBER_SAFE_LENGTH = UNIQUE_NUMBER_SAFE_LENGTH;
|
|
2881
|
+
exports.URL_REGEX = URL_REGEX;
|
|
2603
2882
|
exports.add = add;
|
|
2604
2883
|
exports.addClass = addClass;
|
|
2605
2884
|
exports.arrayEach = arrayEach;
|
|
@@ -2630,9 +2909,10 @@
|
|
|
2630
2909
|
exports.downloadHref = downloadHref;
|
|
2631
2910
|
exports.downloadURL = downloadURL;
|
|
2632
2911
|
exports.encodeToBase64 = encodeToBase64;
|
|
2912
|
+
exports.escapeRegExp = escapeRegExp;
|
|
2913
|
+
exports.executeInScope = executeInScope;
|
|
2633
2914
|
exports.flatTree = flatTree;
|
|
2634
2915
|
exports.forEachDeep = forEachDeep;
|
|
2635
|
-
exports.forEachMap = forEachMap;
|
|
2636
2916
|
exports.formatDate = formatDate;
|
|
2637
2917
|
exports.formatNumber = formatNumber;
|
|
2638
2918
|
exports.formatTree = formatTree;
|
|
@@ -2647,23 +2927,34 @@
|
|
|
2647
2927
|
exports.isBigInt = isBigInt;
|
|
2648
2928
|
exports.isBoolean = isBoolean;
|
|
2649
2929
|
exports.isDate = isDate;
|
|
2930
|
+
exports.isDigit = isDigit;
|
|
2650
2931
|
exports.isDomReady = isDomReady;
|
|
2932
|
+
exports.isEmail = isEmail;
|
|
2651
2933
|
exports.isEmpty = isEmpty;
|
|
2652
2934
|
exports.isError = isError;
|
|
2935
|
+
exports.isFloat = isFloat;
|
|
2653
2936
|
exports.isFunction = isFunction;
|
|
2937
|
+
exports.isIdNo = isIdNo;
|
|
2938
|
+
exports.isInteger = isInteger;
|
|
2939
|
+
exports.isIpV4 = isIpV4;
|
|
2940
|
+
exports.isIpV6 = isIpV6;
|
|
2654
2941
|
exports.isJsonString = isJsonString;
|
|
2655
2942
|
exports.isNaN = isNaN;
|
|
2656
2943
|
exports.isNull = isNull;
|
|
2657
2944
|
exports.isNullOrUnDef = isNullOrUnDef;
|
|
2658
2945
|
exports.isNumber = isNumber;
|
|
2946
|
+
exports.isNumerical = isNumerical;
|
|
2659
2947
|
exports.isObject = isObject;
|
|
2948
|
+
exports.isPhone = isPhone;
|
|
2660
2949
|
exports.isPlainObject = isPlainObject;
|
|
2661
2950
|
exports.isPrimitive = isPrimitive;
|
|
2662
2951
|
exports.isRegExp = isRegExp;
|
|
2663
2952
|
exports.isString = isString;
|
|
2664
2953
|
exports.isSymbol = isSymbol;
|
|
2665
2954
|
exports.isUndefined = isUndefined;
|
|
2955
|
+
exports.isUrl = isUrl;
|
|
2666
2956
|
exports.isValidDate = isValidDate;
|
|
2957
|
+
exports.mapDeep = mapDeep;
|
|
2667
2958
|
exports.multiply = multiply;
|
|
2668
2959
|
exports.numberAbbr = numberAbbr;
|
|
2669
2960
|
exports.numberToHex = numberToHex;
|
|
@@ -2680,6 +2971,7 @@
|
|
|
2680
2971
|
exports.onDomReady = onDomReady;
|
|
2681
2972
|
exports.once = once;
|
|
2682
2973
|
exports.parseQueryParams = parseQueryParams;
|
|
2974
|
+
exports.parseVarFromString = parseVarFromString;
|
|
2683
2975
|
exports.pathJoin = pathJoin;
|
|
2684
2976
|
exports.pathNormalize = pathNormalize;
|
|
2685
2977
|
exports.qsParse = qsParse;
|
|
@@ -2688,6 +2980,7 @@
|
|
|
2688
2980
|
exports.randomString = randomString;
|
|
2689
2981
|
exports.randomUuid = randomUuid;
|
|
2690
2982
|
exports.removeClass = removeClass;
|
|
2983
|
+
exports.replaceVarFromString = replaceVarFromString;
|
|
2691
2984
|
exports.searchTreeById = searchTreeById;
|
|
2692
2985
|
exports.setGlobal = setGlobal;
|
|
2693
2986
|
exports.setStyle = setStyle;
|
|
@@ -2706,6 +2999,7 @@
|
|
|
2706
2999
|
exports.typeIs = typeIs;
|
|
2707
3000
|
exports.uniqueNumber = uniqueNumber;
|
|
2708
3001
|
exports.uniqueString = uniqueString;
|
|
3002
|
+
exports.uniqueSymbol = uniqueSymbol;
|
|
2709
3003
|
exports.urlDelParams = urlDelParams;
|
|
2710
3004
|
exports.urlParse = urlParse;
|
|
2711
3005
|
exports.urlSetParams = urlSetParams;
|