tinybase 3.0.0-beta.0 → 3.0.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.
Files changed (110) hide show
  1. package/bin/cli.js +1 -1
  2. package/lib/checkpoints.d.ts +18 -3
  3. package/lib/checkpoints.js +1 -1
  4. package/lib/checkpoints.js.gz +0 -0
  5. package/lib/debug/checkpoints.d.ts +18 -3
  6. package/lib/debug/checkpoints.js +97 -49
  7. package/lib/debug/indexes.js +31 -16
  8. package/lib/debug/metrics.js +31 -16
  9. package/lib/debug/persisters.d.ts +33 -23
  10. package/lib/debug/persisters.js +10 -5
  11. package/lib/debug/queries.js +2 -2
  12. package/lib/debug/relationships.js +31 -16
  13. package/lib/debug/store.d.ts +2053 -381
  14. package/lib/debug/store.js +444 -106
  15. package/lib/debug/tinybase.js +512 -138
  16. package/lib/debug/tools.d.ts +109 -38
  17. package/lib/debug/tools.js +759 -453
  18. package/lib/debug/ui-react.d.ts +1218 -138
  19. package/lib/debug/ui-react.js +163 -12
  20. package/lib/es6/checkpoints.d.ts +18 -3
  21. package/lib/es6/checkpoints.js +1 -1
  22. package/lib/es6/checkpoints.js.gz +0 -0
  23. package/lib/es6/indexes.js +1 -1
  24. package/lib/es6/indexes.js.gz +0 -0
  25. package/lib/es6/metrics.js +1 -1
  26. package/lib/es6/metrics.js.gz +0 -0
  27. package/lib/es6/persisters.d.ts +33 -23
  28. package/lib/es6/persisters.js +1 -1
  29. package/lib/es6/persisters.js.gz +0 -0
  30. package/lib/es6/relationships.js +1 -1
  31. package/lib/es6/relationships.js.gz +0 -0
  32. package/lib/es6/store.d.ts +2053 -381
  33. package/lib/es6/store.js +1 -1
  34. package/lib/es6/store.js.gz +0 -0
  35. package/lib/es6/tinybase.js +1 -1
  36. package/lib/es6/tinybase.js.gz +0 -0
  37. package/lib/es6/tools.d.ts +109 -38
  38. package/lib/es6/tools.js +1 -1
  39. package/lib/es6/tools.js.gz +0 -0
  40. package/lib/es6/ui-react.d.ts +1218 -138
  41. package/lib/es6/ui-react.js +1 -1
  42. package/lib/es6/ui-react.js.gz +0 -0
  43. package/lib/indexes.js +1 -1
  44. package/lib/indexes.js.gz +0 -0
  45. package/lib/metrics.js +1 -1
  46. package/lib/metrics.js.gz +0 -0
  47. package/lib/persisters.d.ts +33 -23
  48. package/lib/persisters.js +1 -1
  49. package/lib/persisters.js.gz +0 -0
  50. package/lib/relationships.js +1 -1
  51. package/lib/relationships.js.gz +0 -0
  52. package/lib/store.d.ts +2053 -381
  53. package/lib/store.js +1 -1
  54. package/lib/store.js.gz +0 -0
  55. package/lib/tinybase.js +1 -1
  56. package/lib/tinybase.js.gz +0 -0
  57. package/lib/tools.d.ts +109 -38
  58. package/lib/tools.js +1 -1
  59. package/lib/tools.js.gz +0 -0
  60. package/lib/ui-react.d.ts +1218 -138
  61. package/lib/ui-react.js +1 -1
  62. package/lib/ui-react.js.gz +0 -0
  63. package/lib/umd/checkpoints.d.ts +18 -3
  64. package/lib/umd/checkpoints.js +1 -1
  65. package/lib/umd/checkpoints.js.gz +0 -0
  66. package/lib/umd/indexes.js +1 -1
  67. package/lib/umd/indexes.js.gz +0 -0
  68. package/lib/umd/metrics.js +1 -1
  69. package/lib/umd/metrics.js.gz +0 -0
  70. package/lib/umd/persisters.d.ts +33 -23
  71. package/lib/umd/persisters.js +1 -1
  72. package/lib/umd/persisters.js.gz +0 -0
  73. package/lib/umd/relationships.js +1 -1
  74. package/lib/umd/relationships.js.gz +0 -0
  75. package/lib/umd/store.d.ts +2053 -381
  76. package/lib/umd/store.js +1 -1
  77. package/lib/umd/store.js.gz +0 -0
  78. package/lib/umd/tinybase.js +1 -1
  79. package/lib/umd/tinybase.js.gz +0 -0
  80. package/lib/umd/tools.d.ts +109 -38
  81. package/lib/umd/tools.js +1 -1
  82. package/lib/umd/tools.js.gz +0 -0
  83. package/lib/umd/ui-react.d.ts +1218 -138
  84. package/lib/umd/ui-react.js +1 -1
  85. package/lib/umd/ui-react.js.gz +0 -0
  86. package/lib/umd-es6/checkpoints.d.ts +18 -3
  87. package/lib/umd-es6/checkpoints.js +1 -1
  88. package/lib/umd-es6/checkpoints.js.gz +0 -0
  89. package/lib/umd-es6/indexes.js +1 -1
  90. package/lib/umd-es6/indexes.js.gz +0 -0
  91. package/lib/umd-es6/metrics.js +1 -1
  92. package/lib/umd-es6/metrics.js.gz +0 -0
  93. package/lib/umd-es6/persisters.d.ts +33 -23
  94. package/lib/umd-es6/persisters.js +1 -1
  95. package/lib/umd-es6/persisters.js.gz +0 -0
  96. package/lib/umd-es6/relationships.js +1 -1
  97. package/lib/umd-es6/relationships.js.gz +0 -0
  98. package/lib/umd-es6/store.d.ts +2053 -381
  99. package/lib/umd-es6/store.js +1 -1
  100. package/lib/umd-es6/store.js.gz +0 -0
  101. package/lib/umd-es6/tinybase.js +1 -1
  102. package/lib/umd-es6/tinybase.js.gz +0 -0
  103. package/lib/umd-es6/tools.d.ts +109 -38
  104. package/lib/umd-es6/tools.js +1 -1
  105. package/lib/umd-es6/tools.js.gz +0 -0
  106. package/lib/umd-es6/ui-react.d.ts +1218 -138
  107. package/lib/umd-es6/ui-react.js +1 -1
  108. package/lib/umd-es6/ui-react.js.gz +0 -0
  109. package/package.json +20 -20
  110. package/readme.md +27 -16
