reactronic 0.94.25037 → 0.95.25043

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 (40) hide show
  1. package/README.md +67 -66
  2. package/build/dist/source/Enums.d.ts +3 -3
  3. package/build/dist/source/Enums.js +3 -3
  4. package/build/dist/source/OperationEx.d.ts +2 -2
  5. package/build/dist/source/OperationEx.js +5 -5
  6. package/build/dist/source/Options.d.ts +2 -2
  7. package/build/dist/source/Pipe.d.ts +2 -2
  8. package/build/dist/source/Pipe.js +2 -2
  9. package/build/dist/source/Ref.d.ts +2 -2
  10. package/build/dist/source/Ref.js +5 -5
  11. package/build/dist/source/System.d.ts +14 -14
  12. package/build/dist/source/System.js +22 -22
  13. package/build/dist/source/api.d.ts +7 -7
  14. package/build/dist/source/api.js +6 -6
  15. package/build/dist/source/core/Changeset.js +1 -1
  16. package/build/dist/source/core/Data.d.ts +1 -1
  17. package/build/dist/source/core/Indicator.d.ts +2 -2
  18. package/build/dist/source/core/Indicator.js +2 -2
  19. package/build/dist/source/core/Journal.d.ts +2 -2
  20. package/build/dist/source/core/Journal.js +2 -2
  21. package/build/dist/source/core/Mvcc.d.ts +10 -10
  22. package/build/dist/source/core/Mvcc.js +19 -19
  23. package/build/dist/source/core/MvccArray.d.ts +3 -3
  24. package/build/dist/source/core/MvccArray.js +4 -4
  25. package/build/dist/source/core/MvccMap.d.ts +3 -3
  26. package/build/dist/source/core/MvccMap.js +4 -4
  27. package/build/dist/source/core/MvccReconciliationList.d.ts +12 -11
  28. package/build/dist/source/core/MvccReconciliationList.js +12 -11
  29. package/build/dist/source/core/Operation.d.ts +8 -8
  30. package/build/dist/source/core/Operation.js +41 -41
  31. package/build/dist/source/core/Transaction.js +28 -28
  32. package/build/dist/source/core/TreeNode.d.ts +17 -17
  33. package/build/dist/source/core/TreeNode.js +52 -52
  34. package/build/dist/source/util/LinkedList.d.ts +52 -0
  35. package/build/dist/source/util/LinkedList.js +177 -0
  36. package/build/dist/source/util/LinkedListRenovation.d.ts +20 -0
  37. package/build/dist/source/util/LinkedListRenovation.js +134 -0
  38. package/build/dist/source/util/ReconciliationList.d.ts +10 -8
  39. package/build/dist/source/util/ReconciliationList.js +59 -58
  40. package/package.json +10 -9
