reactronic 0.24.275 → 0.24.301

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.
@@ -18,7 +18,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
18
18
  };
19
19
  import { MergeList } from "../util/MergeList.js";
20
20
  import { emitLetters, getCallerInfo } from "../util/Utils.js";
21
- import { Reentrance } from "../Options.js";
21
+ import { Isolation, Reentrance } from "../Options.js";
22
22
  import { ObservableObject } from "../core/Mvcc.js";
23
23
  import { Transaction } from "../core/Transaction.js";
24
24
  import { RxSystem, options, raw, reactive, unobs } from "../RxSystem.js";
@@ -281,7 +281,7 @@ class RxNodeImpl extends RxNode {
281
281
  configureReactronic(options) {
282
282
  if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.independentUpdate))
283
283
  throw new Error("reactronic can be configured only for elements with independent update mode and only during activation");
284
- return RxSystem.getReaction(this.update).configure(options);
284
+ return RxSystem.getOperation(this.update).configure(options);
285
285
  }
286
286
  static get ownSeat() {
287
287
  if (!gOwnSeat)
@@ -311,7 +311,7 @@ class RxNodeImpl extends RxNode {
311
311
  node.outer = owner;
312
312
  else
313
313
  node.outer = owner.outer;
314
- Transaction.run({ separation: true }, () => {
314
+ Transaction.run({ isolation: Isolation.joinAsNestedTransaction }, () => {
315
315
  const ctx = node.context;
316
316
  if (ctx) {
317
317
  ctx.variable = variable;
@@ -449,7 +449,7 @@ function triggerUpdateViaSeat(seat) {
449
449
  Transaction.outside(() => {
450
450
  if (RxSystem.isLogging)
451
451
  RxSystem.setLoggingHint(node.element, node.key);
452
- RxSystem.getReaction(node.update).configure({
452
+ RxSystem.getOperation(node.update).configure({
453
453
  order: node.level,
454
454
  });
455
455
  });
@@ -519,7 +519,7 @@ function triggerDeactivation(seat, isLeader, individual) {
519
519
  else
520
520
  gFirstToDispose = gLastToDispose = seat;
521
521
  if (gFirstToDispose === seat)
522
- Transaction.run({ separation: "disposal", hint: `runDisposalLoop(initiator=${seat.instance.key})` }, () => {
522
+ Transaction.run({ isolation: Isolation.disjoinForInternalDisposal, hint: `runDisposalLoop(initiator=${seat.instance.key})` }, () => {
523
523
  void runDisposalLoop().then(NOP, error => console.log(error));
524
524
  });
525
525
  }
@@ -1,6 +1,7 @@
1
1
  import { F } from "../util/Utils.js";
2
2
  import { Worker } from "../Worker.js";
3
3
  import { SnapshotOptions } from "../Options.js";
4
+ import { ObjectHandle, ObjectVersion, Observer, FieldVersion, FieldKey } from "./Data.js";
4
5
  import { Changeset } from "./Changeset.js";
5
6
  export declare abstract class Transaction implements Worker {
6
7
  static get current(): Transaction;
@@ -20,11 +21,69 @@ export declare abstract class Transaction implements Worker {
20
21
  abstract readonly isCanceled: boolean;
21
22
  abstract readonly isFinished: boolean;
22
23
  whenFinished(): Promise<void>;
23
- static create(options: SnapshotOptions | null): Transaction;
24
+ static create(options: SnapshotOptions | null, parent?: Transaction): Transaction;
24
25
  static run<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
25
- static separate<T>(func: F<T>, ...args: any[]): T;
26
+ static isolate<T>(func: F<T>, ...args: any[]): T;
26
27
  static outside<T>(func: F<T>, ...args: any[]): T;
27
28
  static isFrameOver(everyN?: number, timeLimit?: number): boolean;
28
29
  static requestNextFrame(sleepTime?: number): Promise<void>;
29
30
  static get isCanceled(): boolean;
30
31
  }
32
+ export declare class TransactionImpl extends Transaction {
33
+ private static readonly none;
34
+ private static curr;
35
+ private static inspection;
36
+ private static frameStartTime;
37
+ private static frameOverCounter;
38
+ readonly margin: number;
39
+ readonly parent?: TransactionImpl;
40
+ readonly changeset: Changeset;
41
+ private pending;
42
+ private sealed;
43
+ private canceled?;
44
+ private after?;
45
+ private promise?;
46
+ private resolve;
47
+ private reject;
48
+ constructor(options: SnapshotOptions | null, parent?: TransactionImpl);
49
+ static get current(): TransactionImpl;
50
+ get id(): number;
51
+ get hint(): string;
52
+ get options(): SnapshotOptions;
53
+ get timestamp(): number;
54
+ get error(): Error | undefined;
55
+ run<T>(func: F<T>, ...args: any[]): T;
56
+ inspect<T>(func: F<T>, ...args: any[]): T;
57
+ apply(): void;
58
+ seal(): this;
59
+ wrap<T>(func: F<T>, error: boolean): F<T>;
60
+ private static wrapperEnter;
61
+ private static wrapperLeave;
62
+ cancel(error: Error, restartAfter?: Worker | null): this;
63
+ get isCanceled(): boolean;
64
+ get isFinished(): boolean;
65
+ whenFinished(): Promise<void>;
66
+ static run<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
67
+ static isolate<T>(func: F<T>, ...args: any[]): T;
68
+ static outside<T>(func: F<T>, ...args: any[]): T;
69
+ static isFrameOver(everyN?: number, timeLimit?: number): boolean;
70
+ static requestNextFrame(sleepTime?: number): Promise<void>;
71
+ private static acquire;
72
+ private guard;
73
+ private wrapToRetry;
74
+ private wrapToWaitUntilFinish;
75
+ private runImpl;
76
+ private static seal;
77
+ private checkForConflicts;
78
+ private tryResolveConflicts;
79
+ private applyOrDiscard;
80
+ applyOrDiscardChangeset(): Array<Observer>;
81
+ applyObjectChanges(h: ObjectHandle, ov: ObjectVersion): void;
82
+ static migrateObjectChangesToAnotherTransaction(h: ObjectHandle, ov: ObjectVersion, tParent: Transaction): void;
83
+ static migrateFieldVersionToAnotherTransaction(h: ObjectHandle, fk: FieldKey, ov: ObjectVersion, ovParent: ObjectVersion, tParent: Transaction): void;
84
+ private acquirePromise;
85
+ private static getCurrentChangeset;
86
+ private static getEditableChangeset;
87
+ static createFieldVersion: (fv: FieldVersion, target: Transaction) => FieldVersion;
88
+ static _init(): void;
89
+ }
@@ -9,25 +9,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { UNDEF, pause } from "../util/Utils.js";
11
11
  import { Log, misuse, error, fatal } from "../util/Dbg.js";
12
- import { Changeset, Dump } from "./Changeset.js";
12
+ import { Isolation } from "../Options.js";
13
+ import { Meta } from "./Data.js";
14
+ import { Changeset, Dump, EMPTY_OBJECT_VERSION, UNDEFINED_REVISION } from "./Changeset.js";
13
15
  export class Transaction {
14
16
  static get current() { return TransactionImpl.current; }
15
17
  whenFinished() {
16
18
  return __awaiter(this, void 0, void 0, function* () { });
17
19
  }
18
- static create(options) { return new TransactionImpl(options); }
20
+ static create(options, parent) { return new TransactionImpl(options, parent); }
19
21
  static run(options, func, ...args) { return TransactionImpl.run(options, func, ...args); }
20
- static separate(func, ...args) { return TransactionImpl.separate(func, ...args); }
22
+ static isolate(func, ...args) { return TransactionImpl.isolate(func, ...args); }
21
23
  static outside(func, ...args) { return TransactionImpl.outside(func, ...args); }
22
24
  static isFrameOver(everyN = 1, timeLimit = 10) { return TransactionImpl.isFrameOver(everyN, timeLimit); }
23
25
  static requestNextFrame(sleepTime = 0) { return TransactionImpl.requestNextFrame(sleepTime); }
24
26
  static get isCanceled() { return TransactionImpl.current.isCanceled; }
25
27
  }
26
- class TransactionImpl extends Transaction {
27
- constructor(options) {
28
+ export class TransactionImpl extends Transaction {
29
+ constructor(options, parent) {
28
30
  super();
29
31
  this.margin = TransactionImpl.curr !== undefined ? TransactionImpl.curr.margin + 1 : -1;
30
- this.changeset = new Changeset(options);
32
+ this.parent = parent;
33
+ this.changeset = new Changeset(options, parent === null || parent === void 0 ? void 0 : parent.changeset);
31
34
  this.pending = 0;
32
35
  this.sealed = false;
33
36
  this.canceled = undefined;
@@ -126,8 +129,8 @@ class TransactionImpl extends Transaction {
126
129
  }
127
130
  return result;
128
131
  }
129
- static separate(func, ...args) {
130
- return TransactionImpl.run({ separation: true }, func, ...args);
132
+ static isolate(func, ...args) {
133
+ return TransactionImpl.run({ isolation: Isolation.disjoinFromOuterTransaction }, func, ...args);
131
134
  }
132
135
  static outside(func, ...args) {
133
136
  const outer = TransactionImpl.curr;
@@ -152,11 +155,17 @@ class TransactionImpl extends Transaction {
152
155
  return pause(sleepTime);
153
156
  }
154
157
  static acquire(options) {
155
- const curr = TransactionImpl.curr;
156
- if ((options === null || options === void 0 ? void 0 : options.separation) || curr.isFinished || curr.options.separation === "isolated")
158
+ var _a;
159
+ const outer = TransactionImpl.curr;
160
+ const isolation = (_a = options === null || options === void 0 ? void 0 : options.isolation) !== null && _a !== void 0 ? _a : Isolation.joinToCurrentTransaction;
161
+ if (outer.isFinished || outer.options.isolation === Isolation.disjoinFromOuterAndInnerTransactions)
162
+ return new TransactionImpl(options);
163
+ else if (isolation === Isolation.joinAsNestedTransaction)
164
+ return new TransactionImpl(options, outer);
165
+ else if (isolation !== Isolation.joinToCurrentTransaction)
157
166
  return new TransactionImpl(options);
158
167
  else
159
- return TransactionImpl.curr;
168
+ return outer;
160
169
  }
161
170
  guard() {
162
171
  if (this.sealed && TransactionImpl.curr !== this)
@@ -176,7 +185,7 @@ class TransactionImpl extends Transaction {
176
185
  yield this.after.whenFinished();
177
186
  const options = {
178
187
  hint: `${this.hint} - restart after T${this.after.id}`,
179
- separation: this.options.separation === "isolated" ? "isolated" : true,
188
+ isolation: this.options.isolation === Isolation.joinToCurrentTransaction ? Isolation.disjoinFromOuterTransaction : this.options.isolation,
180
189
  logging: this.changeset.options.logging,
181
190
  token: this.changeset.options.token,
182
191
  };
@@ -255,11 +264,12 @@ class TransactionImpl extends Transaction {
255
264
  throw error(`T${this.id}[${this.hint}] conflicts with: ${Dump.conflicts(conflicts)}`, undefined);
256
265
  }
257
266
  applyOrDiscard() {
258
- let reactive;
267
+ let observers;
259
268
  try {
260
269
  if (Log.isOn && Log.opt.change)
261
270
  Log.write("╠═", "", "", undefined, "changes");
262
- reactive = this.changeset.applyOrDiscard(this.canceled);
271
+ this.changeset.seal();
272
+ observers = this.applyOrDiscardChangeset();
263
273
  this.changeset.triggerGarbageCollection();
264
274
  if (this.promise) {
265
275
  if (this.canceled && !this.after)
@@ -274,7 +284,153 @@ class TransactionImpl extends Transaction {
274
284
  fatal(e);
275
285
  throw e;
276
286
  }
277
- return reactive;
287
+ return observers;
288
+ }
289
+ applyOrDiscardChangeset() {
290
+ const error = this.canceled;
291
+ const changeset = this.changeset;
292
+ changeset.items.forEach((ov, h) => {
293
+ changeset.sealObjectVersion(h, ov);
294
+ if (!error) {
295
+ this.applyObjectChanges(h, ov);
296
+ if (Changeset.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
297
+ Changeset.totalObjectSnapshotCount++;
298
+ if (ov.former.objectVersion === EMPTY_OBJECT_VERSION)
299
+ Changeset.totalObjectHandleCount++;
300
+ }
301
+ }
302
+ });
303
+ if (Log.isOn) {
304
+ if (Log.opt.change && !error && !changeset.parent) {
305
+ changeset.items.forEach((ov, h) => {
306
+ const fields = [];
307
+ ov.changes.forEach((o, fk) => fields.push(fk.toString()));
308
+ const s = fields.join(", ");
309
+ Log.write("║", "√", `${Dump.snapshot2(h, ov.changeset)} (${s}) is ${ov.former.objectVersion === EMPTY_OBJECT_VERSION ? "constructed" : `applied over #${h.id}t${ov.former.objectVersion.changeset.id}s${ov.former.objectVersion.changeset.timestamp}`}`);
310
+ });
311
+ }
312
+ if (Log.opt.transaction)
313
+ Log.write(changeset.timestamp < UNDEFINED_REVISION ? "╚══" : "═══", `s${this.timestamp}`, `${this.hint} - ${error ? "CANCEL" : "APPLY"}(${this.changeset.items.size})${error ? ` - ${error}` : ""}`);
314
+ }
315
+ if (!error && !this.parent)
316
+ Changeset.propagateAllChangesThroughSubscriptions(changeset);
317
+ return changeset.obsolete;
318
+ }
319
+ applyObjectChanges(h, ov) {
320
+ const parent = this.parent;
321
+ if (parent)
322
+ TransactionImpl.migrateObjectChangesToAnotherTransaction(h, ov, parent);
323
+ else
324
+ h.applied = ov;
325
+ }
326
+ static migrateObjectChangesToAnotherTransaction(h, ov, tParent) {
327
+ const csParent = tParent.changeset;
328
+ const ovParent = csParent.getEditableObjectVersion(h, Meta.Undefined, undefined);
329
+ if (ov.former.objectVersion.changeset === EMPTY_OBJECT_VERSION.changeset) {
330
+ for (const fk in ov.data) {
331
+ TransactionImpl.migrateFieldVersionToAnotherTransaction(h, fk, ov, ovParent, tParent);
332
+ }
333
+ }
334
+ else {
335
+ ov.changes.forEach((o, fk) => {
336
+ TransactionImpl.migrateFieldVersionToAnotherTransaction(h, fk, ov, ovParent, tParent);
337
+ });
338
+ }
339
+ }
340
+ static migrateFieldVersionToAnotherTransaction(h, fk, ov, ovParent, tParent) {
341
+ const csParent = tParent.changeset;
342
+ const fv = ov.data[fk];
343
+ const fvParent = ovParent.data[fk];
344
+ if (fv.isLaunch) {
345
+ const migrated = TransactionImpl.createFieldVersion(fv, tParent);
346
+ if (ovParent.former.objectVersion.data[fk] !== fvParent) {
347
+ let observers = fvParent.observers;
348
+ if (observers) {
349
+ const migratedObservers = migrated.observers = new Set();
350
+ observers.forEach(o => {
351
+ var _a, _b;
352
+ const sub = o.observables.get(fvParent);
353
+ (_a = o.observables) === null || _a === void 0 ? void 0 : _a.delete(fvParent);
354
+ (_b = o.observables) === null || _b === void 0 ? void 0 : _b.set(migrated, sub);
355
+ migratedObservers.add(o);
356
+ });
357
+ fvParent.observers = undefined;
358
+ }
359
+ observers = fv.observers;
360
+ if (observers) {
361
+ let migratedObservers = migrated.observers;
362
+ if (migratedObservers === undefined)
363
+ migratedObservers = migrated.observers = new Set();
364
+ observers.forEach(o => {
365
+ var _a, _b;
366
+ const sub = o.observables.get(fv);
367
+ (_a = o.observables) === null || _a === void 0 ? void 0 : _a.delete(fv);
368
+ (_b = o.observables) === null || _b === void 0 ? void 0 : _b.set(migrated, sub);
369
+ migratedObservers === null || migratedObservers === void 0 ? void 0 : migratedObservers.add(o);
370
+ });
371
+ fv.observers = undefined;
372
+ }
373
+ const observables = fv.observables;
374
+ const migratedObservables = migrated.observables;
375
+ if (observables) {
376
+ observables.forEach((s, o) => {
377
+ var _a, _b;
378
+ (_a = o.observers) === null || _a === void 0 ? void 0 : _a.delete(fv);
379
+ (_b = o.observers) === null || _b === void 0 ? void 0 : _b.add(migrated);
380
+ migratedObservables === null || migratedObservables === void 0 ? void 0 : migratedObservables.set(o, s);
381
+ });
382
+ observables.clear();
383
+ }
384
+ ovParent.data[fk] = migrated;
385
+ }
386
+ else {
387
+ const observers = fv.observers;
388
+ if (observers) {
389
+ const migratedObservers = migrated.observers = new Set();
390
+ observers.forEach(o => {
391
+ var _a, _b;
392
+ const sub = o.observables.get(fv);
393
+ (_a = o.observables) === null || _a === void 0 ? void 0 : _a.delete(fv);
394
+ (_b = o.observables) === null || _b === void 0 ? void 0 : _b.set(migrated, sub);
395
+ migratedObservers.add(o);
396
+ });
397
+ fv.observers = undefined;
398
+ }
399
+ const observables = fv.observables;
400
+ const migratedObservables = migrated.observables;
401
+ if (observables) {
402
+ observables.forEach((s, o) => {
403
+ var _a, _b;
404
+ (_a = o.observers) === null || _a === void 0 ? void 0 : _a.delete(fv);
405
+ (_b = o.observers) === null || _b === void 0 ? void 0 : _b.add(migrated);
406
+ migratedObservables === null || migratedObservables === void 0 ? void 0 : migratedObservables.set(o, s);
407
+ });
408
+ observables.clear();
409
+ }
410
+ ovParent.data[fk] = migrated;
411
+ }
412
+ csParent.bumpBy(ovParent.former.objectVersion.changeset.timestamp);
413
+ Changeset.markEdited(undefined, migrated, true, ovParent, fk, h);
414
+ }
415
+ else {
416
+ const parentContent = fvParent === null || fvParent === void 0 ? void 0 : fvParent.content;
417
+ if (ovParent.former.objectVersion.data[fk] !== fvParent) {
418
+ fvParent.content = fv.content;
419
+ const observers = fv.observers;
420
+ if (observers) {
421
+ observers.forEach(o => {
422
+ var _a, _b, _c;
423
+ const sub = o.observables.get(fv);
424
+ (_a = o.observables) === null || _a === void 0 ? void 0 : _a.delete(fv);
425
+ (_b = o.observables) === null || _b === void 0 ? void 0 : _b.set(fvParent, sub);
426
+ (_c = fvParent.observers) === null || _c === void 0 ? void 0 : _c.add(o);
427
+ });
428
+ }
429
+ }
430
+ else
431
+ ovParent.data[fk] = fv;
432
+ Changeset.markEdited(parentContent, fv.content, true, ovParent, fk, h);
433
+ }
278
434
  }
279
435
  acquirePromise() {
280
436
  if (!this.promise) {
@@ -297,7 +453,7 @@ class TransactionImpl extends Transaction {
297
453
  Changeset.current = TransactionImpl.getCurrentChangeset;
298
454
  Changeset.edit = TransactionImpl.getEditableChangeset;
299
455
  TransactionImpl.none.sealed = true;
300
- TransactionImpl.none.changeset.applyOrDiscard();
456
+ TransactionImpl.none.changeset.seal();
301
457
  Changeset._init();
302
458
  }
303
459
  }
@@ -306,4 +462,7 @@ TransactionImpl.curr = TransactionImpl.none;
306
462
  TransactionImpl.inspection = false;
307
463
  TransactionImpl.frameStartTime = 0;
308
464
  TransactionImpl.frameOverCounter = 0;
465
+ TransactionImpl.createFieldVersion = function (fv, target) {
466
+ throw misuse("this implementation of cloneLaunch should never be called");
467
+ };
309
468
  TransactionImpl._init();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactronic",
3
- "version": "0.24.275",
3
+ "version": "0.24.301",
4
4
  "description": "Reactronic - Transactional Reactive State Management",
5
5
  "publisher": "Nezaboodka Software",
6
6
  "license": "Apache-2.0",
@@ -32,13 +32,13 @@
32
32
  "homepage": "https://github.com/nezaboodka/reactronic/blob/master/README.md#readme",
33
33
  "devDependencies": {
34
34
  "@types/node": "20.11.28",
35
- "@types/react": "18.2.66",
35
+ "@types/react": "18.3.4",
36
36
  "@typescript-eslint/eslint-plugin": "7.2.0",
37
37
  "@typescript-eslint/parser": "7.2.0",
38
38
  "ava": "6.1.2",
39
39
  "c8": "9.1.0",
40
40
  "eslint": "8.57.0",
41
- "react": "18.2.0",
41
+ "react": "18.3.1",
42
42
  "ts-node": "10.9.2",
43
43
  "typescript": "5.3.2"
44
44
  },