package/bin/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #! /usr/bin/env node
2
- import{resolve as t,dirname as e}from"path";import{writeFileSync as r,readFileSync as s}from"fs";import{createStore as o}from"tinybase";import{createTools as a}from"tinybase/tools";import{fileURLToPath as i}from"url";const n=JSON.parse,m=Object,p=(...t)=>{return e=t=>process.stdout.write(t+"\n"),t.forEach(e);var e},c=t=>n(s(t,"utf8")),f=()=>{var t,e;p("","tinybase <command>","","Usage:",""),t=u,e=([,t,e],r)=>p(` tinybase ${r} ${t}`," - "+e,""),((t,e)=>{t.map(e)})(m.entries(t),(([t,r])=>e(r,t)))},u={help:[f,"","print this message"],version:[()=>p(c(t(e(i(import.meta.url)),"../package.json")).version),"","get the current TinyBase version"],getStoreApi:[async(e,s,i)=>{try{const n=a(o().setSchema(c(e))),[m,f]=await n.getPrettyStoreApi(s),u=t(i,s+".d.ts"),h=t(i,s+".ts");r(u,m,"utf8"),r(h,f,"utf8"),p(" Definition: "+u,"Implementation: "+h)}catch{process.stderr.write("ERROR: provide a valid schemaFile, storeName, and outputDir\n")}},"<schemaFile> <storeName> <outputDir>","generate .d.ts and .ts files from a schema file"]};(()=>{const[,,t,...e]=process.argv;(u[t]?.[0]??f)(...e)})();
2
+ import{resolve as e,dirname as t}from"path";import{writeFileSync as r,readFileSync as s}from"fs";import{createStore as o}from"tinybase";import{createTools as a}from"tinybase/tools";import{fileURLToPath as i}from"url";const n=JSON.parse,m=Object,p=(...e)=>{return t=e=>process.stdout.write(e+"\n"),e.forEach(t);var t},c=e=>n(s(e,"utf8")),f=()=>{var e,t;p("","tinybase <command>","","Usage:",""),e=l,t=([,e,t],r)=>p(` tinybase ${r} ${e}`," - "+t,""),((e,t)=>{e.map(t)})(m.entries(e),(([e,r])=>t(r,e))),p("See also http://tinybase.org/guides/developer-tools/command-line/","")},l={help:[f,"","print this message"],version:[()=>p(c(e(t(i(import.meta.url)),"../package.json")).version),"","get the current TinyBase version"],getStoreApi:[async(t,s,i)=>{try{const m=c(t),f=a(o().setSchema(...(n=m,Array.isArray(n)?m:[m]))),[l,u]=await f.getPrettyStoreApi(s),d=e(i,s+".d.ts"),h=e(i,s+".ts");r(d,l,"utf8"),r(h,u,"utf8"),p(" Definition: "+d,"Implementation: "+h)}catch{process.stderr.write("ERROR: provide a valid schemaFile, storeName, and outputDir\n")}var n},"<schemaFile> <storeName> <outputDir>","generate .d.ts and .ts files from a schema file"]};(()=>{const[,,e,...t]=process.argv;(l[e]?.[0]??f)(...t)})();
@@ -115,6 +115,8 @@ export type CheckpointsListenerStats = {
115
115
  * method), and add listeners for when the list checkpoints changes (with the
116
116
  * addCheckpointIdsListener method).
