reactronic 0.21.523 → 0.21.527
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 +15 -1
- package/build/dist/source/Options.d.ts +3 -1
- package/build/dist/source/Reactronic.d.ts +1 -1
- package/build/dist/source/Reactronic.js +1 -1
- package/build/dist/source/Trace.d.ts +1 -1
- package/build/dist/source/Trace.js +1 -1
- package/build/dist/source/impl/Data.d.ts +2 -0
- package/build/dist/source/impl/Data.js +1 -0
- package/build/dist/source/impl/Hooks.d.ts +4 -3
- package/build/dist/source/impl/Hooks.js +10 -9
- package/build/dist/source/impl/Monitor.js +2 -2
- package/build/dist/source/impl/Operation.d.ts +3 -1
- package/build/dist/source/impl/Operation.js +51 -38
- package/build/dist/source/impl/Snapshot.d.ts +2 -2
- package/build/dist/source/impl/Snapshot.js +14 -11
- package/build/dist/source/impl/Transaction.d.ts +2 -2
- package/build/dist/source/impl/Transaction.js +21 -19
- package/build/dist/source/impl/TransactionJournal.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -300,6 +300,7 @@ function unobservable(proto, prop) // field only
|
|
|
300
300
|
function transaction(proto, prop, pd) // method only
|
|
301
301
|
function reaction(proto, prop, pd) // method only
|
|
302
302
|
function cached(proto, prop, pd) // method only
|
|
303
|
+
function options(value: Partial<MemberOptions>): F<any>
|
|
303
304
|
|
|
304
305
|
function noSideEffects(value: boolean) // transaction & cached & reaction
|
|
305
306
|
function sensitiveArgs(value: boolean) // cached & reaction
|
|
@@ -324,6 +325,19 @@ interface Options {
|
|
|
324
325
|
readonly trace?: Partial<TraceOptions>
|
|
325
326
|
}
|
|
326
327
|
|
|
328
|
+
export interface MemberOptions {
|
|
329
|
+
readonly kind: Kind
|
|
330
|
+
readonly standalone: StandaloneMode
|
|
331
|
+
readonly order: number
|
|
332
|
+
readonly noSideEffects: boolean
|
|
333
|
+
readonly sensitiveArgs: boolean
|
|
334
|
+
readonly throttling: number // milliseconds, -1 is immediately, Number.MAX_SAFE_INTEGER is never
|
|
335
|
+
readonly reentrance: Reentrance
|
|
336
|
+
readonly journal: TransactionJournal | undefined
|
|
337
|
+
readonly monitor: Monitor | null
|
|
338
|
+
readonly trace?: Partial<TraceOptions>
|
|
339
|
+
}
|
|
340
|
+
|
|
327
341
|
enum Kind {
|
|
328
342
|
Plain = 0,
|
|
329
343
|
Transaction = 1,
|
|
@@ -430,7 +444,7 @@ abstract class Controller<T> {
|
|
|
430
444
|
class Reactronic {
|
|
431
445
|
static why(short: boolean = false): string
|
|
432
446
|
static getMethodCache<T>(method: F<T>): Cache<T>
|
|
433
|
-
static
|
|
447
|
+
static configureCurrentOperation(options: Partial<Options>): Options
|
|
434
448
|
// static configureObject<T extends object>(obj: T, options: Partial<ObjectOptions>): void
|
|
435
449
|
// static assign<T, P extends keyof T>(obj: T, prop: P, value: T[P], sensitivity: Sensitivity)
|
|
436
450
|
static takeSnapshot<T>(obj: T): T
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { TraceOptions } from './Trace';
|
|
2
|
+
import { StandaloneMode } from './impl/Data';
|
|
2
3
|
export { TraceOptions, ProfilingOptions, TraceLevel } from './Trace';
|
|
3
4
|
import { TransactionJournal } from './impl/TransactionJournal';
|
|
4
5
|
import { Monitor } from './impl/Monitor';
|
|
5
6
|
export interface SnapshotOptions {
|
|
6
7
|
readonly hint?: string;
|
|
7
|
-
readonly standalone?:
|
|
8
|
+
readonly standalone?: StandaloneMode;
|
|
8
9
|
readonly journal?: TransactionJournal;
|
|
9
10
|
readonly trace?: Partial<TraceOptions>;
|
|
10
11
|
readonly token?: any;
|
|
11
12
|
}
|
|
12
13
|
export interface MemberOptions {
|
|
13
14
|
readonly kind: Kind;
|
|
15
|
+
readonly standalone: StandaloneMode;
|
|
14
16
|
readonly order: number;
|
|
15
17
|
readonly noSideEffects: boolean;
|
|
16
18
|
readonly sensitiveArgs: boolean;
|
|
@@ -5,7 +5,7 @@ export declare class Reactronic {
|
|
|
5
5
|
static why(brief?: boolean): string;
|
|
6
6
|
static getController<T>(method: F<T>): Controller<T>;
|
|
7
7
|
static pullLastResult<T>(method: F<Promise<T>>, args?: any[]): T | undefined;
|
|
8
|
-
static
|
|
8
|
+
static configureCurrentOperation(options: Partial<MemberOptions>): MemberOptions;
|
|
9
9
|
static takeSnapshot<T>(obj: T): T;
|
|
10
10
|
static dispose(obj: any): void;
|
|
11
11
|
static get reactionsAutoStartDisabled(): boolean;
|
|
@@ -12,7 +12,7 @@ class Reactronic {
|
|
|
12
12
|
static why(brief = false) { return brief ? Operation_1.OperationController.briefWhy() : Operation_1.OperationController.why(); }
|
|
13
13
|
static getController(method) { return Operation_1.OperationController.of(method); }
|
|
14
14
|
static pullLastResult(method, args) { return Reactronic.getController(method).pullLastResult(args); }
|
|
15
|
-
static
|
|
15
|
+
static configureCurrentOperation(options) { return Operation_1.OperationController.configureImpl(undefined, options); }
|
|
16
16
|
static takeSnapshot(obj) { return Snapshot_1.Snapshot.takeSnapshot(obj); }
|
|
17
17
|
static dispose(obj) { Snapshot_1.Snapshot.dispose(obj); }
|
|
18
18
|
static get reactionsAutoStartDisabled() { return Hooks_1.Hooks.reactionsAutoStartDisabled; }
|
|
@@ -23,7 +23,7 @@ export interface ProfilingOptions {
|
|
|
23
23
|
garbageCollectionSummaryInterval: number;
|
|
24
24
|
}
|
|
25
25
|
export declare const TraceLevel: {
|
|
26
|
-
|
|
26
|
+
ErrorsOnly: TraceOptions;
|
|
27
27
|
Transactions: TraceOptions;
|
|
28
28
|
Operations: TraceOptions;
|
|
29
29
|
Debug: TraceOptions;
|
|
@@ -9,8 +9,10 @@ export declare class Observable {
|
|
|
9
9
|
value: any;
|
|
10
10
|
observers?: Set<Observer>;
|
|
11
11
|
get isOperation(): boolean;
|
|
12
|
+
get selfSnapshotId(): number | undefined;
|
|
12
13
|
constructor(value: any);
|
|
13
14
|
}
|
|
15
|
+
export declare type StandaloneMode = boolean | 'isolated';
|
|
14
16
|
export interface Observer {
|
|
15
17
|
readonly order: number;
|
|
16
18
|
readonly observables: Map<Observable, MemberInfo> | undefined;
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "Meta", { enumerable: true, get: function () { re
|
|
|
8
8
|
class Observable {
|
|
9
9
|
constructor(value) { this.value = value; }
|
|
10
10
|
get isOperation() { return false; }
|
|
11
|
+
get selfSnapshotId() { return 0; }
|
|
11
12
|
}
|
|
12
13
|
exports.Observable = Observable;
|
|
13
14
|
class ObjectRevision {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { F } from '../util/Utils';
|
|
2
2
|
import { MemberOptions, Kind, Reentrance } from '../Options';
|
|
3
3
|
import { TraceOptions, ProfilingOptions } from '../Trace';
|
|
4
|
-
import { MemberName, ObjectHolder } from './Data';
|
|
4
|
+
import { MemberName, ObjectHolder, StandaloneMode } from './Data';
|
|
5
5
|
import { TransactionJournal } from './TransactionJournal';
|
|
6
6
|
import { Monitor } from './Monitor';
|
|
7
7
|
export declare abstract class ObservableObject {
|
|
@@ -12,6 +12,7 @@ export declare class OptionsImpl implements MemberOptions {
|
|
|
12
12
|
readonly getter: Function;
|
|
13
13
|
readonly setter: Function;
|
|
14
14
|
readonly kind: Kind;
|
|
15
|
+
readonly standalone: StandaloneMode;
|
|
15
16
|
readonly order: number;
|
|
16
17
|
readonly noSideEffects: boolean;
|
|
17
18
|
readonly sensitiveArgs: boolean;
|
|
@@ -37,10 +38,10 @@ export declare class Hooks implements ProxyHandler<ObjectHolder> {
|
|
|
37
38
|
getOwnPropertyDescriptor(h: ObjectHolder, m: MemberName): PropertyDescriptor | undefined;
|
|
38
39
|
ownKeys(h: ObjectHolder): Array<string | symbol>;
|
|
39
40
|
static decorateData(observable: boolean, proto: any, m: MemberName): any;
|
|
40
|
-
static decorateOperation(implicit: boolean, decorator: Function, options: Partial<MemberOptions>, proto: any, member: MemberName, pd: PropertyDescriptor): any;
|
|
41
|
+
static decorateOperation(implicit: boolean, decorator: Function, options: Partial<MemberOptions>, proto: any, member: MemberName, pd: PropertyDescriptor | undefined): any;
|
|
41
42
|
static decorateOperationParametrized(decorator: Function, options: Partial<MemberOptions>): F<any>;
|
|
42
43
|
static acquireObjectHolder(obj: any): ObjectHolder;
|
|
43
|
-
static createObjectHolder(unobservable: any, blank: any, hint: string): ObjectHolder;
|
|
44
|
+
static createObjectHolder(proto: any, unobservable: any, blank: any, hint: string): ObjectHolder;
|
|
44
45
|
static setProfilingMode(enabled: boolean, options?: Partial<ProfilingOptions>): void;
|
|
45
46
|
static sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
46
47
|
static setHint<T>(obj: T, hint: string | undefined): T;
|
|
@@ -10,12 +10,7 @@ class ObservableObject {
|
|
|
10
10
|
constructor() {
|
|
11
11
|
const proto = new.target.prototype;
|
|
12
12
|
const initial = Data_1.Meta.getFrom(proto, Data_1.Meta.Initial);
|
|
13
|
-
const h = Hooks.createObjectHolder(this, initial, new.target.name);
|
|
14
|
-
if (!Hooks.reactionsAutoStartDisabled) {
|
|
15
|
-
const reactions = Data_1.Meta.getFrom(proto, Data_1.Meta.Reactions);
|
|
16
|
-
for (const member in reactions)
|
|
17
|
-
h.proxy[member][Data_1.Meta.Controller].markObsolete();
|
|
18
|
-
}
|
|
13
|
+
const h = Hooks.createObjectHolder(proto, this, initial, new.target.name);
|
|
19
14
|
return h.proxy;
|
|
20
15
|
}
|
|
21
16
|
[Symbol.toStringTag]() {
|
|
@@ -26,6 +21,7 @@ class ObservableObject {
|
|
|
26
21
|
exports.ObservableObject = ObservableObject;
|
|
27
22
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
28
23
|
kind: Options_1.Kind.Plain,
|
|
24
|
+
standalone: false,
|
|
29
25
|
order: 0,
|
|
30
26
|
noSideEffects: false,
|
|
31
27
|
sensitiveArgs: false,
|
|
@@ -40,6 +36,7 @@ class OptionsImpl {
|
|
|
40
36
|
this.getter = getter !== undefined ? getter : existing.getter;
|
|
41
37
|
this.setter = setter !== undefined ? setter : existing.setter;
|
|
42
38
|
this.kind = merge(DEFAULT_OPTIONS.kind, existing.kind, patch.kind, implicit);
|
|
39
|
+
this.standalone = merge(DEFAULT_OPTIONS.standalone, existing.standalone, patch.standalone, implicit);
|
|
43
40
|
this.order = merge(DEFAULT_OPTIONS.order, existing.order, patch.order, implicit);
|
|
44
41
|
this.noSideEffects = merge(DEFAULT_OPTIONS.noSideEffects, existing.noSideEffects, patch.noSideEffects, implicit);
|
|
45
42
|
this.sensitiveArgs = merge(DEFAULT_OPTIONS.sensitiveArgs, existing.sensitiveArgs, patch.sensitiveArgs, implicit);
|
|
@@ -81,13 +78,14 @@ class Hooks {
|
|
|
81
78
|
let curr = r.data[m];
|
|
82
79
|
if (curr !== undefined || (r.prev.revision.snapshot === Snapshot_1.ROOT_REV.snapshot && (m in h.unobservable) === false)) {
|
|
83
80
|
if (curr === undefined || curr.value !== value || Hooks.sensitivity) {
|
|
81
|
+
const old = curr === null || curr === void 0 ? void 0 : curr.value;
|
|
84
82
|
if (r.prev.revision.data[m] === curr) {
|
|
85
83
|
curr = r.data[m] = new Data_1.Observable(value);
|
|
86
|
-
Snapshot_1.Snapshot.markEdited(value, true, r, m, h);
|
|
84
|
+
Snapshot_1.Snapshot.markEdited(old, value, true, r, m, h);
|
|
87
85
|
}
|
|
88
86
|
else {
|
|
89
87
|
curr.value = value;
|
|
90
|
-
Snapshot_1.Snapshot.markEdited(value, true, r, m, h);
|
|
88
|
+
Snapshot_1.Snapshot.markEdited(old, value, true, r, m, h);
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
}
|
|
@@ -184,10 +182,13 @@ class Hooks {
|
|
|
184
182
|
}
|
|
185
183
|
return h;
|
|
186
184
|
}
|
|
187
|
-
static createObjectHolder(unobservable, blank, hint) {
|
|
185
|
+
static createObjectHolder(proto, unobservable, blank, hint) {
|
|
188
186
|
const ctx = Snapshot_1.Snapshot.edit();
|
|
189
187
|
const h = new Data_1.ObjectHolder(unobservable, undefined, Hooks.proxy, Snapshot_1.ROOT_REV, hint);
|
|
190
188
|
ctx.getEditableRevision(h, Data_1.Meta.Holder, blank);
|
|
189
|
+
if (!Hooks.reactionsAutoStartDisabled)
|
|
190
|
+
for (const m in Data_1.Meta.getFrom(proto, Data_1.Meta.Reactions))
|
|
191
|
+
h.proxy[m][Data_1.Meta.Controller].markObsolete();
|
|
191
192
|
return h;
|
|
192
193
|
}
|
|
193
194
|
static setProfilingMode(enabled, options) {
|
|
@@ -53,7 +53,7 @@ class MonitorImpl extends Monitor {
|
|
|
53
53
|
static activate(mon, delay) {
|
|
54
54
|
if (delay >= 0) {
|
|
55
55
|
if (mon.internals.activationTimeout === undefined)
|
|
56
|
-
mon.internals.activationTimeout = setTimeout(() => Transaction_1.Transaction.runAs({ hint: 'Monitor.activate', standalone:
|
|
56
|
+
mon.internals.activationTimeout = setTimeout(() => Transaction_1.Transaction.runAs({ hint: 'Monitor.activate', standalone: 'isolated' }, MonitorImpl.activate, mon, -1), delay);
|
|
57
57
|
}
|
|
58
58
|
else if (mon.counter > 0)
|
|
59
59
|
mon.isActive = true;
|
|
@@ -61,7 +61,7 @@ class MonitorImpl extends Monitor {
|
|
|
61
61
|
static deactivate(mon, delay) {
|
|
62
62
|
if (delay >= 0) {
|
|
63
63
|
clearTimeout(mon.internals.deactivationTimeout);
|
|
64
|
-
mon.internals.deactivationTimeout = setTimeout(() => Transaction_1.Transaction.runAs({ hint: 'Monitor.deactivate', standalone:
|
|
64
|
+
mon.internals.deactivationTimeout = setTimeout(() => Transaction_1.Transaction.runAs({ hint: 'Monitor.deactivate', standalone: 'isolated' }, MonitorImpl.deactivate, mon, -1), delay);
|
|
65
65
|
}
|
|
66
66
|
else if (mon.counter <= 0) {
|
|
67
67
|
mon.isActive = false;
|
|
@@ -51,8 +51,10 @@ declare class Operation extends Observable implements Observer {
|
|
|
51
51
|
successor: Operation | undefined;
|
|
52
52
|
constructor(controller: OperationController, revision: ObjectRevision, prev: Operation | OptionsImpl);
|
|
53
53
|
get isOperation(): boolean;
|
|
54
|
+
get selfSnapshotId(): number;
|
|
54
55
|
hint(): string;
|
|
55
56
|
get order(): number;
|
|
57
|
+
get ['#this'](): string;
|
|
56
58
|
why(): string;
|
|
57
59
|
briefWhy(): string;
|
|
58
60
|
dependencies(): string[];
|
|
@@ -77,7 +79,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
77
79
|
private static propagateMemberChangeThroughSubscriptions;
|
|
78
80
|
private unsubscribeFromAllObservables;
|
|
79
81
|
private subscribeTo;
|
|
80
|
-
private static
|
|
82
|
+
private static canSubscribe;
|
|
81
83
|
private static createControllerAndGetHook;
|
|
82
84
|
private static rememberOperationOptions;
|
|
83
85
|
static init(): void;
|
|
@@ -39,7 +39,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
39
39
|
&& (!weak || op.cause === ROOT_TRIGGER || !op.successor ||
|
|
40
40
|
op.successor.transaction.isFinished)) {
|
|
41
41
|
const outerOpts = (_a = Operation.current) === null || _a === void 0 ? void 0 : _a.options;
|
|
42
|
-
const standalone = weak || opts.kind === Options_1.Kind.Reaction ||
|
|
42
|
+
const standalone = weak || opts.standalone || opts.kind === Options_1.Kind.Reaction ||
|
|
43
43
|
(opts.kind === Options_1.Kind.Transaction && outerOpts && (outerOpts.noSideEffects || outerOpts.kind === Options_1.Kind.Cache)) ||
|
|
44
44
|
(opts.kind === Options_1.Kind.Cache && (oc.revision.snapshot.sealed ||
|
|
45
45
|
oc.revision.prev.revision !== Snapshot_1.ROOT_REV));
|
|
@@ -72,7 +72,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
72
72
|
throw (0, Dbg_1.misuse)('a method is expected with reactronic decorator');
|
|
73
73
|
op.options = new Hooks_1.OptionsImpl(op.options.getter, op.options.setter, op.options, options, false);
|
|
74
74
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
|
|
75
|
-
Dbg_1.Dbg.log('║', ' ✎', `${op.hint()}.options
|
|
75
|
+
Dbg_1.Dbg.log('║', ' ✎', `${op.hint()}.options are changed`);
|
|
76
76
|
return op.options;
|
|
77
77
|
}
|
|
78
78
|
static runWithin(op, func, ...args) {
|
|
@@ -107,7 +107,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
107
107
|
peek(args) {
|
|
108
108
|
const ctx = Snapshot_1.Snapshot.current();
|
|
109
109
|
const r = ctx.seekRevision(this.ownHolder, this.memberName);
|
|
110
|
-
const op = this.peekFromRevision(r);
|
|
110
|
+
const op = this.peekFromRevision(r, args);
|
|
111
111
|
const isValid = op.options.kind !== Options_1.Kind.Transaction && op.cause !== ROOT_TRIGGER &&
|
|
112
112
|
(ctx === op.revision.snapshot || ctx.timestamp < op.obsoleteSince) &&
|
|
113
113
|
(!op.options.sensitiveArgs || args === undefined ||
|
|
@@ -125,16 +125,17 @@ class OperationController extends Controller_1.Controller {
|
|
|
125
125
|
const m = this.memberName;
|
|
126
126
|
const ctx = Snapshot_1.Snapshot.edit();
|
|
127
127
|
const r = ctx.getEditableRevision(h, m, Data_1.Meta.Holder, this);
|
|
128
|
-
let op = this.peekFromRevision(r);
|
|
128
|
+
let op = this.peekFromRevision(r, undefined);
|
|
129
129
|
if (op.revision !== r) {
|
|
130
130
|
const op2 = new Operation(this, r, op);
|
|
131
|
-
|
|
131
|
+
r.data[m] = op2.reenterOver(op);
|
|
132
132
|
ctx.bumpBy(r.prev.revision.snapshot.timestamp);
|
|
133
|
-
Snapshot_1.Snapshot.markEdited(op, true, r, m, h);
|
|
133
|
+
Snapshot_1.Snapshot.markEdited(op, op2, true, r, m, h);
|
|
134
|
+
op = op2;
|
|
134
135
|
}
|
|
135
136
|
return { operation: op, isUpToDate: true, snapshot: ctx, revision: r };
|
|
136
137
|
}
|
|
137
|
-
peekFromRevision(r) {
|
|
138
|
+
peekFromRevision(r, args) {
|
|
138
139
|
const m = this.memberName;
|
|
139
140
|
let op = r.data[m];
|
|
140
141
|
if (op.controller !== this) {
|
|
@@ -146,9 +147,13 @@ class OperationController extends Controller_1.Controller {
|
|
|
146
147
|
let op2 = r2.data[m];
|
|
147
148
|
if (op2.controller !== this) {
|
|
148
149
|
r2 = Snapshot_1.Snapshot.edit().getEditableRevision(h, m, Data_1.Meta.Holder, this);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
const t = new Operation(this, r2, op2);
|
|
151
|
+
if (args)
|
|
152
|
+
t.args = args;
|
|
153
|
+
t.cause = ROOT_TRIGGER;
|
|
154
|
+
r2.data[m] = t;
|
|
155
|
+
Snapshot_1.Snapshot.markEdited(op2, t, true, r2, m, h);
|
|
156
|
+
op2 = t;
|
|
152
157
|
}
|
|
153
158
|
return op2;
|
|
154
159
|
});
|
|
@@ -162,7 +167,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
162
167
|
const result = Transaction_1.Transaction.runAs(opts, (argsx) => {
|
|
163
168
|
if (!oc.operation.transaction.isCanceled) {
|
|
164
169
|
oc = this.edit();
|
|
165
|
-
if (Dbg_1.Dbg.isOn &&
|
|
170
|
+
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.operation)
|
|
166
171
|
Dbg_1.Dbg.log('║', ' 𝑓', `${oc.operation.why()}`);
|
|
167
172
|
oc.operation.run(this.ownHolder.proxy, argsx);
|
|
168
173
|
}
|
|
@@ -170,7 +175,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
170
175
|
oc = this.peek(argsx);
|
|
171
176
|
if (oc.operation.options.kind === Options_1.Kind.Transaction || !oc.isUpToDate) {
|
|
172
177
|
oc = this.edit();
|
|
173
|
-
if (Dbg_1.Dbg.isOn &&
|
|
178
|
+
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.operation)
|
|
174
179
|
Dbg_1.Dbg.log('║', ' 𝑓', `${oc.operation.why()}`);
|
|
175
180
|
oc.operation.run(this.ownHolder.proxy, argsx);
|
|
176
181
|
}
|
|
@@ -211,8 +216,12 @@ class Operation extends Data_1.Observable {
|
|
|
211
216
|
this.successor = undefined;
|
|
212
217
|
}
|
|
213
218
|
get isOperation() { return true; }
|
|
219
|
+
get selfSnapshotId() { return this.revision.snapshot.id; }
|
|
214
220
|
hint() { return `${Snapshot_1.Dump.rev(this.revision, this.controller.memberName)}`; }
|
|
215
221
|
get order() { return this.options.order; }
|
|
222
|
+
get ['#this']() {
|
|
223
|
+
return `Operation: ${this.why()}`;
|
|
224
|
+
}
|
|
216
225
|
why() {
|
|
217
226
|
let ms = Date.now();
|
|
218
227
|
const prev = this.revision.prev.revision.data[this.controller.memberName];
|
|
@@ -224,7 +233,7 @@ class Operation extends Data_1.Observable {
|
|
|
224
233
|
else if (this.controller.options.kind === Options_1.Kind.Transaction)
|
|
225
234
|
trigger = ' << operation';
|
|
226
235
|
else
|
|
227
|
-
trigger = ` <<
|
|
236
|
+
trigger = ` << T${this.revision.snapshot.id}[${this.revision.snapshot.hint}]`;
|
|
228
237
|
return `${this.hint()}${trigger} (${ms !== Infinity ? `${ms}ms since previous run` : 'initial run'})`;
|
|
229
238
|
}
|
|
230
239
|
briefWhy() {
|
|
@@ -369,18 +378,18 @@ class Operation extends Data_1.Observable {
|
|
|
369
378
|
if (this.result instanceof Promise) {
|
|
370
379
|
this.result = this.result.then(value => {
|
|
371
380
|
this.value = value;
|
|
372
|
-
this.leave(false, '
|
|
381
|
+
this.leave(false, ' ⚐', '- finished ', ' OK ──┘');
|
|
373
382
|
return value;
|
|
374
383
|
}, error => {
|
|
375
384
|
this.error = error;
|
|
376
|
-
this.leave(false, '
|
|
385
|
+
this.leave(false, ' ⚐', '- finished ', 'ERR ──┘');
|
|
377
386
|
throw error;
|
|
378
387
|
});
|
|
379
388
|
if (Dbg_1.Dbg.isOn) {
|
|
380
389
|
if (Dbg_1.Dbg.trace.operation)
|
|
381
390
|
Dbg_1.Dbg.log('║', '_/', `${this.hint()} - leave... `, 0, 'ASYNC ──┐');
|
|
382
391
|
else if (Dbg_1.Dbg.trace.transaction)
|
|
383
|
-
Dbg_1.Dbg.log('║', ' ', `${this.
|
|
392
|
+
Dbg_1.Dbg.log('║', ' ', `${this.why()} ...`, 0, 'ASYNC');
|
|
384
393
|
}
|
|
385
394
|
}
|
|
386
395
|
else {
|
|
@@ -401,8 +410,8 @@ class Operation extends Data_1.Observable {
|
|
|
401
410
|
monitorEnter(mon) {
|
|
402
411
|
const options = {
|
|
403
412
|
hint: 'Monitor.enter',
|
|
404
|
-
standalone:
|
|
405
|
-
trace: Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.monitor ? undefined : Dbg_1.Dbg.global
|
|
413
|
+
standalone: 'isolated',
|
|
414
|
+
trace: Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.monitor ? undefined : Dbg_1.Dbg.global
|
|
406
415
|
};
|
|
407
416
|
OperationController.runWithin(undefined, Transaction_1.Transaction.runAs, options, Monitor_1.MonitorImpl.enter, mon, this.transaction);
|
|
408
417
|
}
|
|
@@ -411,8 +420,8 @@ class Operation extends Data_1.Observable {
|
|
|
411
420
|
const leave = () => {
|
|
412
421
|
const options = {
|
|
413
422
|
hint: 'Monitor.leave',
|
|
414
|
-
standalone:
|
|
415
|
-
trace: Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.monitor ? undefined : Dbg_1.Dbg.DefaultLevel
|
|
423
|
+
standalone: 'isolated',
|
|
424
|
+
trace: Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.monitor ? undefined : Dbg_1.Dbg.DefaultLevel
|
|
416
425
|
};
|
|
417
426
|
OperationController.runWithin(undefined, Transaction_1.Transaction.runAs, options, Monitor_1.MonitorImpl.leave, mon, this.transaction);
|
|
418
427
|
};
|
|
@@ -443,10 +452,10 @@ class Operation extends Data_1.Observable {
|
|
|
443
452
|
}
|
|
444
453
|
}
|
|
445
454
|
}
|
|
446
|
-
static markEdited(
|
|
455
|
+
static markEdited(oldValue, newValue, edited, r, m, h) {
|
|
447
456
|
edited ? r.changes.set(m, Operation.current) : r.changes.delete(m);
|
|
448
457
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
|
|
449
|
-
edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev(r, m)}
|
|
458
|
+
edited ? Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev(r, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`) : Dbg_1.Dbg.log('║', ' ✎', `${Snapshot_1.Dump.rev(r, m)} is changed from ${valueHint(oldValue, m)} to ${valueHint(newValue, m)}`, undefined, ' (same as previous)');
|
|
450
459
|
}
|
|
451
460
|
static isConflicting(oldValue, newValue) {
|
|
452
461
|
let result = oldValue !== newValue;
|
|
@@ -518,29 +527,33 @@ class Operation extends Data_1.Observable {
|
|
|
518
527
|
this.observables = undefined;
|
|
519
528
|
}
|
|
520
529
|
subscribeTo(observable, r, m, h, timestamp) {
|
|
521
|
-
var _a, _b;
|
|
522
|
-
const
|
|
523
|
-
if (
|
|
530
|
+
var _a, _b, _c;
|
|
531
|
+
const ok = Operation.canSubscribe(observable, r, m, h, timestamp);
|
|
532
|
+
if (ok) {
|
|
524
533
|
let times = 0;
|
|
525
534
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
526
535
|
const existing = this.observables.get(observable);
|
|
527
536
|
times = existing ? existing.usageCount + 1 : 1;
|
|
528
537
|
}
|
|
529
|
-
if (
|
|
530
|
-
observable.observers
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
Dbg_1.Dbg.
|
|
538
|
+
if (this.observables !== undefined) {
|
|
539
|
+
if (!observable.observers)
|
|
540
|
+
observable.observers = new Set();
|
|
541
|
+
const info = { revision: r, memberName: m, usageCount: times };
|
|
542
|
+
observable.observers.add(this);
|
|
543
|
+
this.observables.set(observable, info);
|
|
544
|
+
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_a = this.options.trace) === null || _a === void 0 ? void 0 : _a.read)))
|
|
545
|
+
Dbg_1.Dbg.log('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev(r, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
|
|
546
|
+
}
|
|
547
|
+
else if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_b = this.options.trace) === null || _b === void 0 ? void 0 : _b.read)))
|
|
548
|
+
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Snapshot_1.Dump.rev(r, m)}`);
|
|
536
549
|
}
|
|
537
550
|
else {
|
|
538
|
-
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((
|
|
551
|
+
if (Dbg_1.Dbg.isOn && (Dbg_1.Dbg.trace.read || ((_c = this.options.trace) === null || _c === void 0 ? void 0 : _c.read)))
|
|
539
552
|
Dbg_1.Dbg.log('║', ' x ', `${this.hint()} is NOT subscribed to already obsolete ${Snapshot_1.Dump.rev(r, m)}`);
|
|
540
553
|
}
|
|
541
|
-
return
|
|
554
|
+
return ok;
|
|
542
555
|
}
|
|
543
|
-
static
|
|
556
|
+
static canSubscribe(observable, r, m, h, timestamp) {
|
|
544
557
|
let result = !r.snapshot.sealed || observable === h.head.data[m];
|
|
545
558
|
if (result && timestamp !== -1)
|
|
546
559
|
result = !(observable instanceof Operation && timestamp >= observable.obsoleteSince);
|
|
@@ -618,7 +631,7 @@ function propagationHint(cause, full) {
|
|
|
618
631
|
full && result.push(cause.revision.snapshot.hint);
|
|
619
632
|
return result;
|
|
620
633
|
}
|
|
621
|
-
function valueHint(value) {
|
|
634
|
+
function valueHint(value, m) {
|
|
622
635
|
let result = '';
|
|
623
636
|
if (Array.isArray(value))
|
|
624
637
|
result = `Array(${value.length})`;
|
|
@@ -627,13 +640,13 @@ function valueHint(value) {
|
|
|
627
640
|
else if (value instanceof Map)
|
|
628
641
|
result = `Map(${value.size})`;
|
|
629
642
|
else if (value instanceof Operation)
|
|
630
|
-
result =
|
|
643
|
+
result = `${Snapshot_1.Dump.rev(value.revision, m)}`;
|
|
631
644
|
else if (value === Data_1.Meta.Disposed)
|
|
632
645
|
result = '<disposed>';
|
|
633
646
|
else if (value !== undefined && value !== null)
|
|
634
647
|
result = value.toString().slice(0, 20);
|
|
635
648
|
else
|
|
636
|
-
result = '
|
|
649
|
+
result = '∅';
|
|
637
650
|
return result;
|
|
638
651
|
}
|
|
639
652
|
function getMergedTraceOptions(local) {
|
|
@@ -24,7 +24,7 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
24
24
|
static current: () => Snapshot;
|
|
25
25
|
static edit: () => Snapshot;
|
|
26
26
|
static markUsed: (observable: Observable, r: ObjectRevision, m: MemberName, h: ObjectHolder, kind: Kind, weak: boolean) => void;
|
|
27
|
-
static markEdited: (
|
|
27
|
+
static markEdited: (oldValue: any, newValue: any, edited: boolean, r: ObjectRevision, m: MemberName, h: ObjectHolder) => void;
|
|
28
28
|
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
29
|
static propagateAllChangesThroughSubscriptions: (snapshot: Snapshot) => void;
|
|
30
30
|
static revokeAllSubscriptions: (snapshot: Snapshot) => void;
|
|
@@ -49,7 +49,7 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
49
49
|
static _init(): void;
|
|
50
50
|
}
|
|
51
51
|
export declare class Dump {
|
|
52
|
-
static obj(h: ObjectHolder | undefined, m?: MemberName | undefined, stamp?: number, op?: number, typeless?: boolean): string;
|
|
52
|
+
static obj(h: ObjectHolder | undefined, m?: MemberName | undefined, stamp?: number, op?: number, xop?: number, typeless?: boolean): string;
|
|
53
53
|
static rev(r: ObjectRevision, m?: MemberName): string;
|
|
54
54
|
static conflicts(conflicts: ObjectRevision[]): string;
|
|
55
55
|
static conflictingMemberHint(m: MemberName, ours: ObjectRevision, theirs: ObjectRevision): string;
|
|
@@ -10,11 +10,11 @@ const SealedSet_1 = require("../util/SealedSet");
|
|
|
10
10
|
const Data_1 = require("./Data");
|
|
11
11
|
exports.MAX_TIMESTAMP = Number.MAX_SAFE_INTEGER;
|
|
12
12
|
exports.UNDEFINED_TIMESTAMP = exports.MAX_TIMESTAMP - 1;
|
|
13
|
-
Object.defineProperty(Data_1.ObjectHolder.prototype, '
|
|
13
|
+
Object.defineProperty(Data_1.ObjectHolder.prototype, '#this', {
|
|
14
14
|
configurable: false, enumerable: false,
|
|
15
15
|
get() {
|
|
16
16
|
const result = {};
|
|
17
|
-
const data = Snapshot.current().getCurrentRevision(this, '
|
|
17
|
+
const data = Snapshot.current().getCurrentRevision(this, '#this').data;
|
|
18
18
|
for (const m in data) {
|
|
19
19
|
const v = data[m];
|
|
20
20
|
if (v instanceof Data_1.Observable)
|
|
@@ -71,6 +71,8 @@ class Snapshot {
|
|
|
71
71
|
this.changeset.set(h, r);
|
|
72
72
|
h.editing = r;
|
|
73
73
|
h.editors++;
|
|
74
|
+
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.write)
|
|
75
|
+
Dbg_1.Dbg.log('║', ' ⎘', `${Dump.obj(h)} is cloned`);
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
else
|
|
@@ -78,7 +80,7 @@ class Snapshot {
|
|
|
78
80
|
return r;
|
|
79
81
|
}
|
|
80
82
|
static takeSnapshot(obj) {
|
|
81
|
-
return obj[Data_1.Meta.Holder]['
|
|
83
|
+
return obj[Data_1.Meta.Holder]['#this'];
|
|
82
84
|
}
|
|
83
85
|
static dispose(obj) {
|
|
84
86
|
const ctx = Snapshot.edit();
|
|
@@ -90,7 +92,7 @@ class Snapshot {
|
|
|
90
92
|
const r = ctx.getEditableRevision(h, Data_1.Meta.Disposed, Data_1.Meta.Disposed);
|
|
91
93
|
if (r !== exports.ROOT_REV) {
|
|
92
94
|
r.data[Data_1.Meta.Disposed] = Data_1.Meta.Disposed;
|
|
93
|
-
Snapshot.markEdited(Data_1.Meta.Disposed, true, r, Data_1.Meta.Disposed, h);
|
|
95
|
+
Snapshot.markEdited(Data_1.Meta.Disposed, Data_1.Meta.Disposed, true, r, Data_1.Meta.Disposed, h);
|
|
94
96
|
}
|
|
95
97
|
return r;
|
|
96
98
|
}
|
|
@@ -132,7 +134,7 @@ class Snapshot {
|
|
|
132
134
|
conflicts = [];
|
|
133
135
|
conflicts.push(r);
|
|
134
136
|
}
|
|
135
|
-
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.
|
|
137
|
+
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.transaction)
|
|
136
138
|
Dbg_1.Dbg.log('╠╝', '', `${Dump.rev(r)} is merged with ${Dump.rev(h.head)} among ${merged} properties with ${r.conflicts.size} conflicts.`);
|
|
137
139
|
}
|
|
138
140
|
});
|
|
@@ -193,7 +195,7 @@ class Snapshot {
|
|
|
193
195
|
}
|
|
194
196
|
});
|
|
195
197
|
if (Dbg_1.Dbg.isOn) {
|
|
196
|
-
if (Dbg_1.Dbg.trace.change) {
|
|
198
|
+
if (Dbg_1.Dbg.trace.change && !error) {
|
|
197
199
|
this.changeset.forEach((r, h) => {
|
|
198
200
|
const members = [];
|
|
199
201
|
r.changes.forEach((o, m) => members.push(m.toString()));
|
|
@@ -308,15 +310,16 @@ Snapshot.isConflicting = Utils_1.UNDEF;
|
|
|
308
310
|
Snapshot.propagateAllChangesThroughSubscriptions = (snapshot) => { };
|
|
309
311
|
Snapshot.revokeAllSubscriptions = (snapshot) => { };
|
|
310
312
|
class Dump {
|
|
311
|
-
static obj(h, m, stamp, op, typeless) {
|
|
313
|
+
static obj(h, m, stamp, op, xop, typeless) {
|
|
312
314
|
const member = m !== undefined ? `.${m.toString()}` : '';
|
|
313
315
|
return h === undefined
|
|
314
316
|
? `root${member}`
|
|
315
|
-
: stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}`;
|
|
317
|
+
: stamp === undefined ? `${h.hint}${member} #${h.id}` : `${h.hint}${member} #${h.id}t${op}v${stamp}${xop !== undefined && xop !== 0 ? `t${xop}` : ''}`;
|
|
316
318
|
}
|
|
317
319
|
static rev(r, m) {
|
|
318
320
|
const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
|
|
319
|
-
|
|
321
|
+
const value = m !== undefined ? r.data[m] : undefined;
|
|
322
|
+
return Dump.obj(h, m, r.snapshot.timestamp, r.snapshot.id, value === null || value === void 0 ? void 0 : value.selfSnapshotId);
|
|
320
323
|
}
|
|
321
324
|
static conflicts(conflicts) {
|
|
322
325
|
return conflicts.map(ours => {
|
|
@@ -328,11 +331,11 @@ class Dump {
|
|
|
328
331
|
}).join(', ');
|
|
329
332
|
}
|
|
330
333
|
static conflictingMemberHint(m, ours, theirs) {
|
|
331
|
-
return `${theirs.snapshot.hint}
|
|
334
|
+
return `${theirs.snapshot.hint} (${Dump.rev(theirs, m)})`;
|
|
332
335
|
}
|
|
333
336
|
}
|
|
334
337
|
exports.Dump = Dump;
|
|
335
|
-
exports.ROOT_REV = new Data_1.ObjectRevision(new Snapshot({ hint: 'root' }), undefined, {});
|
|
338
|
+
exports.ROOT_REV = new Data_1.ObjectRevision(new Snapshot({ hint: 'root-rev' }), undefined, {});
|
|
336
339
|
exports.DefaultSnapshotOptions = Object.freeze({
|
|
337
340
|
hint: 'noname',
|
|
338
341
|
standalone: false,
|
|
@@ -24,7 +24,7 @@ export declare abstract class Transaction implements Worker {
|
|
|
24
24
|
static run<T>(func: F<T>, ...args: any[]): T;
|
|
25
25
|
static runAs<T>(options: SnapshotOptions | null, func: F<T>, ...args: any[]): T;
|
|
26
26
|
static standalone<T>(func: F<T>, ...args: any[]): T;
|
|
27
|
-
static
|
|
28
|
-
static
|
|
27
|
+
static isFrameOver(everyN?: number, timeLimit?: number): boolean;
|
|
28
|
+
static requestNextFrame(sleepTime?: number): Promise<void>;
|
|
29
29
|
static get isCanceled(): boolean;
|
|
30
30
|
}
|
|
@@ -22,8 +22,8 @@ class Transaction {
|
|
|
22
22
|
static run(func, ...args) { return TransactionImpl.run(func, ...args); }
|
|
23
23
|
static runAs(options, func, ...args) { return TransactionImpl.runAs(options, func, ...args); }
|
|
24
24
|
static standalone(func, ...args) { return TransactionImpl.standalone(func, ...args); }
|
|
25
|
-
static
|
|
26
|
-
static
|
|
25
|
+
static isFrameOver(everyN = 1, timeLimit = 14) { return TransactionImpl.isFrameOver(everyN, timeLimit); }
|
|
26
|
+
static requestNextFrame(sleepTime = 0) { return TransactionImpl.requestNextFrame(sleepTime); }
|
|
27
27
|
static get isCanceled() { return TransactionImpl.current.isCanceled; }
|
|
28
28
|
}
|
|
29
29
|
exports.Transaction = Transaction;
|
|
@@ -124,10 +124,11 @@ class TransactionImpl extends Transaction {
|
|
|
124
124
|
t.guard();
|
|
125
125
|
let result = t.runImpl(options === null || options === void 0 ? void 0 : options.trace, func, ...args);
|
|
126
126
|
if (root) {
|
|
127
|
-
if (result instanceof Promise)
|
|
127
|
+
if (result instanceof Promise) {
|
|
128
128
|
result = TransactionImpl.standalone(() => {
|
|
129
129
|
return t.wrapToRetry(t.wrapToWaitUntilFinish(result), func, ...args);
|
|
130
130
|
});
|
|
131
|
+
}
|
|
131
132
|
t.seal();
|
|
132
133
|
}
|
|
133
134
|
return result;
|
|
@@ -142,22 +143,24 @@ class TransactionImpl extends Transaction {
|
|
|
142
143
|
TransactionImpl.curr = outer;
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
|
-
static
|
|
146
|
-
TransactionImpl.
|
|
147
|
-
let result = TransactionImpl.
|
|
146
|
+
static isFrameOver(everyN = 1, timeLimit = 14) {
|
|
147
|
+
TransactionImpl.frameOverCounter++;
|
|
148
|
+
let result = TransactionImpl.frameOverCounter % everyN === 0;
|
|
148
149
|
if (result) {
|
|
149
|
-
const ms = performance.now() - TransactionImpl.
|
|
150
|
-
result = ms >
|
|
150
|
+
const ms = performance.now() - TransactionImpl.frameStartTime;
|
|
151
|
+
result = ms > timeLimit;
|
|
151
152
|
}
|
|
152
153
|
return result;
|
|
153
154
|
}
|
|
154
|
-
static
|
|
155
|
+
static requestNextFrame(sleepTime = 0) {
|
|
155
156
|
return (0, Utils_1.pause)(sleepTime);
|
|
156
157
|
}
|
|
157
158
|
static acquire(options) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
const curr = TransactionImpl.curr;
|
|
160
|
+
if ((options === null || options === void 0 ? void 0 : options.standalone) || curr.isFinished || curr.options.standalone === 'isolated')
|
|
161
|
+
return new TransactionImpl(options);
|
|
162
|
+
else
|
|
163
|
+
return TransactionImpl.curr;
|
|
161
164
|
}
|
|
162
165
|
guard() {
|
|
163
166
|
if (this.sealed && TransactionImpl.curr !== this)
|
|
@@ -177,7 +180,7 @@ class TransactionImpl extends Transaction {
|
|
|
177
180
|
yield this.after.whenFinished();
|
|
178
181
|
const options = {
|
|
179
182
|
hint: `${this.hint} - restart after T${this.after.id}`,
|
|
180
|
-
standalone: true,
|
|
183
|
+
standalone: this.options.standalone === 'isolated' ? 'isolated' : true,
|
|
181
184
|
trace: this.snapshot.options.trace,
|
|
182
185
|
token: this.snapshot.options.token,
|
|
183
186
|
};
|
|
@@ -203,8 +206,8 @@ class TransactionImpl extends Transaction {
|
|
|
203
206
|
const outer = TransactionImpl.curr;
|
|
204
207
|
try {
|
|
205
208
|
if (outer === TransactionImpl.none) {
|
|
206
|
-
TransactionImpl.
|
|
207
|
-
TransactionImpl.
|
|
209
|
+
TransactionImpl.frameStartTime = performance.now();
|
|
210
|
+
TransactionImpl.frameOverCounter = 0;
|
|
208
211
|
}
|
|
209
212
|
TransactionImpl.curr = this;
|
|
210
213
|
this.pending++;
|
|
@@ -261,7 +264,7 @@ class TransactionImpl extends Transaction {
|
|
|
261
264
|
applyOrDiscard() {
|
|
262
265
|
try {
|
|
263
266
|
if (Dbg_1.Dbg.isOn && Dbg_1.Dbg.trace.change)
|
|
264
|
-
Dbg_1.Dbg.log('
|
|
267
|
+
Dbg_1.Dbg.log('╠═', '', '', undefined, 'changes');
|
|
265
268
|
this.snapshot.applyOrDiscard(this.canceled);
|
|
266
269
|
this.snapshot.collectGarbage();
|
|
267
270
|
if (this.promise) {
|
|
@@ -306,7 +309,6 @@ class TransactionImpl extends Transaction {
|
|
|
306
309
|
TransactionImpl.none = new TransactionImpl({ hint: '<none>' });
|
|
307
310
|
TransactionImpl.curr = TransactionImpl.none;
|
|
308
311
|
TransactionImpl.inspection = false;
|
|
309
|
-
TransactionImpl.
|
|
310
|
-
TransactionImpl.
|
|
311
|
-
TransactionImpl.checkCount = 0;
|
|
312
|
+
TransactionImpl.frameStartTime = 0;
|
|
313
|
+
TransactionImpl.frameOverCounter = 0;
|
|
312
314
|
TransactionImpl._init();
|
|
@@ -24,7 +24,7 @@ class TransactionJournalImpl extends TransactionJournal {
|
|
|
24
24
|
get canUndo() { return this._items.length > 0 && this._position > 0; }
|
|
25
25
|
get canRedo() { return this._position < this._items.length; }
|
|
26
26
|
remember(p) {
|
|
27
|
-
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.remember', standalone:
|
|
27
|
+
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.remember', standalone: 'isolated' }, () => {
|
|
28
28
|
const items = this._items = this._items.toMutable();
|
|
29
29
|
if (items.length >= this._capacity)
|
|
30
30
|
items.shift();
|
|
@@ -35,7 +35,7 @@ class TransactionJournalImpl extends TransactionJournal {
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
undo(count = 1) {
|
|
38
|
-
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.undo', standalone:
|
|
38
|
+
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.undo', standalone: 'isolated' }, () => {
|
|
39
39
|
let i = this._position - 1;
|
|
40
40
|
while (i >= 0 && count > 0) {
|
|
41
41
|
const patch = this._items[i];
|
|
@@ -46,7 +46,7 @@ class TransactionJournalImpl extends TransactionJournal {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
redo(count = 1) {
|
|
49
|
-
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.redo', standalone:
|
|
49
|
+
Transaction_1.Transaction.runAs({ hint: 'TransactionJournal.redo', standalone: 'isolated' }, () => {
|
|
50
50
|
let i = this._position;
|
|
51
51
|
while (i < this._items.length && count > 0) {
|
|
52
52
|
const patch = this._items[i];
|
|
@@ -61,7 +61,7 @@ class TransactionJournalImpl extends TransactionJournal {
|
|
|
61
61
|
changeset.forEach((r, h) => {
|
|
62
62
|
const p = { current: {}, former: {} };
|
|
63
63
|
const old = r.prev.revision !== Snapshot_1.ROOT_REV ? r.prev.revision.data : undefined;
|
|
64
|
-
r.changes.forEach((
|
|
64
|
+
r.changes.forEach((episode, m) => {
|
|
65
65
|
p.current[m] = unseal(r.data[m]);
|
|
66
66
|
if (old)
|
|
67
67
|
p.former[m] = unseal(old[m]);
|
|
@@ -79,14 +79,14 @@ class TransactionJournalImpl extends TransactionJournal {
|
|
|
79
79
|
patch.objects.forEach((p, obj) => {
|
|
80
80
|
const h = Data_1.Meta.get(obj, Data_1.Meta.Holder);
|
|
81
81
|
const data = undo ? p.former : p.current;
|
|
82
|
-
if (data[Data_1.Meta.Disposed]
|
|
82
|
+
if (data[Data_1.Meta.Disposed] === undefined) {
|
|
83
83
|
for (const m in data) {
|
|
84
84
|
const value = data[m];
|
|
85
85
|
const r = ctx.getEditableRevision(h, m, value);
|
|
86
86
|
if (r.snapshot === ctx) {
|
|
87
87
|
r.data[m] = new Data_1.Observable(value);
|
|
88
88
|
const v = r.prev.revision.data[m];
|
|
89
|
-
Snapshot_1.Snapshot.markEdited(value, v !== value, r, m, h);
|
|
89
|
+
Snapshot_1.Snapshot.markEdited(v, value, v !== value, r, m, h);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|