@umbraci/jsmind 0.10.6 → 0.10.8

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.
@@ -5,5 +5,5 @@
5
5
  * Project Home:
6
6
  * https://github.com/hizzgdev/jsmind/
7
7
  */
8
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),"function"!=typeof String.prototype.startsWith&&(String.prototype.startsWith=function(t){return this.slice(0,t.length)===t});const t=1,e=3,r=6,i=1,n=2,o=3,s=4;var a=function(){};let u="undefined"==typeof console?{level:a,log:a,debug:a,info:a,warn:a,error:a}:{level:function(t){u.debug=t>i?a:console.debug;u.info=t>n?a:console.info;u.warn=t>o?a:console.warn;u.error=t>s?a:console.error},log:console.log,debug:console.debug,info:console.info,warn:console.warn,error:console.error};class h{static instanceName="";static preload=!1;constructor({jm:t,pluginOpt:e}){this.jm=t,this.options=e||{}}beforePluginRemove(){}beforePluginDestroy(){this.beforePluginRemove()}}var c=Object.getOwnPropertyNames,l=Object.getOwnPropertySymbols,d=Object.prototype.hasOwnProperty;function f(t,e){return function(r,i,n){return t(r,i,n)&&e(r,i,n)}}function p(t){return function(e,r,i){if(!e||!r||"object"!=typeof e||"object"!=typeof r)return t(e,r,i);var n=i.cache,o=n.get(e),s=n.get(r);if(o&&s)return o===r&&s===e;n.set(e,r),n.set(r,e);var a=t(e,r,i);return n.delete(e),n.delete(r),a}}function y(t){return c(t).concat(l(t))}var g=Object.hasOwn||function(t,e){return d.call(t,e)};function m(t,e){return t===e||!t&&!e&&t!=t&&e!=e}var _=Object.getOwnPropertyDescriptor,b=Object.keys;function v(t,e,r){var i=t.length;if(e.length!==i)return!1;for(;i-- >0;)if(!r.equals(t[i],e[i],i,i,t,e,r))return!1;return!0}function x(t,e){return m(t.getTime(),e.getTime())}function j(t,e){return t.name===e.name&&t.message===e.message&&t.cause===e.cause&&t.stack===e.stack}function S(t,e){return t===e}function w(t,e,r){var i=t.size;if(i!==e.size)return!1;if(!i)return!0;for(var n,o,s=new Array(i),a=t.entries(),u=0;(n=a.next())&&!n.done;){for(var h=e.entries(),c=!1,l=0;(o=h.next())&&!o.done;)if(s[l])l++;else{var d=n.value,f=o.value;if(r.equals(d[0],f[0],u,l,t,e,r)&&r.equals(d[1],f[1],d[0],f[0],t,e,r)){c=s[l]=!0;break}l++}if(!c)return!1;u++}return!0}var k=m;function M(t,e,r){var i=b(t),n=i.length;if(b(e).length!==n)return!1;for(;n-- >0;)if(!N(t,e,r,i[n]))return!1;return!0}function O(t,e,r){var i,n,o,s=y(t),a=s.length;if(y(e).length!==a)return!1;for(;a-- >0;){if(!N(t,e,r,i=s[a]))return!1;if(n=_(t,i),o=_(e,i),(n||o)&&(!n||!o||n.configurable!==o.configurable||n.enumerable!==o.enumerable||n.writable!==o.writable))return!1}return!0}function q(t,e){return m(t.valueOf(),e.valueOf())}function A(t,e){return t.source===e.source&&t.flags===e.flags}function E(t,e,r){var i=t.size;if(i!==e.size)return!1;if(!i)return!0;for(var n,o,s=new Array(i),a=t.values();(n=a.next())&&!n.done;){for(var u=e.values(),h=!1,c=0;(o=u.next())&&!o.done;){if(!s[c]&&r.equals(n.value,o.value,n.value,o.value,t,e,r)){h=s[c]=!0;break}c++}if(!h)return!1}return!0}function P(t,e){var r=t.length;if(e.length!==r)return!1;for(;r-- >0;)if(t[r]!==e[r])return!1;return!0}function C(t,e){return t.hostname===e.hostname&&t.pathname===e.pathname&&t.protocol===e.protocol&&t.port===e.port&&t.hash===e.hash&&t.username===e.username&&t.password===e.password}function N(t,e,r,i){return!("_owner"!==i&&"__o"!==i&&"__v"!==i||!t.$$typeof&&!e.$$typeof)||g(e,i)&&r.equals(t[i],e[i],i,i,t,e,r)}var T=Array.isArray,D="function"==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView:null,I=Object.assign,z=Object.prototype.toString.call.bind(Object.prototype.toString);function F(t){var e=t.areArraysEqual,r=t.areDatesEqual,i=t.areErrorsEqual,n=t.areFunctionsEqual,o=t.areMapsEqual,s=t.areNumbersEqual,a=t.areObjectsEqual,u=t.arePrimitiveWrappersEqual,h=t.areRegExpsEqual,c=t.areSetsEqual,l=t.areTypedArraysEqual,d=t.areUrlsEqual,f=t.unknownTagComparators;return function(t,p,y){if(t===p)return!0;if(null==t||null==p)return!1;var g=typeof t;if(g!==typeof p)return!1;if("object"!==g)return"number"===g?s(t,p,y):"function"===g&&n(t,p,y);var m=t.constructor;if(m!==p.constructor)return!1;if(m===Object)return a(t,p,y);if(T(t))return e(t,p,y);if(null!=D&&D(t))return l(t,p,y);if(m===Date)return r(t,p,y);if(m===RegExp)return h(t,p,y);if(m===Map)return o(t,p,y);if(m===Set)return c(t,p,y);var _,b=z(t);if("[object Date]"===b)return r(t,p,y);if("[object RegExp]"===b)return h(t,p,y);if("[object Map]"===b)return o(t,p,y);if("[object Set]"===b)return c(t,p,y);if("[object Object]"===b)return"function"!=typeof t.then&&"function"!=typeof p.then&&a(t,p,y);if("[object URL]"===b)return d(t,p,y);if("[object Error]"===b)return i(t,p,y);if("[object Arguments]"===b)return a(t,p,y);if("[object Boolean]"===b||"[object Number]"===b||"[object String]"===b)return u(t,p,y);if(f){var v=f[b];if(!v){var x=null!=(_=t)?_[Symbol.toStringTag]:void 0;x&&(v=f[x])}if(v)return v(t,p,y)}return!1}}var K=R();function R(t){void 0===t&&(t={});var e,r=t.circular,i=void 0!==r&&r,n=t.createInternalComparator,o=t.createState,s=t.strict,a=void 0!==s&&s,u=function(t){var e=t.circular,r=t.createCustomConfig,i=t.strict,n={areArraysEqual:i?O:v,areDatesEqual:x,areErrorsEqual:j,areFunctionsEqual:S,areMapsEqual:i?f(w,O):w,areNumbersEqual:k,areObjectsEqual:i?O:M,arePrimitiveWrappersEqual:q,areRegExpsEqual:A,areSetsEqual:i?f(E,O):E,areTypedArraysEqual:i?O:P,areUrlsEqual:C,unknownTagComparators:void 0};if(r&&(n=I({},n,r(n))),e){var o=p(n.areArraysEqual),s=p(n.areMapsEqual),a=p(n.areObjectsEqual),u=p(n.areSetsEqual);n=I({},n,{areArraysEqual:o,areMapsEqual:s,areObjectsEqual:a,areSetsEqual:u})}return n}(t),h=F(u);return function(t){var e=t.circular,r=t.comparator,i=t.createState,n=t.equals,o=t.strict;if(i)return function(t,s){var a=i(),u=a.cache,h=void 0===u?e?new WeakMap:void 0:u,c=a.meta;return r(t,s,{cache:h,equals:n,meta:c,strict:o})};if(e)return function(t,e){return r(t,e,{cache:new WeakMap,equals:n,meta:void 0,strict:o})};var s={cache:void 0,equals:n,meta:void 0,strict:o};return function(t,e){return r(t,e,s)}}({circular:i,comparator:h,createState:o,equals:n?n(h):(e=h,function(t,r,i,n,o,s,a){return e(t,r,a)}),strict:a})}function B(t,e){const r=function(t){return(e=t)&&"object"==typeof e&&"data"in e?t.data:t;var e}(t),i=e&&Array.isArray(e.fields)?e.fields:["topic","data","id"],n=e&&e.idKey?e.idKey:"id",o=e&&e.childrenKey?e.childrenKey:"children",s=!e||!1!==e.includeStructure,a=new Map;return r&&r[n]&&function t(e,r,u){const h=function(t){const e={};n in t&&(e[n]=t[n]);for(const r of i)r in t&&r!==n&&(e[r]=t[r]);return e}(e),c=e[n];s&&(h.parentid=r||null,h.index="number"==typeof u?u:0),a.set(c,h);const l=e[o];l&&Array.isArray(l)&&l.forEach((e,r)=>t(e,c,r))}(r,null,0),a}function H(t,e){if(t===e)return!0;if(!t||!e)return!1;const r=Object.keys(t),i=Object.keys(e);if(r.length!==i.length)return!1;for(const i of r){const r=t[i],n=e[i];if(r===n)continue;if(r&&n&&"object"==typeof r&&"object"==typeof n){if(!K(r,n))return!1}else if(r!==n)return!1}return!0}function U(t,e){const r=[];if(!t||!e)return r;const i=new Set([...Object.keys(t),...Object.keys(e)]);i.delete("id");for(const n of i){const i=t[n],o=e[n];if(i===o)continue;(i&&o&&"object"==typeof i&&"object"==typeof o?!K(i,o):i!==o)&&r.push({key:n,before:i,after:o})}return r}function W(t){let e=!1,r=!1;for(const i of t)"parentid"===i.key&&(e=!0),"index"===i.key&&(r=!0);return{moved:e||r,parentChanged:e,orderChanged:r}}function $(t,e,r){const i=r&&r.fields,n=r&&r.idKey,o=r&&r.childrenKey,s=!r||!1!==r.includeStructure,a=r&&"number"==typeof r.maxSize?r.maxSize:5e3,u=r&&!0===r.categorize,h=B(t,{fields:i,idKey:n,childrenKey:o,includeStructure:s}),c=B(e,{fields:i,idKey:n,childrenKey:o,includeStructure:s}),l=[],d=[],f=[];for(const[t,e]of c){if(!h.has(t)){l.push(e);continue}const r=h.get(t);if(!H(r,e)){const i=U(r,e);d.push({id:t,before:r,after:e,changes:i})}}for(const[t,e]of h)c.has(t)||f.push(e);let p=!1;const y=l.length+d.length+f.length;if(y>a){p=!0;const t=Math.max(0,a),e=Math.min(l.length,Math.floor(t*(l.length/y))),r=Math.min(d.length,Math.floor(t*(d.length/y))),i=Math.min(f.length,Math.max(0,t-e-r));l.length=e,d.length=r,f.length=i}if(u&&s){const t=function(t){const e=[],r=[],i=[];for(const n of t){const{id:t,before:o,after:s,changes:a}=n,u=W(a);if(u.moved){const r={parentChanged:u.parentChanged,orderChanged:u.orderChanged,fromParent:o.parentid,toParent:s.parentid,fromOrder:o.index,toOrder:s.index},n=a.filter(t=>"parentid"!==t.key&&"index"!==t.key);n.length>0?i.push({id:t,before:o,after:s,changes:n,moveInfo:r}):e.push({id:t,before:o,after:s,moveInfo:r})}else r.push({id:t,before:o,after:s,changes:a})}return{moved:e,modified:r,movedAndModified:i}}(d);return{created:l,updated:d,deleted:f,truncated:p,moved:t.moved,modified:t.modified,movedAndModified:t.movedAndModified}}return{created:l,updated:d,deleted:f,truncated:p}}R({strict:!0}),R({circular:!0}),R({circular:!0,strict:!0}),R({createInternalComparator:function(){return m}}),R({strict:!0,createInternalComparator:function(){return m}}),R({circular:!0,createInternalComparator:function(){return m}}),R({circular:!0,createInternalComparator:function(){return m},strict:!0});const J={enabled:!0,throttleMs:100,maxHistory:500,storageMode:"object",autoSwitchThreshold:0,keymap:{enabled:!1,redoUsesY:!1},detail:{enabled:!1},diff:{flat:!0,fields:void 0,maxSize:5e3}};class Y extends h{static instanceName="historyPlugin";static preload=!0;constructor({jm:t,pluginOpt:e}){super({jm:t,pluginOpt:e}),this.options=function(t){const e=Object.assign({},J,t||{});return e.keymap||(e.keymap={enabled:!1,redoUsesY:!1}),e.detail||(e.detail={enabled:!1}),e.diff||(e.diff={flat:!0,fields:void 0,maxSize:5e3}),e}(e),this._mounted=!1,this._core=null,this._mountAPI(),this._initCore()}beforePluginDestroy(){u.debug("[history] beforePluginDestroy: clearing history stack"),this._core&&this._core.clear()}_initCore(){const r=this.jm,i=this.options;i.keymap&&i.keymap.enabled&&r.options&&r.options.shortcut&&this._injectShortcuts(r.options.shortcut,!!i.keymap.redoUsesY);const n=new V(r,i);this._core=n,r.history&&(r.history.add=(t,e)=>n.add(t,e),r.history.pause=()=>n.pause(),r.history.resume=t=>n.resume(!!t),r.history.clear=()=>n.clear(),r.history.canBack=()=>n.canBack(),r.history.canForward=()=>n.canForward(),r.history.back=t=>n.back("number"==typeof t?t:1),r.history.forward=t=>n.forward("number"==typeof t?t:1),r.history.length=()=>n.length(),r.history.index=()=>n.index(),r.history.setMax=t=>n.setMax(t),r.history.setThrottle=t=>n.setThrottle(t),r.history.exportSnapshot=()=>n.exportSnapshot(),r.history.importSnapshot=(t,e)=>n.importSnapshot(t,e),r.history.getStack=()=>n.getStackMeta(),r.history.diff=(t,e,r)=>{const i=this.jm.options.fieldNames,n=i?.id||"id";return $(t,e,{fields:[i?.topic||"topic","data",n],idKey:n,childrenKey:i?.children||"children",...r})},this._listener=(r,i)=>{try{if(r===t&&i&&"data"in i){let t=null;const e=i.data&&i.data[0];if(e)if(e.data)if(Array.isArray(e.data)){const r=e.data.find(t=>t.isroot);t=r&&r.id}else t=e.data.id;else e.id&&(t=e.id);return void(t&&t!==n._lastRootId&&(u.debug("[history] root id changed, clearing stack and pausing"),n.clear(),n._lastRootId=t,setTimeout(()=>{try{u.debug("[history] adding bootstrap snapshot after show"),n._addNow&&n._addNow("bootstrap"),u.debug("[history] resuming history recording")}catch(t){u.warn("[history] failed to add bootstrap snapshot",t)}},100)))}r===e&&i&&i.evt&&n.add(i.evt,i)}catch(t){u.warn("[history] listener error",t)}},r.add_event_listener(this._listener))}_injectShortcuts(t,e){const r=[4186,8282],i=e?[4185,8281]:[5210,9306];t.handles.history_back=(t,e)=>{t.history&&t.history.back()&&(e.preventDefault(),e.stopPropagation&&e.stopPropagation())},t.handles.history_forward=(t,e)=>{t.history&&t.history.forward()&&(e.preventDefault(),e.stopPropagation&&e.stopPropagation())},t.mapping.history_back=r,t.mapping.history_forward=i}_mountAPI(){if(this._mounted)return;const t=this.jm,e={add:()=>{},pause:()=>{},resume:t=>{},clear:()=>{},canBack:()=>!1,canForward:()=>!1,back:t=>!1,forward:t=>!1,length:()=>0,index:()=>-1,setMax:t=>{},setThrottle:t=>{},exportSnapshot:()=>null,importSnapshot:(t,e)=>{},getStack:()=>({items:[],index:-1}),diff:(t,e,r)=>{const i=this.jm.options.fieldNames,n=i?.id||"id";return $(t,e,{fields:[i?.topic||"topic","data",n],idKey:n,childrenKey:i?.children||"children",...r})},getOptions:()=>Object.assign({},this.options)};Object.defineProperty(t,"history",{value:e,configurable:!0,enumerable:!1,writable:!1}),this._mounted=!0,u.info("[history] API mounted (preload).")}beforePluginRemove(){try{if(this._listener&&this.jm&&Array.isArray(this.jm.event_handles)){const t=this.jm.event_handles.indexOf(this._listener);t>=0&&this.jm.event_handles.splice(t,1)}this.jm&&Object.prototype.hasOwnProperty.call(this.jm,"history")&&delete this.jm.history,this._mounted=!1}catch(t){u.error("[history] remove failed:",t)}}beforePluginDestroy(){u.error("beforePluginDestroy"),this.beforePluginRemove()}}class V{constructor(t,e){this.jm=t,this.options=e,this.enabled=!!e.enabled,this.maxHistory=Math.max(1,0|e.maxHistory),this.throttleMs=Math.max(0,0|e.throttleMs),this.storageMode=e.storageMode||"object",this.autoSwitchThreshold=Math.max(0,0|e.autoSwitchThreshold),this._history=[],this._idx=-1,this._paused=!1,this._lastAddAt=0,this._timer=0,this._pending=!1,this._pendingMeta=void 0,this._lastSig=null,this._lastRootId=null}add(t="manual",e){if(!this.enabled||this._paused)return;const r=Date.now()-this._lastAddAt;if(r>=this.throttleMs)return this._addNow(t,e),void(this._lastAddAt=Date.now());if(this._pending=!0,this._pendingMeta=e,this._timer)return;const i=Math.max(0,this.throttleMs-r);this._timer=setTimeout(()=>{this._timer=0,!this._paused&&this.enabled&&(this._addNow(t,this._pendingMeta),this._lastAddAt=Date.now()),this._pending=!1,this._pendingMeta=void 0},i)}pause(){this._paused=!0}resume(t=!1){this._paused=!1,t&&this._pending&&(clearTimeout(this._timer),this._timer=0,this._addNow("resume-flush",this._pendingMeta),this._lastAddAt=Date.now(),this._pending=!1,this._pendingMeta=void 0)}clear(){this._history=[],this._idx=-1,this._lastSig=null,this._notifyChange()}canBack(){return this._idx>0}canForward(){return this._idx>=0&&this._idx<this._history.length-1}back(t=1){if((!Number.isFinite(t)||t<=0)&&(t=1),this._idx-t<0)return!1;this._idx-=t;const e=this._applyIndex();return e&&this._notifyChange(),e}forward(t=1){if((!Number.isFinite(t)||t<=0)&&(t=1),this._idx+t>=this._history.length)return!1;this._idx+=t;const e=this._applyIndex();return e&&this._notifyChange(),e}length(){return this._history.length}index(){return this._idx}setMax(t){this.maxHistory=Math.max(1,0|t)}setThrottle(t){this.throttleMs=Math.max(0,0|t)}exportSnapshot(){return this._takeSnapshot()}importSnapshot(t,e){return this._applySnapshot(t,e)}getStackMeta(){return{items:this._history.slice(),index:this._idx}}_notifyChange(){try{this.jm.invoke_event_handle(r,{index:this._idx,length:this._history.length,canBack:this.canBack(),canForward:this.canForward()})}catch(t){u.warn("[history] failed to notify change",t)}}_addNow(t,e){const r=this._takeSnapshot();let i=this.storageMode;if(this.autoSwitchThreshold>0&&"object"===i){const t=this._countNodes(r);t>this.autoSwitchThreshold&&(i="string",u.debug(`[history] auto-switched to string mode (${t} nodes > ${this.autoSwitchThreshold})`))}let n=null;try{n=JSON.stringify(r)}catch{}if(!n||!this._lastSig||n!==this._lastSig){if(this._idx<this._history.length-1&&(this._history=this._history.slice(0,this._idx+1)),this._history.length>=this.maxHistory&&(this._history.shift(),this._idx=Math.max(-1,this._idx-1)),"string"===i)this._history.push(n);else{const t=this._deepFreeze(r);this._history.push(t)}this._idx=this._history.length-1,this._lastSig=n,this._notifyChange()}}_applyIndex(){const t=this._history[this._idx];if(!t)return!1;try{let e;if("string"==typeof t)e=JSON.parse(t),this._lastSig=t;else{e=this._cloneSnapshot(t);try{this._lastSig=JSON.stringify(t)}catch{this._lastSig=null}}return this._applySnapshot(e,{skipCentering:!0}),!0}catch(t){return u.error("[history] apply snapshot failed",t),!1}}_takeSnapshot(){return this.jm.get_data("node_tree")}_applySnapshot(t,e){const r=!(!e||!e.skipCentering);return this.jm.show(t,r),!0}_countNodes(t){let e=0;return function t(r){if(r&&(e++,r.children&&Array.isArray(r.children)))for(const e of r.children)t(e)}(t&&t.data?t.data:t),e}_deepFreeze(t){if(!t||"object"!=typeof t)return t;if(Object.isFrozen(t))return t;if(Object.freeze(t),Array.isArray(t))for(const e of t)this._deepFreeze(e);else for(const e of Object.keys(t))this._deepFreeze(t[e]);return t}_cloneSnapshot(t){if("function"==typeof structuredClone)try{return structuredClone(t)}catch{}try{return JSON.parse(JSON.stringify(t))}catch{return t}}}exports.HistoryPlugin=Y,exports.default=Y;
8
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),"function"!=typeof String.prototype.startsWith&&(String.prototype.startsWith=function(t){return this.slice(0,t.length)===t});const t=1,e=3,r=6,i=1,n=2,o=3,s=4;var a=function(){};let u="undefined"==typeof console?{level:a,log:a,debug:a,info:a,warn:a,error:a}:{level:function(t){u.debug=t>i?a:console.debug;u.info=t>n?a:console.info;u.warn=t>o?a:console.warn;u.error=t>s?a:console.error},log:console.log,debug:console.debug,info:console.info,warn:console.warn,error:console.error};class h{static instanceName="";static preload=!1;constructor({jm:t,pluginOpt:e}){this.jm=t,this.options=e||{}}beforePluginRemove(){}beforePluginDestroy(){this.beforePluginRemove()}}var c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,l=Object.prototype.hasOwnProperty;function f(t,e){return function(r,i,n){return t(r,i,n)&&e(r,i,n)}}function p(t){return function(e,r,i){if(!e||!r||"object"!=typeof e||"object"!=typeof r)return t(e,r,i);var n=i.cache,o=n.get(e),s=n.get(r);if(o&&s)return o===r&&s===e;n.set(e,r),n.set(r,e);var a=t(e,r,i);return n.delete(e),n.delete(r),a}}function y(t){return c(t).concat(d(t))}var g=Object.hasOwn||function(t,e){return l.call(t,e)};function m(t,e){return t===e||!t&&!e&&t!=t&&e!=e}var _=Object.getOwnPropertyDescriptor,b=Object.keys;function v(t,e,r){var i=t.length;if(e.length!==i)return!1;for(;i-- >0;)if(!r.equals(t[i],e[i],i,i,t,e,r))return!1;return!0}function x(t,e){return m(t.getTime(),e.getTime())}function j(t,e){return t.name===e.name&&t.message===e.message&&t.cause===e.cause&&t.stack===e.stack}function S(t,e){return t===e}function w(t,e,r){var i=t.size;if(i!==e.size)return!1;if(!i)return!0;for(var n,o,s=new Array(i),a=t.entries(),u=0;(n=a.next())&&!n.done;){for(var h=e.entries(),c=!1,d=0;(o=h.next())&&!o.done;)if(s[d])d++;else{var l=n.value,f=o.value;if(r.equals(l[0],f[0],u,d,t,e,r)&&r.equals(l[1],f[1],l[0],f[0],t,e,r)){c=s[d]=!0;break}d++}if(!c)return!1;u++}return!0}var k=m;function M(t,e,r){var i=b(t),n=i.length;if(b(e).length!==n)return!1;for(;n-- >0;)if(!N(t,e,r,i[n]))return!1;return!0}function O(t,e,r){var i,n,o,s=y(t),a=s.length;if(y(e).length!==a)return!1;for(;a-- >0;){if(!N(t,e,r,i=s[a]))return!1;if(n=_(t,i),o=_(e,i),(n||o)&&(!n||!o||n.configurable!==o.configurable||n.enumerable!==o.enumerable||n.writable!==o.writable))return!1}return!0}function q(t,e){return m(t.valueOf(),e.valueOf())}function A(t,e){return t.source===e.source&&t.flags===e.flags}function E(t,e,r){var i=t.size;if(i!==e.size)return!1;if(!i)return!0;for(var n,o,s=new Array(i),a=t.values();(n=a.next())&&!n.done;){for(var u=e.values(),h=!1,c=0;(o=u.next())&&!o.done;){if(!s[c]&&r.equals(n.value,o.value,n.value,o.value,t,e,r)){h=s[c]=!0;break}c++}if(!h)return!1}return!0}function P(t,e){var r=t.length;if(e.length!==r)return!1;for(;r-- >0;)if(t[r]!==e[r])return!1;return!0}function C(t,e){return t.hostname===e.hostname&&t.pathname===e.pathname&&t.protocol===e.protocol&&t.port===e.port&&t.hash===e.hash&&t.username===e.username&&t.password===e.password}function N(t,e,r,i){return!("_owner"!==i&&"__o"!==i&&"__v"!==i||!t.$$typeof&&!e.$$typeof)||g(e,i)&&r.equals(t[i],e[i],i,i,t,e,r)}var T=Array.isArray,D="function"==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView:null,I=Object.assign,z=Object.prototype.toString.call.bind(Object.prototype.toString);function F(t){var e=t.areArraysEqual,r=t.areDatesEqual,i=t.areErrorsEqual,n=t.areFunctionsEqual,o=t.areMapsEqual,s=t.areNumbersEqual,a=t.areObjectsEqual,u=t.arePrimitiveWrappersEqual,h=t.areRegExpsEqual,c=t.areSetsEqual,d=t.areTypedArraysEqual,l=t.areUrlsEqual,f=t.unknownTagComparators;return function(t,p,y){if(t===p)return!0;if(null==t||null==p)return!1;var g=typeof t;if(g!==typeof p)return!1;if("object"!==g)return"number"===g?s(t,p,y):"function"===g&&n(t,p,y);var m=t.constructor;if(m!==p.constructor)return!1;if(m===Object)return a(t,p,y);if(T(t))return e(t,p,y);if(null!=D&&D(t))return d(t,p,y);if(m===Date)return r(t,p,y);if(m===RegExp)return h(t,p,y);if(m===Map)return o(t,p,y);if(m===Set)return c(t,p,y);var _,b=z(t);if("[object Date]"===b)return r(t,p,y);if("[object RegExp]"===b)return h(t,p,y);if("[object Map]"===b)return o(t,p,y);if("[object Set]"===b)return c(t,p,y);if("[object Object]"===b)return"function"!=typeof t.then&&"function"!=typeof p.then&&a(t,p,y);if("[object URL]"===b)return l(t,p,y);if("[object Error]"===b)return i(t,p,y);if("[object Arguments]"===b)return a(t,p,y);if("[object Boolean]"===b||"[object Number]"===b||"[object String]"===b)return u(t,p,y);if(f){var v=f[b];if(!v){var x=null!=(_=t)?_[Symbol.toStringTag]:void 0;x&&(v=f[x])}if(v)return v(t,p,y)}return!1}}var K=R();function R(t){void 0===t&&(t={});var e,r=t.circular,i=void 0!==r&&r,n=t.createInternalComparator,o=t.createState,s=t.strict,a=void 0!==s&&s,u=function(t){var e=t.circular,r=t.createCustomConfig,i=t.strict,n={areArraysEqual:i?O:v,areDatesEqual:x,areErrorsEqual:j,areFunctionsEqual:S,areMapsEqual:i?f(w,O):w,areNumbersEqual:k,areObjectsEqual:i?O:M,arePrimitiveWrappersEqual:q,areRegExpsEqual:A,areSetsEqual:i?f(E,O):E,areTypedArraysEqual:i?O:P,areUrlsEqual:C,unknownTagComparators:void 0};if(r&&(n=I({},n,r(n))),e){var o=p(n.areArraysEqual),s=p(n.areMapsEqual),a=p(n.areObjectsEqual),u=p(n.areSetsEqual);n=I({},n,{areArraysEqual:o,areMapsEqual:s,areObjectsEqual:a,areSetsEqual:u})}return n}(t),h=F(u);return function(t){var e=t.circular,r=t.comparator,i=t.createState,n=t.equals,o=t.strict;if(i)return function(t,s){var a=i(),u=a.cache,h=void 0===u?e?new WeakMap:void 0:u,c=a.meta;return r(t,s,{cache:h,equals:n,meta:c,strict:o})};if(e)return function(t,e){return r(t,e,{cache:new WeakMap,equals:n,meta:void 0,strict:o})};var s={cache:void 0,equals:n,meta:void 0,strict:o};return function(t,e){return r(t,e,s)}}({circular:i,comparator:h,createState:o,equals:n?n(h):(e=h,function(t,r,i,n,o,s,a){return e(t,r,a)}),strict:a})}function B(t,e){const r=function(t){return(e=t)&&"object"==typeof e&&"data"in e?t.data:t;var e}(t),i=e&&Array.isArray(e.fields)?e.fields:["topic","data","id"],n=e&&e.idKey?e.idKey:"id",o=e&&e.childrenKey?e.childrenKey:"children",s=!e||!1!==e.includeStructure,a=new Map;return r&&r[n]&&function t(e,r,u){const h=function(t){const e={};n in t&&(e[n]=t[n]);const r=new Set([n,o,"direction","expanded","parentid","index","isroot"]);i.includes("data");for(const o of i)if("data"===o){const n={};let o=!1;for(const e in t)r.has(e)||i.includes(e)||(n[e]=t[e],o=!0);o&&(e.data=n)}else o in t&&o!==n&&(e[o]=t[o]);return e}(e),c=e[n];s&&(h.parentid=r||null,h.index="number"==typeof u?u:0),a.set(c,h);const d=e[o];d&&Array.isArray(d)&&d.forEach((e,r)=>t(e,c,r))}(r,null,0),a}function H(t,e){if(t===e)return!0;if(!t||!e)return!1;const r=Object.keys(t),i=Object.keys(e);if(r.length!==i.length)return!1;for(const i of r){const r=t[i],n=e[i];if(r===n)continue;if(r&&n&&"object"==typeof r&&"object"==typeof n){if(!K(r,n))return!1}else if(r!==n)return!1}return!0}function U(t,e){const r=[];if(!t||!e)return r;const i=new Set([...Object.keys(t),...Object.keys(e)]);i.delete("id");for(const n of i){const i=t[n],o=e[n];if(i===o)continue;(i&&o&&"object"==typeof i&&"object"==typeof o?!K(i,o):i!==o)&&r.push({key:n,before:i,after:o})}return r}function W(t){let e=!1,r=!1;for(const i of t)"parentid"===i.key&&(e=!0),"index"===i.key&&(r=!0);return{moved:e||r,parentChanged:e,orderChanged:r}}function $(t,e,r){const i=r&&r.fields,n=r&&r.idKey,o=r&&r.childrenKey,s=!r||!1!==r.includeStructure,a=r&&"number"==typeof r.maxSize?r.maxSize:5e3,u=r&&!0===r.categorize,h=B(t,{fields:i,idKey:n,childrenKey:o,includeStructure:s}),c=B(e,{fields:i,idKey:n,childrenKey:o,includeStructure:s}),d=[],l=[],f=[];for(const[t,e]of c){if(!h.has(t)){d.push(e);continue}const r=h.get(t);if(!H(r,e)){const i=U(r,e);l.push({id:t,before:r,after:e,changes:i})}}for(const[t,e]of h)c.has(t)||f.push(e);let p=!1;const y=d.length+l.length+f.length;if(y>a){p=!0;const t=Math.max(0,a),e=Math.min(d.length,Math.floor(t*(d.length/y))),r=Math.min(l.length,Math.floor(t*(l.length/y))),i=Math.min(f.length,Math.max(0,t-e-r));d.length=e,l.length=r,f.length=i}if(u&&s){const t=function(t){const e=[],r=[],i=[];for(const n of t){const{id:t,before:o,after:s,changes:a}=n,u=W(a);if(u.moved){const r={parentChanged:u.parentChanged,orderChanged:u.orderChanged,fromParent:o.parentid,toParent:s.parentid,fromOrder:o.index,toOrder:s.index},n=a.filter(t=>"parentid"!==t.key&&"index"!==t.key);n.length>0?i.push({id:t,before:o,after:s,changes:n,moveInfo:r}):e.push({id:t,before:o,after:s,moveInfo:r})}else r.push({id:t,before:o,after:s,changes:a})}return{moved:e,modified:r,movedAndModified:i}}(l);return{created:d,updated:l,deleted:f,truncated:p,moved:t.moved,modified:t.modified,movedAndModified:t.movedAndModified}}return{created:d,updated:l,deleted:f,truncated:p}}R({strict:!0}),R({circular:!0}),R({circular:!0,strict:!0}),R({createInternalComparator:function(){return m}}),R({strict:!0,createInternalComparator:function(){return m}}),R({circular:!0,createInternalComparator:function(){return m}}),R({circular:!0,createInternalComparator:function(){return m},strict:!0});const J={enabled:!0,throttleMs:100,maxHistory:500,storageMode:"object",autoSwitchThreshold:0,keymap:{enabled:!1,redoUsesY:!1},detail:{enabled:!1},diff:{flat:!0,fields:void 0,maxSize:5e3}};class Y extends h{static instanceName="historyPlugin";static preload=!0;constructor({jm:t,pluginOpt:e}){super({jm:t,pluginOpt:e}),this.options=function(t){const e=Object.assign({},J,t||{});return e.keymap||(e.keymap={enabled:!1,redoUsesY:!1}),e.detail||(e.detail={enabled:!1}),e.diff||(e.diff={flat:!0,fields:void 0,maxSize:5e3}),e}(e),this._mounted=!1,this._core=null,this._mountAPI(),this._initCore()}beforePluginDestroy(){u.debug("[history] beforePluginDestroy: clearing history stack"),this._core&&this._core.clear()}_initCore(){const r=this.jm,i=this.options;i.keymap&&i.keymap.enabled&&r.options&&r.options.shortcut&&this._injectShortcuts(r.options.shortcut,!!i.keymap.redoUsesY);const n=new V(r,i);this._core=n,r.history&&(r.history.add=(t,e)=>n.add(t,e),r.history.pause=()=>n.pause(),r.history.resume=t=>n.resume(!!t),r.history.clear=()=>n.clear(),r.history.canBack=()=>n.canBack(),r.history.canForward=()=>n.canForward(),r.history.back=t=>n.back("number"==typeof t?t:1),r.history.forward=t=>n.forward("number"==typeof t?t:1),r.history.length=()=>n.length(),r.history.index=()=>n.index(),r.history.setMax=t=>n.setMax(t),r.history.setThrottle=t=>n.setThrottle(t),r.history.exportSnapshot=()=>n.exportSnapshot(),r.history.importSnapshot=(t,e)=>n.importSnapshot(t,e),r.history.getStack=()=>n.getStackMeta(),r.history.diff=(t,e,r)=>{const i=this.jm.options.fieldNames,n=i?.id||"id";return $(t,e,{fields:[i?.topic||"topic","data",n],idKey:n,childrenKey:i?.children||"children",...r})},this._listener=(r,i)=>{try{if(r===t&&i&&"data"in i){let t=null;const e=i.data&&i.data[0];if(e)if(e.data)if(Array.isArray(e.data)){const r=e.data.find(t=>t.isroot);t=r&&r.id}else t=e.data.id;else e.id&&(t=e.id);return void(t&&t!==n._lastRootId&&(u.debug("[history] root id changed, clearing stack and pausing"),n.clear(),n._lastRootId=t,setTimeout(()=>{try{u.debug("[history] adding bootstrap snapshot after show"),n._addNow&&n._addNow("bootstrap"),u.debug("[history] resuming history recording")}catch(t){u.warn("[history] failed to add bootstrap snapshot",t)}},100)))}r===e&&i&&i.evt&&n.add(i.evt,i)}catch(t){u.warn("[history] listener error",t)}},r.add_event_listener(this._listener))}_injectShortcuts(t,e){const r=[4186,8282],i=e?[4185,8281]:[5210,9306];t.handles.history_back=(t,e)=>{t.history&&t.history.back()&&(e.preventDefault(),e.stopPropagation&&e.stopPropagation())},t.handles.history_forward=(t,e)=>{t.history&&t.history.forward()&&(e.preventDefault(),e.stopPropagation&&e.stopPropagation())},t.mapping.history_back=r,t.mapping.history_forward=i}_mountAPI(){if(this._mounted)return;const t=this.jm,e={add:()=>{},pause:()=>{},resume:t=>{},clear:()=>{},canBack:()=>!1,canForward:()=>!1,back:t=>!1,forward:t=>!1,length:()=>0,index:()=>-1,setMax:t=>{},setThrottle:t=>{},exportSnapshot:()=>null,importSnapshot:(t,e)=>{},getStack:()=>({items:[],index:-1}),diff:(t,e,r)=>{const i=this.jm.options.fieldNames,n=i?.id||"id";return $(t,e,{fields:[i?.topic||"topic","data",n],idKey:n,childrenKey:i?.children||"children",...r})},getOptions:()=>Object.assign({},this.options)};Object.defineProperty(t,"history",{value:e,configurable:!0,enumerable:!1,writable:!1}),this._mounted=!0,u.info("[history] API mounted (preload).")}beforePluginRemove(){try{if(this._listener&&this.jm&&Array.isArray(this.jm.event_handles)){const t=this.jm.event_handles.indexOf(this._listener);t>=0&&this.jm.event_handles.splice(t,1)}this.jm&&Object.prototype.hasOwnProperty.call(this.jm,"history")&&delete this.jm.history,this._mounted=!1}catch(t){u.error("[history] remove failed:",t)}}beforePluginDestroy(){u.error("beforePluginDestroy"),this.beforePluginRemove()}}class V{constructor(t,e){this.jm=t,this.options=e,this.enabled=!!e.enabled,this.maxHistory=Math.max(1,0|e.maxHistory),this.throttleMs=Math.max(0,0|e.throttleMs),this.storageMode=e.storageMode||"object",this.autoSwitchThreshold=Math.max(0,0|e.autoSwitchThreshold),this._history=[],this._idx=-1,this._paused=!1,this._lastAddAt=0,this._timer=0,this._pending=!1,this._pendingMeta=void 0,this._lastSig=null,this._lastRootId=null}add(t="manual",e){if(!this.enabled||this._paused)return;const r=Date.now()-this._lastAddAt;if(r>=this.throttleMs)return this._addNow(t,e),void(this._lastAddAt=Date.now());if(this._pending=!0,this._pendingMeta=e,this._timer)return;const i=Math.max(0,this.throttleMs-r);this._timer=setTimeout(()=>{this._timer=0,!this._paused&&this.enabled&&(this._addNow(t,this._pendingMeta),this._lastAddAt=Date.now()),this._pending=!1,this._pendingMeta=void 0},i)}pause(){this._paused=!0}resume(t=!1){this._paused=!1,t&&this._pending&&(clearTimeout(this._timer),this._timer=0,this._addNow("resume-flush",this._pendingMeta),this._lastAddAt=Date.now(),this._pending=!1,this._pendingMeta=void 0)}clear(){this._history=[],this._idx=-1,this._lastSig=null,this._notifyChange()}canBack(){return this._idx>0}canForward(){return this._idx>=0&&this._idx<this._history.length-1}back(t=1){if((!Number.isFinite(t)||t<=0)&&(t=1),this._idx-t<0)return!1;this._idx-=t;const e=this._applyIndex();return e&&this._notifyChange(),e}forward(t=1){if((!Number.isFinite(t)||t<=0)&&(t=1),this._idx+t>=this._history.length)return!1;this._idx+=t;const e=this._applyIndex();return e&&this._notifyChange(),e}length(){return this._history.length}index(){return this._idx}setMax(t){this.maxHistory=Math.max(1,0|t)}setThrottle(t){this.throttleMs=Math.max(0,0|t)}exportSnapshot(){return this._takeSnapshot()}importSnapshot(t,e){return this._applySnapshot(t,e)}getStackMeta(){return{items:this._history.slice(),index:this._idx}}_notifyChange(){try{this.jm.invoke_event_handle(r,{index:this._idx,length:this._history.length,canBack:this.canBack(),canForward:this.canForward()})}catch(t){u.warn("[history] failed to notify change",t)}}_addNow(t,e){const r=this._takeSnapshot();let i=this.storageMode;if(this.autoSwitchThreshold>0&&"object"===i){const t=this._countNodes(r);t>this.autoSwitchThreshold&&(i="string",u.debug(`[history] auto-switched to string mode (${t} nodes > ${this.autoSwitchThreshold})`))}let n=null;try{n=JSON.stringify(r)}catch{}if(!n||!this._lastSig||n!==this._lastSig){if(this._idx<this._history.length-1&&(this._history=this._history.slice(0,this._idx+1)),this._history.length>=this.maxHistory&&(this._history.shift(),this._idx=Math.max(-1,this._idx-1)),"string"===i)this._history.push(n);else{const t=this._deepFreeze(r);this._history.push(t)}this._idx=this._history.length-1,this._lastSig=n,this._notifyChange()}}_applyIndex(){const t=this._history[this._idx];if(!t)return!1;try{let e;if("string"==typeof t)e=JSON.parse(t),this._lastSig=t;else{e=this._cloneSnapshot(t);try{this._lastSig=JSON.stringify(t)}catch{this._lastSig=null}}return this._applySnapshot(e,{skipCentering:!0}),!0}catch(t){return u.error("[history] apply snapshot failed",t),!1}}_takeSnapshot(){return this.jm.get_data("node_tree")}_applySnapshot(t,e){const r=!(!e||!e.skipCentering);return this.jm.show(t,r),!0}_countNodes(t){let e=0;return function t(r){if(r&&(e++,r.children&&Array.isArray(r.children)))for(const e of r.children)t(e)}(t&&t.data?t.data:t),e}_deepFreeze(t){if(!t||"object"!=typeof t)return t;if(Object.isFrozen(t))return t;if(Object.freeze(t),Array.isArray(t))for(const e of t)this._deepFreeze(e);else for(const e of Object.keys(t))this._deepFreeze(t[e]);return t}_cloneSnapshot(t){if("function"==typeof structuredClone)try{return structuredClone(t)}catch{}try{return JSON.parse(JSON.stringify(t))}catch{return t}}}exports.HistoryPlugin=Y,exports.default=Y;
9
9
  //# sourceMappingURL=jsmind.history.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsmind.history.js","sources":["../src/jsmind.common.js","../src/jsmind.enhanced-plugin.js","../node_modules/.pnpm/fast-equals@5.3.2/node_modules/fast-equals/dist/esm/index.mjs","../src/plugins/history/history-diff.js","../src/plugins/history/jsmind.history.js"],"sourcesContent":["/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\n/**\n * Library version string.\n * @type {string}\n */\nexport const __version__ = '0.9.0';\n/**\n * Library author.\n * @type {string}\n */\nexport const __author__ = 'UmbraCi';\n\nif (typeof String.prototype.startsWith != 'function') {\n String.prototype.startsWith = function (p) {\n return this.slice(0, p.length) === p;\n };\n}\n\n/**\n * Direction constants and parser.\n * @typedef {{left:number,center:number,right:number,of:(dir:(string|number))=>number|undefined}} DirectionType\n */\n/** @type {DirectionType} */\nexport const Direction = {\n left: -1,\n center: 0,\n right: 1,\n of: function (dir) {\n if (!dir || dir === -1 || dir === 0 || dir === 1) {\n return dir;\n }\n if (dir === '-1' || dir === '0' || dir === '1') {\n return parseInt(dir);\n }\n if (dir.toLowerCase() === 'left') {\n return this.left;\n }\n if (dir.toLowerCase() === 'right') {\n return this.right;\n }\n if (dir.toLowerCase() === 'center') {\n return this.center;\n }\n },\n};\n/** @enum {number} */\nexport const EventType = { show: 1, resize: 2, edit: 3, select: 4, reset: 5, history_change: 6 };\n/** @enum {number} */\nexport const Key = { meta: 1 << 13, ctrl: 1 << 12, alt: 1 << 11, shift: 1 << 10 };\n/** @enum {number} */\nexport const LogLevel = { debug: 1, info: 2, warn: 3, error: 4, disable: 9 };\n\n// an noop function define\nvar _noop = function () {};\n/**\n * Logger facade with dynamic level.\n * @type {{level:(lvl:number)=>void,log:Function,debug:Function,info:Function,warn:Function,error:Function}}\n */\nexport let logger =\n typeof console === 'undefined'\n ? {\n level: _noop,\n log: _noop,\n debug: _noop,\n info: _noop,\n warn: _noop,\n error: _noop,\n }\n : {\n level: setup_logger_level,\n log: console.log,\n debug: console.debug,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n\n/**\n * Set logger level.\n * @param {number} log_level\n */\nfunction setup_logger_level(log_level) {\n if (log_level > LogLevel.debug) {\n logger.debug = _noop;\n } else {\n logger.debug = console.debug;\n }\n if (log_level > LogLevel.info) {\n logger.info = _noop;\n } else {\n logger.info = console.info;\n }\n if (log_level > LogLevel.warn) {\n logger.warn = _noop;\n } else {\n logger.warn = console.warn;\n }\n if (log_level > LogLevel.error) {\n logger.error = _noop;\n } else {\n logger.error = console.error;\n }\n}\n","/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\nimport { logger } from './jsmind.common.js';\n\n/**\n * Enhanced Plugin Manager\n * Manages the lifecycle of enhanced plugins with synchronous initialization,\n * preload support, and lifecycle hooks.\n */\nexport class EnhancedPluginManager {\n /**\n * @param {import('./jsmind.js').default} jm - jsMind instance\n */\n constructor(jm) {\n this.jm = jm;\n /** @type {Map<string, EnhancedPlugin>} */\n this.plugins = new Map();\n }\n\n /**\n * Initialize preload plugins (before core modules)\n */\n initPreloadPlugins() {\n const preloadPlugins = this.jm.constructor.enhancedPluginList.filter(d => d.preload);\n logger.info('Initializing ' + preloadPlugins.length + ' preload plugins');\n preloadPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Initialize normal plugins (after core modules)\n */\n initNormalPlugins() {\n const normalPlugins = this.jm.constructor.enhancedPluginList.filter(d => !d.preload);\n logger.info('Initializing ' + normalPlugins.length + ' normal plugins');\n normalPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Internal method: Initialize a single plugin\n * @param {PluginDescriptor} descriptor\n * @private\n */\n _initPlugin(descriptor) {\n try {\n const { PluginClass, pluginOpt } = descriptor;\n\n // Check instanceName\n if (!PluginClass.instanceName) {\n throw new Error('Plugin ' + PluginClass.name + ' must define static instanceName');\n }\n\n // Check naming conflict\n if (this.plugins.has(PluginClass.instanceName)) {\n logger.warn(\n 'Plugin ' + PluginClass.instanceName + ' already exists, will be replaced'\n );\n }\n\n // Instantiate plugin\n const instance = new PluginClass({\n jm: this.jm,\n pluginOpt: pluginOpt || {},\n });\n\n // Save instance\n this.plugins.set(PluginClass.instanceName, instance);\n this.jm[PluginClass.instanceName] = instance;\n descriptor.instance = instance;\n\n logger.info('Enhanced plugin ' + PluginClass.instanceName + ' initialized');\n } catch (error) {\n logger.error('Failed to initialize plugin ' + descriptor.PluginClass.name + ':', error);\n }\n }\n\n /**\n * Remove a plugin\n * @param {typeof EnhancedPlugin} PluginClass\n */\n removePlugin(PluginClass) {\n const instanceName = PluginClass.instanceName;\n if (!instanceName) {\n return;\n }\n\n const instance = this.plugins.get(instanceName);\n if (!instance) {\n return;\n }\n\n try {\n // Call lifecycle hook\n if (typeof instance.beforePluginRemove === 'function') {\n instance.beforePluginRemove();\n }\n\n // Remove from Map\n this.plugins.delete(instanceName);\n\n // Remove from jsMind instance\n delete this.jm[instanceName];\n\n // Remove from plugin list\n const list = this.jm.constructor.enhancedPluginList;\n const index = list.findIndex(d => d.PluginClass === PluginClass);\n if (index !== -1) {\n list.splice(index, 1);\n }\n\n logger.info('Enhanced plugin ' + instanceName + ' removed');\n } catch (error) {\n logger.error('Failed to remove plugin ' + instanceName + ':', error);\n }\n }\n\n /**\n * Destroy all plugins\n */\n destroyAllPlugins() {\n this.plugins.forEach((instance, instanceName) => {\n try {\n // Call lifecycle hook\n if (typeof instance.beforePluginDestroy === 'function') {\n instance.beforePluginDestroy();\n }\n } catch (error) {\n logger.error('Failed to destroy plugin ' + instanceName + ':', error);\n }\n });\n\n this.plugins.clear();\n }\n\n /**\n * Get plugin instance by name\n * @param {string} instanceName\n * @returns {EnhancedPlugin | undefined}\n */\n getPlugin(instanceName) {\n return this.plugins.get(instanceName);\n }\n}\n\n/**\n * Enhanced Plugin Base Class\n * Provides standard interface for enhanced plugins\n */\nexport class EnhancedPlugin {\n /**\n * Plugin instance name (must be defined by subclass)\n * @type {string}\n */\n static instanceName = '';\n\n /**\n * Whether to initialize before core modules\n * @type {boolean}\n */\n static preload = false;\n\n /**\n * @param {{ jm: import('./jsmind.js').default, pluginOpt: object }} params\n */\n constructor({ jm, pluginOpt }) {\n this.jm = jm;\n this.options = pluginOpt || {};\n }\n\n /**\n * Called before plugin is removed\n * Override this method to clean up resources\n */\n beforePluginRemove() {\n // Default implementation: do nothing\n }\n\n /**\n * Called before jsMind instance is destroyed\n * Override this method to clean up resources\n */\n beforePluginDestroy() {\n // Default implementation: call beforePluginRemove\n this.beforePluginRemove();\n }\n}\n\n/**\n * Plugin descriptor\n * @typedef {object} PluginDescriptor\n * @property {typeof EnhancedPlugin} PluginClass - Plugin class\n * @property {string} instanceName - Plugin instance name\n * @property {boolean} preload - Whether to preload\n * @property {object} pluginOpt - Plugin options\n * @property {EnhancedPlugin | null} instance - Plugin instance (after initialization)\n */\n","var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n/**\n * Combine two comparators into a single comparators.\n */\nfunction combineComparators(comparatorA, comparatorB) {\n return function isEqual(a, b, state) {\n return comparatorA(a, b, state) && comparatorB(a, b, state);\n };\n}\n/**\n * Wrap the provided `areItemsEqual` method to manage the circular state, allowing\n * for circular references to be safely included in the comparison without creating\n * stack overflows.\n */\nfunction createIsCircular(areItemsEqual) {\n return function isCircular(a, b, state) {\n if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {\n return areItemsEqual(a, b, state);\n }\n var cache = state.cache;\n var cachedA = cache.get(a);\n var cachedB = cache.get(b);\n if (cachedA && cachedB) {\n return cachedA === b && cachedB === a;\n }\n cache.set(a, b);\n cache.set(b, a);\n var result = areItemsEqual(a, b, state);\n cache.delete(a);\n cache.delete(b);\n return result;\n };\n}\n/**\n * Get the `@@toStringTag` of the value, if it exists.\n */\nfunction getShortTag(value) {\n return value != null ? value[Symbol.toStringTag] : undefined;\n}\n/**\n * Get the properties to strictly examine, which include both own properties that are\n * not enumerable and symbol properties.\n */\nfunction getStrictProperties(object) {\n return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));\n}\n/**\n * Whether the object contains the property passed as an own property.\n */\nvar hasOwn = Object.hasOwn ||\n (function (object, property) {\n return hasOwnProperty.call(object, property);\n });\n/**\n * Whether the values passed are strictly equal or both NaN.\n */\nfunction sameValueZeroEqual(a, b) {\n return a === b || (!a && !b && a !== a && b !== b);\n}\n\nvar PREACT_VNODE = '__v';\nvar PREACT_OWNER = '__o';\nvar REACT_OWNER = '_owner';\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, keys = Object.keys;\n/**\n * Whether the arrays are equal in value.\n */\nfunction areArraysEqual(a, b, state) {\n var index = a.length;\n if (b.length !== index) {\n return false;\n }\n while (index-- > 0) {\n if (!state.equals(a[index], b[index], index, index, a, b, state)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the dates passed are equal in value.\n */\nfunction areDatesEqual(a, b) {\n return sameValueZeroEqual(a.getTime(), b.getTime());\n}\n/**\n * Whether the errors passed are equal in value.\n */\nfunction areErrorsEqual(a, b) {\n return (a.name === b.name &&\n a.message === b.message &&\n a.cause === b.cause &&\n a.stack === b.stack);\n}\n/**\n * Whether the functions passed are equal in value.\n */\nfunction areFunctionsEqual(a, b) {\n return a === b;\n}\n/**\n * Whether the `Map`s are equal in value.\n */\nfunction areMapsEqual(a, b, state) {\n var size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n var matchedIndices = new Array(size);\n var aIterable = a.entries();\n var aResult;\n var bResult;\n var index = 0;\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n var bIterable = b.entries();\n var hasMatch = false;\n var matchIndex = 0;\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (matchedIndices[matchIndex]) {\n matchIndex++;\n continue;\n }\n var aEntry = aResult.value;\n var bEntry = bResult.value;\n if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) &&\n state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n index++;\n }\n return true;\n}\n/**\n * Whether the numbers are equal in value.\n */\nvar areNumbersEqual = sameValueZeroEqual;\n/**\n * Whether the objects are equal in value.\n */\nfunction areObjectsEqual(a, b, state) {\n var properties = keys(a);\n var index = properties.length;\n if (keys(b).length !== index) {\n return false;\n }\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n if (!isPropertyEqual(a, b, state, properties[index])) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the objects are equal in value with strict property checking.\n */\nfunction areObjectsEqualStrict(a, b, state) {\n var properties = getStrictProperties(a);\n var index = properties.length;\n if (getStrictProperties(b).length !== index) {\n return false;\n }\n var property;\n var descriptorA;\n var descriptorB;\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n property = properties[index];\n if (!isPropertyEqual(a, b, state, property)) {\n return false;\n }\n descriptorA = getOwnPropertyDescriptor(a, property);\n descriptorB = getOwnPropertyDescriptor(b, property);\n if ((descriptorA || descriptorB) &&\n (!descriptorA ||\n !descriptorB ||\n descriptorA.configurable !== descriptorB.configurable ||\n descriptorA.enumerable !== descriptorB.enumerable ||\n descriptorA.writable !== descriptorB.writable)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the primitive wrappers passed are equal in value.\n */\nfunction arePrimitiveWrappersEqual(a, b) {\n return sameValueZeroEqual(a.valueOf(), b.valueOf());\n}\n/**\n * Whether the regexps passed are equal in value.\n */\nfunction areRegExpsEqual(a, b) {\n return a.source === b.source && a.flags === b.flags;\n}\n/**\n * Whether the `Set`s are equal in value.\n */\nfunction areSetsEqual(a, b, state) {\n var size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n var matchedIndices = new Array(size);\n var aIterable = a.values();\n var aResult;\n var bResult;\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n var bIterable = b.values();\n var hasMatch = false;\n var matchIndex = 0;\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (!matchedIndices[matchIndex] &&\n state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the TypedArray instances are equal in value.\n */\nfunction areTypedArraysEqual(a, b) {\n var index = a.length;\n if (b.length !== index) {\n return false;\n }\n while (index-- > 0) {\n if (a[index] !== b[index]) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the URL instances are equal in value.\n */\nfunction areUrlsEqual(a, b) {\n return (a.hostname === b.hostname &&\n a.pathname === b.pathname &&\n a.protocol === b.protocol &&\n a.port === b.port &&\n a.hash === b.hash &&\n a.username === b.username &&\n a.password === b.password);\n}\nfunction isPropertyEqual(a, b, state, property) {\n if ((property === REACT_OWNER ||\n property === PREACT_OWNER ||\n property === PREACT_VNODE) &&\n (a.$$typeof || b.$$typeof)) {\n return true;\n }\n return (hasOwn(b, property) &&\n state.equals(a[property], b[property], property, property, a, b, state));\n}\n\nvar ARGUMENTS_TAG = '[object Arguments]';\nvar BOOLEAN_TAG = '[object Boolean]';\nvar DATE_TAG = '[object Date]';\nvar ERROR_TAG = '[object Error]';\nvar MAP_TAG = '[object Map]';\nvar NUMBER_TAG = '[object Number]';\nvar OBJECT_TAG = '[object Object]';\nvar REG_EXP_TAG = '[object RegExp]';\nvar SET_TAG = '[object Set]';\nvar STRING_TAG = '[object String]';\nvar URL_TAG = '[object URL]';\nvar isArray = Array.isArray;\nvar isTypedArray = typeof ArrayBuffer === 'function' && ArrayBuffer.isView\n ? ArrayBuffer.isView\n : null;\nvar assign = Object.assign;\nvar getTag = Object.prototype.toString.call.bind(Object.prototype.toString);\n/**\n * Create a comparator method based on the type-specific equality comparators passed.\n */\nfunction createEqualityComparator(_a) {\n var areArraysEqual = _a.areArraysEqual, areDatesEqual = _a.areDatesEqual, areErrorsEqual = _a.areErrorsEqual, areFunctionsEqual = _a.areFunctionsEqual, areMapsEqual = _a.areMapsEqual, areNumbersEqual = _a.areNumbersEqual, areObjectsEqual = _a.areObjectsEqual, arePrimitiveWrappersEqual = _a.arePrimitiveWrappersEqual, areRegExpsEqual = _a.areRegExpsEqual, areSetsEqual = _a.areSetsEqual, areTypedArraysEqual = _a.areTypedArraysEqual, areUrlsEqual = _a.areUrlsEqual, unknownTagComparators = _a.unknownTagComparators;\n /**\n * compare the value of the two objects and return true if they are equivalent in values\n */\n return function comparator(a, b, state) {\n // If the items are strictly equal, no need to do a value comparison.\n if (a === b) {\n return true;\n }\n // If either of the items are nullish and fail the strictly equal check\n // above, then they must be unequal.\n if (a == null || b == null) {\n return false;\n }\n var type = typeof a;\n if (type !== typeof b) {\n return false;\n }\n if (type !== 'object') {\n if (type === 'number') {\n return areNumbersEqual(a, b, state);\n }\n if (type === 'function') {\n return areFunctionsEqual(a, b, state);\n }\n // If a primitive value that is not strictly equal, it must be unequal.\n return false;\n }\n var constructor = a.constructor;\n // Checks are listed in order of commonality of use-case:\n // 1. Common complex object types (plain object, array)\n // 2. Common data values (date, regexp)\n // 3. Less-common complex object types (map, set)\n // 4. Less-common data values (promise, primitive wrappers)\n // Inherently this is both subjective and assumptive, however\n // when reviewing comparable libraries in the wild this order\n // appears to be generally consistent.\n // Constructors should match, otherwise there is potential for false positives\n // between class and subclass or custom object and POJO.\n if (constructor !== b.constructor) {\n return false;\n }\n // `isPlainObject` only checks against the object's own realm. Cross-realm\n // comparisons are rare, and will be handled in the ultimate fallback, so\n // we can avoid capturing the string tag.\n if (constructor === Object) {\n return areObjectsEqual(a, b, state);\n }\n // `isArray()` works on subclasses and is cross-realm, so we can avoid capturing\n // the string tag or doing an `instanceof` check.\n if (isArray(a)) {\n return areArraysEqual(a, b, state);\n }\n // `isTypedArray()` works on all possible TypedArray classes, so we can avoid\n // capturing the string tag or comparing against all possible constructors.\n if (isTypedArray != null && isTypedArray(a)) {\n return areTypedArraysEqual(a, b, state);\n }\n // Try to fast-path equality checks for other complex object types in the\n // same realm to avoid capturing the string tag. Strict equality is used\n // instead of `instanceof` because it is more performant for the common\n // use-case. If someone is subclassing a native class, it will be handled\n // with the string tag comparison.\n if (constructor === Date) {\n return areDatesEqual(a, b, state);\n }\n if (constructor === RegExp) {\n return areRegExpsEqual(a, b, state);\n }\n if (constructor === Map) {\n return areMapsEqual(a, b, state);\n }\n if (constructor === Set) {\n return areSetsEqual(a, b, state);\n }\n // Since this is a custom object, capture the string tag to determing its type.\n // This is reasonably performant in modern environments like v8 and SpiderMonkey.\n var tag = getTag(a);\n if (tag === DATE_TAG) {\n return areDatesEqual(a, b, state);\n }\n // For RegExp, the properties are not enumerable, and therefore will give false positives if\n // tested like a standard object.\n if (tag === REG_EXP_TAG) {\n return areRegExpsEqual(a, b, state);\n }\n if (tag === MAP_TAG) {\n return areMapsEqual(a, b, state);\n }\n if (tag === SET_TAG) {\n return areSetsEqual(a, b, state);\n }\n if (tag === OBJECT_TAG) {\n // The exception for value comparison is custom `Promise`-like class instances. These should\n // be treated the same as standard `Promise` objects, which means strict equality, and if\n // it reaches this point then that strict equality comparison has already failed.\n return (typeof a.then !== 'function' &&\n typeof b.then !== 'function' &&\n areObjectsEqual(a, b, state));\n }\n // If a URL tag, it should be tested explicitly. Like RegExp, the properties are not\n // enumerable, and therefore will give false positives if tested like a standard object.\n if (tag === URL_TAG) {\n return areUrlsEqual(a, b, state);\n }\n // If an error tag, it should be tested explicitly. Like RegExp, the properties are not\n // enumerable, and therefore will give false positives if tested like a standard object.\n if (tag === ERROR_TAG) {\n return areErrorsEqual(a, b, state);\n }\n // If an arguments tag, it should be treated as a standard object.\n if (tag === ARGUMENTS_TAG) {\n return areObjectsEqual(a, b, state);\n }\n // As the penultimate fallback, check if the values passed are primitive wrappers. This\n // is very rare in modern JS, which is why it is deprioritized compared to all other object\n // types.\n if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {\n return arePrimitiveWrappersEqual(a, b, state);\n }\n if (unknownTagComparators) {\n var unknownTagComparator = unknownTagComparators[tag];\n if (!unknownTagComparator) {\n var shortTag = getShortTag(a);\n if (shortTag) {\n unknownTagComparator = unknownTagComparators[shortTag];\n }\n }\n // If the custom config has an unknown tag comparator that matches the captured tag or the\n // @@toStringTag, it is the source of truth for whether the values are equal.\n if (unknownTagComparator) {\n return unknownTagComparator(a, b, state);\n }\n }\n // If not matching any tags that require a specific type of comparison, then we hard-code false because\n // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:\n // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only\n // comparison that can be made.\n // - For types that can be introspected, but rarely have requirements to be compared\n // (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common\n // use-cases (may be included in a future release, if requested enough).\n // - For types that can be introspected but do not have an objective definition of what\n // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.\n // In all cases, these decisions should be reevaluated based on changes to the language and\n // common development practices.\n return false;\n };\n}\n/**\n * Create the configuration object used for building comparators.\n */\nfunction createEqualityComparatorConfig(_a) {\n var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;\n var config = {\n areArraysEqual: strict\n ? areObjectsEqualStrict\n : areArraysEqual,\n areDatesEqual: areDatesEqual,\n areErrorsEqual: areErrorsEqual,\n areFunctionsEqual: areFunctionsEqual,\n areMapsEqual: strict\n ? combineComparators(areMapsEqual, areObjectsEqualStrict)\n : areMapsEqual,\n areNumbersEqual: areNumbersEqual,\n areObjectsEqual: strict\n ? areObjectsEqualStrict\n : areObjectsEqual,\n arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,\n areRegExpsEqual: areRegExpsEqual,\n areSetsEqual: strict\n ? combineComparators(areSetsEqual, areObjectsEqualStrict)\n : areSetsEqual,\n areTypedArraysEqual: strict\n ? areObjectsEqualStrict\n : areTypedArraysEqual,\n areUrlsEqual: areUrlsEqual,\n unknownTagComparators: undefined,\n };\n if (createCustomConfig) {\n config = assign({}, config, createCustomConfig(config));\n }\n if (circular) {\n var areArraysEqual$1 = createIsCircular(config.areArraysEqual);\n var areMapsEqual$1 = createIsCircular(config.areMapsEqual);\n var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);\n var areSetsEqual$1 = createIsCircular(config.areSetsEqual);\n config = assign({}, config, {\n areArraysEqual: areArraysEqual$1,\n areMapsEqual: areMapsEqual$1,\n areObjectsEqual: areObjectsEqual$1,\n areSetsEqual: areSetsEqual$1,\n });\n }\n return config;\n}\n/**\n * Default equality comparator pass-through, used as the standard `isEqual` creator for\n * use inside the built comparator.\n */\nfunction createInternalEqualityComparator(compare) {\n return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {\n return compare(a, b, state);\n };\n}\n/**\n * Create the `isEqual` function used by the consuming application.\n */\nfunction createIsEqual(_a) {\n var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;\n if (createState) {\n return function isEqual(a, b) {\n var _a = createState(), _b = _a.cache, cache = _b === void 0 ? circular ? new WeakMap() : undefined : _b, meta = _a.meta;\n return comparator(a, b, {\n cache: cache,\n equals: equals,\n meta: meta,\n strict: strict,\n });\n };\n }\n if (circular) {\n return function isEqual(a, b) {\n return comparator(a, b, {\n cache: new WeakMap(),\n equals: equals,\n meta: undefined,\n strict: strict,\n });\n };\n }\n var state = {\n cache: undefined,\n equals: equals,\n meta: undefined,\n strict: strict,\n };\n return function isEqual(a, b) {\n return comparator(a, b, state);\n };\n}\n\n/**\n * Whether the items passed are deeply-equal in value.\n */\nvar deepEqual = createCustomEqual();\n/**\n * Whether the items passed are deeply-equal in value based on strict comparison.\n */\nvar strictDeepEqual = createCustomEqual({ strict: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references.\n */\nvar circularDeepEqual = createCustomEqual({ circular: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references,\n * based on strict comparison.\n */\nvar strictCircularDeepEqual = createCustomEqual({\n circular: true,\n strict: true,\n});\n/**\n * Whether the items passed are shallowly-equal in value.\n */\nvar shallowEqual = createCustomEqual({\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value based on strict comparison\n */\nvar strictShallowEqual = createCustomEqual({\n strict: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references.\n */\nvar circularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references,\n * based on strict comparison.\n */\nvar strictCircularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n strict: true,\n});\n/**\n * Create a custom equality comparison method.\n *\n * This can be done to create very targeted comparisons in extreme hot-path scenarios\n * where the standard methods are not performant enough, but can also be used to provide\n * support for legacy environments that do not support expected features like\n * `RegExp.prototype.flags` out of the box.\n */\nfunction createCustomEqual(options) {\n if (options === void 0) { options = {}; }\n var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;\n var config = createEqualityComparatorConfig(options);\n var comparator = createEqualityComparator(config);\n var equals = createCustomInternalComparator\n ? createCustomInternalComparator(comparator)\n : createInternalEqualityComparator(comparator);\n return createIsEqual({ circular: circular, comparator: comparator, createState: createState, equals: equals, strict: strict });\n}\n\nexport { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };\n//# sourceMappingURL=index.mjs.map\n","import { deepEqual } from 'fast-equals';\n\n/**\n * HistoryDiff utilities\n * Provide flatten() and diff() for NodeTreeFormat snapshots.\n */\n\n/**\n * @typedef {{ meta?: any, format?: 'node_tree', data: NodeTreeData }} NodeTreeFormat\n * @typedef {{ id?: string, topic?: string, expanded?: boolean, direction?: 'left'|'right', data?: Record<string, any>, children?: NodeTreeData[], [key: string]: any }} NodeTreeData\n */\n\n/**\n * @typedef {Object} FlatNode\n * @property {string} id - Node ID\n * @property {string} [topic] - Node topic/title\n * @property {Record<string, any>} [data] - Node data\n * @property {string|null} [parentid] - Parent node ID (structure field)\n * @property {number} [index] - Node order in parent's children (structure field)\n */\n\n/**\n * @typedef {Object} ChangeDetail\n * @property {string} key - The field name that changed\n * @property {any} before - Value before change\n * @property {any} after - Value after change\n */\n\n/**\n * @typedef {Object} UpdatedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before change\n * @property {FlatNode} after - Node state after change\n * @property {ChangeDetail[]} changes - Array of field changes\n */\n\n/**\n * @typedef {Object} MoveInfo\n * @property {boolean} parentChanged - Whether parent changed\n * @property {boolean} orderChanged - Whether order changed\n * @property {string|null} fromParent - Original parent ID\n * @property {string|null} toParent - New parent ID\n * @property {number} fromOrder - Original order\n * @property {number} toOrder - New order\n */\n\n/**\n * @typedef {Object} MovedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before move\n * @property {FlatNode} after - Node state after move\n * @property {MoveInfo} moveInfo - Movement details\n */\n\n/**\n * @typedef {Object} ModifiedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before modification\n * @property {FlatNode} after - Node state after modification\n * @property {ChangeDetail[]} changes - Array of field changes (excluding structure fields)\n */\n\n/**\n * @typedef {Object} MovedAndModifiedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before change\n * @property {FlatNode} after - Node state after change\n * @property {ChangeDetail[]} changes - Array of field changes (excluding structure fields)\n * @property {MoveInfo} moveInfo - Movement details\n */\n\n/**\n * @typedef {Object} DiffResult\n * @property {FlatNode[]} created - Newly created nodes\n * @property {UpdatedNode[]} updated - Updated nodes (all changes)\n * @property {FlatNode[]} deleted - Deleted nodes\n * @property {boolean} truncated - Whether results were truncated due to maxSize\n * @property {MovedNode[]} [moved] - Nodes that were only moved (when categorize=true)\n * @property {ModifiedNode[]} [modified] - Nodes that were only modified (when categorize=true)\n * @property {MovedAndModifiedNode[]} [movedAndModified] - Nodes that were both moved and modified (when categorize=true)\n */\n\n/**\n * @typedef {Object} FlattenOptions\n * @property {string[]} [fields] - Array of field names to include. Defaults to ['topic', 'data', 'id'].\n * When using custom fieldNames (e.g., { id: 'key', topic: 'name' }), this should be\n * ['name', 'data', 'key'] to match the actual field names in the data.\n * @property {string} [idKey] - The field name to use as the node ID. Defaults to 'id'.\n * When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.\n * @property {string} [childrenKey] - The field name to use for children array. Defaults to 'children'.\n * When using custom fieldNames (e.g., { children: 'items' }), this should be 'items'.\n * @property {boolean} [includeStructure] - Whether to include parentid and index. Defaults to true\n */\n\n/**\n * @typedef {Object} DiffOptions\n * @property {string[]} [fields] - Array of field names to compare. Defaults to ['topic', 'data', 'id'].\n * When using custom fieldNames (e.g., { id: 'key', topic: 'name' }), this should be\n * ['name', 'data', 'key'] to match the actual field names in the data.\n * Note: When using jm.history.diff(), this is automatically handled based\n * on the configured fieldNames, so you don't need to specify it manually.\n * @property {string} [idKey] - The field name to use as the node ID. Defaults to 'id'.\n * When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.\n * Note: When using jm.history.diff(), this is automatically handled.\n * @property {string} [childrenKey] - The field name to use for children array. Defaults to 'children'.\n * When using custom fieldNames (e.g., { children: 'items' }), this should be 'items'.\n * Note: When using jm.history.diff(), this is automatically handled.\n * @property {boolean} [includeStructure] - Whether to include parentid and index in comparison. Defaults to true\n * @property {number} [maxSize] - Maximum number of diff results. Defaults to 5000\n * @property {boolean} [categorize] - Whether to categorize updates into moved/modified/movedAndModified. Defaults to false\n */\n\nfunction isFormat(obj) {\n return obj && typeof obj === 'object' && 'data' in obj;\n}\nfunction getRootData(tree) {\n return isFormat(tree) ? tree.data : tree;\n}\n\n/**\n * Flatten a tree into a Map of nodes keyed by id.\n *\n * Note: When using custom fieldNames, make sure to pass the correct field names in opts.fields.\n * For example, if you configured fieldNames: { topic: 'name' }, you should pass fields: ['name', 'data', 'id'].\n *\n * @param {NodeTreeFormat|NodeTreeData} tree - The tree to flatten\n * @param {FlattenOptions} [opts] - Flatten options\n * @returns {Map<string, FlatNode>} Map of node id -> flattened node object\n *\n * @example\n * // With default fieldNames\n * const tree = { data: { id: 'root', topic: 'Root', children: [...] } };\n * const flatMap = flatten(tree);\n * const rootNode = flatMap.get('root'); // { id: 'root', topic: 'Root', data: {...}, parentid: null, index: 0 }\n *\n * @example\n * // With custom fieldNames: { topic: 'name' }\n * const tree = { data: { id: 'root', name: 'Root', children: [...] } };\n * const flatMap = flatten(tree, { fields: ['name', 'data', 'id'] });\n * const rootNode = flatMap.get('root'); // { id: 'root', name: 'Root', data: {...}, parentid: null, index: 0 }\n */\nexport function flatten(tree, opts) {\n const root = getRootData(tree);\n // Default fields: ['topic', 'data', 'id'] when not specified\n const fields = opts && Array.isArray(opts.fields) ? opts.fields : ['topic', 'data', 'id'];\n const idKey = opts && opts.idKey ? opts.idKey : 'id';\n const childrenKey = opts && opts.childrenKey ? opts.childrenKey : 'children';\n const includeStructure = !opts || opts.includeStructure !== false;\n /** @type {Map<string, any>} */\n const map = new Map();\n\n function pick(node) {\n const out = {};\n // Always include the id field (using custom key name if provided)\n if (idKey in node) {\n out[idKey] = node[idKey];\n }\n\n // Include other specified fields\n for (const k of fields) {\n if (k in node && k !== idKey) {\n // Avoid duplicating id field\n out[k] = node[k];\n }\n }\n return out;\n }\n\n function walk(n, parentId, index) {\n const item = pick(n);\n const nodeId = n[idKey]; // Use custom idKey to get node ID\n if (includeStructure) {\n item.parentid = parentId || null;\n item.index = typeof index === 'number' ? index : 0;\n }\n map.set(nodeId, item);\n const children = n[childrenKey]; // Use custom childrenKey to get children array\n if (children && Array.isArray(children)) children.forEach((c, i) => walk(c, nodeId, i));\n }\n\n if (root && root[idKey]) walk(root, null, 0);\n return map;\n}\n\nfunction shallowEqual(a, b) {\n if (a === b) return true;\n if (!a || !b) return false;\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n if (ka.length !== kb.length) return false;\n for (const k of ka) {\n const va = a[k];\n const vb = b[k];\n if (va === vb) continue;\n const isObj = va && vb && typeof va === 'object' && typeof vb === 'object';\n if (isObj) {\n if (!deepEqual(va, vb)) return false;\n continue;\n }\n if (va !== vb) return false;\n }\n return true;\n}\n\n/**\n * Compute changed top-level keys between two flattened node items.\n * For object values (e.g., data), uses deep-equal; reports the key as a whole.\n * Note: 'id' key会被忽略,因为它与 map key 相同且不应作为差异。\n * @param {Record<string, any>} a\n * @param {Record<string, any>} b\n * @returns {{ key: string, before: any, after: any }[]}\n */\nfunction computeChanges(a, b) {\n /** @type {{ key:string, before:any, after:any }[]} */\n const changes = [];\n if (!a || !b) return changes;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n keys.delete('id');\n for (const k of keys) {\n const va = a[k];\n const vb = b[k];\n if (va === vb) continue;\n const bothObj = va && vb && typeof va === 'object' && typeof vb === 'object';\n const different = bothObj ? !deepEqual(va, vb) : va !== vb;\n if (different) changes.push({ key: k, before: va, after: vb });\n }\n return changes;\n}\n\n/**\n * Detect if a node has been moved (parent or order changed)\n * @param {{ key: string, before: any, after: any }[]} changes - Array of changes from computeChanges()\n * @returns {{ moved: boolean, parentChanged: boolean, orderChanged: boolean }}\n */\nfunction detectMove(changes) {\n let parentChanged = false;\n let orderChanged = false;\n\n // Check if parentid or index are in the changes array\n for (const change of changes) {\n if (change.key === 'parentid') {\n parentChanged = true;\n }\n if (change.key === 'index') {\n orderChanged = true;\n }\n }\n\n const moved = parentChanged || orderChanged;\n return { moved, parentChanged, orderChanged };\n}\n\n/**\n * Categorize updated nodes into moved, modified, or movedAndModified\n * @param {{ id: string, before: any, after: any, changes: { key: string, before: any, after: any }[] }[]} updates\n * @returns {{\n * moved: { id: string, before: any, after: any, moveInfo: { parentChanged: boolean, orderChanged: boolean, fromParent: any, toParent: any, fromOrder: any, toOrder: any } }[],\n * modified: { id: string, before: any, after: any, changes: { key: string, before: any, after: any }[] }[],\n * movedAndModified: { id: string, before: any, after: any, changes: { key: string, before: any, after: any }[], moveInfo: { parentChanged: boolean, orderChanged: boolean, fromParent: any, toParent: any, fromOrder: any, toOrder: any } }[]\n * }}\n */\nfunction categorizeUpdates(updates) {\n const moved = [];\n const modified = [];\n const movedAndModified = [];\n\n for (const update of updates) {\n const { id, before, after, changes } = update;\n const moveDetection = detectMove(changes);\n\n if (moveDetection.moved) {\n // Build moveInfo\n const moveInfo = {\n parentChanged: moveDetection.parentChanged,\n orderChanged: moveDetection.orderChanged,\n fromParent: before.parentid,\n toParent: after.parentid,\n fromOrder: before.index,\n toOrder: after.index,\n };\n\n // Filter out structure-only changes (parentid, index)\n const contentChanges = changes.filter(c => c.key !== 'parentid' && c.key !== 'index');\n\n if (contentChanges.length > 0) {\n // Both moved and modified\n movedAndModified.push({ id, before, after, changes: contentChanges, moveInfo });\n } else {\n // Only moved\n moved.push({ id, before, after, moveInfo });\n }\n } else {\n // Only modified (no movement)\n modified.push({ id, before, after, changes });\n }\n }\n\n return { moved, modified, movedAndModified };\n}\n\n/**\n * Compute diff between two snapshots.\n *\n * Note: When using custom fieldNames, make sure to pass the correct field names in opts.fields.\n * For example, if you configured fieldNames: { topic: 'name' }, you should pass fields: ['name', 'data', 'id'].\n * When using jm.history.diff(), this is automatically handled for you.\n *\n * @param {NodeTreeFormat|NodeTreeData} a - First snapshot (before)\n * @param {NodeTreeFormat|NodeTreeData} b - Second snapshot (after)\n * @param {DiffOptions} [opts] - Diff options\n * @returns {DiffResult} Diff result with created, updated, deleted nodes, and optionally categorized updates\n *\n * @example\n * // Basic usage with default fieldNames\n * const result = diff(snapshot1, snapshot2);\n * console.log(result.created); // Newly created nodes\n * console.log(result.updated); // Updated nodes with changes\n * console.log(result.deleted); // Deleted nodes\n *\n * @example\n * // With categorization\n * const result = diff(snapshot1, snapshot2, { categorize: true });\n * console.log(result.moved); // Nodes that were only moved\n * console.log(result.modified); // Nodes that were only modified\n * console.log(result.movedAndModified); // Nodes that were both moved and modified\n *\n * @example\n * // With custom fieldNames: { topic: 'name' }\n * const result = diff(snapshot1, snapshot2, { fields: ['name', 'data', 'id'] });\n * // Now the diff will correctly detect changes in the 'name' field\n *\n * @example\n * // Using jm.history.diff() (recommended - automatically handles fieldNames)\n * const before = jm.get_data('node_tree');\n * // ... make changes ...\n * const after = jm.get_data('node_tree');\n * const result = jm.history.diff(before, after);\n * // fieldNames are automatically applied, no need to specify fields manually\n */\nexport function diff(a, b, opts) {\n const fields = opts && opts.fields;\n const idKey = opts && opts.idKey;\n const childrenKey = opts && opts.childrenKey;\n const includeStructure = !opts || opts.includeStructure !== false;\n const maxSize = opts && typeof opts.maxSize === 'number' ? opts.maxSize : 5000;\n const categorize = opts && opts.categorize === true;\n const A = flatten(a, { fields, idKey, childrenKey, includeStructure });\n const B = flatten(b, { fields, idKey, childrenKey, includeStructure });\n /** @type {any[]} */ const created = [];\n /** @type {{id:string,before:any,after:any,changes:{key:string,before:any,after:any}[]}[]} */ const updated =\n [];\n /** @type {any[]} */ const deleted = [];\n\n // created / updated\n for (const [id, nodeB] of B) {\n if (!A.has(id)) {\n created.push(nodeB);\n continue;\n }\n const nodeA = A.get(id);\n if (!shallowEqual(nodeA, nodeB)) {\n const changes = computeChanges(nodeA, nodeB);\n updated.push({ id, before: nodeA, after: nodeB, changes });\n }\n }\n // deleted\n for (const [id, nodeA] of A) {\n if (!B.has(id)) deleted.push(nodeA);\n }\n\n let truncated = false;\n const total = created.length + updated.length + deleted.length;\n if (total > maxSize) {\n truncated = true;\n const limit = Math.max(0, maxSize);\n // proportional slice\n const c = Math.min(created.length, Math.floor(limit * (created.length / total)));\n const u = Math.min(updated.length, Math.floor(limit * (updated.length / total)));\n const d = Math.min(deleted.length, Math.max(0, limit - c - u));\n created.length = c;\n updated.length = u;\n deleted.length = d;\n }\n\n // Categorize updates if requested\n if (categorize && includeStructure) {\n const categorized = categorizeUpdates(updated);\n return {\n created,\n updated,\n deleted,\n truncated,\n moved: categorized.moved,\n modified: categorized.modified,\n movedAndModified: categorized.movedAndModified,\n };\n }\n\n return { created, updated, deleted, truncated };\n}\n","/**\n * @license BSD\n *\n * HistoryPlugin (EnhancedPlugin)\n * Undo/Redo & History stack for jsMind with public APIs and future diff support.\n * This is the initial skeleton (Task 1): preload plugin, mount jm.history with no-op methods.\n */\n\nimport { EnhancedPlugin } from '../../jsmind.enhanced-plugin.js';\nimport { logger, EventType } from '../../jsmind.common.js';\nimport { diff as diffSnapshots } from './history-diff.js';\n\n/**\n * @typedef {import('../../jsmind.js').default} JsMind\n * @typedef {import('./history-diff.js').DiffResult} DiffResult\n * @typedef {import('./history-diff.js').DiffOptions} DiffOptions\n */\n\nconst DEFAULT_OPTIONS = {\n enabled: true,\n throttleMs: 100,\n maxHistory: 500,\n storageMode: 'object', // 'object' | 'string'\n autoSwitchThreshold: 0, // 0 = disabled, > 0 = auto switch to 'string' mode when node count exceeds threshold\n keymap: { enabled: false, redoUsesY: false },\n detail: { enabled: false },\n diff: { flat: true, fields: undefined, maxSize: 5000 },\n};\n\n/**\n * Normalize and freeze options (shallow)\n */\nfunction normalizeOptions(opt) {\n const o = Object.assign({}, DEFAULT_OPTIONS, opt || {});\n if (!o.keymap) o.keymap = { enabled: false, redoUsesY: false };\n if (!o.detail) o.detail = { enabled: false };\n if (!o.diff) o.diff = { flat: true, fields: undefined, maxSize: 5000 };\n return o;\n}\n\n/**\n * HistoryPlugin skeleton (Task 1)\n */\nclass HistoryPlugin extends EnhancedPlugin {\n static instanceName = 'historyPlugin';\n static preload = true;\n\n /**\n * @param {{ jm: JsMind, pluginOpt?: any }} params\n */\n constructor({ jm, pluginOpt }) {\n super({ jm, pluginOpt });\n this.options = normalizeOptions(pluginOpt);\n\n // In preload stage, core providers may not be ready. Only mount API.\n this._mounted = false;\n this._core = null;\n this._mountAPI();\n\n // Prepare core after jm providers are ready (later tasks may rebind events)\n // Here we set up functional methods for Task 2 (HistoryCore minimal implementation)\n this._initCore();\n }\n\n /**\n * Lifecycle hook: called when jsMind instance is destroyed\n */\n beforePluginDestroy() {\n logger.debug('[history] beforePluginDestroy: clearing history stack');\n if (this._core) {\n this._core.clear();\n }\n }\n\n /** Initialize HistoryCore and wire API methods */\n _initCore() {\n const jm = this.jm;\n const opt = this.options;\n\n // Inject shortcut mapping in preload phase so ShortcutProvider can pick them up in init()\n if (opt.keymap && opt.keymap.enabled && jm.options && jm.options.shortcut) {\n this._injectShortcuts(jm.options.shortcut, !!opt.keymap.redoUsesY);\n }\n\n const core = new HistoryCore(jm, opt);\n this._core = core;\n\n if (!jm.history) return; // should exist after _mountAPI\n\n // Wire real implementations\n jm.history.add = (reason, meta) => core.add(reason, meta);\n jm.history.pause = () => core.pause();\n jm.history.resume = flush => core.resume(!!flush);\n jm.history.clear = () => core.clear();\n\n jm.history.canBack = () => core.canBack();\n jm.history.canForward = () => core.canForward();\n jm.history.back = steps => core.back(typeof steps === 'number' ? steps : 1);\n jm.history.forward = steps => core.forward(typeof steps === 'number' ? steps : 1);\n\n jm.history.length = () => core.length();\n jm.history.index = () => core.index();\n jm.history.setMax = count => core.setMax(count);\n jm.history.setThrottle = ms => core.setThrottle(ms);\n\n jm.history.exportSnapshot = () => core.exportSnapshot();\n jm.history.importSnapshot = (data, applyOptions) => core.importSnapshot(data, applyOptions);\n jm.history.getStack = () => core.getStackMeta();\n jm.history.diff = (a, b, opts) => {\n // Auto-inject fieldNames configuration if not explicitly provided\n const fieldNames = this.jm.options.fieldNames;\n const idKey = fieldNames?.id || 'id';\n const topicKey = fieldNames?.topic || 'topic';\n const childrenKey = fieldNames?.children || 'children';\n const mergedOpts = {\n fields: [topicKey, 'data', idKey],\n idKey: idKey, // Pass idKey for pick() function\n childrenKey: childrenKey, // Pass childrenKey for walk() function\n ...opts,\n };\n return diffSnapshots(a, b, mergedOpts);\n };\n\n // Bind events: detect mind-map switching, seed initial snapshot, capture edits\n this._listener = (type, payload) => {\n try {\n // Handle show event: detect mind-map switching and seed initial snapshot\n if (type === EventType.show && payload && 'data' in payload) {\n // Extract root id from payload\n // payload.data is an array: [mind_data]\n // mind_data can be node_tree format {meta, format, data: {id, topic, children}}\n // or node_array format {meta, format, data: [{id, isroot, topic}, ...]}\n let currentRootId = null;\n const mindData = payload.data && payload.data[0];\n if (mindData) {\n if (mindData.data) {\n // node_tree format or node_array format\n if (Array.isArray(mindData.data)) {\n // node_array format: find root node\n const rootNode = mindData.data.find(n => n.isroot);\n currentRootId = rootNode && rootNode.id;\n } else {\n // node_tree format: data.id is root id\n currentRootId = mindData.data.id;\n }\n } else if (mindData.id) {\n // Direct node_tree format without meta\n currentRootId = mindData.id;\n }\n }\n\n // Check if root id changed (new mind-map or first load)\n if (currentRootId && currentRootId !== core._lastRootId) {\n // Clear stack and pause history recording immediately when switching mind-map\n // This prevents capturing intermediate edit events during rendering\n logger.debug('[history] root id changed, clearing stack and pausing');\n core.clear();\n core._lastRootId = currentRootId;\n\n // Defer initial snapshot to next event loop tick\n // Ensures all synchronous rendering and event handlers have completed\n setTimeout(() => {\n try {\n logger.debug('[history] adding bootstrap snapshot after show');\n core._addNow && core._addNow('bootstrap');\n logger.debug('[history] resuming history recording');\n } catch (e) {\n logger.warn('[history] failed to add bootstrap snapshot', e);\n }\n }, 100); // Use 100ms delay to ensure all rendering is complete\n }\n return;\n }\n\n // Capture standard edit operations\n if (type === EventType.edit && payload && payload.evt) {\n core.add(payload.evt, payload);\n }\n } catch (e) {\n logger.warn('[history] listener error', e);\n }\n };\n jm.add_event_listener(this._listener);\n }\n\n /**\n * Inject shortcut options so provider can register mapping in its init phase\n * @param {{ enable?: boolean, handles: Record<string,Function>, mapping: Record<string, number|number[]> }} sc\n * @param {boolean} redoUsesY\n */\n _injectShortcuts(sc, redoUsesY) {\n // Build key codes as ShortcutProvider expects\n const CTRL = 1 << 12,\n META = 1 << 13,\n SHIFT = 1 << 10;\n const Z = 90,\n Y = 89;\n const backKeys = [CTRL + Z, META + Z];\n const forwardKeys = redoUsesY ? [CTRL + Y, META + Y] : [CTRL + SHIFT + Z, META + SHIFT + Z];\n\n sc.handles['history_back'] = (jm, e) => {\n if (jm.history && jm.history.back()) {\n e.preventDefault();\n e.stopPropagation && e.stopPropagation();\n }\n };\n sc.handles['history_forward'] = (jm, e) => {\n if (jm.history && jm.history.forward()) {\n e.preventDefault();\n e.stopPropagation && e.stopPropagation();\n }\n };\n sc.mapping['history_back'] = backKeys;\n sc.mapping['history_forward'] = forwardKeys;\n }\n\n /** Mount public API on jm.history (placeholder defaults) */\n _mountAPI() {\n if (this._mounted) return;\n const jm = this.jm;\n\n // Public surface designed by requirements; will be wired to core in _initCore.\n const api = {\n // control & stack\n add: () => undefined,\n pause: () => undefined,\n resume: _flush => undefined,\n clear: () => undefined,\n\n // navigation\n canBack: () => false,\n canForward: () => false,\n back: _steps => false,\n forward: _steps => false,\n\n // info/config\n length: () => 0,\n index: () => -1,\n setMax: _count => undefined,\n setThrottle: _ms => undefined,\n\n // snapshots\n exportSnapshot: () => null,\n importSnapshot: (_data, _opts) => undefined,\n\n // stack & diff (wired in _initCore)\n getStack: () => ({ items: [], index: -1 }),\n /**\n * Compare two snapshots and return the differences.\n * Automatically uses the configured fieldNames to ensure correct field comparison.\n *\n * @param {object} a - First snapshot (before state)\n * @param {object} b - Second snapshot (after state)\n * @param {DiffOptions} [opts] - Diff options. If opts.fields is provided, it will override the auto-detected fields.\n * @returns {DiffResult} Diff result containing created, deleted, updated, moved, modified, and movedAndModified nodes\n *\n * @example\n * // With default fieldNames\n * const before = jm.get_data('node_tree');\n * // ... make changes ...\n * const after = jm.get_data('node_tree');\n * const diff = jm.history.diff(before, after);\n *\n * @example\n * // With custom fieldNames: { id: 'key', topic: 'name', children: 'items' }\n * // The diff method automatically uses 'key', 'name', and 'items' instead of 'id', 'topic', and 'children'\n * const diff = jm.history.diff(before, after);\n * // diff.updated will correctly detect changes in the 'name' field\n * // and correctly traverse the 'items' array\n */\n diff: (a, b, opts) => {\n // Auto-inject fieldNames configuration if not explicitly provided\n const fieldNames = this.jm.options.fieldNames;\n const idKey = fieldNames?.id || 'id';\n const topicKey = fieldNames?.topic || 'topic';\n const childrenKey = fieldNames?.children || 'children';\n const mergedOpts = {\n fields: [topicKey, 'data', idKey],\n idKey: idKey, // Pass idKey for pick() function\n childrenKey: childrenKey, // Pass childrenKey for walk() function\n ...opts,\n };\n return diffSnapshots(a, b, mergedOpts);\n },\n\n // options getter (read-only view)\n getOptions: () => Object.assign({}, this.options),\n };\n\n Object.defineProperty(jm, 'history', {\n value: api,\n configurable: true,\n enumerable: false,\n writable: false,\n });\n this._mounted = true;\n logger.info('[history] API mounted (preload).');\n }\n\n /** Cleanup before plugin removed */\n beforePluginRemove() {\n try {\n // detach event listener if possible\n if (this._listener && this.jm && Array.isArray(this.jm.event_handles)) {\n const idx = this.jm.event_handles.indexOf(this._listener);\n if (idx >= 0) this.jm.event_handles.splice(idx, 1);\n }\n\n if (this.jm && Object.prototype.hasOwnProperty.call(this.jm, 'history')) {\n // remove mounted API\n // @ts-ignore - JM is JS runtime\n delete this.jm.history;\n }\n this._mounted = false;\n } catch (e) {\n logger.error('[history] remove failed:', e);\n }\n }\n\n /** Default: call beforePluginRemove on destroy */\n beforePluginDestroy() {\n logger.error('beforePluginDestroy');\n this.beforePluginRemove();\n }\n}\n\n// ---------------- HistoryCore (Task 2 minimal implementation) ----------------\nclass HistoryCore {\n /** @param {JsMind} jm @param {any} options */\n constructor(jm, options) {\n this.jm = jm;\n this.options = options;\n this.enabled = !!options.enabled;\n this.maxHistory = Math.max(1, options.maxHistory | 0);\n this.throttleMs = Math.max(0, options.throttleMs | 0);\n this.storageMode = options.storageMode || 'object'; // 'object' | 'string'\n this.autoSwitchThreshold = Math.max(0, options.autoSwitchThreshold | 0);\n\n this._history = []; // of frozen snapshot objects or JSON strings\n this._idx = -1;\n this._paused = false;\n this._lastAddAt = 0;\n this._timer = 0;\n this._pending = false;\n this._pendingMeta = undefined;\n this._lastSig = null; // last snapshot JSON signature for dedupe\n this._lastRootId = null; // track root id to detect mind-map switching\n\n // Defer initial snapshot seeding to first EventType.show (post-show)\n // Avoid calling _addNow here because providers are not ready in preload stage.\n }\n\n // ----- public API wrappers -----\n add(reason = 'manual', meta) {\n if (!this.enabled || this._paused) return;\n const now = Date.now();\n const elapsed = now - this._lastAddAt;\n if (elapsed >= this.throttleMs) {\n this._addNow(reason, meta);\n this._lastAddAt = Date.now();\n return;\n }\n // schedule a coalesced add\n this._pending = true;\n this._pendingMeta = meta;\n if (this._timer) return;\n const delay = Math.max(0, this.throttleMs - elapsed);\n this._timer = setTimeout(() => {\n this._timer = 0;\n if (!this._paused && this.enabled) {\n this._addNow(reason, this._pendingMeta);\n this._lastAddAt = Date.now();\n }\n this._pending = false;\n this._pendingMeta = undefined;\n }, delay);\n }\n pause() {\n this._paused = true;\n }\n resume(flush = false) {\n this._paused = false;\n if (flush && this._pending) {\n clearTimeout(this._timer);\n this._timer = 0;\n this._addNow('resume-flush', this._pendingMeta);\n this._lastAddAt = Date.now();\n this._pending = false;\n this._pendingMeta = undefined;\n }\n }\n clear() {\n this._history = [];\n this._idx = -1;\n this._lastSig = null;\n this._notifyChange();\n }\n canBack() {\n return this._idx > 0;\n }\n canForward() {\n return this._idx >= 0 && this._idx < this._history.length - 1;\n }\n back(steps = 1) {\n if (!Number.isFinite(steps) || steps <= 0) steps = 1;\n if (this._idx - steps < 0) return false;\n this._idx -= steps;\n const result = this._applyIndex();\n if (result) this._notifyChange();\n return result;\n }\n forward(steps = 1) {\n if (!Number.isFinite(steps) || steps <= 0) steps = 1;\n if (this._idx + steps >= this._history.length) return false;\n this._idx += steps;\n const result = this._applyIndex();\n if (result) this._notifyChange();\n return result;\n }\n length() {\n return this._history.length;\n }\n index() {\n return this._idx;\n }\n setMax(count) {\n this.maxHistory = Math.max(1, count | 0);\n }\n setThrottle(ms) {\n this.throttleMs = Math.max(0, ms | 0);\n }\n exportSnapshot() {\n return this._takeSnapshot();\n }\n importSnapshot(data, applyOptions) {\n return this._applySnapshot(data, applyOptions);\n }\n getStackMeta() {\n return { items: this._history.slice(), index: this._idx };\n }\n\n // ----- internals -----\n _notifyChange() {\n try {\n this.jm.invoke_event_handle(EventType.history_change, {\n index: this._idx,\n length: this._history.length,\n canBack: this.canBack(),\n canForward: this.canForward(),\n });\n } catch (e) {\n logger.warn('[history] failed to notify change', e);\n }\n }\n _addNow(_reason, _meta) {\n const snapshot = this._takeSnapshot();\n\n // Auto-switch storage mode based on node count threshold\n let effectiveMode = this.storageMode;\n if (this.autoSwitchThreshold > 0 && effectiveMode === 'object') {\n const nodeCount = this._countNodes(snapshot);\n if (nodeCount > this.autoSwitchThreshold) {\n effectiveMode = 'string';\n logger.debug(\n `[history] auto-switched to string mode (${nodeCount} nodes > ${this.autoSwitchThreshold})`\n );\n }\n }\n\n // Compute signature for dedupe against last snapshot\n let sig = null;\n try {\n sig = JSON.stringify(snapshot);\n } catch {}\n if (sig && this._lastSig && sig === this._lastSig) return; // dedupe\n\n // trim future\n if (this._idx < this._history.length - 1)\n this._history = this._history.slice(0, this._idx + 1);\n\n // push with cap\n if (this._history.length >= this.maxHistory) {\n this._history.shift();\n this._idx = Math.max(-1, this._idx - 1);\n }\n\n // Store based on effective mode\n if (effectiveMode === 'string') {\n this._history.push(sig); // Store JSON string directly\n } else {\n const frozen = this._deepFreeze(snapshot);\n this._history.push(frozen); // Store frozen object\n }\n\n this._idx = this._history.length - 1;\n this._lastSig = sig;\n this._notifyChange();\n }\n\n _applyIndex() {\n const item = this._history[this._idx];\n if (!item) return false;\n\n try {\n // Restore data based on storage type\n let data;\n if (typeof item === 'string') {\n // String mode: parse JSON\n data = JSON.parse(item);\n this._lastSig = item; // Already a string\n } else {\n // Object mode: clone frozen object\n data = this._cloneSnapshot(item);\n try {\n this._lastSig = JSON.stringify(item);\n } catch {\n this._lastSig = null;\n }\n }\n\n this._applySnapshot(data, { skipCentering: true });\n return true;\n } catch (e) {\n logger.error('[history] apply snapshot failed', e);\n return false;\n }\n }\n\n _takeSnapshot() {\n return this.jm.get_data('node_tree');\n }\n _applySnapshot(data, applyOptions) {\n const skip = !!(applyOptions && applyOptions.skipCentering);\n this.jm.show(data, skip);\n return true;\n }\n\n _countNodes(snapshot) {\n // Count total nodes in the snapshot tree\n let count = 0;\n const root = snapshot && snapshot.data ? snapshot.data : snapshot;\n\n function traverse(node) {\n if (!node) return;\n count++;\n if (node.children && Array.isArray(node.children)) {\n for (const child of node.children) {\n traverse(child);\n }\n }\n }\n\n traverse(root);\n return count;\n }\n\n _deepFreeze(obj) {\n if (!obj || typeof obj !== 'object') return obj;\n if (Object.isFrozen(obj)) return obj;\n Object.freeze(obj);\n if (Array.isArray(obj)) {\n for (const v of obj) this._deepFreeze(v);\n } else {\n for (const k of Object.keys(obj)) this._deepFreeze(obj[k]);\n }\n return obj;\n }\n\n _cloneSnapshot(obj) {\n // Prefer structuredClone when available to avoid JSON pitfalls\n if (typeof structuredClone === 'function') {\n try {\n return structuredClone(obj);\n } catch {}\n }\n try {\n return JSON.parse(JSON.stringify(obj));\n } catch {\n return obj;\n }\n }\n}\n\nexport default HistoryPlugin;\nexport { HistoryPlugin };\n"],"names":["String","prototype","startsWith","p","this","slice","length","EventType","LogLevel","_noop","logger","console","level","log","debug","info","warn","error","log_level","EnhancedPlugin","static","constructor","jm","pluginOpt","options","beforePluginRemove","beforePluginDestroy","getOwnPropertyNames","Object","getOwnPropertySymbols","hasOwnProperty","combineComparators","comparatorA","comparatorB","a","b","state","createIsCircular","areItemsEqual","cache","cachedA","get","cachedB","set","result","delete","getStrictProperties","object","concat","hasOwn","property","call","sameValueZeroEqual","getOwnPropertyDescriptor","keys","areArraysEqual","index","equals","areDatesEqual","getTime","areErrorsEqual","name","message","cause","stack","areFunctionsEqual","areMapsEqual","size","aResult","bResult","matchedIndices","Array","aIterable","entries","next","done","bIterable","hasMatch","matchIndex","aEntry","value","bEntry","areNumbersEqual","areObjectsEqual","properties","isPropertyEqual","areObjectsEqualStrict","descriptorA","descriptorB","configurable","enumerable","writable","arePrimitiveWrappersEqual","valueOf","areRegExpsEqual","source","flags","areSetsEqual","values","areTypedArraysEqual","areUrlsEqual","hostname","pathname","protocol","port","hash","username","password","$$typeof","isArray","isTypedArray","ArrayBuffer","isView","assign","getTag","toString","bind","createEqualityComparator","_a","unknownTagComparators","type","Date","RegExp","Map","Set","tag","then","unknownTagComparator","shortTag","Symbol","toStringTag","undefined","deepEqual","createCustomEqual","compare","circular","createCustomInternalComparator","createInternalComparator","createState","_b","strict","config","createCustomConfig","areArraysEqual$1","areMapsEqual$1","areObjectsEqual$1","areSetsEqual$1","createEqualityComparatorConfig","comparator","WeakMap","meta","createIsEqual","_indexOrKeyA","_indexOrKeyB","_parentA","_parentB","flatten","tree","opts","root","obj","data","getRootData","fields","idKey","childrenKey","includeStructure","map","walk","n","parentId","item","node","out","k","pick","nodeId","parentid","children","forEach","c","i","shallowEqual","ka","kb","va","vb","computeChanges","changes","push","key","before","after","detectMove","parentChanged","orderChanged","change","moved","diff","maxSize","categorize","A","B","created","updated","deleted","id","nodeB","has","nodeA","truncated","total","limit","Math","max","min","floor","u","d","categorized","updates","modified","movedAndModified","update","moveDetection","moveInfo","fromParent","toParent","fromOrder","toOrder","contentChanges","filter","categorizeUpdates","DEFAULT_OPTIONS","enabled","throttleMs","maxHistory","storageMode","autoSwitchThreshold","keymap","redoUsesY","detail","flat","HistoryPlugin","super","opt","o","normalizeOptions","_mounted","_core","_mountAPI","_initCore","clear","shortcut","_injectShortcuts","core","HistoryCore","history","add","reason","pause","resume","flush","canBack","canForward","back","steps","forward","setMax","count","setThrottle","ms","exportSnapshot","importSnapshot","applyOptions","getStack","getStackMeta","fieldNames","diffSnapshots","topic","_listener","payload","currentRootId","mindData","rootNode","find","isroot","_lastRootId","setTimeout","_addNow","e","evt","add_event_listener","sc","backKeys","CTRL","META","forwardKeys","handles","preventDefault","stopPropagation","mapping","api","_flush","_steps","_count","_ms","_data","_opts","items","getOptions","defineProperty","event_handles","idx","indexOf","splice","_history","_idx","_paused","_lastAddAt","_timer","_pending","_pendingMeta","_lastSig","elapsed","now","delay","clearTimeout","_notifyChange","Number","isFinite","_applyIndex","_takeSnapshot","_applySnapshot","invoke_event_handle","_reason","_meta","snapshot","effectiveMode","nodeCount","_countNodes","sig","JSON","stringify","shift","frozen","_deepFreeze","parse","_cloneSnapshot","skipCentering","get_data","skip","show","traverse","child","isFrozen","freeze","v","structuredClone"],"mappings":"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"}