117
117
  *
118
+ * Checkpoints work for both changes to tabular data and to keyed value data.
119
+ *
118
120
  * Every checkpoint can be given a label which can be used to describe the
119
121
  * actions that changed the Store before this checkpoint. This can be useful for
120
122
  * interfaces that let users 'Undo [last action]'.
@@ -127,7 +129,9 @@ export type CheckpointsListenerStats = {
127
129
  * registering and removing a listener for them.
128
130
  *
129
131
  * ```js
130
- * const store = createStore().setTables({pets: {fido: {sold: false}}});
132
+ * const store = createStore()
133
+ * .setTables({pets: {fido: {sold: false}}})
134
+ * .setValue('open', true);
131
135
  *
132
136
  * const checkpoints = createCheckpoints(store);
133
137
  * checkpoints.setSize(200);
@@ -145,14 +149,25 @@ export type CheckpointsListenerStats = {
145
149
  * console.log(checkpoints.getCheckpointIds());
146
150
  * // -> [[], '0', ['1']]
147
151
  *
152
+ * store.setValue('open', false);
153
+ * checkpoints.addCheckpoint('closed');
154
+ * console.log(checkpoints.getCheckpointIds());
155
+ * // -> [['0'], '2', []]
156
+ *
157
+ * checkpoints.goBackward();
158
+ * console.log(store.getValue('open'));
159
+ * // -> true
160
+ * console.log(checkpoints.getCheckpointIds());
161
+ * // -> [[], '0', ['2']]
162
+ *
148
163
  * const listenerId = checkpoints.addCheckpointIdsListener(() => {
149
164
  * console.log(checkpoints.getCheckpointIds());
150
165
  * });
151
166
  * store.setCell('pets', 'fido', 'species', 'dog');
152
167
  * // -> [['0'], undefined, []]
153
168
  * checkpoints.addCheckpoint();
154
- * // -> [['0'], '2', []]
155
- * // Previous redo of checkpoint '1' is now not possible.
169
+ * // -> [['0'], '3', []]
170
+ * // Previous redo of checkpoints '1' and '2' are now not possible.
156
171
  *
157
172
  * checkpoints.delListener(listenerId);
158
173
  * checkpoints.destroy();
@@ -1 +1 @@
1
- const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,r=e=>0==n(e),s=(e,...t)=>e.push(...t),o=e=>e.pop(),l=e=>e.shift(),c=e=>null==e,i=(e,t,n)=>c(e)?n?.():t(e),a=(e,t)=>e?.has(t)??!1,d=e=>c(e)||0==(e=>e.size)(e),u=(e,t)=>e?.forEach(t),h=(e,t)=>e?.delete(t),p=e=>new Map(e),C=(e,t)=>e?.get(t),g=(e,t,n)=>c(n)?(h(e,t),e):e?.set(t,n),k=(e,t,n)=>(a(e,t)||g(e,t,n()),C(e,t)),f=(e,t,r,s,o=0)=>i((r?k:C)(e,t[o],o>n(t)-2?r:p),(l=>{if(o>n(t)-2)return s?.(l)&&g(e,t[o]),l;const c=f(l,t,r,s,o+1);return d(l)&&g(e,t[o]),c})),v=e=>new Set(Array.isArray(e)||c(e)?e:[e]),L=/^\d+$/,w=Object.freeze,S=(S=>{const y=new WeakMap;return S=>(y.has(S)||y.set(S,(S=>{let y,z,E,A=100,I=p(),M=1;const b=p(),j=p(),[x,B,F]=(e=>{let r;const[o,a]=(()=>{const e=[];let t=0;return[()=>l(e)??""+t++,t=>{L.test(t)&&n(e)<1e3&&s(e,t)}]})(),k=p();return[(e,t,n)=>{r??=V;const s=o();var l;return g(k,s,[e,t,n]),l=s,f(t,n??[""],v)?.add(l),s},(e,o,...l)=>t(((e,r=[""])=>{const o=[],l=(e,c)=>c==n(r)?s(o,e):null===r[c]?u(e,(e=>l(e,c+1))):t([r[c],null],(t=>l(C(e,t),c+1)));return l(e,0),o})(e,o),(e=>u(e,(e=>C(k,e)[0](r,...o??[],...l))))),e=>i(C(k,e),(([,t,n])=>(f(t,n??[""],void 0,(t=>(h(t,e),d(t)?1:0))),g(k,e),a(e),n))),(e,s,o)=>i(C(k,e),(([e,,l=[]])=>{const i=(...a)=>{const d=n(a);d==n(l)?e(r,...a,...o(a)):c(l[d])?t(s[d](...a),(e=>i(...a,e))):i(...a,l[d])};i()}))]})(),O=p(),T=p(),W=[],$=[],m=(e,t)=>{M=0,S.transaction((()=>u(C(O,t),((t,n)=>u(t,((t,r)=>u(t,((t,s)=>((e,t,n,r,s)=>c(s)?e.delCell(t,n,r,!0):e.setCell(t,n,r,s))(S,n,r,s,t[e]))))))))),M=1},q=e=>{g(O,e),g(T,e),B(j,[e])},D=(e,r)=>t(((e,t)=>e.splice(0,t))(e,r??n(e)),q),G=()=>D(W,n(W)-A),H=S.addCellListener(null,null,null,((e,t,n,r,l,c)=>{if(M){i(y,(()=>{s(W,y),G(),D($),y=void 0,E=1}));const e=k(I,t,p),a=k(e,n,p),u=k(a,r,(()=>[c,void 0]));u[1]=l,u[0]===l&&d(g(a,r))&&d(g(e,n))&&d(g(I,t))&&(y=o(W),E=1),P()}})),J=(e="")=>(c(y)&&(y=""+z++,g(O,y,I),R(y,e),I=p(),E=1),y),K=()=>{r(W)||(((e,...t)=>{e.unshift(...t)})($,J()),m(0,y),y=o(W),E=1)},N=()=>{r($)||(s(W,y),y=l($),m(1,y),E=1)},P=()=>{E&&(B(b),E=0)},Q=e=>{const t=J(e);return P(),t},R=(e,t)=>(U(e)&&C(T,e)!==t&&(g(T,e,t),B(j,[e])),V),U=e=>a(O,e),V={setSize:e=>(A=e,G(),V),addCheckpoint:Q,setCheckpoint:R,getStore:()=>S,getCheckpointIds:()=>[[...W],y,[...$]],forEachCheckpoint:e=>{return t=e,u(T,((e,n)=>t(n,e)));var t},hasCheckpoint:U,getCheckpoint:e=>C(T,e),goBackward:()=>(K(),P(),V),goForward:()=>(N(),P(),V),goTo:t=>{const n=e(W,t)?K:e($,t)?N:null;for(;!c(n)&&t!=y;)n();return P(),V},addCheckpointIdsListener:e=>x(e,b),addCheckpointListener:(e,t)=>x(t,j,[e]),delListener:e=>(F(e),V),clear:()=>(D(W),D($),c(y)||q(y),y=void 0,z=0,Q(),V),destroy:()=>{S.delListener(H)},getListenerStats:()=>({})};return w(V.clear())})(S)),y.get(S))})();export{S as createCheckpoints};
1
+ const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,r=e=>0==n(e),s=(e,...t)=>e.push(...t),o=e=>e.pop(),l=e=>e.shift(),c=e=>null==e,i=(e,t,n)=>c(e)?n?.():t(e),a=(e,t)=>e?.has(t)??!1,d=e=>c(e)||0==(e=>e.size)(e),u=(e,t)=>e?.forEach(t),h=(e,t)=>e?.delete(t),p=e=>new Map(e),C=(e,t)=>e?.get(t),f=(e,t,n)=>c(n)?(h(e,t),e):e?.set(t,n),g=(e,t,n)=>(a(e,t)||f(e,t,n()),C(e,t)),k=(e,t,r,s,o=0)=>i((r?g:C)(e,t[o],o>n(t)-2?r:p),(l=>{if(o>n(t)-2)return s?.(l)&&f(e,t[o]),l;const c=k(l,t,r,s,o+1);return d(l)&&f(e,t[o]),c})),L=e=>new Set(Array.isArray(e)||c(e)?e:[e]),v=/^\d+$/,w=Object.freeze,S=(S=>{const y=new WeakMap;return S=>(y.has(S)||y.set(S,(S=>{let y,z,E,V=100,A=p(),I=p(),M=1;const b=p(),j=p(),[x,B,F]=(e=>{let r;const[o,a]=(()=>{const e=[];let t=0;return[()=>l(e)??""+t++,t=>{v.test(t)&&n(e)<1e3&&s(e,t)}]})(),g=p();return[(e,t,n,s=[],l=(()=>[]))=>{r??=_;const c=o();var i;return f(g,c,[e,t,n,s,l]),i=c,k(t,n??[""],L)?.add(i),c},(e,o,...l)=>t(((e,r=[""])=>{const o=[],l=(e,c)=>c==n(r)?s(o,e):null===r[c]?u(e,(e=>l(e,c+1))):t([r[c],null],(t=>l(C(e,t),c+1)));return l(e,0),o})(e,o),(e=>u(e,(e=>C(g,e)[0](r,...o??[],...l))))),e=>i(C(g,e),(([,t,n])=>(k(t,n??[""],void 0,(t=>(h(t,e),d(t)?1:0))),f(g,e),a(e),n))),e=>i(C(g,e),(([e,,s=[],o,l])=>{const i=(...a)=>{const d=n(a);d==n(s)?e(r,...a,...l(a)):c(s[d])?t(o[d]?.(...a)??[],(e=>i(...a,e))):i(...a,s[d])};i()}))]})(),O=p(),T=p(),W=[],$=[],m=(e,t)=>{M=0,S.transaction((()=>{const[n,r]=C(O,t);u(n,((t,n)=>u(t,((t,r)=>u(t,((t,s)=>((e,t,n,r,s)=>c(s)?e.delCell(t,n,r,!0):e.setCell(t,n,r,s))(S,n,r,s,t[e]))))))),u(r,((t,n)=>((e,t,n)=>c(n)?e.delValue(t):e.setValue(t,n))(S,n,t[e])))})),M=1},q=e=>{f(O,e),f(T,e),B(j,[e])},D=(e,r)=>t(((e,t)=>e.splice(0,t))(e,r??n(e)),q),G=()=>D(W,n(W)-V),H=()=>i(y,(()=>{s(W,y),G(),D($),y=void 0,E=1})),J=()=>{y=o(W),E=1},K=S.addCellListener(null,null,null,((e,t,n,r,s,o)=>{if(M){H();const e=g(A,t,p),l=g(e,n,p),c=g(l,r,(()=>[o,void 0]));c[1]=s,c[0]===s&&d(f(l,r))&&d(f(e,n))&&d(f(A,t))&&J(),U()}})),N=S.addValueListener(null,((e,t,n,r)=>{if(M){H();const e=g(I,t,(()=>[r,void 0]));e[1]=n,e[0]===n&&d(f(I,t))&&J(),U()}})),P=(e="")=>(c(y)&&(y=""+z++,f(O,y,[A,I]),Y(y,e),A=p(),I=p(),E=1),y),Q=()=>{r(W)||(((e,...t)=>{e.unshift(...t)})($,P()),m(0,y),y=o(W),E=1)},R=()=>{r($)||(s(W,y),y=l($),m(1,y),E=1)},U=()=>{E&&(B(b),E=0)},X=e=>{const t=P(e);return U(),t},Y=(e,t)=>(Z(e)&&C(T,e)!==t&&(f(T,e,t),B(j,[e])),_),Z=e=>a(O,e),_={setSize:e=>(V=e,G(),_),addCheckpoint:X,setCheckpoint:Y,getStore:()=>S,getCheckpointIds:()=>[[...W],y,[...$]],forEachCheckpoint:e=>{return t=e,u(T,((e,n)=>t(n,e)));var t},hasCheckpoint:Z,getCheckpoint:e=>C(T,e),goBackward:()=>(Q(),U(),_),goForward:()=>(R(),U(),_),goTo:t=>{const n=e(W,t)?Q:e($,t)?R:null;for(;!c(n)&&t!=y;)n();return U(),_},addCheckpointIdsListener:e=>x(e,b),addCheckpointListener:(e,t)=>x(t,j,[e]),delListener:e=>(F(e),_),clear:()=>(D(W),D($),c(y)||q(y),y=void 0,z=0,X(),_),destroy:()=>{S.delListener(K),S.delListener(N)},getListenerStats:()=>({})};return w(_.clear())})(S)),y.get(S))})();export{S as createCheckpoints};
Binary file
@@ -115,6 +115,8 @@ export type CheckpointsListenerStats = {
115
115
  * method), and add listeners for when the list checkpoints changes (with the
116
116
  * addCheckpointIdsListener method).
117
117
  *
118
+ * Checkpoints work for both changes to tabular data and to keyed value data.
119
+ *
118
120
  * Every checkpoint can be given a label which can be used to describe the
119
121
  * actions that changed the Store before this checkpoint. This can be useful for
120
122
  * interfaces that let users 'Undo [last action]'.
@@ -127,7 +129,9 @@ export type CheckpointsListenerStats = {
127
129
  * registering and removing a listener for them.
128
130
  *
129
131
  * ```js
130
- * const store = createStore().setTables({pets: {fido: {sold: false}}});
132
+ * const store = createStore()
133
+ * .setTables({pets: {fido: {sold: false}}})
134
+ * .setValue('open', true);
131
135
  *
132
136
  * const checkpoints = createCheckpoints(store);
133
137
  * checkpoints.setSize(200);
@@ -145,14 +149,25 @@ export type CheckpointsListenerStats = {
145
149
  * console.log(checkpoints.getCheckpointIds());
146
150
  * // -> [[], '0', ['1']]
147
151
  *
152
+ * store.setValue('open', false);
153
+ * checkpoints.addCheckpoint('closed');
154
+ * console.log(checkpoints.getCheckpointIds());
155
+ * // -> [['0'], '2', []]
156
+ *
157
+ * checkpoints.goBackward();
158
+ * console.log(store.getValue('open'));
159
+ * // -> true
160
+ * console.log(checkpoints.getCheckpointIds());
161
+ * // -> [[], '0', ['2']]
162
+ *
148
163
  * const listenerId = checkpoints.addCheckpointIdsListener(() => {
149
164
  * console.log(checkpoints.getCheckpointIds());
150
165
  * });
151
166
  * store.setCell('pets', 'fido', 'species', 'dog');
152
167
  * // -> [['0'], undefined, []]
153
168
  * checkpoints.addCheckpoint();
154
- * // -> [['0'], '2', []]
155
- * // Previous redo of checkpoint '1' is now not possible.
169
+ * // -> [['0'], '3', []]
170
+ * // Previous redo of checkpoints '1' and '2' are now not possible.
156
171
  *
157
172
  * checkpoints.delListener(listenerId);
158
173
  * checkpoints.destroy();
@@ -61,6 +61,13 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
61
61
  },
62
62
  );