@@ -0,0 +1,134 @@
1
+ import { misuse } from "./Dbg.js";
2
+ import { LinkedList, LinkedItem, LinkedSubList, Mark } from "./LinkedList.js";
3
+ export class LinkedListRenovation {
4
+ constructor(list, diff) {
5
+ if (list.former$ !== undefined)
6
+ throw misuse("renovation is in progress already");
7
+ const former = list.items$;
8
+ this.list = list;
9
+ this.diff = diff;
10
+ this.lost$ = former;
11
+ this.expected = former.first;
12
+ this.absent = undefined;
13
+ list.former$ = former;
14
+ list.items$ = new LinkedSubList();
15
+ }
16
+ lookup(key) {
17
+ let result = undefined;
18
+ if (key !== undefined && key !== this.absent) {
19
+ result = this.list.lookup(key);
20
+ if (result !== undefined) {
21
+ if (this.list.keyOf(result) !== key) {
22
+ this.absent = key;
23
+ result = undefined;
24
+ }
25
+ }
26
+ else
27
+ this.absent = key;
28
+ }
29
+ return result;
30
+ }
31
+ tryToProlonge(key, resolution, error) {
32
+ var _a, _b;
33
+ const list = this.list;
34
+ if (!list.isRenovationInProgress)
35
+ throw misuse(error !== null && error !== void 0 ? error : "renovation is no longer in progress");
36
+ let x = this.expected;
37
+ if (key !== (x ? list.keyOf(x) : undefined))
38
+ x = this.lookup(key);
39
+ if (x !== undefined) {
40
+ const result = this.list.items$;
41
+ if (x.list !== result) {
42
+ const next = x.next;
43
+ const expected = (_a = grabExternalIfAny(result, x)) !== null && _a !== void 0 ? _a : x;
44
+ LinkedItem.link$(result, x, undefined);
45
+ if (list.isStrictOrder && expected !== this.expected) {
46
+ LinkedItem.setStatus$(x, Mark.modified, result.count);
47
+ (_b = this.diff) === null || _b === void 0 ? void 0 : _b.push(x);
48
+ }
49
+ else
50
+ LinkedItem.setStatus$(x, Mark.prolonged, result.count);
51
+ this.expected = next;
52
+ if (resolution)
53
+ resolution.isDuplicate = false;
54
+ }
55
+ else if (resolution)
56
+ resolution.isDuplicate = true;
57
+ else
58
+ throw misuse(`duplicate linked item key: ${key}`);
59
+ }
60
+ else if (resolution)
61
+ resolution.isDuplicate = false;
62
+ return x;
63
+ }
64
+ thisIsAdded(item, before) {
65
+ var _a;
66
+ this.list.add(item, before);
67
+ LinkedItem.setStatus$(item, Mark.added, this.list.items$.count);
68
+ this.absent = undefined;
69
+ this.expected = undefined;
70
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
71
+ return item;
72
+ }
73
+ thisIsModified(item) {
74
+ if (item.list !== this.list.items$)
75
+ throw misuse("only prolonged items can be marked as modified");
76
+ const m = item.mark;
77
+ if (m === Mark.prolonged)
78
+ LinkedItem.setStatus$(item, Mark.modified, item.rank);
79
+ else if (m !== Mark.modified)
80
+ throw misuse("item is renovated already and cannot be marked as modified");
81
+ }
82
+ thisIsMoved(item, before) {
83
+ var _a;
84
+ if (item.list !== this.list.former$)
85
+ throw misuse("cannot move item which doesn't belong to former list");
86
+ LinkedList.move$(this.list, item, before);
87
+ LinkedItem.setStatus$(item, Mark.modified, 0);
88
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
89
+ }
90
+ thisIsRemoved(item) {
91
+ var _a;
92
+ if (item.list !== this.list.former$)
93
+ throw misuse("cannot remove item which doesn't belong to former list");
94
+ LinkedList.remove$(this.list, item);
95
+ LinkedItem.setStatus$(item, Mark.removed, 0);
96
+ (_a = this.diff) === null || _a === void 0 ? void 0 : _a.push(item);
97
+ }
98
+ get lostItemCount() { return this.lost$.count; }
99
+ lostItems() { return this.lost$.items(); }
100
+ done(error) {
101
+ const list = this.list;
102
+ if (!list.isRenovationInProgress)
103
+ throw misuse("renovation is ended already");
104
+ const items = this.list.items$;
105
+ const lost = this.lost$;
106
+ if (error === undefined) {
107
+ for (const x of lost.items()) {
108
+ if (!x.isManagedExternally) {
109
+ LinkedList.removeKey$(list, list.keyOf(x));
110
+ LinkedItem.setStatus$(x, Mark.removed, 0);
111
+ }
112
+ else
113
+ LinkedItem.link$(items, x, undefined);
114
+ }
115
+ }
116
+ else {
117
+ for (const x of lost.items()) {
118
+ LinkedItem.link$(items, x, undefined);
119
+ LinkedItem.setStatus$(x, Mark.prolonged, items.count);
120
+ }
121
+ }
122
+ list.former$ = undefined;
123
+ }
124
+ }
125
+ function grabExternalIfAny(list, item) {
126
+ let x = item.prev;
127
+ let before = undefined;
128
+ while (x !== undefined && x.isManagedExternally) {
129
+ LinkedItem.link$(list, x, before);
130
+ before = x;
131
+ x = x.prev;
132
+ }
133
+ return before;
134
+ }
@@ -9,12 +9,13 @@ export type ReconciliationListReader<T> = {
9
9
  firstItem(): LinkedItem<T> | undefined;
10
10
  lastItem(): LinkedItem<T> | undefined;
11
11
  items(onlyAfter?: LinkedItem<T>): Generator<LinkedItem<T>>;
12
- itemsAdded(reset?: boolean): Generator<LinkedItem<T>>;
13
- itemsRemoved(reset?: boolean): Generator<LinkedItem<T>>;
12
+ itemsAdded(clear?: boolean): Generator<LinkedItem<T>>;
13
+ itemsRemoved(clear?: boolean): Generator<LinkedItem<T>>;
14
14
  isAdded(item: LinkedItem<T>): boolean;
15
15
  isMoved(item: LinkedItem<T>): boolean;
16
16
  isRemoved(item: LinkedItem<T>): boolean;
17
- isFresh(item: LinkedItem<T>): boolean;
17
+ isActual(item: LinkedItem<T>): boolean;
18
+ isExternal(item: LinkedItem<T>): boolean;
18
19
  };
