@jucie.io/state 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/dist/plugins/history.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var w=Symbol("STATE_CONTEXT"),x=Symbol("MATCHER"),a="CREATED",c="DELETED",d="UPDATED";var A={[a]:c,[c]:a,[d]:d};function E(i){let{address:t,path:e,method:n,from:s,to:o,operation:f}=i;return{address:t,path:e,method:n,to:s,from:o,operation:g(f)}}function g(i){return A[i]}function h(i,t){let e=null,n=0;return typeof i=="function"?(e=i,typeof t=="number"&&(n=t)):typeof i=="number"&&(n=i),(...s)=>new Promise((o,f)=>{setTimeout(()=>{try{let l=e?e(...s):void 0;o(l)}catch(l){f(l)}},n)})}var u=class{static name=null;static options={};static configure(t){return t={...this.options,...t},{install:e=>this.install(e,t),name:this.name,options:t}}static install(t,e){e={...this.options,...e};let n=new this(t,e);return Object.defineProperty(n,"state",{value:t,writable:!1,configurable:!1}),Object.defineProperty(n,"options",{value:e,writable:!1,configurable:!1}),n}};var r=class{constructor(t=""){this.isMarker=!0,this.description=t}},p=class extends u{static name="history";static options={maxSize:100};#t=[];#u=!1;#o=new Set;#e=0;#n=0;#s=new Map;#i=!0;#r=!1;onUndoRedo=null;initialize(t){this.onUndoRedo=e=>t.apply(e)}#f(){this.#t=[new r("History Start")],this.#e=0,this.#u=!0,this.#s.clear(),this.#n=0,this.#r=!1}actions(t){return{undo:e=>this.undo(e),redo:e=>this.redo(e),canUndo:()=>this.canUndo(),canRedo:()=>this.canRedo(),batch:()=>this.batch(),commit:()=>this.commit(),onCommit:e=>this.onCommit(e),addMarker:e=>this.addMarker(e),size:()=>this.size(),start:()=>this.#f()}}#l=h(()=>{this.#h(),this.#r=!1});onStateChange(t,e,n){if(!this.#u||!this.#i||e.method==="apply")return;let s=this.#s.get(t.address),o=s?{...e,from:s.from}:e;this.#s.set(t.address,o),!n&&this.#n===0&&this.#a()}addMarker(t=""){this.#h(t),this.#e=this.#t.length-1}undo=h(t=>{if(!this.onUndoRedo)throw new Error("Undo/redo handler is required for undo operation");if(this.#h(),this.#e<=0)return!1;if(this.#i=!1,!(this.#t[this.#e]instanceof r))return console.warn("Expected to be at a marker for undo operation"),!1;let e=new Set,n=this.#e-1;for(;n>0;){let s=this.#t[n];if(s instanceof r)break;e.add(E(s)),n--}return this.#e=n,this.onUndoRedo(Array.from(e)),t&&typeof t=="function"&&t(),this.#i=!0,!0});redo=h(t=>{if(!this.onUndoRedo)throw new Error("Undo/redo handler is required for redo operation");if(this.#e>=this.#t.length-1)return!1;if(this.#i=!1,!(this.#t[this.#e]instanceof r))return console.warn("Expected to be at a marker for redo operation"),!1;let e=new Set;for(this.#e++;this.#e<this.#t.length;){let n=this.#t[this.#e];if(n instanceof r)break;e.add(n),this.#e++}return this.onUndoRedo(e),t&&typeof t=="function"&&t(),this.#i=!0,!0});canUndo(){return this.#e>0}canRedo(){return this.#e<this.#t.length-1}size(){return this.#t.length}batch(){return this.#n++,()=>{this.#n--}}commit(){return this.#n=this.#n-1<0?0:this.#n-1,this.#n===0&&this.#h(),this}pause(){this.#i=!1}resume(){this.#i=!0}onCommit(t){return this.#o.add(t),()=>{this.#o.delete(t)}}reset(){this.#t=[new r("History Start")],this.#o=new Set,this.#e=0,this.#n=0,this.#s=new Map,this.#i=!0,this.#r=!1,this.#u=!1,this.onUndoRedo=null}#a(){this.#r||(this.#r=!0,this.#l())}#h(t=""){if(this.#s.size===0)return;this.#e<this.#t.length-1&&this.#t.splice(this.#e+1);let e=Array.from(this.#s.values());for(this.#t.push(...e),this.#o.forEach(s=>s(e)),this.#t[this.#t.length-1]instanceof r||this.#t.push(new r(t||Date.now().toString()));this.#t.length>this.options.maxSize;)this.#t.shift();this.#s.clear(),this.#e=this.#t.length-1}};export{p as HistoryManager};
|
|
2
|
-
//# sourceMappingURL=history.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/lib/TOKENS.js", "../../src/lib/change.js", "../../src/utils/defer.js", "../../src/Plugin.js", "../../plugins/history/src/HistoryManager.js"],
|
|
4
|
-
"sourcesContent": ["export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG, CREATED, DELETED, UPDATED } from './TOKENS.js';\nimport { dispatch } from './marker.js';\n\nexport const OPERATION_INVERSES = {\n [CREATED]: DELETED,\n [DELETED]: CREATED,\n [UPDATED]: UPDATED,\n}\n\n/**\n * Determines the operation type based on from/to values\n * \n * @private\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {'created'|'deleted'|'updated'} Operation type\n */\nfunction determineOperation(to, from) {\n if (from === undefined) return CREATED;\n if (to === undefined) return DELETED;\n return UPDATED;\n}\n\n/**\n * Creates a change object with the given parameters\n * \n * @param {string} method - Method that triggered the change\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {Object} Change object\n * @example\n * createChange('set', undefined, 'new value') \n * // => { method: 'set', operation: 'created', from: undefined, to: 'new value' }\n */\nexport function createChange(marker, method, to, from) {\n return dispatch(marker, {\n global: () => ({\n path: GLOBAL_TAG,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n path: (marker) => ({\n path: marker.path,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n });\n}\n\n/**\n * Inverts a change object for undo operations\n * \n * @param {Object} change - Change object to invert\n * @param {string} change.method - Original method\n * @param {string} change.operation - Original operation\n * @param {*} change.from - Original from value\n * @param {*} change.to - Original to value\n * @returns {Object} Inverted change object\n * @example\n * invertChange({ method: 'set', operation: 'created', from: undefined, to: 'value' })\n * // => { method: 'set', operation: 'deleted', from: 'value', to: undefined }\n */\nexport function invertChange(change) {\n const {address, path, method, from, to, operation } = change;\n return {\n address,\n path,\n method,\n to: from,\n from: to,\n operation: invertOperation(operation),\n }\n}\n\nexport function invertOperation(operation) {\n return OPERATION_INVERSES[operation];\n}\n\n/**\n * Checks if a change needs to be inverted based on the method\n * \n * @param {string} method - Method to check\n * @returns {boolean} True if the change should be inverted\n * @example\n * shouldInvertChange('undo') // => true\n * shouldInvertChange('set') // => false\n */\nexport function shouldInvertChange(method) {\n return ['undo', 'redo', 'stepBackward', 'stepForward'].includes(method);\n}", "export function defer(arg1, arg2) {\n let callback = null;\n let delay = 0;\n\n if (typeof arg1 === 'function') {\n callback = arg1;\n if (typeof arg2 === 'number') {\n delay = arg2;\n }\n } else if (typeof arg1 === 'number') {\n delay = arg1;\n }\n \n return (...args) => new Promise((resolve, reject) => {\n setTimeout(() => {\n try {\n const result = callback ? callback(...args) : undefined;\n resolve(result);\n } catch (error) {\n reject(error);\n }\n }, delay);\n });\n}\n", "export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { invertChange } from \"../../../src/lib/change.js\";\nimport { defer } from \"../../../src/utils/defer.js\";\nimport { Plugin } from \"../../../src/Plugin.js\";\n\nclass Marker {\n constructor(description = '') {\n this.isMarker = true;\n this.description = description;\n }\n}\n\nexport class HistoryManager extends Plugin {\n static name = 'history';\n static options = {\n maxSize: 100\n };\n\n #changes = [];\n #started = false;\n #commitListeners = new Set();\n #cursor = 0;\n #batchDepth = 0;\n #pendingChanges = new Map();\n #isRecording = true;\n #commitScheduled = false;\n onUndoRedo = null;\n\n initialize(state) {\n this.onUndoRedo = (changes) => state.apply(changes);\n }\n\n #start() {\n // Reset history and set baseline at current state\n this.#changes = [new Marker('History Start')];\n this.#cursor = 0;\n this.#started = true;\n this.#pendingChanges.clear();\n this.#batchDepth = 0;\n this.#commitScheduled = false;\n }\n\n actions (state) {\n return {\n undo: (cb) => this.undo(cb),\n redo: (cb) => this.redo(cb),\n canUndo: () => this.canUndo(),\n canRedo: () => this.canRedo(),\n batch: () => this.batch(),\n commit: () => this.commit(),\n onCommit: (callback) => this.onCommit(callback),\n addMarker: (description) => this.addMarker(description),\n size: () => this.size(),\n start: () => this.#start()\n }\n }\n\n #deferredCommit = defer(() => {\n this.#commitPendingChanges();\n this.#commitScheduled = false;\n });\n\n onStateChange(marker, change, batching) {\n // Ignore all changes if history hasn't been started yet\n if (!this.#started) return;\n if (!this.#isRecording || change.method === 'apply') return;\n \n const existingChange = this.#pendingChanges.get(marker.address);\n const recordedChange = existingChange \n ? { ...change, from: existingChange.from } // Need to preserve original 'from'\n : change; // Can use original object directly\n this.#pendingChanges.set(marker.address, recordedChange);\n\n if (!batching && this.#batchDepth === 0) {\n this.#scheduleCommit();\n }\n }\n\n addMarker(description = '') {\n this.#commitPendingChanges(description);\n this.#cursor = this.#changes.length - 1;\n }\n\n undo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for undo operation');\n }\n\n this.#commitPendingChanges();\n\n // We should always have at least the initial marker\n if (this.#cursor <= 0) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for undo operation');\n return false;\n }\n \n const changesToUndo = new Set();\n let tempCursor = this.#cursor - 1; // Don't modify the actual cursor yet\n \n // Collect changes until we hit the next marker\n while (tempCursor > 0) { // Changed from >= 0 to > 0 to preserve initial marker\n const changeEntry = this.#changes[tempCursor];\n \n if (changeEntry instanceof Marker) {\n break;\n }\n \n changesToUndo.add(invertChange(changeEntry));\n tempCursor--;\n }\n \n // Only update cursor after successfully collecting changes\n this.#cursor = tempCursor;\n \n // Apply the changes (already in correct order)\n this.onUndoRedo(Array.from(changesToUndo));\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n redo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for redo operation');\n }\n\n if (this.#cursor >= this.#changes.length - 1) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for redo operation');\n return false;\n }\n \n const changesToRedo = new Set();\n this.#cursor++; // Move past current marker\n \n // Collect changes until we hit the next marker\n while (this.#cursor < this.#changes.length) {\n const change = this.#changes[this.#cursor];\n \n if (change instanceof Marker) {\n break;\n }\n \n changesToRedo.add(change);\n this.#cursor++;\n }\n\n // Apply the changes in original order\n this.onUndoRedo(changesToRedo);\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n canUndo() {\n return this.#cursor > 0;\n }\n\n canRedo() {\n return this.#cursor < this.#changes.length - 1;\n }\n\n size() {\n return this.#changes.length;\n }\n\n\n batch() {\n this.#batchDepth++;\n\n return () => {\n this.#batchDepth--;\n };\n }\n\n commit() {\n this.#batchDepth = this.#batchDepth - 1 < 0 ? 0 : this.#batchDepth - 1;\n\n if (this.#batchDepth === 0) {\n this.#commitPendingChanges();\n }\n \n return this;\n }\n\n pause() {\n this.#isRecording = false;\n }\n\n resume() {\n this.#isRecording = true;\n }\n\n onCommit(callback) {\n this.#commitListeners.add(callback);\n\n return () => {\n this.#commitListeners.delete(callback);\n };\n }\n\n reset() {\n this.#changes = [new Marker('History Start')];\n this.#commitListeners = new Set();\n this.#cursor = 0;\n this.#batchDepth = 0;\n this.#pendingChanges = new Map();\n this.#isRecording = true;\n this.#commitScheduled = false;\n this.#started = false;\n this.onUndoRedo = null;\n }\n\n #scheduleCommit() {\n if (!this.#commitScheduled) {\n this.#commitScheduled = true;\n this.#deferredCommit();\n }\n }\n\n #commitPendingChanges(description = '') {\n if (this.#pendingChanges.size === 0) return;\n\n // Truncate future changes if we're not at the end\n if (this.#cursor < this.#changes.length - 1) {\n this.#changes.splice(this.#cursor + 1);\n }\n\n // Add all pending changes individually\n const changes = Array.from(this.#pendingChanges.values());\n this.#changes.push(...changes);\n\n // Notify listeners\n this.#commitListeners.forEach(listener => listener(changes));\n \n // Add a marker automatically after the changes, but only if the last item isn't already a marker\n const lastItem = this.#changes[this.#changes.length - 1];\n \n if (!(lastItem instanceof Marker)) {\n this.#changes.push(new Marker(description || Date.now().toString()));\n }\n\n // Ensure the changes do not exceed maxSize\n while (this.#changes.length > this.options.maxSize) {\n this.#changes.shift(); // Remove the oldest change\n }\n\n // Clear pending changes\n this.#pendingChanges.clear();\n\n // Update current index\n this.#cursor = this.#changes.length - 1;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["STATE_CONTEXT", "MATCHER", "CREATED", "DELETED", "UPDATED", "OPERATION_INVERSES", "CREATED", "DELETED", "UPDATED", "invertChange", "change", "address", "path", "method", "from", "to", "operation", "invertOperation", "OPERATION_INVERSES", "defer", "arg1", "arg2", "callback", "delay", "args", "resolve", "reject", "result", "error", "Plugin", "options", "state", "pluginInstance", "Marker", "description", "HistoryManager", "Plugin", "#changes", "#started", "#commitListeners", "#cursor", "#batchDepth", "#pendingChanges", "#isRecording", "#commitScheduled", "state", "changes", "#start", "cb", "callback", "#deferredCommit", "defer", "#commitPendingChanges", "marker", "change", "batching", "existingChange", "recordedChange", "#scheduleCommit", "changesToUndo", "tempCursor", "changeEntry", "invertChange", "changesToRedo", "listener"]
|
|
7
|
-
}
|
package/dist/plugins/matcher.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var A=class{static name=null;static options={};static configure(e){return e={...this.options,...e},{install:n=>this.install(n,e),name:this.name,options:e}}static install(e,n){n={...this.options,...n};let r=new this(e,n);return Object.defineProperty(r,"state",{value:e,writable:!1,configurable:!1}),Object.defineProperty(r,"options",{value:n,writable:!1,configurable:!1}),r}};var u="*",B=Symbol("STATE_CONTEXT"),M=Symbol("MATCHER");var E=1,f=2,g=4,m=8,h=0,d=1,y=2,C=-1;function D(t){let e="";for(let n=0;n<t.length;n++){let r=t[n];r==="~"?e+="~~":r==="."?e+="~d":e+=r}return e.length===0?"~e":e}function N(t){let e=new Array(t.length);for(let n=0;n<t.length;n++){let r=t[n];if(typeof r=="number"&&Number.isInteger(r))e[n]="n"+String(r);else if(typeof r=="string")e[n]="s"+D(r);else throw new TypeError(`Unsupported segment type at index ${n}: ${r}`)}return e.join(".")}function T(t){return(t.type&E)===E}function G(t){return(t.type&f)===f}function S(t){return(t.type&g)===g}function P(t){return(t.type&m)===m}function v(t){return!t||t.length===0||t===u||t[0]===u}function I(t=[]){let e=t.length;return e===0?[0,[]]:e===1&&t[0]===u?[0,[]]:Array.isArray(t[0])?e===1?[1,[t[0]]]:[e,t]:[1,[[...t]]]}function K(t){if(!Array.isArray(t))return!1;for(let e=0;e<t.length;e++){let n=t[e];if(typeof n=="string"&&n.charCodeAt(0)===46)return!0}return!1}function _(t=[]){if(v(t))return{address:u,isMarker:!0,length:0,path:[],children:null,type:E};let[e,n]=I(t),r=e===1?f:g,o=e===1?n[0]:n,s=e>1?n.map(i=>_(i)):null,c=r===f?K(o):s.some(i=>P(i)),a=r;return c&&(a|=m),{address:r===f?N(o):null,isMarker:!0,length:e,path:o,children:s,type:a}}function b(t,{global:e,path:n,ephemeral:r,error:o}){try{if(!t.isMarker)return;if(T(t))return e?e(t):void 0;if(P(t))return r?r(t):n?n(t):void 0;if(G(t))return n?n(t):void 0;if(S(t)){let s=new Array(t.length),c=0;for(;c<t.length;){let a=t.children[c];s[c]=b(a,{global:e,path:n,ephemeral:r,error:o}),c++}return s}return}catch(s){return o?o(s.message):void 0}}function R(t,e){return T(t)&&T(e)?h:T(e)?d:!t.address||!e.address?C:t.address===e.address?h:t.address.startsWith(e.address+".")?d:e.address.startsWith(t.address+".")?y:C}var H=class extends A{static name="matcher";static options={matchers:[]};#t=new Set;initialize(e,n){if(n.matchers&&n.matchers.length>0)for(let r of n.matchers)if(typeof r=="function"&&r._isMatcher===M)this.#n(r),this.#e(r);else{if(!r.path||!r.handler)throw new Error("Matcher path and handler are required");this.#e(L(r.path,r.handler))}}actions(){return{createMatcher:(e,n)=>{let r=L(e,n);return this.#n(r),this.#e(r),()=>this.#r(r)},addMatcher:e=>this.#e(e),removeMatcher:e=>this.#r(e)}}#n(e){Object.defineProperty(e,"_state",{value:this.state,writable:!1,configurable:!1})}#e(e){return this.#n(e),this.#t.add(e),()=>this.#r(e)}#r(e){this.#t.delete(e)}onStateChange(e,n){this.#t.forEach(r=>r(e,n))}};function L(t,e){if(!Array.isArray(t))throw new Error("matchPath must be an array");if(t.length===0)throw new Error("matchPath must be a non-empty array");if(e===void 0||typeof e!="function")throw new Error("Matcher function is required");let n=new Map,r=!1,o=_(t),s=i=>{R(o,i)>=0&&a(i)};function c(){r||(r=!0,setTimeout(()=>{let i=Array.from(n.values()),l={},p=!1;for(let w of i)b(w,{global:()=>{l=s._state.get(t),p=!0},path:()=>{switch(R(o,w)){case d:case h:l=s._state.get(t),p=!0;break;case y:let x=w.path.slice(0,t.length+1),O=x[x.length-1];l=typeof l=="object"&&l!==null?l:{},l[O]=s._state.get(x),p=!0;break}}});p&&e(l),n.clear(),r=!1},0))}function a(i){n.has(i.address)&&n.delete(i.address),n.set(i.address,i),c()}return Object.defineProperty(s,"_isMatcher",{value:M,writable:!1,enumerable:!1,configurable:!0}),s}export{H as Matcher,L as createMatcher};
|
|
2
|
-
//# sourceMappingURL=matcher.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/Plugin.js", "../../src/lib/TOKENS.js", "../../src/lib/pathEncoder.js", "../../src/lib/marker.js", "../../plugins/matcher/src/Matcher.js"],
|
|
4
|
-
"sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG } from './TOKENS.js';\n\n// Fast helpers\nfunction escapeStr(str) {\n // Order matters: escape ~ first, then .\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") out += \"~~\";\n else if (ch === \".\") out += \"~d\";\n else out += ch;\n }\n // Represent empty strings as ~e to avoid trailing-dot filenames\n return out.length === 0 ? \"~e\" : out;\n}\n\nfunction unescapeStr(str) {\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") {\n const next = str[++i];\n if (next === \"~\") out += \"~\";\n else if (next === \"d\") out += \".\";\n else if (next === \"e\") out += \"\"; // empty string marker\n else {\n // Unknown escape: treat as literal (robustness)\n out += \"~\" + (next ?? \"\");\n }\n } else {\n out += ch;\n }\n }\n return out;\n}\n\nexport function encodePath(segments) {\n // segments: array of strings or integers\n // Produces: filename/URL-safe string like \"sfoo.n0.sbaz\"\n const parts = new Array(segments.length);\n for (let i = 0; i < segments.length; i++) {\n const v = segments[i];\n if (typeof v === \"number\" && Number.isInteger(v)) {\n // 'n' tag\n parts[i] = \"n\" + String(v); // decimal; includes \"-\" if negative\n } else if (typeof v === \"string\") {\n // 's' tag\n parts[i] = \"s\" + escapeStr(v);\n } else {\n // If you need more types, add here (e.g., booleans 'b', floats 'f').\n throw new TypeError(`Unsupported segment type at index ${i}: ${v}`);\n }\n }\n // Use '.' as separator (safe in URLs and filenames; we avoid trailing '.')\n return parts.join(\".\");\n}\n\nexport function decodeAddress(address) {\n if (address === GLOBAL_TAG) return GLOBAL_TAG;\n if (address.length === 0) return [];\n const raw = address.split(\".\");\n const out = new Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n if (token.length === 0) {\n // Disallow empty tokens (would imply trailing or double dots)\n throw new Error(\"Invalid address: empty token\");\n }\n const tag = token[0];\n const body = token.slice(1);\n if (tag === \"n\") {\n // Fast parse (no regex)\n if (body.length === 0 || !/^[-]?\\d+$/.test(body)) {\n throw new Error(`Invalid numeric token: \"${token}\"`);\n }\n const num = Number(body);\n // Ensure it was an integer\n if (!Number.isInteger(num)) {\n throw new Error(`Non-integer numeric token: \"${token}\"`);\n }\n out[i] = num;\n } else if (tag === \"s\") {\n out[i] = unescapeStr(body);\n } else {\n throw new Error(`Unknown type tag \"${tag}\" in token \"${token}\"`);\n }\n }\n return out;\n}\n", "import { encodePath } from './pathEncoder.js';\nimport { GLOBAL_TAG } from './TOKENS.js';\nimport {\n MARKER_GLOBAL,\n MARKER_SINGLE,\n MARKER_MANY,\n MARKER_EPHEMERAL,\n MATCH_EXACT,\n MATCH_PARENT,\n MATCH_CHILD,\n MATCH_NONE \n} from './TOKENS.js';\n\n// Marker type bitflags\n\n// Helper functions to check marker type\nexport function isGlobalMarker(marker) {\n return (marker.type & MARKER_GLOBAL) === MARKER_GLOBAL;\n}\n\nexport function isPathMarker(marker) {\n return (marker.type & MARKER_SINGLE) === MARKER_SINGLE;\n}\n\nexport function isMarkers(marker) {\n return (marker.type & MARKER_MANY) === MARKER_MANY;\n}\n\nexport function isEphemeralMarker(marker) {\n return (marker.type & MARKER_EPHEMERAL) === MARKER_EPHEMERAL;\n}\n\nexport function isGlobalPath(path) {\n return !path || path.length === 0 || path === GLOBAL_TAG || path[0] === GLOBAL_TAG;\n}\n\nexport function normalizePaths(args = []) { \n const len = args.length;\n if (len === 0) return [0, [] ];\n if (len === 1 && args[0] === GLOBAL_TAG) return [0, [] ];\n \n if (Array.isArray(args[0])) {\n return len === 1 \n ? [1, [args[0]] ]\n : [len, args ];\n }\n \n return [1, [[...args]] ];\n}\n\nfunction pathHasEphemeral(path) {\n if (!Array.isArray(path)) {\n return false;\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment === 'string' && segment.charCodeAt(0) === 46) { // '.'\n return true;\n }\n }\n\n return false;\n}\n\n// Marker factory\nexport function createMarker(paths = []) {\n if (isGlobalPath(paths)) {\n return {\n address: GLOBAL_TAG,\n isMarker: true,\n length: 0,\n path: [],\n children: null,\n type: MARKER_GLOBAL\n };\n }\n \n const [length, normalizedPaths] = normalizePaths(paths);\n const type = length === 1 ? MARKER_SINGLE : MARKER_MANY;\n const path = length === 1 ? normalizedPaths[0] : normalizedPaths;\n const children = length > 1 ? normalizedPaths.map(path => createMarker(path)) : null;\n const isEphemeral = type === MARKER_SINGLE\n ? pathHasEphemeral(path)\n : children.some(child => isEphemeralMarker(child));\n\n let markerType = type;\n if (isEphemeral) {\n markerType |= MARKER_EPHEMERAL;\n }\n\n return {\n address: type === MARKER_SINGLE ? encodePath(path) : null,\n isMarker: true,\n length,\n path,\n children,\n type: markerType\n };\n}\n\nexport function createChildMarker(parentMarker, childPaths) {\n if (childPaths.length === 0) {\n return parentMarker;\n }\n // Normalize the child paths\n const [childLength, normalizedChildPaths] = normalizePaths(childPaths);\n \n // Handle global marker - just return marker with child paths\n if (isGlobalMarker(parentMarker)) {\n return createMarker(normalizedChildPaths, parentMarker.state);\n }\n \n // Handle single path marker\n if (isPathMarker(parentMarker)) {\n if (childLength === 0) {\n // No child paths, return parent as-is\n return parentMarker;\n }\n \n if (childLength === 1) {\n // Single child path - append to parent path\n const newPath = [...parentMarker.path, ...normalizedChildPaths[0]];\n return createMarker(newPath, parentMarker.state);\n } else {\n // Multiple child paths - create many markers\n const newPaths = normalizedChildPaths.map(childPath => \n [...parentMarker.path, ...childPath]\n );\n return createMarker(newPaths, parentMarker.state);\n }\n }\n \n // Handle many markers - recursively create child markers for each\n if (isMarkers(parentMarker)) {\n const newMarkers = new Array(parentMarker.length);\n let i = 0;\n while (i < parentMarker.length) {\n newMarkers[i] = createChildMarker(parentMarker.children[i], childPaths);\n i++;\n }\n \n // Collect all paths from the new markers\n const allPaths = [];\n i = 0;\n while (i < newMarkers.length) {\n const marker = newMarkers[i];\n if (isPathMarker(marker)) {\n allPaths.push(marker.path);\n } else if (isMarkers(marker)) {\n let j = 0;\n while (j < marker.length) {\n allPaths.push(marker.children[j].path);\n j++;\n }\n }\n i++;\n }\n \n return createMarker(allPaths, parentMarker.state);\n }\n \n // Fallback - shouldn't reach here\n return parentMarker;\n}\n\nexport function dispatch(marker, { global, path, ephemeral, error }) {\n try {\n if (!marker.isMarker) return undefined;\n if (isGlobalMarker(marker)) return global ? global(marker) : undefined;\n if (isEphemeralMarker(marker)) return ephemeral ? ephemeral(marker) : path ? path(marker) : undefined;\n if (isPathMarker(marker)) return path ? path(marker) : undefined;\n if (isMarkers(marker)) {\n const results = new Array(marker.length);\n let i = 0;\n while (i < marker.length) {\n const nestedMarker = marker.children[i];\n results[i] = dispatch(nestedMarker, { global, path, ephemeral, error });\n i++;\n }\n return results;\n }\n \n return undefined;\n } catch (err) {\n return error ? error(err.message) : undefined;\n }\n}\n\nexport function compareMarkers(controlMarker, comparedMarker) {\n // Both are global markers or exact address match\n if (isGlobalMarker(controlMarker) && isGlobalMarker(comparedMarker)) {\n return MATCH_EXACT;\n }\n\n // If comparedMarker is global, it's always a parent\n if (isGlobalMarker(comparedMarker)) {\n return MATCH_PARENT;\n }\n \n // Need addresses to compare\n if (!controlMarker.address || !comparedMarker.address) {\n return MATCH_NONE;\n }\n \n // Exact match\n if (controlMarker.address === comparedMarker.address) {\n return MATCH_EXACT;\n }\n \n // controlMarker is more nested (child) - parent changed\n if (controlMarker.address.startsWith(comparedMarker.address + '.')) {\n return MATCH_PARENT;\n }\n \n // comparedMarker is more nested (child) - child changed\n if (comparedMarker.address.startsWith(controlMarker.address + '.')) {\n return MATCH_CHILD;\n }\n \n return MATCH_NONE;\n}\n\nexport const Marker = {\n compare: compareMarkers,\n create: createMarker,\n createChild: createChildMarker,\n dispatch: dispatch,\n isGlobal: isGlobalMarker,\n isSingle: isPathMarker,\n isMarkers: isMarkers,\n isEphemeral: isEphemeralMarker\n};", "import { Plugin } from '@jucie.io/state/Plugin';\nimport { compareMarkers, createMarker, dispatch } from '@jucie.io/state/lib/marker.js';\nimport { MATCHER } from '@jucie.io/state/lib/TOKENS.js';\n\nimport { MATCH_CHILD, MATCH_PARENT, MATCH_EXACT, MATCH_NONE } from '@jucie.io/state/lib/TOKENS.js';\n\nexport class Matcher extends Plugin {\n static name = 'matcher';\n static options = {\n matchers: [],\n };\n \n #matchers = new Set();\n \n initialize(state, config) {\n if (config.matchers && config.matchers.length > 0) {\n for (const matcher of config.matchers) {\n if (typeof matcher === 'function' && matcher._isMatcher === MATCHER) {\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n } else {\n if (!matcher.path || !matcher.handler) {\n throw new Error('Matcher path and handler are required');\n }\n this.#addMatcher(createMatcher(matcher.path, matcher.handler));\n }\n }\n }\n }\n\n actions () {\n return {\n createMatcher: (path, handler) => {\n const matcher = createMatcher(path, handler);\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n return () => this.#removeMatcher(matcher);\n },\n addMatcher: (matcher) => this.#addMatcher(matcher),\n removeMatcher: (matcher) => this.#removeMatcher(matcher),\n }\n }\n\n #assignMatcherState(matcher) {\n Object.defineProperty(matcher, '_state', {\n value: this.state,\n writable: false,\n configurable: false\n });\n }\n\n #addMatcher(matcher) {\n this.#assignMatcherState(matcher);\n this.#matchers.add(matcher);\n return () => this.#removeMatcher(matcher);\n }\n\n #removeMatcher(matcher) {\n this.#matchers.delete(matcher);\n }\n\n onStateChange(marker, change) {\n this.#matchers.forEach(matcher => matcher(marker, change));\n }\n}\n\nexport function createMatcher(matchPath, fn) {\n if (!Array.isArray(matchPath)) {\n throw new Error('matchPath must be an array');\n }\n\n if (matchPath.length === 0) {\n throw new Error('matchPath must be a non-empty array');\n }\n\n if (fn === undefined || typeof fn !== 'function') {\n throw new Error('Matcher function is required');\n }\n\n const changeQueue = new Map();\n let isFlushing = false;\n\n const matchMarker = createMarker(matchPath);\n const matcher = (marker) => {\n if (compareMarkers(matchMarker, marker) >= 0) {\n queueChange(marker);\n };\n }\n\n function flushChanges() {\n if (isFlushing) return;\n isFlushing = true;\n setTimeout(() => {\n const markers = Array.from(changeQueue.values());\n let changes = {};\n let hasChanges = false;\n for (const marker of markers) {\n dispatch(marker, {\n global: () => {\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n },\n path: () => {\n const comp = compareMarkers(matchMarker, marker);\n \n switch (comp) {\n case MATCH_PARENT:\n case MATCH_EXACT:\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n break;\n case MATCH_CHILD:\n const childPath = marker.path.slice(0, matchPath.length + 1);\n const key = childPath[childPath.length - 1];\n changes = typeof changes === 'object' && changes !== null ? changes : {};\n changes[key] = matcher._state.get(childPath);\n hasChanges = true;\n break;\n }\n },\n });\n }\n\n if (hasChanges) {\n fn(changes);\n }\n changeQueue.clear();\n isFlushing = false;\n }, 0);\n }\n\n function queueChange(marker) {\n if (changeQueue.has(marker.address)) {\n changeQueue.delete(marker.address);\n }\n changeQueue.set(marker.address, marker);\n flushChanges();\n }\n\n Object.defineProperty(matcher, '_isMatcher', {\n value: MATCHER,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n\n return matcher;\n}"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Plugin", "options", "state", "pluginInstance", "GLOBAL_TAG", "STATE_CONTEXT", "MATCHER", "MARKER_GLOBAL", "MARKER_SINGLE", "MARKER_MANY", "MARKER_EPHEMERAL", "MATCH_EXACT", "MATCH_PARENT", "MATCH_CHILD", "MATCH_NONE", "escapeStr", "str", "out", "i", "ch", "encodePath", "segments", "parts", "i", "v", "escapeStr", "isGlobalMarker", "marker", "MARKER_GLOBAL", "isPathMarker", "MARKER_SINGLE", "isMarkers", "MARKER_MANY", "isEphemeralMarker", "MARKER_EPHEMERAL", "isGlobalPath", "path", "GLOBAL_TAG", "normalizePaths", "args", "len", "pathHasEphemeral", "i", "segment", "createMarker", "paths", "length", "normalizedPaths", "type", "children", "isEphemeral", "child", "markerType", "encodePath", "dispatch", "marker", "global", "path", "ephemeral", "error", "isGlobalMarker", "isEphemeralMarker", "isPathMarker", "isMarkers", "results", "i", "nestedMarker", "err", "compareMarkers", "controlMarker", "comparedMarker", "MATCH_EXACT", "MATCH_PARENT", "MATCH_NONE", "MATCH_CHILD", "Matcher", "Plugin", "#matchers", "state", "config", "matcher", "MATCHER", "#assignMatcherState", "#addMatcher", "createMatcher", "path", "handler", "#removeMatcher", "marker", "change", "matchPath", "fn", "changeQueue", "isFlushing", "matchMarker", "createMarker", "compareMarkers", "queueChange", "flushChanges", "markers", "changes", "hasChanges", "dispatch", "MATCH_PARENT", "MATCH_EXACT", "MATCH_CHILD", "childPath", "key"]
|
|
7
|
-
}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var r=class{static name=null;static options={};static configure(e){return e={...this.options,...e},{install:t=>this.install(t,e),name:this.name,options:e}}static install(e,t){t={...this.options,...t};let s=new this(e,t);return Object.defineProperty(s,"state",{value:e,writable:!1,configurable:!1}),Object.defineProperty(s,"options",{value:t,writable:!1,configurable:!1}),s}};var i=class extends r{static name="onChange";#t=new Set;#e=new Map;#r=!1;#s=!1;#n=0;constructor(e={}){super(e),this.#n=e.debounce??0}actions(){return{addListener:e=>{if(typeof e=="function")return this.#a(e)},subscribe:e=>{if(typeof e=="function")return this.#a(e)},unsubscribe:e=>{if(typeof e=="function")return this.#i(e)},removeListener:e=>this.#i(e),clear:()=>this.#o()}}onStateChange(e,t){!this.#s||t.method==="apply"||this.#h(e,t)}#h(e,t){this.#e.has(e.address)&&this.#e.delete(e.address),this.#e.set(e.address,t),this.#u()}#u(){if(!this.#r){this.#r=!0;try{setTimeout(()=>{let e=Array.from(this.#e.values());this.#e.clear();for(let t of this.#t)try{t(e)}catch(s){console.error("Error in onChange listener:",s)}this.#r=!1},this.#n)}catch(e){console.error(e)}}}#a(e){return this.#t.add(e),this.#s=!0,()=>this.#i(e)}#i(e){typeof e=="function"&&(this.#t.delete(e),this.#t.size===0&&(this.#s=!1))}#o(){this.#t.clear(),this.#e.clear(),this.#s=!1}};export{i as OnChange};
|
|
2
|
-
//# sourceMappingURL=on-change.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/Plugin.js", "../../plugins/on-change/src/OnChange.js"],
|
|
4
|
-
"sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { Plugin } from '@jucie.io/state/Plugin';\n\nexport class OnChange extends Plugin {\n static name = 'onChange';\n\n #listeners = new Set();\n #changeQueue = new Map();\n #flushing = false;\n #hasListeners = false;\n #debounceMs = 0;\n\n constructor(options = {}) {\n super(options);\n this.#debounceMs = options.debounce ?? 0;\n }\n\n actions() {\n return {\n addListener: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n subscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n unsubscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#removeListener(callback);\n },\n removeListener: (callback) => {\n return this.#removeListener(callback);\n },\n clear: () => this.#clear()\n }\n }\n\n onStateChange(marker, change) {\n if (!this.#hasListeners || change.method === 'apply') {\n return;\n }\n\n this.#queueChange(marker, change);\n }\n\n #queueChange(marker, change) {\n if (this.#changeQueue.has(marker.address)) {\n this.#changeQueue.delete(marker.address);\n }\n this.#changeQueue.set(marker.address, change);\n this.#flush();\n }\n\n #flush() {\n if (this.#flushing) {\n return;\n }\n this.#flushing = true;\n try {\n setTimeout(() => {\n const changes = Array.from(this.#changeQueue.values());\n this.#changeQueue.clear();\n for (const callback of this.#listeners) {\n try {\n callback(changes);\n } catch (error) {\n console.error('Error in onChange listener:', error);\n }\n }\n this.#flushing = false;\n }, this.#debounceMs);\n } catch (error) {\n console.error(error);\n }\n }\n\n #addListener(callback) {\n this.#listeners.add(callback);\n this.#hasListeners = true;\n return () => this.#removeListener(callback);\n }\n\n #removeListener(callback) {\n if (typeof callback !== 'function') {\n return;\n }\n this.#listeners.delete(callback);\n if (this.#listeners.size === 0) {\n this.#hasListeners = false;\n }\n }\n\n #clear() {\n this.#listeners.clear();\n this.#changeQueue.clear();\n this.#hasListeners = false;\n }\n}"],
|
|
5
|
-
"mappings": "AAAO,IAAMA,EAAN,KAAa,CAElB,OAAO,KAAO,KACd,OAAO,QAAU,CAAC,EAElB,OAAO,UAAUC,EAAS,CACxB,OAAAA,EAAU,CAAC,GAAG,KAAK,QAAS,GAAGA,CAAO,EAC/B,CACL,QAAUC,GAAU,KAAK,QAAQA,EAAOD,CAAO,EAC/C,KAAM,KAAK,KACX,QAAAA,CACF,CACF,CAEA,OAAO,QAAQC,EAAOD,EAAS,CAC7BA,EAAU,CAAC,GAAG,KAAK,QAAS,GAAGA,CAAO,EACtC,IAAME,EAAiB,IAAI,KAAKD,EAAOD,CAAO,EAE9C,cAAO,eAAeE,EAAgB,QAAS,CAC7C,MAAOD,EACP,SAAU,GACV,aAAc,EAChB,CAAC,EAED,OAAO,eAAeC,EAAgB,UAAW,CAC/C,MAAOF,EACP,SAAU,GACV,aAAc,EAChB,CAAC,EAGME,CACT,CACF,EC/BO,IAAMC,EAAN,cAAuBC,CAAO,CACnC,OAAO,KAAO,WAEdC,GAAa,IAAI,IACjBC,GAAe,IAAI,IACnBC,GAAY,GACZC,GAAgB,GAChBC,GAAc,EAEd,YAAYC,EAAU,CAAC,EAAG,CACxB,MAAMA,CAAO,EACb,KAAKD,GAAcC,EAAQ,UAAY,CACzC,CAEA,SAAU,CACR,MAAO,CACL,YAAcC,GAAa,CACzB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKC,GAAaD,CAAQ,CACnC,EACA,UAAYA,GAAa,CACvB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKC,GAAaD,CAAQ,CACnC,EACA,YAAcA,GAAa,CACzB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKE,GAAgBF,CAAQ,CACtC,EACA,eAAiBA,GACR,KAAKE,GAAgBF,CAAQ,EAEtC,MAAO,IAAM,KAAKG,GAAO,CAC3B,CACF,CAEA,cAAcC,EAAQC,EAAQ,CACxB,CAAC,KAAKR,IAAiBQ,EAAO,SAAW,SAI7C,KAAKC,GAAaF,EAAQC,CAAM,CAClC,CAEAC,GAAaF,EAAQC,EAAQ,CACvB,KAAKV,GAAa,IAAIS,EAAO,OAAO,GACtC,KAAKT,GAAa,OAAOS,EAAO,OAAO,EAEzC,KAAKT,GAAa,IAAIS,EAAO,QAASC,CAAM,EAC5C,KAAKE,GAAO,CACd,CAEAA,IAAS,CACP,GAAI,MAAKX,GAGT,MAAKA,GAAY,GACjB,GAAI,CACF,WAAW,IAAM,CACf,IAAMY,EAAU,MAAM,KAAK,KAAKb,GAAa,OAAO,CAAC,EACrD,KAAKA,GAAa,MAAM,EACxB,QAAWK,KAAY,KAAKN,GAC1B,GAAI,CACFM,EAASQ,CAAO,CAClB,OAASC,EAAO,CACd,QAAQ,MAAM,8BAA+BA,CAAK,CACpD,CAEF,KAAKb,GAAY,EACnB,EAAG,KAAKE,EAAW,CACrB,OAASW,EAAO,CACd,QAAQ,MAAMA,CAAK,CACrB,EACF,CAEAR,GAAaD,EAAU,CACrB,YAAKN,GAAW,IAAIM,CAAQ,EAC5B,KAAKH,GAAgB,GACd,IAAM,KAAKK,GAAgBF,CAAQ,CAC5C,CAEAE,GAAgBF,EAAU,CACpB,OAAOA,GAAa,aAGxB,KAAKN,GAAW,OAAOM,CAAQ,EAC3B,KAAKN,GAAW,OAAS,IAC3B,KAAKG,GAAgB,IAEzB,CAEAM,IAAS,CACP,KAAKT,GAAW,MAAM,EACtB,KAAKC,GAAa,MAAM,EACxB,KAAKE,GAAgB,EACvB,CACF",
|
|
6
|
-
"names": ["Plugin", "options", "state", "pluginInstance", "OnChange", "Plugin", "#listeners", "#changeQueue", "#flushing", "#hasListeners", "#debounceMs", "options", "callback", "#addListener", "#removeListener", "#clear", "marker", "change", "#queueChange", "#flush", "changes", "error"]
|
|
7
|
-
}
|