63
63
 
64
+ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
65
+ isUndefined(cell)
66
+ ? store.delCell(tableId, rowId, cellId, true)
67
+ : store.setCell(tableId, rowId, cellId, cell);
68
+ const setOrDelValue = (store, valueId, value) =>
69
+ isUndefined(value) ? store.delValue(valueId) : store.setValue(valueId, value);
70
+
64
71
  const setNew = (entryOrEntries) =>
65
72
  new Set(
66
73
  isArray(entryOrEntries) || isUndefined(entryOrEntries)
@@ -108,10 +115,22 @@ const getListenerFunctions = (getThing) => {
108
115
  let thing;
109
116
  const [getId, releaseId] = getPoolFunctions();
110
117
  const allListeners = mapNew();
111
- const addListener = (listener, idSetNode, path) => {
118
+ const addListener = (
119
+ listener,
120
+ idSetNode,
121
+ path,
122
+ pathGetters = [],
123
+ extraArgsGetter = () => [],
124
+ ) => {
112
125
  thing ??= getThing();
113
126
  const id = getId();
114
- mapSet(allListeners, id, [listener, idSetNode, path]);
127
+ mapSet(allListeners, id, [
128
+ listener,
129
+ idSetNode,
130
+ path,
131
+ pathGetters,
132
+ extraArgsGetter,
133
+ ]);
115
134
  setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
116
135
  return id;
117
136
  };
@@ -131,35 +150,34 @@ const getListenerFunctions = (getThing) => {
131
150
  releaseId(id);
132
151
  return idOrNulls;
133
152
  });
134
- const callListener = (id, idNullGetters, extraArgsGetter) =>
135
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
136
- const callWithIds = (...ids) => {
137
- const index = arrayLength(ids);
138
- index == arrayLength(idOrNulls)
139
- ? listener(thing, ...ids, ...extraArgsGetter(ids))
140
- : isUndefined(idOrNulls[index])
141
- ? arrayForEach(idNullGetters[index](...ids), (id2) =>
142
- callWithIds(...ids, id2),
143
- )
144
- : callWithIds(...ids, idOrNulls[index]);
145
- };
146
- callWithIds();
147
- });
153
+ const callListener = (id) =>
154
+ ifNotUndefined(
155
+ mapGet(allListeners, id),
156
+ ([listener, , path = [], pathGetters, extraArgsGetter]) => {
157
+ const callWithIds = (...ids) => {
158
+ const index = arrayLength(ids);
159
+ index == arrayLength(path)
160
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
161
+ : isUndefined(path[index])
162
+ ? arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
163
+ callWithIds(...ids, id2),
164
+ )
165
+ : callWithIds(...ids, path[index]);
166
+ };
167
+ callWithIds();
168
+ },
169
+ );
148
170
  return [addListener, callListeners, delListener, callListener];
