reactronic 0.24.274 → 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.
- package/README.md +2 -2
- package/build/dist/source/Options.d.ts +10 -4
- package/build/dist/source/Options.js +8 -0
- package/build/dist/source/RxSystem.d.ts +2 -2
- package/build/dist/source/RxSystem.js +21 -10
- package/build/dist/source/api.d.ts +3 -3
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/Changeset.d.ts +23 -21
- package/build/dist/source/core/Changeset.js +145 -143
- package/build/dist/source/core/Data.d.ts +17 -18
- package/build/dist/source/core/Data.js +8 -7
- package/build/dist/source/core/Indicator.js +9 -8
- package/build/dist/source/core/Journal.d.ts +2 -2
- package/build/dist/source/core/Journal.js +36 -35
- package/build/dist/source/core/Mvcc.d.ts +12 -12
- package/build/dist/source/core/Mvcc.js +47 -62
- package/build/dist/source/core/{Reaction.d.ts → Operation.d.ts} +21 -19
- package/build/dist/source/core/{Reaction.js → Operation.js} +181 -152
- package/build/dist/source/core/RxNode.d.ts +17 -15
- package/build/dist/source/core/RxNode.js +37 -37
- package/build/dist/source/core/Transaction.d.ts +61 -2
- package/build/dist/source/core/Transaction.js +175 -16
- package/package.json +3 -3
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { LoggingOptions } from "../Logging.js";
|
|
2
2
|
import { MergeListReader, MergedItem } from "../util/MergeList.js";
|
|
3
3
|
import { MemberOptions } from "../Options.js";
|
|
4
|
-
export type
|
|
5
|
-
export type
|
|
4
|
+
export type Script<T> = (el: T, basis: () => void) => void;
|
|
5
|
+
export type ScriptAsync<T> = (el: T, basis: () => Promise<void>) => Promise<void>;
|
|
6
|
+
export type Handler<T = unknown, R = void> = (el: T) => R;
|
|
6
7
|
export declare enum Mode {
|
|
7
8
|
default = 0,
|
|
8
9
|
independentUpdate = 1,
|
|
@@ -35,7 +36,7 @@ export declare abstract class RxNode<E = unknown> {
|
|
|
35
36
|
static readonly longFrameDuration = 300;
|
|
36
37
|
static currentUpdatePriority: Priority;
|
|
37
38
|
static frameDuration: number;
|
|
38
|
-
static declare<E = void>(driver: RxNodeDriver<E>, declaration?: RxNodeDecl<E>,
|
|
39
|
+
static declare<E = void>(driver: RxNodeDriver<E>, declaration?: RxNodeDecl<E>, basis?: RxNodeDecl<E>): RxNode<E>;
|
|
39
40
|
static get isFirstUpdate(): boolean;
|
|
40
41
|
static get key(): string;
|
|
41
42
|
static get stamp(): number;
|
|
@@ -48,31 +49,32 @@ export declare abstract class RxNode<E = unknown> {
|
|
|
48
49
|
static triggerDeactivation(node: RxNode<any>): void;
|
|
49
50
|
static updateNestedNodesThenDo(action: (error: unknown) => void): void;
|
|
50
51
|
static markAsMounted(node: RxNode<any>, yes: boolean): void;
|
|
51
|
-
static findMatchingHost<E = unknown, R = unknown>(node: RxNode<E>, match:
|
|
52
|
-
static findMatchingPrevSibling<E = unknown, R = unknown>(node: RxNode<E>, match:
|
|
53
|
-
static forEachChildRecursively<E = unknown>(node: RxNode<E>, action:
|
|
52
|
+
static findMatchingHost<E = unknown, R = unknown>(node: RxNode<E>, match: Handler<RxNode<E>, boolean>): RxNode<R> | undefined;
|
|
53
|
+
static findMatchingPrevSibling<E = unknown, R = unknown>(node: RxNode<E>, match: Handler<RxNode<E>, boolean>): RxNode<R> | undefined;
|
|
54
|
+
static forEachChildRecursively<E = unknown>(node: RxNode<E>, action: Handler<RxNode<E>>): void;
|
|
54
55
|
static getDefaultLoggingOptions(): LoggingOptions | undefined;
|
|
55
56
|
static setDefaultLoggingOptions(logging?: LoggingOptions): void;
|
|
56
57
|
}
|
|
57
58
|
export type RxNodeDecl<E = unknown> = {
|
|
58
|
-
script?:
|
|
59
|
+
script?: Script<E>;
|
|
60
|
+
scriptAsync?: ScriptAsync<E>;
|
|
59
61
|
key?: string;
|
|
60
62
|
mode?: Mode;
|
|
61
|
-
creation?:
|
|
62
|
-
destruction?:
|
|
63
|
+
creation?: Script<E>;
|
|
64
|
+
destruction?: Script<E>;
|
|
63
65
|
triggers?: unknown;
|
|
64
|
-
|
|
66
|
+
basis?: RxNodeDecl<E>;
|
|
65
67
|
};
|
|
66
68
|
export type RxNodeDriver<E = unknown> = {
|
|
67
69
|
readonly name: string;
|
|
68
70
|
readonly isPartition: boolean;
|
|
69
|
-
readonly
|
|
71
|
+
readonly initialize?: Handler<E>;
|
|
70
72
|
allocate(node: RxNode<E>): E;
|
|
71
73
|
create(node: RxNode<E>): void;
|
|
72
74
|
destroy(node: RxNode<E>, isLeader: boolean): boolean;
|
|
73
75
|
mount(node: RxNode<E>): void;
|
|
74
76
|
update(node: RxNode<E>): void | Promise<void>;
|
|
75
|
-
child(ownerNode: RxNode<E>, childDriver: RxNodeDriver<any>, childDeclaration?: RxNodeDecl<any>,
|
|
77
|
+
child(ownerNode: RxNode<E>, childDriver: RxNodeDriver<any>, childDeclaration?: RxNodeDecl<any>, childBasis?: RxNodeDecl<any>): MergedItem<RxNode> | undefined;
|
|
76
78
|
getHost(node: RxNode<E>): RxNode<E>;
|
|
77
79
|
};
|
|
78
80
|
export type RxNodeContext<T extends Object = Object> = {
|
|
@@ -81,14 +83,14 @@ export type RxNodeContext<T extends Object = Object> = {
|
|
|
81
83
|
export declare abstract class BaseDriver<E = unknown> implements RxNodeDriver<E> {
|
|
82
84
|
readonly name: string;
|
|
83
85
|
readonly isPartition: boolean;
|
|
84
|
-
readonly
|
|
85
|
-
constructor(name: string, isPartition: boolean,
|
|
86
|
+
readonly initialize?: Handler<E, void> | undefined;
|
|
87
|
+
constructor(name: string, isPartition: boolean, initialize?: Handler<E, void> | undefined);
|
|
86
88
|
abstract allocate(node: RxNode<E>): E;
|
|
87
89
|
create(node: RxNode<E>): void;
|
|
88
90
|
destroy(node: RxNode<E>, isLeader: boolean): boolean;
|
|
89
91
|
mount(node: RxNode<E>): void;
|
|
90
92
|
update(node: RxNode<E>): void | Promise<void>;
|
|
91
|
-
child(ownerNode: RxNode<E>, childDriver: RxNodeDriver<any>, childDeclaration?: RxNodeDecl<any>,
|
|
93
|
+
child(ownerNode: RxNode<E>, childDriver: RxNodeDriver<any>, childDeclaration?: RxNodeDecl<any>, childBasis?: RxNodeDecl<any>): MergedItem<RxNode> | undefined;
|
|
92
94
|
getHost(node: RxNode<E>): RxNode<E>;
|
|
93
95
|
}
|
|
94
96
|
export declare class RxNodeVariable<T extends Object = Object> {
|
|
@@ -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";
|
|
@@ -35,16 +35,16 @@ export var Priority;
|
|
|
35
35
|
Priority[Priority["background"] = 2] = "background";
|
|
36
36
|
})(Priority || (Priority = {}));
|
|
37
37
|
export class RxNode {
|
|
38
|
-
static declare(driver, declaration,
|
|
38
|
+
static declare(driver, declaration, basis) {
|
|
39
39
|
let result;
|
|
40
40
|
if (declaration)
|
|
41
|
-
declaration.
|
|
41
|
+
declaration.basis = basis;
|
|
42
42
|
else
|
|
43
|
-
declaration =
|
|
43
|
+
declaration = basis !== null && basis !== void 0 ? basis : {};
|
|
44
44
|
let key = declaration.key;
|
|
45
45
|
const owner = gOwnSeat === null || gOwnSeat === void 0 ? void 0 : gOwnSeat.instance;
|
|
46
46
|
if (owner) {
|
|
47
|
-
let existing = owner.driver.child(owner, driver, declaration,
|
|
47
|
+
let existing = owner.driver.child(owner, driver, declaration, basis);
|
|
48
48
|
const children = owner.children;
|
|
49
49
|
existing !== null && existing !== void 0 ? existing : (existing = children.tryMergeAsExisting(key = key || generateKey(owner), undefined, "nested elements can be declared inside update function only"));
|
|
50
50
|
if (existing) {
|
|
@@ -144,26 +144,26 @@ RxNode.longFrameDuration = 300;
|
|
|
144
144
|
RxNode.currentUpdatePriority = Priority.realtime;
|
|
145
145
|
RxNode.frameDuration = RxNode.longFrameDuration;
|
|
146
146
|
export class BaseDriver {
|
|
147
|
-
constructor(name, isPartition,
|
|
147
|
+
constructor(name, isPartition, initialize) {
|
|
148
148
|
this.name = name;
|
|
149
149
|
this.isPartition = isPartition;
|
|
150
|
-
this.
|
|
150
|
+
this.initialize = initialize;
|
|
151
151
|
}
|
|
152
152
|
create(node) {
|
|
153
153
|
var _a;
|
|
154
|
-
(_a = this.
|
|
155
|
-
|
|
154
|
+
(_a = this.initialize) === null || _a === void 0 ? void 0 : _a.call(this, node.element);
|
|
155
|
+
invokeCreationUsingBasisChain(node.element, node.declaration);
|
|
156
156
|
}
|
|
157
157
|
destroy(node, isLeader) {
|
|
158
|
-
|
|
158
|
+
invokeDestructionUsingBasisChain(node.element, node.declaration);
|
|
159
159
|
return isLeader;
|
|
160
160
|
}
|
|
161
161
|
mount(node) {
|
|
162
162
|
}
|
|
163
163
|
update(node) {
|
|
164
|
-
|
|
164
|
+
invokeScriptUsingBasisChain(node.element, node.declaration);
|
|
165
165
|
}
|
|
166
|
-
child(ownerNode, childDriver, childDeclaration,
|
|
166
|
+
child(ownerNode, childDriver, childDeclaration, childBasis) {
|
|
167
167
|
return undefined;
|
|
168
168
|
}
|
|
169
169
|
getHost(node) {
|
|
@@ -194,33 +194,33 @@ function generateKey(owner) {
|
|
|
194
194
|
result = `·${lettered}`;
|
|
195
195
|
return result;
|
|
196
196
|
}
|
|
197
|
-
function
|
|
197
|
+
function getModeUsingBasisChain(declaration) {
|
|
198
198
|
var _a;
|
|
199
|
-
return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.
|
|
199
|
+
return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.basis) ? getModeUsingBasisChain(declaration === null || declaration === void 0 ? void 0 : declaration.basis) : Mode.default);
|
|
200
200
|
}
|
|
201
|
-
function
|
|
202
|
-
const
|
|
203
|
-
const creation = declaration.creation;
|
|
204
|
-
if (creation)
|
|
205
|
-
creation(element, preset ? () => invokeOnCreateViaPresetChain(element, preset) : NOP);
|
|
206
|
-
else if (preset)
|
|
207
|
-
invokeOnCreateViaPresetChain(element, preset);
|
|
208
|
-
}
|
|
209
|
-
function invokeScriptViaPresetChain(element, declaration) {
|
|
210
|
-
const preset = declaration.preset;
|
|
201
|
+
function invokeScriptUsingBasisChain(element, declaration) {
|
|
202
|
+
const basis = declaration.basis;
|
|
211
203
|
const script = declaration.script;
|
|
212
204
|
if (script)
|
|
213
|
-
script(element,
|
|
214
|
-
else if (
|
|
215
|
-
|
|
205
|
+
script(element, basis ? () => invokeScriptUsingBasisChain(element, basis) : NOP);
|
|
206
|
+
else if (basis)
|
|
207
|
+
invokeScriptUsingBasisChain(element, basis);
|
|
208
|
+
}
|
|
209
|
+
function invokeCreationUsingBasisChain(element, declaration) {
|
|
210
|
+
const basis = declaration.basis;
|
|
211
|
+
const creation = declaration.creation;
|
|
212
|
+
if (creation)
|
|
213
|
+
creation(element, basis ? () => invokeCreationUsingBasisChain(element, basis) : NOP);
|
|
214
|
+
else if (basis)
|
|
215
|
+
invokeCreationUsingBasisChain(element, basis);
|
|
216
216
|
}
|
|
217
|
-
function
|
|
218
|
-
const
|
|
217
|
+
function invokeDestructionUsingBasisChain(element, declaration) {
|
|
218
|
+
const basis = declaration.basis;
|
|
219
219
|
const destruction = declaration.destruction;
|
|
220
220
|
if (destruction)
|
|
221
|
-
destruction(element,
|
|
222
|
-
else if (
|
|
223
|
-
|
|
221
|
+
destruction(element, basis ? () => invokeDestructionUsingBasisChain(element, basis) : NOP);
|
|
222
|
+
else if (basis)
|
|
223
|
+
invokeDestructionUsingBasisChain(element, basis);
|
|
224
224
|
}
|
|
225
225
|
class RxNodeContextImpl extends ObservableObject {
|
|
226
226
|
constructor(variable, value) {
|
|
@@ -273,7 +273,7 @@ class RxNodeImpl extends RxNode {
|
|
|
273
273
|
set strictOrder(value) { this.children.isStrict = value; }
|
|
274
274
|
get isMoved() { return this.owner.children.isMoved(this.seat); }
|
|
275
275
|
has(mode) {
|
|
276
|
-
return (
|
|
276
|
+
return (getModeUsingBasisChain(this.declaration) & mode) === mode;
|
|
277
277
|
}
|
|
278
278
|
update(_triggers) {
|
|
279
279
|
updateNow(this.seat);
|
|
@@ -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.
|
|
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({
|
|
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.
|
|
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({
|
|
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
|
|
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 {
|
|
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
|
|
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.
|
|
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
|
|
130
|
-
return TransactionImpl.run({
|
|
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
|
-
|
|
156
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
267
|
+
let observers;
|
|
259
268
|
try {
|
|
260
269
|
if (Log.isOn && Log.opt.change)
|
|
261
270
|
Log.write("╠═", "", "", undefined, "changes");
|
|
262
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
41
|
+
"react": "18.3.1",
|
|
42
42
|
"ts-node": "10.9.2",
|
|
43
43
|
"typescript": "5.3.2"
|
|
44
44
|
},
|