doit-lib 1.0.0 → 1.2.0

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/dist/index.d.ts CHANGED
@@ -20,6 +20,15 @@ export type Operation = {
20
20
  op: 'batch';
21
21
  ops: Operation[];
22
22
  };
23
+ interface StorageAdapter {
24
+ getItem(key: string): string | null;
25
+ setItem(key: string, value: string): void;
26
+ removeItem(key: string): void;
27
+ }
28
+ interface PersistOptions {
29
+ to: StorageAdapter;
30
+ key?: string;
31
+ }
23
32
  export declare class DoIt {
24
33
  private state;
25
34
  private undoStack;
@@ -29,17 +38,40 @@ export declare class DoIt {
29
38
  private pathCache;
30
39
  private historyDirty;
31
40
  private cachedHistory;
41
+ private storage?;
42
+ private storageKey;
32
43
  constructor(initialState?: any, options?: {
33
44
  maxHistory?: number;
34
45
  });
35
46
  getState(): any;
36
47
  getHistory(): any;
37
- set(path: string, value: any): void;
48
+ set(path: string, value: any, internal?: boolean): {
49
+ undoOp: {
50
+ op: "set";
51
+ path: string;
52
+ value: any;
53
+ } | {
54
+ op: "delete";
55
+ path: string;
56
+ };
57
+ redoOp: {
58
+ op: "set";
59
+ path: string;
60
+ value: any;
61
+ };
62
+ } | undefined;
63
+ batch(callback: (batch: {
64
+ set: (path: string, value: any) => void;
65
+ }) => void): void;
38
66
  undo(): boolean;
39
67
  redo(): boolean;
40
68
  clearHistory(): void;
69
+ persist(options: PersistOptions): this;
70
+ unpersist(): void;
41
71
  subscribe(fn: (state: any, history: any) => void): () => void;
42
72
  private notify;
73
+ private saveToStorage;
74
+ private loadFromStorage;
43
75
  private getParsedPath;
44
76
  private cloneValue;
45
77
  }
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var h=/([^\.\[\]]+)|\[(\d+)\]|\[(\w+):([^\]]+)\]/g,u=class{constructor(e={},i={}){this.undoStack=[];this.redoStack=[];this.listeners=[];this.pathCache=new Map;this.historyDirty=!0;this.state=e,this.maxHistory=i.maxHistory||100}getState(){return this.state}getHistory(){return this.historyDirty?(this.cachedHistory={undo:this.undoStack.length,redo:this.redoStack.length,canUndo:this.undoStack.length>0,canRedo:this.redoStack.length>0},this.historyDirty=!1,this.cachedHistory):this.cachedHistory}set(e,i){let t=this.getParsedPath(e),s=d(this.state,t),n;if(s.missingIndex!==-1){let p=t[s.missingIndex];n={op:"delete",path:f(t.slice(0,s.missingIndex+1))}}else n={op:"set",path:e,value:this.cloneValue(s.value)};let a={op:"set",path:e,value:i};l(this.state,a),this.undoStack.push({undo:n,redo:a}),this.redoStack=[],this.undoStack.length>this.maxHistory&&this.undoStack.shift(),this.notify()}undo(){if(this.undoStack.length===0)return!1;let e=this.undoStack.pop();return l(this.state,e.undo),this.redoStack.push(e),this.notify(),!0}redo(){if(this.redoStack.length===0)return!1;let e=this.redoStack.pop();return l(this.state,e.redo),this.undoStack.push(e),this.notify(),!0}clearHistory(){this.undoStack=[],this.redoStack=[],this.pathCache.clear(),this.notify()}subscribe(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(i=>i!==e)}}notify(){this.historyDirty=!0;let e=this.getHistory();this.listeners.forEach(i=>i(this.state,e))}getParsedPath(e){let i=this.pathCache.get(e);if(!i&&(i=y(e),this.pathCache.set(e,i),this.pathCache.size>1e3)){let t=this.pathCache.keys().next().value;this.pathCache.delete(t)}return i}cloneValue(e){if(e==null||typeof e!="object")return e;if(Array.isArray(e))return e.map(t=>this.cloneValue(t));if(Array.isArray(e))return e.map(t=>this.cloneValue(t));let i={};for(let t in e)e.hasOwnProperty(t)&&(i[t]=this.cloneValue(e[t]));return i}};function y(r){let e=[],i;for(;i=h.exec(r);)if(i[1])e.push({type:"key",value:i[1]});else if(i[2])e.push({type:"index",value:Number(i[2])});else if(i[3]){let t=i[4];isNaN(Number(t))?(t.startsWith("'")&&t.endsWith("'")||t.startsWith('"')&&t.endsWith('"'))&&(t=t.slice(1,-1)):t=Number(t),e.push({type:"filter",key:i[3],value:t})}return e}function f(r){return r.map((e,i)=>{if(e.type==="key")return(i>0?".":"")+e.value;if(e.type==="index")return`[${e.value}]`;if(e.type==="filter"){let t=typeof e.value=="string"?`"${e.value}"`:e.value;return`[${e.key}:${t}]`}return""}).join("")}function d(r,e){let i=r;for(let t=0;t<e.length;t++){let s=e[t];if(i==null)return{exists:!1,value:void 0,missingIndex:t};if(s.type==="key"){if(!(s.value in i))return{exists:!1,value:void 0,missingIndex:t};i=i[s.value]}else if(s.type==="index"){if(!Array.isArray(i))return{exists:!1,value:void 0,missingIndex:t};if(s.value<0||s.value>=i.length)return{exists:!1,value:void 0,missingIndex:t};i=i[s.value]}else if(s.type==="filter"){if(!Array.isArray(i))return{exists:!1,value:void 0,missingIndex:t};let n=i.find(a=>a[s.key]==s.value);if(!n)return{exists:!1,value:void 0,missingIndex:t};i=n}}return{exists:!0,value:i,missingIndex:-1}}function l(r,e){if(e.op==="batch"){e.ops.forEach(s=>l(r,s));return}let i=y(e.path),t=r;if(e.op==="delete"){for(let n=0;n<i.length-1;n++){let a=i[n];if(t=o(t,a,!1),!t)return}let s=i[i.length-1];if(s.type==="key")delete t[s.value];else if(s.type==="index")Array.isArray(t)&&t.splice(s.value,1);else if(s.type==="filter"&&Array.isArray(t)){let n=t.findIndex(a=>a[s.key]==s.value);n!==-1&&t.splice(n,1)}}else if(e.op==="set"){for(let n=0;n<i.length-1;n++){let a=i[n];t=o(t,a,!0)}let s=i[i.length-1];if(s.type==="key")t[s.value]=e.value;else if(s.type==="index")t[s.value]=e.value;else if(s.type==="filter"&&Array.isArray(t)){let n=t.find(a=>a&&a[s.key]==s.value);if(n||(n={[s.key]:s.value},t.push(n)),typeof e.value=="object"&&!Array.isArray(e.value))Object.assign(n,e.value);else{let a=t.indexOf(n);t[a]={...n,...e.value}}}}}function o(r,e,i){if(e.type==="key")return(r[e.value]===void 0||typeof r[e.value]!="object")&&i&&(r[e.value]={}),r[e.value];if(e.type==="index")return i&&r[e.value]===void 0&&(r[e.value]={}),r[e.value];if(e.type==="filter"){if(!Array.isArray(r))return;let t=r.find(s=>s[e.key]==e.value);return!t&&i&&(t={[e.key]:e.value},r.push(t)),t}}export{u as DoIt,l as applyOperation,y as parsePath,d as probe,f as reconstructPath};
1
+ var p=/([^\.\[\]]+)|\[(\d+)\]|\[(\w+):([^\]]+)\]/g,y=class{constructor(e={},t={}){this.undoStack=[];this.redoStack=[];this.listeners=[];this.pathCache=new Map;this.historyDirty=!0;this.storageKey="doit-state";this.state=e,this.maxHistory=t.maxHistory||100}getState(){return this.state}getHistory(){return this.historyDirty?(this.cachedHistory={undo:this.undoStack.length,redo:this.redoStack.length,canUndo:this.undoStack.length>0,canRedo:this.redoStack.length>0},this.historyDirty=!1,this.cachedHistory):this.cachedHistory}set(e,t,s=!1){let i=this.getParsedPath(e),r=v(this.state,i);if(r.exists&&c(r.value,t))return;let a;r.missingIndex!==-1?a={op:"delete",path:g(i.slice(0,r.missingIndex+1))}:a={op:"set",path:e,value:this.cloneValue(r.value)};let o={op:"set",path:e,value:t};return u(this.state,o),s||(this.undoStack.push({undo:a,redo:o}),this.redoStack=[],this.undoStack.length>this.maxHistory&&this.undoStack.shift(),this.notify()),{undoOp:a,redoOp:o}}batch(e){let t=[],s=[];if(e({set:(o,h)=>{let l=this.set(o,h,!0);l&&(t.push(l.undoOp),s.push(l.redoOp))}}),t.length===0)return;let r={op:"batch",ops:t.reverse()},a={op:"batch",ops:s};this.undoStack.push({undo:r,redo:a}),this.redoStack=[],this.undoStack.length>this.maxHistory&&this.undoStack.shift(),this.notify()}undo(){if(this.undoStack.length===0)return!1;let e=this.undoStack.pop();return u(this.state,e.undo),this.redoStack.push(e),this.notify(),!0}redo(){if(this.redoStack.length===0)return!1;let e=this.redoStack.pop();return u(this.state,e.redo),this.undoStack.push(e),this.notify(),!0}clearHistory(){this.undoStack=[],this.redoStack=[],this.pathCache.clear(),this.notify()}persist(e){return this.storage=e.to,this.storageKey=e.key||"doit-state",this.loadFromStorage(),this}unpersist(){this.storage=void 0}subscribe(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter(t=>t!==e)}}notify(){this.historyDirty=!0;let e=this.getHistory();this.listeners.forEach(t=>t(this.state,e)),this.saveToStorage()}saveToStorage(){if(this.storage)try{let e={state:this.state,undoStack:this.undoStack,redoStack:this.redoStack};this.storage.setItem(this.storageKey,JSON.stringify(e))}catch(e){console.error("Failed to save to storage:",e)}}loadFromStorage(){if(this.storage)try{let e=this.storage.getItem(this.storageKey);if(!e)return;let t=JSON.parse(e);t.state&&(this.state=t.state),t.undoStack&&(this.undoStack=t.undoStack),t.redoStack&&(this.redoStack=t.redoStack),this.notify()}catch(e){console.error("Failed to load from storage:",e)}}getParsedPath(e){let t=this.pathCache.get(e);if(!t&&(t=f(e),this.pathCache.set(e,t),this.pathCache.size>1e3)){let s=this.pathCache.keys().next().value;s&&this.pathCache.delete(s)}return t}cloneValue(e){if(e==null||typeof e!="object")return e;if(Array.isArray(e))return e.map(s=>this.cloneValue(s));let t={};for(let s in e)e.hasOwnProperty(s)&&(t[s]=this.cloneValue(e[s]));return t}};function f(n){let e=[],t;for(;t=p.exec(n);)if(t[1])e.push({type:"key",value:t[1]});else if(t[2])e.push({type:"index",value:Number(t[2])});else if(t[3]){let s=t[4];isNaN(Number(s))?(s.startsWith("'")&&s.endsWith("'")||s.startsWith('"')&&s.endsWith('"'))&&(s=s.slice(1,-1)):s=Number(s),e.push({type:"filter",key:t[3],value:s})}return e}function g(n){return n.map((e,t)=>{if(e.type==="key")return(t>0?".":"")+e.value;if(e.type==="index")return`[${e.value}]`;if(e.type==="filter"){let s=typeof e.value=="string"?`"${e.value}"`:e.value;return`[${e.key}:${s}]`}return""}).join("")}function v(n,e){let t=n;for(let s=0;s<e.length;s++){let i=e[s];if(t==null)return{exists:!1,value:void 0,missingIndex:s};if(i.type==="key"){if(!(i.value in t))return{exists:!1,value:void 0,missingIndex:s};t=t[i.value]}else if(i.type==="index"){if(!Array.isArray(t))return{exists:!1,value:void 0,missingIndex:s};if(i.value<0||i.value>=t.length)return{exists:!1,value:void 0,missingIndex:s};t=t[i.value]}else if(i.type==="filter"){if(!Array.isArray(t))return{exists:!1,value:void 0,missingIndex:s};let r=t.find(a=>a[i.key]==i.value);if(!r)return{exists:!1,value:void 0,missingIndex:s};t=r}}return{exists:!0,value:t,missingIndex:-1}}function u(n,e){if(e.op==="batch"){e.ops.forEach(i=>u(n,i));return}let t=f(e.path),s=n;if(e.op==="delete"){for(let r=0;r<t.length-1;r++){let a=t[r];if(s=d(s,a,!1),!s)return}let i=t[t.length-1];if(i.type==="key")delete s[i.value];else if(i.type==="index"&&Array.isArray(s))s.splice(i.value,1);else if(i.type==="filter"&&Array.isArray(s)){let r=s.findIndex(a=>a[i.key]==i.value);r!==-1&&s.splice(r,1)}}else if(e.op==="set"){for(let r=0;r<t.length-1;r++){let a=t[r];s=d(s,a,!0)}let i=t[t.length-1];if(i.type==="key")s[i.value]=e.value;else if(i.type==="index")s[i.value]=e.value;else if(i.type==="filter"&&Array.isArray(s)){let r=s.find(a=>a&&a[i.key]==i.value);if(r||(r={[i.key]:i.value},s.push(r)),typeof e.value=="object"&&!Array.isArray(e.value))Object.assign(r,e.value);else{let a=s.indexOf(r);s[a]={...r,...e.value}}}}}function d(n,e,t){if(e.type==="key")return(n[e.value]===void 0||typeof n[e.value]!="object")&&t&&(n[e.value]={}),n[e.value];if(e.type==="index")return t&&n[e.value]===void 0&&(n[e.value]={}),n[e.value];if(e.type==="filter"){if(!Array.isArray(n))return;let s=n.find(i=>i[e.key]==e.value);return!s&&t&&(s={[e.key]:e.value},n.push(s)),s}}function c(n,e){if(n===e)return!0;if(n==null||e==null||typeof n!="object"||typeof e!="object")return!1;let t=Object.keys(n),s=Object.keys(e);if(t.length!==s.length)return!1;for(let i of t)if(!s.includes(i)||!c(n[i],e[i]))return!1;return!0}export{y as DoIt,u as applyOperation,f as parsePath,v as probe,g as reconstructPath};
Binary file
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "doit-lib",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "test": "vitest run",
9
- "build": "tsc --emitDeclarationOnly && esbuild src/index.ts --bundle --minify --format=esm --outfile=dist/index.js",
10
- "build-obfus": "tsc --emitDeclarationOnly && node build.mjs"
9
+ "build": "tsc --emitDeclarationOnly && esbuild src/index.ts --bundle --minify --format=esm --outfile=dist/index.js && gzip -k -f dist/index.js"
11
10
  },
12
- "keywords": [],
11
+ "keywords": [
12
+ "undo-redo",
13
+ "state-management",
14
+ "framework-agnostic",
15
+ "typescript"
16
+ ],
13
17
  "author": {
14
18
  "name": "Khalif",
15
19
  "email": "",
@@ -17,13 +21,16 @@
17
21
  },
18
22
  "license": "MIT",
19
23
  "description": "",
20
- "files": ["dist"],
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
21
29
  "devDependencies": {
22
30
  "@types/node": "^25.0.3",
23
31
  "esbuild": "^0.27.2",
24
- "javascript-obfuscator": "^5.1.0",
25
32
  "terser": "^5.44.1",
26
33
  "typescript": "^5.9.3",
27
34
  "vitest": "^4.0.16"
28
35
  }
29
- }
36
+ }