149
171
  };
150
172
 
151
173
  const object = Object;
152
174
  const objFreeze = object.freeze;
153
175
 
154
- const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
155
- isUndefined(cell)
156
- ? store.delCell(tableId, rowId, cellId, true)
157
- : store.setCell(tableId, rowId, cellId, cell);
158
-
159
176
  const createCheckpoints = getCreateFunction((store) => {
160
177
  let backwardIdsSize = 100;
161
178
  let currentId;
162
- let delta = mapNew();
179
+ let cellsDelta = mapNew();
180
+ let valuesDelta = mapNew();
163
181
  let listening = 1;
164
182
  let nextCheckpointId;
165
183
  let checkpointsChanged;
@@ -174,15 +192,19 @@ const createCheckpoints = getCreateFunction((store) => {
174
192
  const forwardIds = [];
175
193
  const updateStore = (oldOrNew, checkpointId) => {
176
194
  listening = 0;
177
- store.transaction(() =>
178
- collForEach(mapGet(deltas, checkpointId), (table, tableId) =>
195
+ store.transaction(() => {
196
+ const [cellsDelta2, valuesDelta2] = mapGet(deltas, checkpointId);
197
+ collForEach(cellsDelta2, (table, tableId) =>
179
198
  collForEach(table, (row, rowId) =>
180
199
  collForEach(row, (oldNew, cellId) =>
181
200
  setOrDelCell(store, tableId, rowId, cellId, oldNew[oldOrNew]),
182
201
  ),
183
202
  ),
184
- ),
185
- );
203
+ );
204
+ collForEach(valuesDelta2, (oldNew, valueId) =>
205
+ setOrDelValue(store, valueId, oldNew[oldOrNew]),
206
+ );
207
+ });
186
208
  listening = 1;
187
209
  };
188
210
  const clearCheckpointId = (checkpointId) => {
@@ -197,32 +219,56 @@ const createCheckpoints = getCreateFunction((store) => {
197
219
  );
198
220
  const trimBackwardsIds = () =>
199
221
  clearCheckpointIds(backwardIds, arrayLength(backwardIds) - backwardIdsSize);
200
- const listenerId = store.addCellListener(
222
+ const storeChanged = () =>
223
+ ifNotUndefined(currentId, () => {
224
+ arrayPush(backwardIds, currentId);
225
+ trimBackwardsIds();
226
+ clearCheckpointIds(forwardIds);
227
+ currentId = void 0;
228
+ checkpointsChanged = 1;
229
+ });
230
+ const storeUnchanged = () => {
231
+ currentId = arrayPop(backwardIds);
232
+ checkpointsChanged = 1;
233
+ };
234
+ const cellListenerId = store.addCellListener(
201
235
  null,
202
236
  null,
203
237
  null,
204
238
  (_store, tableId, rowId, cellId, newCell, oldCell) => {
205
239
  if (listening) {
206
- ifNotUndefined(currentId, () => {
207
- arrayPush(backwardIds, currentId);
208
- trimBackwardsIds();
209
- clearCheckpointIds(forwardIds);
210
- currentId = void 0;
211
- checkpointsChanged = 1;
212
- });
213
- const table = mapEnsure(delta, tableId, mapNew);
240
+ storeChanged();
241
+ const table = mapEnsure(cellsDelta, tableId, mapNew);
214
242
  const row = mapEnsure(table, rowId, mapNew);
215
243
  const oldNew = mapEnsure(row, cellId, () => [oldCell, void 0]);
216
244
  oldNew[1] = newCell;
217
- if (oldNew[0] === newCell) {
218
- if (collIsEmpty(mapSet(row, cellId))) {
219
- if (collIsEmpty(mapSet(table, rowId))) {
220
- if (collIsEmpty(mapSet(delta, tableId))) {
221
- currentId = arrayPop(backwardIds);
222
- checkpointsChanged = 1;
223
- }
224
- }
225
- }
245
+ if (
246
+ oldNew[0] === newCell &&
247
+ collIsEmpty(mapSet(row, cellId)) &&
248
+ collIsEmpty(mapSet(table, rowId)) &&
249
+ collIsEmpty(mapSet(cellsDelta, tableId))
250
+ ) {
251
+ storeUnchanged();
252
+ }
253
+ callListenersIfChanged();
254
+ }
255
+ },
256
+ );
257
+ const valueListenerId = store.addValueListener(
258
+ null,
259
+ (_store, valueId, newValue, oldValue) => {
260
+ if (listening) {
261
+ storeChanged();
262
+ const oldNew = mapEnsure(valuesDelta, valueId, () => [
263
+ oldValue,
264
+ void 0,
265
+ ]);
266
+ oldNew[1] = newValue;
267
+ if (
268
+ oldNew[0] === newValue &&
269
+ collIsEmpty(mapSet(valuesDelta, valueId))
270
+ ) {
271
+ storeUnchanged();
226
272
  }
227
273
  callListenersIfChanged();
228
274
  }
@@ -231,9 +277,10 @@ const createCheckpoints = getCreateFunction((store) => {
231
277
  const addCheckpointImpl = (label = EMPTY_STRING) => {
232
278
  if (isUndefined(currentId)) {
233
279
  currentId = EMPTY_STRING + nextCheckpointId++;
234
- mapSet(deltas, currentId, delta);
280
+ mapSet(deltas, currentId, [cellsDelta, valuesDelta]);
235
281
  setCheckpoint(currentId, label);
236
- delta = mapNew();
282
+ cellsDelta = mapNew();
283
+ valuesDelta = mapNew();
237
284
  checkpointsChanged = 1;
238
285
  }
239
286
  return currentId;
@@ -309,8 +356,8 @@ const createCheckpoints = getCreateFunction((store) => {
309
356
  addListener(listener, checkpointIdsListeners);
310
357
  const addCheckpointListener = (checkpointId, listener) =>
311
358
  addListener(listener, checkpointListeners, [checkpointId]);
312
- const delListener = (listenerId2) => {
313
- delListenerImpl(listenerId2);
359
+ const delListener = (listenerId) => {
360
+ delListenerImpl(listenerId);
314
361
  return checkpoints;
315
362
  };
316
363
  const clear = () => {
@@ -325,7 +372,8 @@ const createCheckpoints = getCreateFunction((store) => {
325
372
  return checkpoints;
326
373
  };
327
374
  const destroy = () => {
328
- store.delListener(listenerId);
375
+ store.delListener(cellListenerId);
376
+ store.delListener(valueListenerId);
329
377
  };
330
378
  const getListenerStats = () => ({
331
379
  checkpointIds: collSize2(checkpointIdsListeners),
@@ -272,10 +272,22 @@ const getListenerFunctions = (getThing) => {
272
272
  let thing;
273
273
  const [getId, releaseId] = getPoolFunctions();
274
274
  const allListeners = mapNew();
275
- const addListener = (listener, idSetNode, path) => {
275
+ const addListener = (
276
+ listener,
277
+ idSetNode,
278
+ path,
279
+ pathGetters = [],
280
+ extraArgsGetter = () => [],
281
+ ) => {
276
282
  thing ??= getThing();
277
283
  const id = getId();
278
- mapSet(allListeners, id, [listener, idSetNode, path]);
284
+ mapSet(allListeners, id, [
285
+ listener,
286
+ idSetNode,
287
+ path,
288
+ pathGetters,
289
+ extraArgsGetter,
290
+ ]);
279
291
  setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
280
292
  return id;
281
293
  };
@@ -295,20 +307,23 @@ const getListenerFunctions = (getThing) => {
295
307
  releaseId(id);
296
308
  return idOrNulls;
297
309
  });
298
- const callListener = (id, idNullGetters, extraArgsGetter) =>
299
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
300
- const callWithIds = (...ids) => {
301
- const index = arrayLength(ids);
302
- index == arrayLength(idOrNulls)
303
- ? listener(thing, ...ids, ...extraArgsGetter(ids))
304
- : isUndefined(idOrNulls[index])
305
- ? arrayForEach(idNullGetters[index](...ids), (id2) =>
306
- callWithIds(...ids, id2),
307
- )
308
- : callWithIds(...ids, idOrNulls[index]);
309
- };
310
- callWithIds();
311
- });
310
+ const callListener = (id) =>
311
+ ifNotUndefined(
312
+ mapGet(allListeners, id),
313
+ ([listener, , path = [], pathGetters, extraArgsGetter]) => {
314
+ const callWithIds = (...ids) => {
315
+ const index = arrayLength(ids);
316
+ index == arrayLength(path)
317
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
318
+ : isUndefined(path[index])
319
+ ? arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
320
+ callWithIds(...ids, id2),
321
+ )
322
+ : callWithIds(...ids, path[index]);
323
+ };
324
+ callWithIds();
325
+ },
326
+ );
312
327
  return [addListener, callListeners, delListener, callListener];
313
328
  };
314
329
 
@@ -341,10 +341,22 @@ const getListenerFunctions = (getThing) => {
341
341
  let thing;
342
342
  const [getId, releaseId] = getPoolFunctions();
343
343
  const allListeners = mapNew();
344
- const addListener = (listener, idSetNode, path) => {
344
+ const addListener = (
345
+ listener,
346
+ idSetNode,
347
+ path,
348
+ pathGetters = [],
349
+ extraArgsGetter = () => [],
350
+ ) => {
345
351
  thing ??= getThing();
346
352
  const id = getId();
347
- mapSet(allListeners, id, [listener, idSetNode, path]);
353
+ mapSet(allListeners, id, [
354
+ listener,
355
+ idSetNode,
356
+ path,
357
+ pathGetters,
358
+ extraArgsGetter,
359
+ ]);
348
360
  setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
349
361
  return id;
350
362
  };
@@ -364,20 +376,23 @@ const getListenerFunctions = (getThing) => {
364
376
  releaseId(id);
365
377
  return idOrNulls;
366
378
  });
367
- const callListener = (id, idNullGetters, extraArgsGetter) =>
368
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
369
- const callWithIds = (...ids) => {
370
- const index = arrayLength(ids);
371
- index == arrayLength(idOrNulls)
372
- ? listener(thing, ...ids, ...extraArgsGetter(ids))
373
- : isUndefined(idOrNulls[index])
374
- ? arrayForEach(idNullGetters[index](...ids), (id2) =>
375
- callWithIds(...ids, id2),
376
- )
377
- : callWithIds(...ids, idOrNulls[index]);
378
- };
379
- callWithIds();
380
- });
379
+ const callListener = (id) =>
380
+ ifNotUndefined(
381
+ mapGet(allListeners, id),
382
+ ([listener, , path = [], pathGetters, extraArgsGetter]) => {
383
+ const callWithIds = (...ids) => {
384
+ const index = arrayLength(ids);
385
+ index == arrayLength(path)
386
+ ? listener(thing, ...ids, ...extraArgsGetter(ids))
387
+ : isUndefined(path[index])
388
+ ? arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
389
+ callWithIds(...ids, id2),
390
+ )
391
+ : callWithIds(...ids, path[index]);
392
+ };
393
+ callWithIds();
394
+ },
395
+ );
381
396
  return [addListener, callListeners, delListener, callListener];
382
397
  };
383
398