19
20
  export type LinkedItem<T> = {
20
21
  readonly instance: T;
@@ -28,7 +29,7 @@ export declare class ReconciliationList<T> implements ReconciliationListReader<T
28
29
  private strict;
29
30
  private map;
30
31
  private tag;
31
- private fresh;
32
+ private actual;
32
33
  private added;
33
34
  private removed;
34
35
  private lastNotFoundKey;
@@ -49,16 +50,17 @@ export declare class ReconciliationList<T> implements ReconciliationListReader<T
49
50
  move(item: LinkedItem<T>, after: LinkedItem<T>): void;
50
51
  beginReconciliation(): void;
51
52
  endReconciliation(error?: unknown): void;
52
- resetAddedAndRemovedLists(): void;
53
+ clearAddedAndRemoved(): void;
53
54
  firstItem(): LinkedItem<T> | undefined;
54
55
  lastItem(): LinkedItem<T> | undefined;
55
56
  items(onlyAfter?: LinkedItem<T>): Generator<LinkedItem<T>>;
56
- itemsAdded(reset?: boolean): Generator<LinkedItem<T>>;
57
- itemsRemoved(reset?: boolean): Generator<LinkedItem<T>>;
57
+ itemsAdded(clear?: boolean): Generator<LinkedItem<T>>;
58
+ itemsRemoved(clear?: boolean): Generator<LinkedItem<T>>;
58
59
  isAdded(item: LinkedItem<T>): boolean;
59
60
  isMoved(item: LinkedItem<T>): boolean;
60
61
  isRemoved(item: LinkedItem<T>): boolean;
61
- isFresh(item: LinkedItem<T>): boolean;
62
+ isActual(item: LinkedItem<T>): boolean;
63
+ isExternal(item: LinkedItem<T>): boolean;
62
64
  markAsMoved(item: LinkedItem<T>): void;
63
65
  static createItem<T>(instance: T): LinkedItem<T>;
64
66
  }
