(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.diff = {})); })(this, (function (exports) { 'use strict'; const NODE_TYPE={ELEMENT:1,ATTR:2,TEXT:3,COMMENT:8,FRAGMENT:11};const EMPTY={STR:"",NUM:1,OBJ:{},ARR:[],MAP:new Map,SET:new Set,DOM:{},FUN:()=>{}};const PATCH_TYPE={SET_ATTRIBUTE:0,REMOVE_ATTRIBUTE:1,NODE_VALUE:2,INSERT_BEFORE:3,REPLACE_CHILD:4,REMOVE_CHILD:5};const StateCache=new Map;const NodeCache=new Map;const MiddlewareCache=new Set;const CreateTreeHookCache=new Set;const CreateNodeHookCache=new Set;const SyncTreeHookCache=new Set;const ReleaseHookCache=new Set;const ParseHookCache=new Set; var internalProcess = typeof process!=="undefined"?process:{env:{NODE_ENV:"development"},argv:[]}; var globalThis = typeof global==="object"?global:(typeof window==="object"?window:self)||{}; const{parseInt}=Number;const{parse: parse$1}=JSON;const globalConfig={collectMetrics:true,executeScripts:true};function formatValue(value,type){const valueAsString=String(value);switch(type){case"boolean":{return valueAsString!=="false"}case"string":{return valueAsString}case"number":{return parseInt(valueAsString,10)}case"object":{return parse$1(valueAsString)}}}function getConfig(name,defaultValue,type=typeof defaultValue,overrides){const{location,URLSearchParams}=globalThis;const hasSearchParams=typeof URLSearchParams!=="undefined";const hasLocation=typeof location!=="undefined";const useSearchParams=hasSearchParams&&hasLocation;const useEnv=internalProcess.env;if(overrides&&name in overrides){return overrides[name]}const keyName=`DIFF_${name.replace(/[^a-zA-Z0-9]/,"")}`;if(useSearchParams){const searchParams=new URLSearchParams(location.search);const lowerKey=keyName.toLowerCase();if(searchParams.has(lowerKey)){return formatValue(decodeURIComponent(String(searchParams.get(lowerKey))),type)}}const upperKey=keyName.toUpperCase();if(useEnv&&upperKey in internalProcess.env){return formatValue(internalProcess.env[upperKey.toUpperCase()],type)}return defaultValue} const size=getConfig("initialPoolSize",5000);const free=new Set;const allocate=new Set;const protect$1=new Set;const shape=()=>({rawNodeName:EMPTY.STR,nodeName:EMPTY.STR,nodeValue:EMPTY.STR,nodeType:NODE_TYPE.ELEMENT,key:EMPTY.STR,childNodes:[],attributes:{}});const memory$3={free,allocated:allocate,protected:protect$1};let freeValues=free.values();const Pool={size,memory: memory$3,fill(){for(let i=free.size;i{if(free.size!==this.size){free.delete(value);}});}},get(){const{value=shape(),done}=freeValues.next();if(done){freeValues=free.values();}free.delete(value);allocate.add(value);return value},protect(vTree){allocate.delete(vTree);protect$1.add(vTree);},unprotect(vTree){if(protect$1.has(vTree)||allocate.has(vTree)){protect$1.delete(vTree);allocate.add(vTree);}}};Pool.fill(); const{isArray: isArray$2}=Array;const{memory: memory$2}=Pool;const fragmentName="#document-fragment";const textName$1="#text";function flatten(vTrees,retVal=[]){for(let i=0;i{if(domNode===input){entry=vTree;}});entry=entry||createTree(inputAsHTMLEl.nodeName,attributes,childNodes);entry.attributes={...entry.attributes,...attributes};entry.childNodes=childNodes;NodeCache.set(entry,inputAsHTMLEl);return entry}if(isObject&&!attributes){const{rawNodeName,nodeName,nodeValue,attributes,childNodes,children}=input;const treeName=rawNodeName||nodeName;const vTree=createTree(treeName,attributes||null,children||childNodes);if(nodeValue){vTree.nodeValue=nodeValue;}return vTree}if(rest.length){childNodes=[childNodes,...rest];}entry=Pool.get();const isTextNode=input===textName$1;const isString=typeof input==="string";if(isString){entry.rawNodeName=input;entry.nodeName=entry.rawNodeName.toLowerCase();}else {entry.rawNodeName=input;entry.nodeName=fragmentName;}entry.nodeValue=EMPTY.STR;entry.key=EMPTY.STR;entry.childNodes.length=0;entry.attributes={};const useAttributes=isArray$2(attributes)||typeof attributes!=="object";const useNodes=useAttributes?attributes:childNodes;const allNodes=flatten(isArray$2(useNodes)?useNodes:[useNodes]);if(isTextNode){const nodeValue=allNodes.join(EMPTY.STR);entry.nodeType=NODE_TYPE.TEXT;entry.nodeValue=String(nodeValue);return entry}else if(entry.nodeName===fragmentName){entry.nodeType=NODE_TYPE.FRAGMENT;}else if(input==="#comment"){entry.nodeType=NODE_TYPE.COMMENT;}else {entry.nodeType=NODE_TYPE.ELEMENT;}if(useNodes&&allNodes.length&&(!attributes||!attributes.childNodes)){for(let i=0;i{if(retVal=fn(entry)){entry=createTree(retVal);}});}return entry} const prefix="diffHTML";const marks=new Map;let count=0;function makeMeasure(transaction){const{mount,input}=transaction;const inputAsVTree=input;const id=count++;if(!getConfig("collectMetrics",false)){return EMPTY.FUN}return name=>{name=`[${id}] ${name}`;const{host}=mount;if(mount&&host){name=`${host.constructor.name} ${name}`;}else if(inputAsVTree&&typeof inputAsVTree.rawNodeName==="function"){name=`${inputAsVTree.rawNodeName.name} ${name}`;}const endName=`${name}-end`;if(marks.has(name)){const prevMark=marks.get(name)||0;const totalMs=(performance.now()-prevMark).toFixed(3);marks.delete(name);performance.mark(endName);performance.measure(`${prefix} ${name} (${totalMs}ms)`,name,endName);}else {marks.set(name,performance.now());performance.mark(name);}}} const{protect,unprotect,memory}=Pool;function protectVTree(vTree){protect(vTree);if(vTree.childNodes.length){for(let i=0;i{vTree.attributes={};vTree.childNodes.length=0;vTree.key=EMPTY.STR;memory.free.add(vTree);memory.allocated.delete(vTree);NodeCache.delete(vTree);});} var memory$1 = /*#__PURE__*/Object.freeze({ __proto__: null, protectVTree: protectVTree, unprotectVTree: unprotectVTree, gc: gc }); function shouldUpdate(transaction){const{mount,input,state:{measure},config:options}=transaction;const prop=options.inner?"innerHTML":"outerHTML";measure("should update");const mountAsHTMLEl=mount;if(typeof input==="string"&&mountAsHTMLEl[prop]===input){return transaction.abort(true)}measure("should update");} const hasIdle=typeof requestIdleCallback!=="undefined";let gcTimerId=-1;const scheduleTimeout=fn=>(hasIdle?requestIdleCallback:setTimeout)(fn);const cancelTimeout=id=>(hasIdle?cancelIdleCallback:clearTimeout)(id);function release(mount){if(StateCache.has(mount)){const{mutationObserver,oldTree}=StateCache.get(mount);mutationObserver&&mutationObserver.disconnect();if(oldTree&&!NodeCache.has(oldTree)){ReleaseHookCache.forEach(fn=>fn(oldTree));unprotectVTree(oldTree);}StateCache.delete(mount);}if(!mount){return}const asHTMLElement=mount;if(asHTMLElement.childNodes&&asHTMLElement.childNodes.length){for(let i=0;i{if(domNode===asHTMLElement){ReleaseHookCache.forEach(fn=>fn(vTree));unprotectVTree(vTree);}});cancelTimeout(gcTimerId);gcTimerId=scheduleTimeout(gc);} function reconcileTrees(transaction){const{state,mount,input,config:options}=transaction;const{inner}=options;const mountAsHTMLEl=mount;if(state.mutationObserver&&!state.isDirty){state.isDirty=Boolean(state.mutationObserver.takeRecords().length);}else if(!state.mutationObserver){state.isDirty=false;}if(state.isDirty||!state.oldTree){release(mountAsHTMLEl);if(mountAsHTMLEl.ownerDocument&&state.mutationObserver){state.mutationObserver.observe(mountAsHTMLEl,{subtree:true,childList:true,attributes:true,characterData:true});}state.oldTree=createTree(mountAsHTMLEl);protectVTree(state.oldTree);StateCache.set(mount,state);}const{nodeName,attributes}=state.oldTree;if(!transaction.newTree){transaction.newTree=createTree(input);}const inputAsVTree=transaction.newTree;if(!inner&&inputAsVTree.nodeType===NODE_TYPE.FRAGMENT&&state.oldTree.nodeType!==NODE_TYPE.FRAGMENT){let foundElements=[];for(let i=0;i1){transaction.newTree=createTree(inputAsVTree.childNodes);}}transaction.oldTree=state.oldTree;const{oldTree,newTree}=transaction;if(inner&&oldTree&&newTree){const isUnknown=typeof newTree.rawNodeName!=="string";const isFragment=newTree.nodeType===NODE_TYPE.FRAGMENT;const children=isFragment&&!isUnknown?newTree.childNodes:newTree;transaction.newTree=createTree(nodeName,attributes,children);}} const{assign: assign$1}=Object;const{max}=Math;const keyNames=["old","new"];const textName="#text";function syncTree(oldTree,newTree,patches=[],state={},transaction=EMPTY.OBJ,attributesOnly){if(!oldTree)oldTree=EMPTY.OBJ;if(!newTree)newTree=EMPTY.OBJ;const{svgElements=new Set}=state;const isEmpty=oldTree===EMPTY.OBJ||attributesOnly;let shortCircuit=null;if(SyncTreeHookCache.size){SyncTreeHookCache.forEach(fn=>{const entry=fn(oldTree,newTree,transaction);if(entry&&entry===oldTree){shortCircuit=patches;}else if(entry===false){shortCircuit=false;}else if(entry){assign$1(newTree,entry);}});}if(shortCircuit!==null||!newTree){return shortCircuit}const oldNodeName=oldTree.nodeName;const newNodeName=newTree.nodeName;const isSVG=newNodeName==="svg"||svgElements.has(newTree);if(newNodeName===textName){if(oldNodeName===textName&&oldTree.nodeValue!==newTree.nodeValue){patches.push(PATCH_TYPE.NODE_VALUE,oldTree,newTree.nodeValue,oldTree.nodeValue);oldTree.nodeValue=newTree.nodeValue;return patches}else if(isEmpty){patches.push(PATCH_TYPE.NODE_VALUE,newTree,newTree.nodeValue,null);return patches}}const newChildNodes=newTree.childNodes||[];if(newTree.nodeType===NODE_TYPE.ELEMENT){const oldAttributes=isEmpty?EMPTY.OBJ:oldTree.attributes;const newAttributes=newTree.attributes||EMPTY.OBJ;for(let key in newAttributes){const value=newAttributes[key];if(key in oldAttributes&&oldAttributes[key]===newAttributes[key]){continue}if(!isEmpty){oldAttributes[key]=value;}if((!oldTree||oldTree.nodeName!=="script")&&newTree.nodeName==="script"&&key==="type"){continue}patches.push(PATCH_TYPE.SET_ATTRIBUTE,isEmpty?newTree:oldTree,key,value);}if(!isEmpty){for(let key in oldAttributes){if(key in newAttributes){continue}patches.push(PATCH_TYPE.REMOVE_ATTRIBUTE,oldTree,key);delete oldAttributes[key];}}}if(attributesOnly){for(let i=0;ii){oldChildNodes.splice(lookupIndex,1);}patches.push(PATCH_TYPE.REPLACE_CHILD,newChildNode,oldChildNode);}}if(oldChildNodes.length!==newChildNodes.length){for(let i=newChildNodes.length;i{if(retVal=fn(vTree)){domNodeCheck=retVal;}});if(!ownerDocument){return domNodeCheck}let domNode=domNodeCheck;if(!domNode){if(nodeName==="#comment"){domNode=ownerDocument.createComment(vTree.nodeValue||EMPTY.STR);}else if(nodeName==="#text"){domNode=ownerDocument.createTextNode(vTree.nodeValue||EMPTY.STR);}else if(nodeName==="#document-fragment"){domNode=ownerDocument.createDocumentFragment();}else if(isSVG){domNode=ownerDocument.createElementNS(namespace,rawNodeName);}else {domNode=ownerDocument.createElement(rawNodeName);}if(nodeName==="script"){domNode.type="no-execute";}}NodeCache.set(vTree,domNode);for(let i=0;i{const isObject=typeof value==="object"&&value;const isFunction=typeof value==="function";const isSymbol=typeof value==="symbol";const isEvent=name.indexOf("on")===0;const anyNode=domNode;const lowerName=isEvent?name.toLowerCase():name;const blocklistName="s-"+vTree.nodeName+"-"+lowerName;const htmlElement=domNode;if(allowlist.has(blocklistName)){anyNode[lowerName]=value;}else if(!blocklist.has(blocklistName)){try{anyNode[lowerName]=value;allowlist.add(blocklistName);}catch{blocklist.add(blocklistName);}}if(!isObject&&!isFunction&&!isSymbol){const emptyValue=value===null||value===undefined||value===true;htmlElement.setAttribute(lowerName,emptyValue?EMPTY.STR:value);}else if(isObject&&lowerName==="style"){const valueKeys=keys$1(value);for(let i=0;i{const blocklistName="r-"+vTree.nodeName+"-"+name;const anyNode=domNode;if(allowlist.has(blocklistName)){anyNode[name]=undefined;delete anyNode[name];}else if(!blocklist.has(blocklistName)){try{anyNode[name]=undefined;delete anyNode[name];allowlist.add(blocklistName);}catch{blocklist.add(blocklistName);}}domNode.removeAttribute(name);};function patchNode$1(patches,state=EMPTY.OBJ){const{ownerDocument,svgElements=new Set}=state;const{length}=patches;let i=0;while(true){const patchType=patches[i];if(i===length){break}switch(patchType){case PATCH_TYPE.REMOVE_ATTRIBUTE:case PATCH_TYPE.SET_ATTRIBUTE:{const isSet=patchType===PATCH_TYPE.SET_ATTRIBUTE;const vTree=patches[i+1];const name=patches[i+2];const value=isSet?decodeEntities(patches[i+3]):null;i+=isSet?4:3;const isSVG=svgElements.has(vTree);const domNode=createNode(vTree,ownerDocument,isSVG);protectVTree(vTree);const setOrRemove=isSet?setAttribute:removeAttribute;setOrRemove(vTree,domNode,name,value);break}case PATCH_TYPE.NODE_VALUE:{const vTree=patches[i+1];const nodeValue=patches[i+2];const isSVG=svgElements.has(vTree);i+=4;const domNode=createNode(vTree,ownerDocument,isSVG);protectVTree(vTree);if(nodeValue.includes("&")){domNode.nodeValue=decodeEntities(nodeValue);}else {domNode.nodeValue=nodeValue;}break}case PATCH_TYPE.INSERT_BEFORE:{const vTree=patches[i+1];const newTree=patches[i+2];let refTree=patches[i+3];i+=4;if(!NodeCache.has(vTree)&&vTree!==$$insertAfter){continue}let domNode=NodeCache.get(vTree);if(vTree===$$insertAfter){const refNode=NodeCache.get(refTree);if(refNode){domNode=refNode.parentNode;refTree=refNode.nextSibling?refNode.nextSibling:null;}}const isSVG=svgElements.has(newTree);protectVTree(newTree);const refNode=refTree&&createNode(refTree,ownerDocument,isSVG);const newNode=createNode(newTree,ownerDocument,isSVG);domNode.insertBefore(newNode,refNode||null);break}case PATCH_TYPE.REPLACE_CHILD:{const newTree=patches[i+1];const oldTree=patches[i+2];i+=3;const isSVG=svgElements.has(newTree);const oldDomNode=NodeCache.get(oldTree);const newDomNode=createNode(newTree,ownerDocument,isSVG);if(!oldDomNode||!oldDomNode.parentNode){break}protectVTree(newTree);oldDomNode.parentNode.insertBefore(newDomNode,oldDomNode);oldDomNode.parentNode.removeChild(oldDomNode);unprotectVTree(oldTree);break}case PATCH_TYPE.REMOVE_CHILD:{const vTree=patches[i+1];i+=2;const domNode=NodeCache.get(vTree);if(!domNode||!domNode.parentNode){break}domNode.parentNode.removeChild(domNode);unprotectVTree(vTree);break}}}} function patchNode(transaction){const{mount,state,patches}=transaction;const{measure,scriptsToExecute}=state;measure("patch node");const{ownerDocument}=mount;state.ownerDocument=ownerDocument||globalThis.document;const collectScripts=(vTree)=>{if(vTree.nodeName==="script"){scriptsToExecute.set(vTree,vTree.attributes.type);}};CreateNodeHookCache.add(collectScripts);if(state.ownerDocument){patchNode$1(patches,state);}CreateNodeHookCache.delete(collectScripts);measure("patch node");} function endAsTransaction(transaction){return transaction.end()} const element=globalThis.document?document.createElement("script"):null;function hasModule(){return Boolean(element&&"noModule"in element)} const{assign}=Object;const defaultTasks=[shouldUpdate,reconcileTrees,syncTrees,patchNode,endAsTransaction];const tasks={shouldUpdate,reconcileTrees,syncTrees,patchNode,endAsTransaction};class Transaction{static create(mount,input,options){return new Transaction(mount,input,options)}static flow(transaction,tasks){let retVal=transaction;for(let i=0;i{const label=`invoke ${fn.name||"anon"}`;measure(label);const result=fn(transaction);if(result){tasks.push(result);}measure(label);});}constructor(mount,input,config){this.mount=mount;this.input=input;this.config=config;const useObserver=!config.disableMutationObserver&&"MutationObserver"in(globalThis.window||EMPTY.OBJ);this.state=StateCache.get(mount)||{measure:makeMeasure(this),svgElements:new Set,scriptsToExecute:new Map,mutationObserver:useObserver&&new globalThis.window.MutationObserver(()=>{this.state.isDirty=true;})};this.tasks=getConfig("tasks",defaultTasks,undefined,config).slice();this.endedCallbacks=new Set;StateCache.set(mount,this.state);}start(){if(internalProcess.env.NODE_ENV!=="production"){Transaction.assert(this);}const{state:{measure},tasks}=this;const takeLastTask=tasks.pop();measure("render");this.aborted=false;Transaction.invokeMiddleware(this);takeLastTask&&tasks.push(takeLastTask);return Transaction.flow(this,tasks)}abort(isReturn){this.aborted=true;if(isReturn){return this.tasks[this.tasks.length-1](this)}}end(){const{state,config,mount}=this;const{mutationObserver,measure,svgElements,scriptsToExecute}=state;const mountAsHTMLEl=mount;measure("finalize");this.completed=true;svgElements.clear();state.isRendering=false;state.isDirty=false;StateCache.forEach(state=>{if(state.mutationObserver){state.mutationObserver.takeRecords();}});if(mountAsHTMLEl.ownerDocument&&mutationObserver){mutationObserver.observe(mountAsHTMLEl,{subtree:true,childList:true,attributes:true,characterData:true});}else {state.isDirty=true;}scriptsToExecute.forEach((type,vTree)=>{const oldNode=NodeCache.get(vTree);oldNode.type=type;if(!config.executeScripts||hasModule()&&type==="nomodule"){return}const newNode=assign(oldNode.ownerDocument.createElement("script"),oldNode);for(let key in vTree.attributes){const value=vTree.attributes[key];newNode.setAttribute(key,value);}newNode.textContent=oldNode.textContent;if(StateCache.has(oldNode)){release(oldNode);StateCache.set(newNode,state);}NodeCache.set(vTree,newNode);oldNode.parentNode&&oldNode.parentNode.replaceChild(newNode,oldNode);});scriptsToExecute.clear();this.endedCallbacks.forEach(callback=>callback(this));this.endedCallbacks.clear();measure("finalize");measure("render");if(state.oldTree)protectVTree(state.oldTree);return this}onceEnded(callback){this.endedCallbacks.add(callback);}state=EMPTY.OBJ;mount=EMPTY.OBJ;input=EMPTY.OBJ;oldTree=undefined;newTree=undefined;tasks=[];patches=[]} function escape(unescaped){return unescaped.replace(/[&<>]/g,match=>`&#${match.charCodeAt(0)};`)} const caches={StateCache,NodeCache,MiddlewareCache,CreateTreeHookCache,CreateNodeHookCache,SyncTreeHookCache,ReleaseHookCache,ParseHookCache};var Internals = {decodeEntities,escape,makeMeasure,memory: memory$1,Pool,process:internalProcess,globalConfig,parse:EMPTY.FUN,PATCH_TYPE,NODE_TYPE,createNode,syncTree,Transaction,defaultTasks,tasks,...caches}; function parseNewTree(transaction){const{state,input,config:options}=transaction;const{measure}=state;if(typeof input==="string"){measure("parsing input for new tree");const{childNodes}=Internals.parse(input,options);const vTree=createTree(childNodes);if(vTree){transaction.newTree=vTree;}measure("parsing input for new tree");}} const rawElementsDefaults=["script","noscript","style","template"];const voidElementsDefaults=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"];const endTagOmissionRules={li:{li:EMPTY.NUM},dt:{dt:EMPTY.NUM,dd:EMPTY.NUM},dd:{dt:EMPTY.NUM,dd:EMPTY.NUM},td:{td:EMPTY.NUM,th:EMPTY.NUM},th:{td:EMPTY.NUM,th:EMPTY.NUM},tbody:{tbody:EMPTY.NUM,tfoot:EMPTY.NUM},tfoot:{tbody:EMPTY.NUM,tfoot:EMPTY.NUM}};const openComment=//g;const openTag=/<([^\s\\/>]*)\s?/g;const closeTag=/\s?(\/>)|(<\/(.*?)>)/g;const attribute=/([^>\/\n ])*?(["'])(?:(?=(\\?))\3.)*?\2|.*?(?=\/>|>|\n| )/gsm;const parseAttr=/([^=]*)=(.*)|([^>])/gsm;const text=/([^<]*)/g;function removeQuotes(value){if(typeof value!=="string"){return value}const quotes=["\"","'"];const rootQuote=quotes.indexOf(value[0]);const hasRootQuote=rootQuote!==-1;const trailingQuote=hasRootQuote&"es.indexOf(value[value.length-1]);if(rootQuote!==-1&&trailingQuote===rootQuote){return value.slice(1,value.length-1)}return value}function parse(html,options={}){const root=createTree("#document-fragment",null,[]);if(!html){root.childNodes.push(createTree("#text",EMPTY.STR));return root}if(!options.parser){options.parser=EMPTY.OBJ;}const blockText=new Set(getConfig("rawElements",rawElementsDefaults,"array",options.parser));const voidElements=new Set(getConfig("voidElements",voidElementsDefaults,"array",options.parser));if(!html.includes("<")&&!html.includes(">")){const newTree=createTree("#text",html);root.childNodes.push(newTree);return root}const stack=[root];let i=0;let pointer=root;let isOpen=false;let lastCommentIndex=html.indexOf("