1
+ {"version":3,"file":"jsmind.history.js","sources":["../src/jsmind.common.js","../src/jsmind.enhanced-plugin.js","../node_modules/.pnpm/fast-equals@5.3.2/node_modules/fast-equals/dist/esm/index.mjs","../src/plugins/history/history-diff.js","../src/plugins/history/jsmind.history.js"],"sourcesContent":["/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\n/**\n * Library version string.\n * @type {string}\n */\nexport const __version__ = '0.9.0';\n/**\n * Library author.\n * @type {string}\n */\nexport const __author__ = 'UmbraCi';\n\nif (typeof String.prototype.startsWith != 'function') {\n String.prototype.startsWith = function (p) {\n return this.slice(0, p.length) === p;\n };\n}\n\n/**\n * Direction constants and parser.\n * @typedef {{left:number,center:number,right:number,of:(dir:(string|number))=>number|undefined}} DirectionType\n */\n/** @type {DirectionType} */\nexport const Direction = {\n left: -1,\n center: 0,\n right: 1,\n of: function (dir) {\n if (!dir || dir === -1 || dir === 0 || dir === 1) {\n return dir;\n }\n if (dir === '-1' || dir === '0' || dir === '1') {\n return parseInt(dir);\n }\n if (dir.toLowerCase() === 'left') {\n return this.left;\n }\n if (dir.toLowerCase() === 'right') {\n return this.right;\n }\n if (dir.toLowerCase() === 'center') {\n return this.center;\n }\n },\n};\n/** @enum {number} */\nexport const EventType = { show: 1, resize: 2, edit: 3, select: 4, reset: 5, history_change: 6 };\n/** @enum {number} */\nexport const Key = { meta: 1 << 13, ctrl: 1 << 12, alt: 1 << 11, shift: 1 << 10 };\n/** @enum {number} */\nexport const LogLevel = { debug: 1, info: 2, warn: 3, error: 4, disable: 9 };\n\n// an noop function define\nvar _noop = function () {};\n/**\n * Logger facade with dynamic level.\n * @type {{level:(lvl:number)=>void,log:Function,debug:Function,info:Function,warn:Function,error:Function}}\n */\nexport let logger =\n typeof console === 'undefined'\n ? {\n level: _noop,\n log: _noop,\n debug: _noop,\n info: _noop,\n warn: _noop,\n error: _noop,\n }\n : {\n level: setup_logger_level,\n log: console.log,\n debug: console.debug,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n\n/**\n * Set logger level.\n * @param {number} log_level\n */\nfunction setup_logger_level(log_level) {\n if (log_level > LogLevel.debug) {\n logger.debug = _noop;\n } else {\n logger.debug = console.debug;\n }\n if (log_level > LogLevel.info) {\n logger.info = _noop;\n } else {\n logger.info = console.info;\n }\n if (log_level > LogLevel.warn) {\n logger.warn = _noop;\n } else {\n logger.warn = console.warn;\n }\n if (log_level > LogLevel.error) {\n logger.error = _noop;\n } else {\n logger.error = console.error;\n }\n}\n","/**\n * @license BSD\n * @copyright 2014-2025 UmbraCi\n *\n * Project Home:\n * https://github.com/UmbraCi/jsmind/\n */\n\nimport { logger } from './jsmind.common.js';\n\n/**\n * Enhanced Plugin Manager\n * Manages the lifecycle of enhanced plugins with synchronous initialization,\n * preload support, and lifecycle hooks.\n */\nexport class EnhancedPluginManager {\n /**\n * @param {import('./jsmind.js').default} jm - jsMind instance\n */\n constructor(jm) {\n this.jm = jm;\n /** @type {Map<string, EnhancedPlugin>} */\n this.plugins = new Map();\n }\n\n /**\n * Initialize preload plugins (before core modules)\n */\n initPreloadPlugins() {\n const preloadPlugins = this.jm.constructor.enhancedPluginList.filter(d => d.preload);\n logger.info('Initializing ' + preloadPlugins.length + ' preload plugins');\n preloadPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Initialize normal plugins (after core modules)\n */\n initNormalPlugins() {\n const normalPlugins = this.jm.constructor.enhancedPluginList.filter(d => !d.preload);\n logger.info('Initializing ' + normalPlugins.length + ' normal plugins');\n normalPlugins.forEach(descriptor => {\n this._initPlugin(descriptor);\n });\n }\n\n /**\n * Internal method: Initialize a single plugin\n * @param {PluginDescriptor} descriptor\n * @private\n */\n _initPlugin(descriptor) {\n try {\n const { PluginClass, pluginOpt } = descriptor;\n\n // Check instanceName\n if (!PluginClass.instanceName) {\n throw new Error('Plugin ' + PluginClass.name + ' must define static instanceName');\n }\n\n // Check naming conflict\n if (this.plugins.has(PluginClass.instanceName)) {\n logger.warn(\n 'Plugin ' + PluginClass.instanceName + ' already exists, will be replaced'\n );\n }\n\n // Instantiate plugin\n const instance = new PluginClass({\n jm: this.jm,\n pluginOpt: pluginOpt || {},\n });\n\n // Save instance\n this.plugins.set(PluginClass.instanceName, instance);\n this.jm[PluginClass.instanceName] = instance;\n descriptor.instance = instance;\n\n logger.info('Enhanced plugin ' + PluginClass.instanceName + ' initialized');\n } catch (error) {\n logger.error('Failed to initialize plugin ' + descriptor.PluginClass.name + ':', error);\n }\n }\n\n /**\n * Remove a plugin\n * @param {typeof EnhancedPlugin} PluginClass\n */\n removePlugin(PluginClass) {\n const instanceName = PluginClass.instanceName;\n if (!instanceName) {\n return;\n }\n\n const instance = this.plugins.get(instanceName);\n if (!instance) {\n return;\n }\n\n try {\n // Call lifecycle hook\n if (typeof instance.beforePluginRemove === 'function') {\n instance.beforePluginRemove();\n }\n\n // Remove from Map\n this.plugins.delete(instanceName);\n\n // Remove from jsMind instance\n delete this.jm[instanceName];\n\n // Remove from plugin list\n const list = this.jm.constructor.enhancedPluginList;\n const index = list.findIndex(d => d.PluginClass === PluginClass);\n if (index !== -1) {\n list.splice(index, 1);\n }\n\n logger.info('Enhanced plugin ' + instanceName + ' removed');\n } catch (error) {\n logger.error('Failed to remove plugin ' + instanceName + ':', error);\n }\n }\n\n /**\n * Destroy all plugins\n */\n destroyAllPlugins() {\n this.plugins.forEach((instance, instanceName) => {\n try {\n // Call lifecycle hook\n if (typeof instance.beforePluginDestroy === 'function') {\n instance.beforePluginDestroy();\n }\n } catch (error) {\n logger.error('Failed to destroy plugin ' + instanceName + ':', error);\n }\n });\n\n this.plugins.clear();\n }\n\n /**\n * Get plugin instance by name\n * @param {string} instanceName\n * @returns {EnhancedPlugin | undefined}\n */\n getPlugin(instanceName) {\n return this.plugins.get(instanceName);\n }\n}\n\n/**\n * Enhanced Plugin Base Class\n * Provides standard interface for enhanced plugins\n */\nexport class EnhancedPlugin {\n /**\n * Plugin instance name (must be defined by subclass)\n * @type {string}\n */\n static instanceName = '';\n\n /**\n * Whether to initialize before core modules\n * @type {boolean}\n */\n static preload = false;\n\n /**\n * @param {{ jm: import('./jsmind.js').default, pluginOpt: object }} params\n */\n constructor({ jm, pluginOpt }) {\n this.jm = jm;\n this.options = pluginOpt || {};\n }\n\n /**\n * Called before plugin is removed\n * Override this method to clean up resources\n */\n beforePluginRemove() {\n // Default implementation: do nothing\n }\n\n /**\n * Called before jsMind instance is destroyed\n * Override this method to clean up resources\n */\n beforePluginDestroy() {\n // Default implementation: call beforePluginRemove\n this.beforePluginRemove();\n }\n}\n\n/**\n * Plugin descriptor\n * @typedef {object} PluginDescriptor\n * @property {typeof EnhancedPlugin} PluginClass - Plugin class\n * @property {string} instanceName - Plugin instance name\n * @property {boolean} preload - Whether to preload\n * @property {object} pluginOpt - Plugin options\n * @property {EnhancedPlugin | null} instance - Plugin instance (after initialization)\n */\n","var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n/**\n * Combine two comparators into a single comparators.\n */\nfunction combineComparators(comparatorA, comparatorB) {\n return function isEqual(a, b, state) {\n return comparatorA(a, b, state) && comparatorB(a, b, state);\n };\n}\n/**\n * Wrap the provided `areItemsEqual` method to manage the circular state, allowing\n * for circular references to be safely included in the comparison without creating\n * stack overflows.\n */\nfunction createIsCircular(areItemsEqual) {\n return function isCircular(a, b, state) {\n if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {\n return areItemsEqual(a, b, state);\n }\n var cache = state.cache;\n var cachedA = cache.get(a);\n var cachedB = cache.get(b);\n if (cachedA && cachedB) {\n return cachedA === b && cachedB === a;\n }\n cache.set(a, b);\n cache.set(b, a);\n var result = areItemsEqual(a, b, state);\n cache.delete(a);\n cache.delete(b);\n return result;\n };\n}\n/**\n * Get the `@@toStringTag` of the value, if it exists.\n */\nfunction getShortTag(value) {\n return value != null ? value[Symbol.toStringTag] : undefined;\n}\n/**\n * Get the properties to strictly examine, which include both own properties that are\n * not enumerable and symbol properties.\n */\nfunction getStrictProperties(object) {\n return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));\n}\n/**\n * Whether the object contains the property passed as an own property.\n */\nvar hasOwn = Object.hasOwn ||\n (function (object, property) {\n return hasOwnProperty.call(object, property);\n });\n/**\n * Whether the values passed are strictly equal or both NaN.\n */\nfunction sameValueZeroEqual(a, b) {\n return a === b || (!a && !b && a !== a && b !== b);\n}\n\nvar PREACT_VNODE = '__v';\nvar PREACT_OWNER = '__o';\nvar REACT_OWNER = '_owner';\nvar getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, keys = Object.keys;\n/**\n * Whether the arrays are equal in value.\n */\nfunction areArraysEqual(a, b, state) {\n var index = a.length;\n if (b.length !== index) {\n return false;\n }\n while (index-- > 0) {\n if (!state.equals(a[index], b[index], index, index, a, b, state)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the dates passed are equal in value.\n */\nfunction areDatesEqual(a, b) {\n return sameValueZeroEqual(a.getTime(), b.getTime());\n}\n/**\n * Whether the errors passed are equal in value.\n */\nfunction areErrorsEqual(a, b) {\n return (a.name === b.name &&\n a.message === b.message &&\n a.cause === b.cause &&\n a.stack === b.stack);\n}\n/**\n * Whether the functions passed are equal in value.\n */\nfunction areFunctionsEqual(a, b) {\n return a === b;\n}\n/**\n * Whether the `Map`s are equal in value.\n */\nfunction areMapsEqual(a, b, state) {\n var size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n var matchedIndices = new Array(size);\n var aIterable = a.entries();\n var aResult;\n var bResult;\n var index = 0;\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n var bIterable = b.entries();\n var hasMatch = false;\n var matchIndex = 0;\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (matchedIndices[matchIndex]) {\n matchIndex++;\n continue;\n }\n var aEntry = aResult.value;\n var bEntry = bResult.value;\n if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) &&\n state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n index++;\n }\n return true;\n}\n/**\n * Whether the numbers are equal in value.\n */\nvar areNumbersEqual = sameValueZeroEqual;\n/**\n * Whether the objects are equal in value.\n */\nfunction areObjectsEqual(a, b, state) {\n var properties = keys(a);\n var index = properties.length;\n if (keys(b).length !== index) {\n return false;\n }\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n if (!isPropertyEqual(a, b, state, properties[index])) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the objects are equal in value with strict property checking.\n */\nfunction areObjectsEqualStrict(a, b, state) {\n var properties = getStrictProperties(a);\n var index = properties.length;\n if (getStrictProperties(b).length !== index) {\n return false;\n }\n var property;\n var descriptorA;\n var descriptorB;\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n property = properties[index];\n if (!isPropertyEqual(a, b, state, property)) {\n return false;\n }\n descriptorA = getOwnPropertyDescriptor(a, property);\n descriptorB = getOwnPropertyDescriptor(b, property);\n if ((descriptorA || descriptorB) &&\n (!descriptorA ||\n !descriptorB ||\n descriptorA.configurable !== descriptorB.configurable ||\n descriptorA.enumerable !== descriptorB.enumerable ||\n descriptorA.writable !== descriptorB.writable)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the primitive wrappers passed are equal in value.\n */\nfunction arePrimitiveWrappersEqual(a, b) {\n return sameValueZeroEqual(a.valueOf(), b.valueOf());\n}\n/**\n * Whether the regexps passed are equal in value.\n */\nfunction areRegExpsEqual(a, b) {\n return a.source === b.source && a.flags === b.flags;\n}\n/**\n * Whether the `Set`s are equal in value.\n */\nfunction areSetsEqual(a, b, state) {\n var size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n var matchedIndices = new Array(size);\n var aIterable = a.values();\n var aResult;\n var bResult;\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n var bIterable = b.values();\n var hasMatch = false;\n var matchIndex = 0;\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (!matchedIndices[matchIndex] &&\n state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the TypedArray instances are equal in value.\n */\nfunction areTypedArraysEqual(a, b) {\n var index = a.length;\n if (b.length !== index) {\n return false;\n }\n while (index-- > 0) {\n if (a[index] !== b[index]) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the URL instances are equal in value.\n */\nfunction areUrlsEqual(a, b) {\n return (a.hostname === b.hostname &&\n a.pathname === b.pathname &&\n a.protocol === b.protocol &&\n a.port === b.port &&\n a.hash === b.hash &&\n a.username === b.username &&\n a.password === b.password);\n}\nfunction isPropertyEqual(a, b, state, property) {\n if ((property === REACT_OWNER ||\n property === PREACT_OWNER ||\n property === PREACT_VNODE) &&\n (a.$$typeof || b.$$typeof)) {\n return true;\n }\n return (hasOwn(b, property) &&\n state.equals(a[property], b[property], property, property, a, b, state));\n}\n\nvar ARGUMENTS_TAG = '[object Arguments]';\nvar BOOLEAN_TAG = '[object Boolean]';\nvar DATE_TAG = '[object Date]';\nvar ERROR_TAG = '[object Error]';\nvar MAP_TAG = '[object Map]';\nvar NUMBER_TAG = '[object Number]';\nvar OBJECT_TAG = '[object Object]';\nvar REG_EXP_TAG = '[object RegExp]';\nvar SET_TAG = '[object Set]';\nvar STRING_TAG = '[object String]';\nvar URL_TAG = '[object URL]';\nvar isArray = Array.isArray;\nvar isTypedArray = typeof ArrayBuffer === 'function' && ArrayBuffer.isView\n ? ArrayBuffer.isView\n : null;\nvar assign = Object.assign;\nvar getTag = Object.prototype.toString.call.bind(Object.prototype.toString);\n/**\n * Create a comparator method based on the type-specific equality comparators passed.\n */\nfunction createEqualityComparator(_a) {\n var areArraysEqual = _a.areArraysEqual, areDatesEqual = _a.areDatesEqual, areErrorsEqual = _a.areErrorsEqual, areFunctionsEqual = _a.areFunctionsEqual, areMapsEqual = _a.areMapsEqual, areNumbersEqual = _a.areNumbersEqual, areObjectsEqual = _a.areObjectsEqual, arePrimitiveWrappersEqual = _a.arePrimitiveWrappersEqual, areRegExpsEqual = _a.areRegExpsEqual, areSetsEqual = _a.areSetsEqual, areTypedArraysEqual = _a.areTypedArraysEqual, areUrlsEqual = _a.areUrlsEqual, unknownTagComparators = _a.unknownTagComparators;\n /**\n * compare the value of the two objects and return true if they are equivalent in values\n */\n return function comparator(a, b, state) {\n // If the items are strictly equal, no need to do a value comparison.\n if (a === b) {\n return true;\n }\n // If either of the items are nullish and fail the strictly equal check\n // above, then they must be unequal.\n if (a == null || b == null) {\n return false;\n }\n var type = typeof a;\n if (type !== typeof b) {\n return false;\n }\n if (type !== 'object') {\n if (type === 'number') {\n return areNumbersEqual(a, b, state);\n }\n if (type === 'function') {\n return areFunctionsEqual(a, b, state);\n }\n // If a primitive value that is not strictly equal, it must be unequal.\n return false;\n }\n var constructor = a.constructor;\n // Checks are listed in order of commonality of use-case:\n // 1. Common complex object types (plain object, array)\n // 2. Common data values (date, regexp)\n // 3. Less-common complex object types (map, set)\n // 4. Less-common data values (promise, primitive wrappers)\n // Inherently this is both subjective and assumptive, however\n // when reviewing comparable libraries in the wild this order\n // appears to be generally consistent.\n // Constructors should match, otherwise there is potential for false positives\n // between class and subclass or custom object and POJO.\n if (constructor !== b.constructor) {\n return false;\n }\n // `isPlainObject` only checks against the object's own realm. Cross-realm\n // comparisons are rare, and will be handled in the ultimate fallback, so\n // we can avoid capturing the string tag.\n if (constructor === Object) {\n return areObjectsEqual(a, b, state);\n }\n // `isArray()` works on subclasses and is cross-realm, so we can avoid capturing\n // the string tag or doing an `instanceof` check.\n if (isArray(a)) {\n return areArraysEqual(a, b, state);\n }\n // `isTypedArray()` works on all possible TypedArray classes, so we can avoid\n // capturing the string tag or comparing against all possible constructors.\n if (isTypedArray != null && isTypedArray(a)) {\n return areTypedArraysEqual(a, b, state);\n }\n // Try to fast-path equality checks for other complex object types in the\n // same realm to avoid capturing the string tag. Strict equality is used\n // instead of `instanceof` because it is more performant for the common\n // use-case. If someone is subclassing a native class, it will be handled\n // with the string tag comparison.\n if (constructor === Date) {\n return areDatesEqual(a, b, state);\n }\n if (constructor === RegExp) {\n return areRegExpsEqual(a, b, state);\n }\n if (constructor === Map) {\n return areMapsEqual(a, b, state);\n }\n if (constructor === Set) {\n return areSetsEqual(a, b, state);\n }\n // Since this is a custom object, capture the string tag to determing its type.\n // This is reasonably performant in modern environments like v8 and SpiderMonkey.\n var tag = getTag(a);\n if (tag === DATE_TAG) {\n return areDatesEqual(a, b, state);\n }\n // For RegExp, the properties are not enumerable, and therefore will give false positives if\n // tested like a standard object.\n if (tag === REG_EXP_TAG) {\n return areRegExpsEqual(a, b, state);\n }\n if (tag === MAP_TAG) {\n return areMapsEqual(a, b, state);\n }\n if (tag === SET_TAG) {\n return areSetsEqual(a, b, state);\n }\n if (tag === OBJECT_TAG) {\n // The exception for value comparison is custom `Promise`-like class instances. These should\n // be treated the same as standard `Promise` objects, which means strict equality, and if\n // it reaches this point then that strict equality comparison has already failed.\n return (typeof a.then !== 'function' &&\n typeof b.then !== 'function' &&\n areObjectsEqual(a, b, state));\n }\n // If a URL tag, it should be tested explicitly. Like RegExp, the properties are not\n // enumerable, and therefore will give false positives if tested like a standard object.\n if (tag === URL_TAG) {\n return areUrlsEqual(a, b, state);\n }\n // If an error tag, it should be tested explicitly. Like RegExp, the properties are not\n // enumerable, and therefore will give false positives if tested like a standard object.\n if (tag === ERROR_TAG) {\n return areErrorsEqual(a, b, state);\n }\n // If an arguments tag, it should be treated as a standard object.\n if (tag === ARGUMENTS_TAG) {\n return areObjectsEqual(a, b, state);\n }\n // As the penultimate fallback, check if the values passed are primitive wrappers. This\n // is very rare in modern JS, which is why it is deprioritized compared to all other object\n // types.\n if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {\n return arePrimitiveWrappersEqual(a, b, state);\n }\n if (unknownTagComparators) {\n var unknownTagComparator = unknownTagComparators[tag];\n if (!unknownTagComparator) {\n var shortTag = getShortTag(a);\n if (shortTag) {\n unknownTagComparator = unknownTagComparators[shortTag];\n }\n }\n // If the custom config has an unknown tag comparator that matches the captured tag or the\n // @@toStringTag, it is the source of truth for whether the values are equal.\n if (unknownTagComparator) {\n return unknownTagComparator(a, b, state);\n }\n }\n // If not matching any tags that require a specific type of comparison, then we hard-code false because\n // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:\n // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only\n // comparison that can be made.\n // - For types that can be introspected, but rarely have requirements to be compared\n // (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common\n // use-cases (may be included in a future release, if requested enough).\n // - For types that can be introspected but do not have an objective definition of what\n // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.\n // In all cases, these decisions should be reevaluated based on changes to the language and\n // common development practices.\n return false;\n };\n}\n/**\n * Create the configuration object used for building comparators.\n */\nfunction createEqualityComparatorConfig(_a) {\n var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;\n var config = {\n areArraysEqual: strict\n ? areObjectsEqualStrict\n : areArraysEqual,\n areDatesEqual: areDatesEqual,\n areErrorsEqual: areErrorsEqual,\n areFunctionsEqual: areFunctionsEqual,\n areMapsEqual: strict\n ? combineComparators(areMapsEqual, areObjectsEqualStrict)\n : areMapsEqual,\n areNumbersEqual: areNumbersEqual,\n areObjectsEqual: strict\n ? areObjectsEqualStrict\n : areObjectsEqual,\n arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,\n areRegExpsEqual: areRegExpsEqual,\n areSetsEqual: strict\n ? combineComparators(areSetsEqual, areObjectsEqualStrict)\n : areSetsEqual,\n areTypedArraysEqual: strict\n ? areObjectsEqualStrict\n : areTypedArraysEqual,\n areUrlsEqual: areUrlsEqual,\n unknownTagComparators: undefined,\n };\n if (createCustomConfig) {\n config = assign({}, config, createCustomConfig(config));\n }\n if (circular) {\n var areArraysEqual$1 = createIsCircular(config.areArraysEqual);\n var areMapsEqual$1 = createIsCircular(config.areMapsEqual);\n var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);\n var areSetsEqual$1 = createIsCircular(config.areSetsEqual);\n config = assign({}, config, {\n areArraysEqual: areArraysEqual$1,\n areMapsEqual: areMapsEqual$1,\n areObjectsEqual: areObjectsEqual$1,\n areSetsEqual: areSetsEqual$1,\n });\n }\n return config;\n}\n/**\n * Default equality comparator pass-through, used as the standard `isEqual` creator for\n * use inside the built comparator.\n */\nfunction createInternalEqualityComparator(compare) {\n return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {\n return compare(a, b, state);\n };\n}\n/**\n * Create the `isEqual` function used by the consuming application.\n */\nfunction createIsEqual(_a) {\n var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;\n if (createState) {\n return function isEqual(a, b) {\n var _a = createState(), _b = _a.cache, cache = _b === void 0 ? circular ? new WeakMap() : undefined : _b, meta = _a.meta;\n return comparator(a, b, {\n cache: cache,\n equals: equals,\n meta: meta,\n strict: strict,\n });\n };\n }\n if (circular) {\n return function isEqual(a, b) {\n return comparator(a, b, {\n cache: new WeakMap(),\n equals: equals,\n meta: undefined,\n strict: strict,\n });\n };\n }\n var state = {\n cache: undefined,\n equals: equals,\n meta: undefined,\n strict: strict,\n };\n return function isEqual(a, b) {\n return comparator(a, b, state);\n };\n}\n\n/**\n * Whether the items passed are deeply-equal in value.\n */\nvar deepEqual = createCustomEqual();\n/**\n * Whether the items passed are deeply-equal in value based on strict comparison.\n */\nvar strictDeepEqual = createCustomEqual({ strict: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references.\n */\nvar circularDeepEqual = createCustomEqual({ circular: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references,\n * based on strict comparison.\n */\nvar strictCircularDeepEqual = createCustomEqual({\n circular: true,\n strict: true,\n});\n/**\n * Whether the items passed are shallowly-equal in value.\n */\nvar shallowEqual = createCustomEqual({\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value based on strict comparison\n */\nvar strictShallowEqual = createCustomEqual({\n strict: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references.\n */\nvar circularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references,\n * based on strict comparison.\n */\nvar strictCircularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: function () { return sameValueZeroEqual; },\n strict: true,\n});\n/**\n * Create a custom equality comparison method.\n *\n * This can be done to create very targeted comparisons in extreme hot-path scenarios\n * where the standard methods are not performant enough, but can also be used to provide\n * support for legacy environments that do not support expected features like\n * `RegExp.prototype.flags` out of the box.\n */\nfunction createCustomEqual(options) {\n if (options === void 0) { options = {}; }\n var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;\n var config = createEqualityComparatorConfig(options);\n var comparator = createEqualityComparator(config);\n var equals = createCustomInternalComparator\n ? createCustomInternalComparator(comparator)\n : createInternalEqualityComparator(comparator);\n return createIsEqual({ circular: circular, comparator: comparator, createState: createState, equals: equals, strict: strict });\n}\n\nexport { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };\n//# sourceMappingURL=index.mjs.map\n","import { deepEqual } from 'fast-equals';\n\n/**\n * HistoryDiff utilities\n * Provide flatten() and diff() for NodeTreeFormat snapshots.\n */\n\n/**\n * @typedef {{ meta?: any, format?: 'node_tree', data: NodeTreeData }} NodeTreeFormat\n * @typedef {{ id?: string, topic?: string, expanded?: boolean, direction?: 'left'|'right', data?: Record<string, any>, children?: NodeTreeData[], [key: string]: any }} NodeTreeData\n */\n\n/**\n * @typedef {Object} FlatNode\n * @property {string} id - Node ID\n * @property {string} [topic] - Node topic/title\n * @property {Record<string, any>} [data] - Node data\n * @property {string|null} [parentid] - Parent node ID (structure field)\n * @property {number} [index] - Node order in parent's children (structure field)\n */\n\n/**\n * @typedef {Object} ChangeDetail\n * @property {string} key - The field name that changed\n * @property {any} before - Value before change\n * @property {any} after - Value after change\n */\n\n/**\n * @typedef {Object} UpdatedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before change\n * @property {FlatNode} after - Node state after change\n * @property {ChangeDetail[]} changes - Array of field changes\n */\n\n/**\n * @typedef {Object} MoveInfo\n * @property {boolean} parentChanged - Whether parent changed\n * @property {boolean} orderChanged - Whether order changed\n * @property {string|null} fromParent - Original parent ID\n * @property {string|null} toParent - New parent ID\n * @property {number} fromOrder - Original order\n * @property {number} toOrder - New order\n */\n\n/**\n * @typedef {Object} MovedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before move\n * @property {FlatNode} after - Node state after move\n * @property {MoveInfo} moveInfo - Movement details\n */\n\n/**\n * @typedef {Object} ModifiedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before modification\n * @property {FlatNode} after - Node state after modification\n * @property {ChangeDetail[]} changes - Array of field changes (excluding structure fields)\n */\n\n/**\n * @typedef {Object} MovedAndModifiedNode\n * @property {string} id - Node ID\n * @property {FlatNode} before - Node state before change\n * @property {FlatNode} after - Node state after change\n * @property {ChangeDetail[]} changes - Array of field changes (excluding structure fields)\n * @property {MoveInfo} moveInfo - Movement details\n */\n\n/**\n * @typedef {Object} DiffResult\n * @property {FlatNode[]} created - Newly created nodes\n * @property {UpdatedNode[]} updated - Updated nodes (all changes)\n * @property {FlatNode[]} deleted - Deleted nodes\n * @property {boolean} truncated - Whether results were truncated due to maxSize\n * @property {MovedNode[]} [moved] - Nodes that were only moved (when categorize=true)\n * @property {ModifiedNode[]} [modified] - Nodes that were only modified (when categorize=true)\n * @property {MovedAndModifiedNode[]} [movedAndModified] - Nodes that were both moved and modified (when categorize=true)\n */\n\n/**\n * @typedef {Object} FlattenOptions\n * @property {string[]} [fields] - Array of field names to include. Defaults to ['topic', 'data', 'id'].\n * When using custom fieldNames (e.g., { id: 'key', topic: 'name' }), this should be\n * ['name', 'data', 'key'] to match the actual field names in the data.\n * @property {string} [idKey] - The field name to use as the node ID. Defaults to 'id'.\n * When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.\n * @property {string} [childrenKey] - The field name to use for children array. Defaults to 'children'.\n * When using custom fieldNames (e.g., { children: 'items' }), this should be 'items'.\n * @property {boolean} [includeStructure] - Whether to include parentid and index. Defaults to true\n */\n\n/**\n * @typedef {Object} DiffOptions\n * @property {string[]} [fields] - Array of field names to compare. Defaults to ['topic', 'data', 'id'].\n * When using custom fieldNames (e.g., { id: 'key', topic: 'name' }), this should be\n * ['name', 'data', 'key'] to match the actual field names in the data.\n * Note: When using jm.history.diff(), this is automatically handled based\n * on the configured fieldNames, so you don't need to specify it manually.\n * @property {string} [idKey] - The field name to use as the node ID. Defaults to 'id'.\n * When using custom fieldNames (e.g., { id: 'key' }), this should be 'key'.\n * Note: When using jm.history.diff(), this is automatically handled.\n * @property {string} [childrenKey] - The field name to use for children array. Defaults to 'children'.\n * When using custom fieldNames (e.g., { children: 'items' }), this should be 'items'.\n * Note: When using jm.history.diff(), this is automatically handled.\n * @property {boolean} [includeStructure] - Whether to include parentid and index in comparison. Defaults to true\n * @property {number} [maxSize] - Maximum number of diff results. Defaults to 5000\n * @property {boolean} [categorize] - Whether to categorize updates into moved/modified/movedAndModified. Defaults to false\n */\n\nfunction isFormat(obj) {\n return obj && typeof obj === 'object' && 'data' in obj;\n}\nfunction getRootData(tree) {\n return isFormat(tree) ? tree.data : tree;\n}\n\n/**\n * Flatten a tree into a Map of nodes keyed by id.\n *\n * Note: When using custom fieldNames, make sure to pass the correct field names in opts.fields.\n * For example, if you configured fieldNames: { topic: 'name' }, you should pass fields: ['name', 'data', 'id'].\n *\n * @param {NodeTreeFormat|NodeTreeData} tree - The tree to flatten\n * @param {FlattenOptions} [opts] - Flatten options\n * @returns {Map<string, FlatNode>} Map of node id -> flattened node object\n *\n * @example\n * // With default fieldNames\n * const tree = { data: { id: 'root', topic: 'Root', children: [...] } };\n * const flatMap = flatten(tree);\n * const rootNode = flatMap.get('root'); // { id: 'root', topic: 'Root', data: {...}, parentid: null, index: 0 }\n *\n * @example\n * // With custom fieldNames: { topic: 'name' }\n * const tree = { data: { id: 'root', name: 'Root', children: [...] } };\n * const flatMap = flatten(tree, { fields: ['name', 'data', 'id'] });\n * const rootNode = flatMap.get('root'); // { id: 'root', name: 'Root', data: {...}, parentid: null, index: 0 }\n */\nexport function flatten(tree, opts) {\n const root = getRootData(tree);\n // Default fields: ['topic', 'data', 'id'] when not specified\n const fields = opts && Array.isArray(opts.fields) ? opts.fields : ['topic', 'data', 'id'];\n const idKey = opts && opts.idKey ? opts.idKey : 'id';\n const childrenKey = opts && opts.childrenKey ? opts.childrenKey : 'children';\n const includeStructure = !opts || opts.includeStructure !== false;\n /** @type {Map<string, any>} */\n const map = new Map();\n\n function pick(node) {\n const out = {};\n // Always include the id field (using custom key name if provided)\n if (idKey in node) {\n out[idKey] = node[idKey];\n }\n\n // Define standard fields that should not be collected into 'data'\n const standardFields = new Set([\n idKey,\n childrenKey,\n 'direction',\n 'expanded',\n 'parentid',\n 'index',\n 'isroot',\n ]);\n\n // Check if 'data' field is requested\n const includeData = fields.includes('data');\n\n // Include other specified fields\n for (const k of fields) {\n if (k === 'data') {\n // Special handling for 'data' field:\n // Collect all non-standard fields into a data object\n const dataObj = {};\n let hasData = false;\n for (const nodeKey in node) {\n if (!standardFields.has(nodeKey) && !fields.includes(nodeKey)) {\n dataObj[nodeKey] = node[nodeKey];\n hasData = true;\n }\n }\n if (hasData) {\n out.data = dataObj;\n }\n } else if (k in node && k !== idKey) {\n // Avoid duplicating id field\n out[k] = node[k];\n }\n }\n return out;\n }\n\n function walk(n, parentId, index) {\n const item = pick(n);\n const nodeId = n[idKey]; // Use custom idKey to get node ID\n if (includeStructure) {\n item.parentid = parentId || null;\n item.index = typeof index === 'number' ? index : 0;\n }\n map.set(nodeId, item);\n const children = n[childrenKey]; // Use custom childrenKey to get children array\n if (children && Array.isArray(children)) children.forEach((c, i) => walk(c, nodeId, i));\n }\n\n if (root && root[idKey]) walk(root, null, 0);\n return map;\n}\n\nfunction shallowEqual(a, b) {\n if (a === b) return true;\n if (!a || !b) return false;\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n if (ka.length !== kb.length) return false;\n for (const k of ka) {\n const va = a[k];\n const vb = b[k];\n if (va === vb) continue;\n const isObj = va && vb && typeof va === 'object' && typeof vb === 'object';\n if (isObj) {\n if (!deepEqual(va, vb)) return false;\n continue;\n }\n if (va !== vb) return false;\n }\n return true;\n}\n\n/**\n * Compute changed top-level keys between two flattened node items.\n * For object values (e.g., data), uses deep-equal; reports the key as a whole.\n * Note: 'id' key会被忽略,因为它与 map key 相同且不应作为差异。\n * @param {Record<string, any>} a\n * @param {Record<string, any>} b\n * @returns {{ key: string, before: any, after: any }[]}\n */\nfunction computeChanges(a, b) {\n /** @type {{ key:string, before:any, after:any }[]} */\n const changes = [];\n if (!a || !b) return changes;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n keys.delete('id');\n for (const k of keys) {\n const va = a[k];\n const vb = b[k];\n if (va === vb) continue;\n const bothObj = va && vb && typeof va === 'object' && typeof vb === 'object';\n const different = bothObj ? !deepEqual(va, vb) : va !== vb;\n if (different) changes.push({ key: k, before: va, after: vb });\n }\n return changes;\n}\n\n/**\n * Detect if a node has been moved (parent or order changed)\n * @param {{ key: string, before: any, after: any }[]} changes - Array of changes from computeChanges()\n * @returns {{ moved: boolean, parentChanged: boolean, orderChanged: boolean }}\n */\nfunction detectMove(changes) {\n let parentChanged = false;\n let orderChanged = false;\n\n // Check if parentid or index are in the changes array\n for (const change of changes) {\n if (change.key === 'parentid') {\n parentChanged = true;\n }\n if (change.key === 'index') {\n orderChanged = true;\n }\n }\n\n const moved = parentChanged || orderChanged;\n return { moved, parentChanged, orderChanged };\n}\n\n/**\n * Categorize updated nodes into moved, modified, or movedAndModified\n * @param {{ id: string, before: any, after: any, changes: { key: string, before: any, after: any }[] }[]} updates\n * @returns {{\n * moved: { id: string, before: any, after: any, moveInfo: { parentChanged: boolean, orderChanged: boolean, fromParent: any, toParent: any, fromOrder: any, toOrder: any } }[],\n * modified: { id: string, before: any, after: any, changes: { key: string, before: any, after: any }[] }[],\n * movedAndModified: { id: string, before: any, after: any, changes: { key: string, before: any, after: any }[], moveInfo: { parentChanged: boolean, orderChanged: boolean, fromParent: any, toParent: any, fromOrder: any, toOrder: any } }[]\n * }}\n */\nfunction categorizeUpdates(updates) {\n const moved = [];\n const modified = [];\n const movedAndModified = [];\n\n for (const update of updates) {\n const { id, before, after, changes } = update;\n const moveDetection = detectMove(changes);\n\n if (moveDetection.moved) {\n // Build moveInfo\n const moveInfo = {\n parentChanged: moveDetection.parentChanged,\n orderChanged: moveDetection.orderChanged,\n fromParent: before.parentid,\n toParent: after.parentid,\n fromOrder: before.index,\n toOrder: after.index,\n };\n\n // Filter out structure-only changes (parentid, index)\n const contentChanges = changes.filter(c => c.key !== 'parentid' && c.key !== 'index');\n\n if (contentChanges.length > 0) {\n // Both moved and modified\n movedAndModified.push({ id, before, after, changes: contentChanges, moveInfo });\n } else {\n // Only moved\n moved.push({ id, before, after, moveInfo });\n }\n } else {\n // Only modified (no movement)\n modified.push({ id, before, after, changes });\n }\n }\n\n return { moved, modified, movedAndModified };\n}\n\n/**\n * Compute diff between two snapshots.\n *\n * Note: When using custom fieldNames, make sure to pass the correct field names in opts.fields.\n * For example, if you configured fieldNames: { topic: 'name' }, you should pass fields: ['name', 'data', 'id'].\n * When using jm.history.diff(), this is automatically handled for you.\n *\n * @param {NodeTreeFormat|NodeTreeData} a - First snapshot (before)\n * @param {NodeTreeFormat|NodeTreeData} b - Second snapshot (after)\n * @param {DiffOptions} [opts] - Diff options\n * @returns {DiffResult} Diff result with created, updated, deleted nodes, and optionally categorized updates\n *\n * @example\n * // Basic usage with default fieldNames\n * const result = diff(snapshot1, snapshot2);\n * console.log(result.created); // Newly created nodes\n * console.log(result.updated); // Updated nodes with changes\n * console.log(result.deleted); // Deleted nodes\n *\n * @example\n * // With categorization\n * const result = diff(snapshot1, snapshot2, { categorize: true });\n * console.log(result.moved); // Nodes that were only moved\n * console.log(result.modified); // Nodes that were only modified\n * console.log(result.movedAndModified); // Nodes that were both moved and modified\n *\n * @example\n * // With custom fieldNames: { topic: 'name' }\n * const result = diff(snapshot1, snapshot2, { fields: ['name', 'data', 'id'] });\n * // Now the diff will correctly detect changes in the 'name' field\n *\n * @example\n * // Using jm.history.diff() (recommended - automatically handles fieldNames)\n * const before = jm.get_data('node_tree');\n * // ... make changes ...\n * const after = jm.get_data('node_tree');\n * const result = jm.history.diff(before, after);\n * // fieldNames are automatically applied, no need to specify fields manually\n */\nexport function diff(a, b, opts) {\n const fields = opts && opts.fields;\n const idKey = opts && opts.idKey;\n const childrenKey = opts && opts.childrenKey;\n const includeStructure = !opts || opts.includeStructure !== false;\n const maxSize = opts && typeof opts.maxSize === 'number' ? opts.maxSize : 5000;\n const categorize = opts && opts.categorize === true;\n const A = flatten(a, { fields, idKey, childrenKey, includeStructure });\n const B = flatten(b, { fields, idKey, childrenKey, includeStructure });\n /** @type {any[]} */ const created = [];\n /** @type {{id:string,before:any,after:any,changes:{key:string,before:any,after:any}[]}[]} */ const updated =\n [];\n /** @type {any[]} */ const deleted = [];\n\n // created / updated\n for (const [id, nodeB] of B) {\n if (!A.has(id)) {\n created.push(nodeB);\n continue;\n }\n const nodeA = A.get(id);\n if (!shallowEqual(nodeA, nodeB)) {\n const changes = computeChanges(nodeA, nodeB);\n updated.push({ id, before: nodeA, after: nodeB, changes });\n }\n }\n // deleted\n for (const [id, nodeA] of A) {\n if (!B.has(id)) deleted.push(nodeA);\n }\n\n let truncated = false;\n const total = created.length + updated.length + deleted.length;\n if (total > maxSize) {\n truncated = true;\n const limit = Math.max(0, maxSize);\n // proportional slice\n const c = Math.min(created.length, Math.floor(limit * (created.length / total)));\n const u = Math.min(updated.length, Math.floor(limit * (updated.length / total)));\n const d = Math.min(deleted.length, Math.max(0, limit - c - u));\n created.length = c;\n updated.length = u;\n deleted.length = d;\n }\n\n // Categorize updates if requested\n if (categorize && includeStructure) {\n const categorized = categorizeUpdates(updated);\n return {\n created,\n updated,\n deleted,\n truncated,\n moved: categorized.moved,\n modified: categorized.modified,\n movedAndModified: categorized.movedAndModified,\n };\n }\n\n return { created, updated, deleted, truncated };\n}\n","/**\n * @license BSD\n *\n * HistoryPlugin (EnhancedPlugin)\n * Undo/Redo & History stack for jsMind with public APIs and future diff support.\n * This is the initial skeleton (Task 1): preload plugin, mount jm.history with no-op methods.\n */\n\nimport { EnhancedPlugin } from '../../jsmind.enhanced-plugin.js';\nimport { logger, EventType } from '../../jsmind.common.js';\nimport { diff as diffSnapshots } from './history-diff.js';\n\n/**\n * @typedef {import('../../jsmind.js').default} JsMind\n * @typedef {import('./history-diff.js').DiffResult} DiffResult\n * @typedef {import('./history-diff.js').DiffOptions} DiffOptions\n */\n\nconst DEFAULT_OPTIONS = {\n enabled: true,\n throttleMs: 100,\n maxHistory: 500,\n storageMode: 'object', // 'object' | 'string'\n autoSwitchThreshold: 0, // 0 = disabled, > 0 = auto switch to 'string' mode when node count exceeds threshold\n keymap: { enabled: false, redoUsesY: false },\n detail: { enabled: false },\n diff: { flat: true, fields: undefined, maxSize: 5000 },\n};\n\n/**\n * Normalize and freeze options (shallow)\n */\nfunction normalizeOptions(opt) {\n const o = Object.assign({}, DEFAULT_OPTIONS, opt || {});\n if (!o.keymap) o.keymap = { enabled: false, redoUsesY: false };\n if (!o.detail) o.detail = { enabled: false };\n if (!o.diff) o.diff = { flat: true, fields: undefined, maxSize: 5000 };\n return o;\n}\n\n/**\n * HistoryPlugin skeleton (Task 1)\n */\nclass HistoryPlugin extends EnhancedPlugin {\n static instanceName = 'historyPlugin';\n static preload = true;\n\n /**\n * @param {{ jm: JsMind, pluginOpt?: any }} params\n */\n constructor({ jm, pluginOpt }) {\n super({ jm, pluginOpt });\n this.options = normalizeOptions(pluginOpt);\n\n // In preload stage, core providers may not be ready. Only mount API.\n this._mounted = false;\n this._core = null;\n this._mountAPI();\n\n // Prepare core after jm providers are ready (later tasks may rebind events)\n // Here we set up functional methods for Task 2 (HistoryCore minimal implementation)\n this._initCore();\n }\n\n /**\n * Lifecycle hook: called when jsMind instance is destroyed\n */\n beforePluginDestroy() {\n logger.debug('[history] beforePluginDestroy: clearing history stack');\n if (this._core) {\n this._core.clear();\n }\n }\n\n /** Initialize HistoryCore and wire API methods */\n _initCore() {\n const jm = this.jm;\n const opt = this.options;\n\n // Inject shortcut mapping in preload phase so ShortcutProvider can pick them up in init()\n if (opt.keymap && opt.keymap.enabled && jm.options && jm.options.shortcut) {\n this._injectShortcuts(jm.options.shortcut, !!opt.keymap.redoUsesY);\n }\n\n const core = new HistoryCore(jm, opt);\n this._core = core;\n\n if (!jm.history) return; // should exist after _mountAPI\n\n // Wire real implementations\n jm.history.add = (reason, meta) => core.add(reason, meta);\n jm.history.pause = () => core.pause();\n jm.history.resume = flush => core.resume(!!flush);\n jm.history.clear = () => core.clear();\n\n jm.history.canBack = () => core.canBack();\n jm.history.canForward = () => core.canForward();\n jm.history.back = steps => core.back(typeof steps === 'number' ? steps : 1);\n jm.history.forward = steps => core.forward(typeof steps === 'number' ? steps : 1);\n\n jm.history.length = () => core.length();\n jm.history.index = () => core.index();\n jm.history.setMax = count => core.setMax(count);\n jm.history.setThrottle = ms => core.setThrottle(ms);\n\n jm.history.exportSnapshot = () => core.exportSnapshot();\n jm.history.importSnapshot = (data, applyOptions) => core.importSnapshot(data, applyOptions);\n jm.history.getStack = () => core.getStackMeta();\n jm.history.diff = (a, b, opts) => {\n // Auto-inject fieldNames configuration if not explicitly provided\n const fieldNames = this.jm.options.fieldNames;\n const idKey = fieldNames?.id || 'id';\n const topicKey = fieldNames?.topic || 'topic';\n const childrenKey = fieldNames?.children || 'children';\n const mergedOpts = {\n fields: [topicKey, 'data', idKey],\n idKey: idKey, // Pass idKey for pick() function\n childrenKey: childrenKey, // Pass childrenKey for walk() function\n ...opts,\n };\n return diffSnapshots(a, b, mergedOpts);\n };\n\n // Bind events: detect mind-map switching, seed initial snapshot, capture edits\n this._listener = (type, payload) => {\n try {\n // Handle show event: detect mind-map switching and seed initial snapshot\n if (type === EventType.show && payload && 'data' in payload) {\n // Extract root id from payload\n // payload.data is an array: [mind_data]\n // mind_data can be node_tree format {meta, format, data: {id, topic, children}}\n // or node_array format {meta, format, data: [{id, isroot, topic}, ...]}\n let currentRootId = null;\n const mindData = payload.data && payload.data[0];\n if (mindData) {\n if (mindData.data) {\n // node_tree format or node_array format\n if (Array.isArray(mindData.data)) {\n // node_array format: find root node\n const rootNode = mindData.data.find(n => n.isroot);\n currentRootId = rootNode && rootNode.id;\n } else {\n // node_tree format: data.id is root id\n currentRootId = mindData.data.id;\n }\n } else if (mindData.id) {\n // Direct node_tree format without meta\n currentRootId = mindData.id;\n }\n }\n\n // Check if root id changed (new mind-map or first load)\n if (currentRootId && currentRootId !== core._lastRootId) {\n // Clear stack and pause history recording immediately when switching mind-map\n // This prevents capturing intermediate edit events during rendering\n logger.debug('[history] root id changed, clearing stack and pausing');\n core.clear();\n core._lastRootId = currentRootId;\n\n // Defer initial snapshot to next event loop tick\n // Ensures all synchronous rendering and event handlers have completed\n setTimeout(() => {\n try {\n logger.debug('[history] adding bootstrap snapshot after show');\n core._addNow && core._addNow('bootstrap');\n logger.debug('[history] resuming history recording');\n } catch (e) {\n logger.warn('[history] failed to add bootstrap snapshot', e);\n }\n }, 100); // Use 100ms delay to ensure all rendering is complete\n }\n return;\n }\n\n // Capture standard edit operations\n if (type === EventType.edit && payload && payload.evt) {\n core.add(payload.evt, payload);\n }\n } catch (e) {\n logger.warn('[history] listener error', e);\n }\n };\n jm.add_event_listener(this._listener);\n }\n\n /**\n * Inject shortcut options so provider can register mapping in its init phase\n * @param {{ enable?: boolean, handles: Record<string,Function>, mapping: Record<string, number|number[]> }} sc\n * @param {boolean} redoUsesY\n */\n _injectShortcuts(sc, redoUsesY) {\n // Build key codes as ShortcutProvider expects\n const CTRL = 1 << 12,\n META = 1 << 13,\n SHIFT = 1 << 10;\n const Z = 90,\n Y = 89;\n const backKeys = [CTRL + Z, META + Z];\n const forwardKeys = redoUsesY ? [CTRL + Y, META + Y] : [CTRL + SHIFT + Z, META + SHIFT + Z];\n\n sc.handles['history_back'] = (jm, e) => {\n if (jm.history && jm.history.back()) {\n e.preventDefault();\n e.stopPropagation && e.stopPropagation();\n }\n };\n sc.handles['history_forward'] = (jm, e) => {\n if (jm.history && jm.history.forward()) {\n e.preventDefault();\n e.stopPropagation && e.stopPropagation();\n }\n };\n sc.mapping['history_back'] = backKeys;\n sc.mapping['history_forward'] = forwardKeys;\n }\n\n /** Mount public API on jm.history (placeholder defaults) */\n _mountAPI() {\n if (this._mounted) return;\n const jm = this.jm;\n\n // Public surface designed by requirements; will be wired to core in _initCore.\n const api = {\n // control & stack\n add: () => undefined,\n pause: () => undefined,\n resume: _flush => undefined,\n clear: () => undefined,\n\n // navigation\n canBack: () => false,\n canForward: () => false,\n back: _steps => false,\n forward: _steps => false,\n\n // info/config\n length: () => 0,\n index: () => -1,\n setMax: _count => undefined,\n setThrottle: _ms => undefined,\n\n // snapshots\n exportSnapshot: () => null,\n importSnapshot: (_data, _opts) => undefined,\n\n // stack & diff (wired in _initCore)\n getStack: () => ({ items: [], index: -1 }),\n /**\n * Compare two snapshots and return the differences.\n * Automatically uses the configured fieldNames to ensure correct field comparison.\n *\n * @param {object} a - First snapshot (before state)\n * @param {object} b - Second snapshot (after state)\n * @param {DiffOptions} [opts] - Diff options. If opts.fields is provided, it will override the auto-detected fields.\n * @returns {DiffResult} Diff result containing created, deleted, updated, moved, modified, and movedAndModified nodes\n *\n * @example\n * // With default fieldNames\n * const before = jm.get_data('node_tree');\n * // ... make changes ...\n * const after = jm.get_data('node_tree');\n * const diff = jm.history.diff(before, after);\n *\n * @example\n * // With custom fieldNames: { id: 'key', topic: 'name', children: 'items' }\n * // The diff method automatically uses 'key', 'name', and 'items' instead of 'id', 'topic', and 'children'\n * const diff = jm.history.diff(before, after);\n * // diff.updated will correctly detect changes in the 'name' field\n * // and correctly traverse the 'items' array\n */\n diff: (a, b, opts) => {\n // Auto-inject fieldNames configuration if not explicitly provided\n const fieldNames = this.jm.options.fieldNames;\n const idKey = fieldNames?.id || 'id';\n const topicKey = fieldNames?.topic || 'topic';\n const childrenKey = fieldNames?.children || 'children';\n const mergedOpts = {\n fields: [topicKey, 'data', idKey],\n idKey: idKey, // Pass idKey for pick() function\n childrenKey: childrenKey, // Pass childrenKey for walk() function\n ...opts,\n };\n return diffSnapshots(a, b, mergedOpts);\n },\n\n // options getter (read-only view)\n getOptions: () => Object.assign({}, this.options),\n };\n\n Object.defineProperty(jm, 'history', {\n value: api,\n configurable: true,\n enumerable: false,\n writable: false,\n });\n this._mounted = true;\n logger.info('[history] API mounted (preload).');\n }\n\n /** Cleanup before plugin removed */\n beforePluginRemove() {\n try {\n // detach event listener if possible\n if (this._listener && this.jm && Array.isArray(this.jm.event_handles)) {\n const idx = this.jm.event_handles.indexOf(this._listener);\n if (idx >= 0) this.jm.event_handles.splice(idx, 1);\n }\n\n if (this.jm && Object.prototype.hasOwnProperty.call(this.jm, 'history')) {\n // remove mounted API\n // @ts-ignore - JM is JS runtime\n delete this.jm.history;\n }\n this._mounted = false;\n } catch (e) {\n logger.error('[history] remove failed:', e);\n }\n }\n\n /** Default: call beforePluginRemove on destroy */\n beforePluginDestroy() {\n logger.error('beforePluginDestroy');\n this.beforePluginRemove();\n }\n}\n\n// ---------------- HistoryCore (Task 2 minimal implementation) ----------------\nclass HistoryCore {\n /** @param {JsMind} jm @param {any} options */\n constructor(jm, options) {\n this.jm = jm;\n this.options = options;\n this.enabled = !!options.enabled;\n this.maxHistory = Math.max(1, options.maxHistory | 0);\n this.throttleMs = Math.max(0, options.throttleMs | 0);\n this.storageMode = options.storageMode || 'object'; // 'object' | 'string'\n this.autoSwitchThreshold = Math.max(0, options.autoSwitchThreshold | 0);\n\n this._history = []; // of frozen snapshot objects or JSON strings\n this._idx = -1;\n this._paused = false;\n this._lastAddAt = 0;\n this._timer = 0;\n this._pending = false;\n this._pendingMeta = undefined;\n this._lastSig = null; // last snapshot JSON signature for dedupe\n this._lastRootId = null; // track root id to detect mind-map switching\n\n // Defer initial snapshot seeding to first EventType.show (post-show)\n // Avoid calling _addNow here because providers are not ready in preload stage.\n }\n\n // ----- public API wrappers -----\n add(reason = 'manual', meta) {\n if (!this.enabled || this._paused) return;\n const now = Date.now();\n const elapsed = now - this._lastAddAt;\n if (elapsed >= this.throttleMs) {\n this._addNow(reason, meta);\n this._lastAddAt = Date.now();\n return;\n }\n // schedule a coalesced add\n this._pending = true;\n this._pendingMeta = meta;\n if (this._timer) return;\n const delay = Math.max(0, this.throttleMs - elapsed);\n this._timer = setTimeout(() => {\n this._timer = 0;\n if (!this._paused && this.enabled) {\n this._addNow(reason, this._pendingMeta);\n this._lastAddAt = Date.now();\n }\n this._pending = false;\n this._pendingMeta = undefined;\n }, delay);\n }\n pause() {\n this._paused = true;\n }\n resume(flush = false) {\n this._paused = false;\n if (flush && this._pending) {\n clearTimeout(this._timer);\n this._timer = 0;\n this._addNow('resume-flush', this._pendingMeta);\n this._lastAddAt = Date.now();\n this._pending = false;\n this._pendingMeta = undefined;\n }\n }\n clear() {\n this._history = [];\n this._idx = -1;\n this._lastSig = null;\n this._notifyChange();\n }\n canBack() {\n return this._idx > 0;\n }\n canForward() {\n return this._idx >= 0 && this._idx < this._history.length - 1;\n }\n back(steps = 1) {\n if (!Number.isFinite(steps) || steps <= 0) steps = 1;\n if (this._idx - steps < 0) return false;\n this._idx -= steps;\n const result = this._applyIndex();\n if (result) this._notifyChange();\n return result;\n }\n forward(steps = 1) {\n if (!Number.isFinite(steps) || steps <= 0) steps = 1;\n if (this._idx + steps >= this._history.length) return false;\n this._idx += steps;\n const result = this._applyIndex();\n if (result) this._notifyChange();\n return result;\n }\n length() {\n return this._history.length;\n }\n index() {\n return this._idx;\n }\n setMax(count) {\n this.maxHistory = Math.max(1, count | 0);\n }\n setThrottle(ms) {\n this.throttleMs = Math.max(0, ms | 0);\n }\n exportSnapshot() {\n return this._takeSnapshot();\n }\n importSnapshot(data, applyOptions) {\n return this._applySnapshot(data, applyOptions);\n }\n getStackMeta() {\n return { items: this._history.slice(), index: this._idx };\n }\n\n // ----- internals -----\n _notifyChange() {\n try {\n this.jm.invoke_event_handle(EventType.history_change, {\n index: this._idx,\n length: this._history.length,\n canBack: this.canBack(),\n canForward: this.canForward(),\n });\n } catch (e) {\n logger.warn('[history] failed to notify change', e);\n }\n }\n _addNow(_reason, _meta) {\n const snapshot = this._takeSnapshot();\n\n // Auto-switch storage mode based on node count threshold\n let effectiveMode = this.storageMode;\n if (this.autoSwitchThreshold > 0 && effectiveMode === 'object') {\n const nodeCount = this._countNodes(snapshot);\n if (nodeCount > this.autoSwitchThreshold) {\n effectiveMode = 'string';\n logger.debug(\n `[history] auto-switched to string mode (${nodeCount} nodes > ${this.autoSwitchThreshold})`\n );\n }\n }\n\n // Compute signature for dedupe against last snapshot\n let sig = null;\n try {\n sig = JSON.stringify(snapshot);\n } catch {}\n if (sig && this._lastSig && sig === this._lastSig) return; // dedupe\n\n // trim future\n if (this._idx < this._history.length - 1)\n this._history = this._history.slice(0, this._idx + 1);\n\n // push with cap\n if (this._history.length >= this.maxHistory) {\n this._history.shift();\n this._idx = Math.max(-1, this._idx - 1);\n }\n\n // Store based on effective mode\n if (effectiveMode === 'string') {\n this._history.push(sig); // Store JSON string directly\n } else {\n const frozen = this._deepFreeze(snapshot);\n this._history.push(frozen); // Store frozen object\n }\n\n this._idx = this._history.length - 1;\n this._lastSig = sig;\n this._notifyChange();\n }\n\n _applyIndex() {\n const item = this._history[this._idx];\n if (!item) return false;\n\n try {\n // Restore data based on storage type\n let data;\n if (typeof item === 'string') {\n // String mode: parse JSON\n data = JSON.parse(item);\n this._lastSig = item; // Already a string\n } else {\n // Object mode: clone frozen object\n data = this._cloneSnapshot(item);\n try {\n this._lastSig = JSON.stringify(item);\n } catch {\n this._lastSig = null;\n }\n }\n\n this._applySnapshot(data, { skipCentering: true });\n return true;\n } catch (e) {\n logger.error('[history] apply snapshot failed', e);\n return false;\n }\n }\n\n _takeSnapshot() {\n return this.jm.get_data('node_tree');\n }\n _applySnapshot(data, applyOptions) {\n const skip = !!(applyOptions && applyOptions.skipCentering);\n this.jm.show(data, skip);\n return true;\n }\n\n _countNodes(snapshot) {\n // Count total nodes in the snapshot tree\n let count = 0;\n const root = snapshot && snapshot.data ? snapshot.data : snapshot;\n\n function traverse(node) {\n if (!node) return;\n count++;\n if (node.children && Array.isArray(node.children)) {\n for (const child of node.children) {\n traverse(child);\n }\n }\n }\n\n traverse(root);\n return count;\n }\n\n _deepFreeze(obj) {\n if (!obj || typeof obj !== 'object') return obj;\n if (Object.isFrozen(obj)) return obj;\n Object.freeze(obj);\n if (Array.isArray(obj)) {\n for (const v of obj) this._deepFreeze(v);\n } else {\n for (const k of Object.keys(obj)) this._deepFreeze(obj[k]);\n }\n return obj;\n }\n\n _cloneSnapshot(obj) {\n // Prefer structuredClone when available to avoid JSON pitfalls\n if (typeof structuredClone === 'function') {\n try {\n return structuredClone(obj);\n } catch {}\n }\n try {\n return JSON.parse(JSON.stringify(obj));\n } catch {\n return obj;\n }\n }\n}\n\nexport default HistoryPlugin;\nexport { HistoryPlugin };\n"],"names":["String","prototype","startsWith","p","this","slice","length","EventType","LogLevel","_noop","logger","console","level","log","debug","info","warn","error","log_level","EnhancedPlugin","static","constructor","jm","pluginOpt","options","beforePluginRemove","beforePluginDestroy","getOwnPropertyNames","Object","getOwnPropertySymbols","hasOwnProperty","combineComparators","comparatorA","comparatorB","a","b","state","createIsCircular","areItemsEqual","cache","cachedA","get","cachedB","set","result","delete","getStrictProperties","object","concat","hasOwn","property","call","sameValueZeroEqual","getOwnPropertyDescriptor","keys","areArraysEqual","index","equals","areDatesEqual","getTime","areErrorsEqual","name","message","cause","stack","areFunctionsEqual","areMapsEqual","size","aResult","bResult","matchedIndices","Array","aIterable","entries","next","done","bIterable","hasMatch","matchIndex","aEntry","value","bEntry","areNumbersEqual","areObjectsEqual","properties","isPropertyEqual","areObjectsEqualStrict","descriptorA","descriptorB","configurable","enumerable","writable","arePrimitiveWrappersEqual","valueOf","areRegExpsEqual","source","flags","areSetsEqual","values","areTypedArraysEqual","areUrlsEqual","hostname","pathname","protocol","port","hash","username","password","$$typeof","isArray","isTypedArray","ArrayBuffer","isView","assign","getTag","toString","bind","createEqualityComparator","_a","unknownTagComparators","type","Date","RegExp","Map","Set","tag","then","unknownTagComparator","shortTag","Symbol","toStringTag","undefined","deepEqual","createCustomEqual","compare","circular","createCustomInternalComparator","createInternalComparator","createState","_b","strict","config","createCustomConfig","areArraysEqual$1","areMapsEqual$1","areObjectsEqual$1","areSetsEqual$1","createEqualityComparatorConfig","comparator","WeakMap","meta","createIsEqual","_indexOrKeyA","_indexOrKeyB","_parentA","_parentB","flatten","tree","opts","root","obj","data","getRootData","fields","idKey","childrenKey","includeStructure","map","walk","n","parentId","item","node","out","standardFields","includes","k","dataObj","hasData","nodeKey","has","pick","nodeId","parentid","children","forEach","c","i","shallowEqual","ka","kb","va","vb","computeChanges","changes","push","key","before","after","detectMove","parentChanged","orderChanged","change","moved","diff","maxSize","categorize","A","B","created","updated","deleted","id","nodeB","nodeA","truncated","total","limit","Math","max","min","floor","u","d","categorized","updates","modified","movedAndModified","update","moveDetection","moveInfo","fromParent","toParent","fromOrder","toOrder","contentChanges","filter","categorizeUpdates","DEFAULT_OPTIONS","enabled","throttleMs","maxHistory","storageMode","autoSwitchThreshold","keymap","redoUsesY","detail","flat","HistoryPlugin","super","opt","o","normalizeOptions","_mounted","_core","_mountAPI","_initCore","clear","shortcut","_injectShortcuts","core","HistoryCore","history","add","reason","pause","resume","flush","canBack","canForward","back","steps","forward","setMax","count","setThrottle","ms","exportSnapshot","importSnapshot","applyOptions","getStack","getStackMeta","fieldNames","diffSnapshots","topic","_listener","payload","currentRootId","mindData","rootNode","find","isroot","_lastRootId","setTimeout","_addNow","e","evt","add_event_listener","sc","backKeys","CTRL","META","forwardKeys","handles","preventDefault","stopPropagation","mapping","api","_flush","_steps","_count","_ms","_data","_opts","items","getOptions","defineProperty","event_handles","idx","indexOf","splice","_history","_idx","_paused","_lastAddAt","_timer","_pending","_pendingMeta","_lastSig","elapsed","now","delay","clearTimeout","_notifyChange","Number","isFinite","_applyIndex","_takeSnapshot","_applySnapshot","invoke_event_handle","_reason","_meta","snapshot","effectiveMode","nodeCount","_countNodes","sig","JSON","stringify","shift","frozen","_deepFreeze","parse","_cloneSnapshot","skipCentering","get_data","skip","show","traverse","child","isFrozen","freeze","v","structuredClone"],"mappings":"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"}