@@ -5,7 +5,7 @@ export class ReconciliationList {
5
5
  this.strict = strict;
6
6
  this.map = new Map();
7
7
  this.tag = ~0;
8
- this.fresh = new LinkedItemChain();
8
+ this.actual = new LinkedItemChain();
9
9
  this.added = new LinkedItemChain();
10
10
  this.removed = new LinkedItemChain();
11
11
  this.lastNotFoundKey = undefined;
@@ -13,12 +13,12 @@ export class ReconciliationList {
13
13
  }
14
14
  get isStrict() { return this.strict; }
15
15
  set isStrict(value) {
16
- if (this.isReconciliationInProgress && this.fresh.count > 0)
16
+ if (this.isReconciliationInProgress && this.actual.count > 0)
17
17
  throw misuse("cannot change strict mode in the middle of reconciliation");
18
18
  this.strict = value;
19
19
  }
20
20
  get count() {
21
- return this.fresh.count;
21
+ return this.actual.count;
22
22
  }
23
23
  get countOfAdded() {
24
24
  return this.added.count;
@@ -55,11 +55,11 @@ export class ReconciliationList {
55
55
  if (item.tag !== tag) {
56
56
  item.tag = tag;
57
57
  if (this.strict && item !== this.strictNextItem)
58
- item.status = tag;
58
+ item.moving = tag;
59
59
  this.strictNextItem = item.next;
60
60
  this.removed.exclude(item);
61
- item.index = this.fresh.count;
62
- this.fresh.include(item);
61
+ item.index = this.actual.count;
62
+ this.actual.include(item);
63
63
  if (resolution)
64
64
  resolution.isDuplicate = false;
65
65
  }
@@ -76,24 +76,21 @@ export class ReconciliationList {
76
76
  const key = this.getKey(instance);
77
77
  if (this.lookup(key) !== undefined)
78
78
  throw misuse(`key is already in use: ${key}`);
79
- let tag = this.tag;
80
- if (tag < 0) {
81
- tag = ~this.tag + 1;
82
- this.tag = ~tag;
83
- }
84
- const item = new LinkedItemImpl(instance, tag);
79
+ const tag = this.tag > 0 ? this.tag : 0;
80
+ const item = new LinkedItem$(instance, tag);
85
81
  this.map.set(key, item);
86
82
  this.lastNotFoundKey = undefined;
87
83
  this.strictNextItem = undefined;
88
- item.index = this.fresh.count;
89
- this.fresh.include(item);
90
- this.added.aux(item);
84
+ item.index = this.actual.count;
85
+ this.actual.include(item);
86
+ if (tag !== 0)
87
+ this.added.includeAux(item);
91
88
  return item;
92
89
  }
93
90
  remove(item) {
94
91
  const t = item;
95
92
  if (!this.isRemoved(t)) {
96
- this.fresh.exclude(t);
93
+ this.actual.exclude(t);
97
94
  this.removed.include(t);
98
95
  t.tag--;
99
96
  }
@@ -105,26 +102,26 @@ export class ReconciliationList {
105
102
  if (this.isReconciliationInProgress)
106
103
  throw misuse("reconciliation is in progress already");
107
104
  this.tag = ~this.tag + 1;
108
- this.strictNextItem = this.fresh.first;
109
- this.removed.grab(this.fresh, false);
110
- this.added.reset();
105
+ this.strictNextItem = this.actual.first;
106
+ this.removed.grab(this.actual, false);
107
+ this.added.clear();
111
108
  }
112
109
  endReconciliation(error) {
113
110
  if (!this.isReconciliationInProgress)
114
111
  throw misuse("reconciliation is ended already");
115
112
  this.tag = ~this.tag;
116
113
  if (error === undefined) {
117
- const freshCount = this.fresh.count;
118
- if (freshCount > 0) {
114
+ const actualCount = this.actual.count;
115
+ if (actualCount > 0) {
119
116
  const getKey = this.getKey;
120
- if (freshCount > this.removed.count) {
117
+ if (actualCount > this.removed.count) {
121
118
  const map = this.map;
122
119
  for (const x of this.removed.items())
123
120
  map.delete(getKey(x.instance));
124
121
  }
125
122
  else {
126
123
  const map = this.map = new Map();
127
- for (const x of this.fresh.items())
124
+ for (const x of this.actual.items())
128
125
  map.set(getKey(x.instance), x);
129
126
  }
130
127
  }
@@ -132,35 +129,35 @@ export class ReconciliationList {
132
129
  this.map = new Map();
133
130
  }
134
131
  else {
135
- this.fresh.grab(this.removed, true);
132
+ this.actual.grab(this.removed, true);
136
133
  const getKey = this.getKey;
137
- for (const x of this.added.itemsViaAux()) {
134
+ for (const x of this.added.itemsAux()) {
138
135
  this.map.delete(getKey(x.instance));
139
- this.fresh.exclude(x);
136
+ this.actual.exclude(x);
140
137
  }
141
- this.added.reset();
138
+ this.added.clear();
142
139
  }
143
140
  }
144
- resetAddedAndRemovedLists() {
145
- this.removed.reset();
146
- this.added.reset();
141
+ clearAddedAndRemoved() {
142
+ this.removed.clear();
143
+ this.added.clear();
147
144
  }
148
145
  firstItem() {
149
- return this.fresh.first;
146
+ return this.actual.first;
150
147
  }
151
148
  lastItem() {
152
- return this.fresh.last;
149
+ return this.actual.last;
153
150
  }
154
151
  *items(onlyAfter) {
155
152
  var _a;
156
- let x = (_a = onlyAfter === null || onlyAfter === void 0 ? void 0 : onlyAfter.next) !== null && _a !== void 0 ? _a : this.fresh.first;
153
+ let x = (_a = onlyAfter === null || onlyAfter === void 0 ? void 0 : onlyAfter.next) !== null && _a !== void 0 ? _a : this.actual.first;
157
154
  while (x !== undefined) {
158
155
  const next = x.next;
159
156
  yield x;
160
157
  x = next;
161
158
  }
162
159
  }
163
- *itemsAdded(reset) {
160
+ *itemsAdded(clear) {
164
161
  let x = this.added.first;
165
162
  while (x !== undefined) {
166
163
  const next = x.aux;
@@ -168,57 +165,61 @@ export class ReconciliationList {
168
165
  yield x;
169
166
  x = next;
170
167
  }
171
- if (reset)
172
- this.added.reset();
168
+ if (clear)
169
+ this.added.clear();
173
170
  }
174
- *itemsRemoved(reset) {
171
+ *itemsRemoved(clear) {
175
172
  let x = this.removed.first;
176
173
  while (x !== undefined) {
177
174
  const next = x.next;
178
175
  yield x;
179
176
  x = next;
180
177
  }
181
- if (reset)
182
- this.removed.reset();
178
+ if (clear)
179
+ this.removed.clear();
183
180
  }
184
181
  isAdded(item) {
185
182
  const t = item;
186
183
  let tag = this.tag;
187
184
  if (tag < 0)
188
185
  tag = ~tag;
189
- return t.status === ~tag && t.tag > 0;
186
+ return t.moving === ~tag && t.tag > 0;
190
187
  }
191
188
  isMoved(item) {
192
189
  const t = item;
193
190
  let tag = this.tag;
194
191
  if (tag < 0)
195
192
  tag = ~tag;
196
- return t.status === tag && t.tag > 0;
193
+ return t.moving === tag && t.tag > 0;
197
194
  }
198
195
  isRemoved(item) {
199
196
  const t = item;
200
197
  const tag = this.tag;
201
198
  return tag > 0 ? t.tag < tag : t.tag < tag - 1;
202
199
  }
203
- isFresh(item) {
200
+ isActual(item) {
204
201
  const t = item;
205
202
  return t.tag === this.tag;
206
203
  }
204
+ isExternal(item) {
205
+ const t = item;
206
+ return t.tag === 0;
207
+ }
207
208
  markAsMoved(item) {
208
209
  const t = item;
209
210
  if (t.tag > 0)
210
- t.status = t.tag;
211
+ t.moving = t.tag;
211
212
  }
212
213
  static createItem(instance) {
213
- return new LinkedItemImpl(instance, 0);
214
+ return new LinkedItem$(instance, 0);
214
215
  }
215
216
  }
216
- class LinkedItemImpl {
217
+ class LinkedItem$ {
217
218
  constructor(instance, tag) {
218
219
  this.instance = instance;
219
220
  this.index = -1;
220
221
  this.tag = tag;
221
- this.status = ~tag;
222
+ this.moving = ~tag;
222
223
  this.next = undefined;
223
224
  this.prev = undefined;
224
225
  this.aux = undefined;
@@ -238,7 +239,7 @@ class LinkedItemChain {
238
239
  x = next;
239
240
  }
240
241
  }
241
- *itemsViaAux() {
242
+ *itemsAux() {
242
243
  let x = this.first;
243
244
  while (x !== undefined) {
244
245
  const next = x.aux;
@@ -246,7 +247,7 @@ class LinkedItemChain {
246
247
  x = next;
247
248
  }
248
249
  }
249
- reset() {
250
+ clear() {
250
251
  this.count = 0;
251
252
  this.first = undefined;
252
253
  this.last = undefined;
@@ -267,7 +268,7 @@ class LinkedItemChain {
267
268
  this.first = head;
268
269
  this.last = from.last;
269
270
  }
270
- from.reset();
271
+ from.clear();
271
272
  }
272
273
  include(item) {
273
274
  const last = this.last;
@@ -279,6 +280,15 @@ class LinkedItemChain {
279
280
  this.first = this.last = item;
280
281
  this.count++;
281
282
  }
283
+ includeAux(item) {
284
+ item.aux = undefined;
285
+ const last = this.last;
286
+ if (last)
287
+ this.last = last.aux = item;
288
+ else
289
+ this.first = this.last = item;
290
+ this.count++;
291
+ }
282
292
  exclude(item) {
283
293
  if (item.prev !== undefined)
284
294
  item.prev.next = item.next;
@@ -288,13 +298,4 @@ class LinkedItemChain {
288
298
  this.first = item.next;
289
299
  this.count--;
290
300
  }
291
- aux(item) {
292
- item.aux = undefined;
293
- const last = this.last;
294
- if (last)
295
- this.last = last.aux = item;
296
- else
297
- this.first = this.last = item;
298
- this.count++;
299
- }
300
301
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.94.25037",
3
+ "version": "0.95.25043",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",
@@ -31,16 +31,17 @@
31
31
  },
32
32
  "homepage": "https://github.com/nezaboodka/reactronic/blob/master/README.md#readme",
33
33
  "devDependencies": {
34
- "@types/node": "22.13.0",
35
- "@types/react": "19.0.8",
36
- "@typescript-eslint/eslint-plugin": "8.22.0",
37
- "@typescript-eslint/parser": "8.22.0",
38
- "ava": "6.2.0",
34
+ "@types/node": "24.10.2",
35
+ "@types/react": "19.2.7",
36
+ "@typescript-eslint/eslint-plugin": "8.49.0",
37
+ "@typescript-eslint/parser": "8.49.0",
38
+ "tsimp": "2.0.12",
39
+ "ava": "6.4.1",
39
40
  "c8": "10.1.3",
40
- "eslint": "9.19.0",
41
- "react": "19.0.0",
41
+ "eslint": "9.39.1",
42
+ "react": "19.2.1",
42
43
  "ts-node": "10.9.2",
43
- "typescript": "5.5.4"
44
+ "typescript": "5.9.3"
44
45
  },
45
46
  "scripts": {
46
47
  "build": "eslint source/**.ts test/**.test.ts react/**.tsx && tsc",