reactronic 0.22.205 → 0.22.300
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 +24 -24
- package/build/dist/source/Buffer.d.ts +2 -2
- package/build/dist/source/Buffer.js +1 -1
- package/build/dist/source/Options.d.ts +3 -3
- package/build/dist/source/Ref.d.ts +1 -1
- package/build/dist/source/Ref.js +2 -2
- package/build/dist/source/Rx.d.ts +2 -2
- package/build/dist/source/Rx.js +6 -6
- package/build/dist/source/api.d.ts +3 -3
- package/build/dist/source/api.js +6 -6
- package/build/dist/source/impl/Data.d.ts +22 -27
- package/build/dist/source/impl/Data.js +14 -14
- package/build/dist/source/impl/Hooks.d.ts +15 -15
- package/build/dist/source/impl/Hooks.js +35 -35
- package/build/dist/source/impl/Journal.d.ts +34 -0
- package/build/dist/source/impl/Journal.js +138 -0
- package/build/dist/source/impl/Meta.d.ts +1 -1
- package/build/dist/source/impl/Meta.js +1 -1
- package/build/dist/source/impl/Monitor.d.ts +2 -2
- package/build/dist/source/impl/Monitor.js +1 -1
- package/build/dist/source/impl/Operation.d.ts +10 -10
- package/build/dist/source/impl/Operation.js +62 -68
- package/build/dist/source/impl/Snapshot.d.ts +23 -23
- package/build/dist/source/impl/Snapshot.js +34 -34
- package/package.json +1 -1
- package/build/dist/source/impl/EditJournal.d.ts +0 -37
- package/build/dist/source/impl/EditJournal.js +0 -130
|
@@ -9,10 +9,10 @@ const Snapshot_1 = require("./Snapshot");
|
|
|
9
9
|
const Transaction_1 = require("./Transaction");
|
|
10
10
|
const Monitor_1 = require("./Monitor");
|
|
11
11
|
const Hooks_1 = require("./Hooks");
|
|
12
|
-
const
|
|
12
|
+
const Journal_1 = require("./Journal");
|
|
13
13
|
const BOOT_ARGS = [];
|
|
14
14
|
const BOOT_CAUSE = '<boot>';
|
|
15
|
-
const ROOT_HOLDER = new Data_1.
|
|
15
|
+
const ROOT_HOLDER = new Data_1.DataHolder(undefined, undefined, Hooks_1.Hooks.proxy, Snapshot_1.ROOT_REV, '<root>');
|
|
16
16
|
class OperationController extends Controller_1.Controller {
|
|
17
17
|
constructor(ownHolder, memberName) {
|
|
18
18
|
super();
|
|
@@ -21,14 +21,14 @@ class OperationController extends Controller_1.Controller {
|
|
|
21
21
|
}
|
|
22
22
|
configure(options) { return OperationController.configureImpl(this, options); }
|
|
23
23
|
get options() { return this.peek(undefined).operation.options; }
|
|
24
|
-
get
|
|
24
|
+
get nonsubscribing() { return this.peek(undefined).operation.content; }
|
|
25
25
|
get args() { return this.use().operation.args; }
|
|
26
|
-
get result() { return this.useOrRun(true, undefined).
|
|
26
|
+
get result() { return this.useOrRun(true, undefined).content; }
|
|
27
27
|
get error() { return this.use().operation.error; }
|
|
28
28
|
get stamp() { return this.use().revision.snapshot.timestamp; }
|
|
29
29
|
get isUpToDate() { return this.use().isUpToDate; }
|
|
30
30
|
markObsolete() { Transaction_1.Transaction.run({ hint: Dbg_1.Log.isOn ? `markObsolete(${Snapshot_1.Dump.obj(this.ownHolder, this.memberName)})` : 'markObsolete()' }, OperationController.markObsolete, this); }
|
|
31
|
-
pullLastResult(args) { return this.useOrRun(true, args).
|
|
31
|
+
pullLastResult(args) { return this.useOrRun(true, args).content; }
|
|
32
32
|
useOrRun(weak, args) {
|
|
33
33
|
var _a;
|
|
34
34
|
let oc = this.peek(args);
|
|
@@ -42,7 +42,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
42
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
|
-
oc.revision.
|
|
45
|
+
oc.revision.former.revision !== Snapshot_1.ROOT_REV));
|
|
46
46
|
const token = opts.noSideEffects ? this : undefined;
|
|
47
47
|
const oc2 = this.run(oc, standalone, opts, token, args);
|
|
48
48
|
const ctx2 = oc2.operation.snapshot;
|
|
@@ -129,7 +129,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
129
129
|
if (op.snapshot !== r.snapshot) {
|
|
130
130
|
const op2 = new Operation(this, r.snapshot, op);
|
|
131
131
|
r.data[m] = op2.reenterOver(op);
|
|
132
|
-
ctx.bumpBy(r.
|
|
132
|
+
ctx.bumpBy(r.former.revision.snapshot.timestamp);
|
|
133
133
|
Snapshot_1.Snapshot.markEdited(op, op2, true, r, m, h);
|
|
134
134
|
op = op2;
|
|
135
135
|
}
|
|
@@ -141,7 +141,7 @@ class OperationController extends Controller_1.Controller {
|
|
|
141
141
|
if (op.controller !== this) {
|
|
142
142
|
if (r.snapshot !== Snapshot_1.ROOT_REV.snapshot) {
|
|
143
143
|
const hint = Dbg_1.Log.isOn ? `${Snapshot_1.Dump.obj(this.ownHolder, m)}/boot` : 'MethodController/init';
|
|
144
|
-
const standalone = r.snapshot.sealed || r.
|
|
144
|
+
const standalone = r.snapshot.sealed || r.former.revision !== Snapshot_1.ROOT_REV;
|
|
145
145
|
op = Transaction_1.Transaction.run({ hint, standalone, token: this }, () => {
|
|
146
146
|
const h = this.ownHolder;
|
|
147
147
|
let r2 = Snapshot_1.Snapshot.current().getCurrentRevision(h, m);
|
|
@@ -204,21 +204,21 @@ class OperationController extends Controller_1.Controller {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
exports.OperationController = OperationController;
|
|
207
|
-
class Operation extends Data_1.
|
|
208
|
-
constructor(controller, snapshot,
|
|
207
|
+
class Operation extends Data_1.Subscription {
|
|
208
|
+
constructor(controller, snapshot, former) {
|
|
209
209
|
super(undefined);
|
|
210
210
|
this.margin = Operation.current ? Operation.current.margin + 1 : 1;
|
|
211
211
|
this.transaction = Transaction_1.Transaction.current;
|
|
212
212
|
this.controller = controller;
|
|
213
213
|
this.snapshot = snapshot;
|
|
214
|
-
this.
|
|
215
|
-
if (
|
|
216
|
-
this.options =
|
|
217
|
-
this.args =
|
|
218
|
-
this.cause =
|
|
214
|
+
this.subscriptions = new Map();
|
|
215
|
+
if (former instanceof Operation) {
|
|
216
|
+
this.options = former.options;
|
|
217
|
+
this.args = former.args;
|
|
218
|
+
this.cause = former.obsoleteDueTo;
|
|
219
219
|
}
|
|
220
220
|
else {
|
|
221
|
-
this.options =
|
|
221
|
+
this.options = former;
|
|
222
222
|
this.args = BOOT_ARGS;
|
|
223
223
|
this.cause = undefined;
|
|
224
224
|
}
|
|
@@ -274,14 +274,14 @@ class Operation extends Data_1.Observable {
|
|
|
274
274
|
else
|
|
275
275
|
this.result = Promise.reject(this.error);
|
|
276
276
|
}
|
|
277
|
-
markObsoleteDueTo(
|
|
277
|
+
markObsoleteDueTo(subscription, memberName, snapshot, holder, outer, since, reactions) {
|
|
278
278
|
var _a, _b, _c;
|
|
279
|
-
if (this.
|
|
280
|
-
const skip = !
|
|
279
|
+
if (this.subscriptions !== undefined) {
|
|
280
|
+
const skip = !subscription.isOperation &&
|
|
281
281
|
snapshot === this.snapshot;
|
|
282
282
|
if (!skip) {
|
|
283
|
-
const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName,
|
|
284
|
-
this.
|
|
283
|
+
const why = `${Snapshot_1.Dump.rev2(holder, snapshot, memberName, subscription)} << ${outer}`;
|
|
284
|
+
this.unsubscribeFromAllSubscriptions();
|
|
285
285
|
this.obsoleteDueTo = why;
|
|
286
286
|
this.obsoleteSince = since;
|
|
287
287
|
const isReaction = this.options.kind === Options_1.Kind.Reaction;
|
|
@@ -292,11 +292,11 @@ class Operation extends Data_1.Observable {
|
|
|
292
292
|
if (isReaction)
|
|
293
293
|
reactions.push(this);
|
|
294
294
|
else
|
|
295
|
-
(_b = this.
|
|
295
|
+
(_b = this.subscribers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.controller.memberName, this.snapshot, this.controller.ownHolder, why, since, reactions));
|
|
296
296
|
const tran = this.transaction;
|
|
297
297
|
if (tran.snapshot === snapshot) {
|
|
298
298
|
}
|
|
299
|
-
else if (!tran.isFinished && this !==
|
|
299
|
+
else if (!tran.isFinished && this !== subscription)
|
|
300
300
|
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Snapshot_1.Dump.rev2(holder, snapshot, memberName)} changed by T${snapshot.id}[${snapshot.hint}]`), null);
|
|
301
301
|
}
|
|
302
302
|
else if (Dbg_1.Log.isOn && (Dbg_1.Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
@@ -390,7 +390,7 @@ class Operation extends Data_1.Observable {
|
|
|
390
390
|
leaveOrAsync() {
|
|
391
391
|
if (this.result instanceof Promise) {
|
|
392
392
|
this.result = this.result.then(value => {
|
|
393
|
-
this.
|
|
393
|
+
this.content = value;
|
|
394
394
|
this.leave(false, ' ⚐', '- finished ', ' OK ──┘');
|
|
395
395
|
return value;
|
|
396
396
|
}, error => {
|
|
@@ -406,7 +406,7 @@ class Operation extends Data_1.Observable {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
else {
|
|
409
|
-
this.
|
|
409
|
+
this.content = this.result;
|
|
410
410
|
this.leave(true, '_/', '- leave');
|
|
411
411
|
}
|
|
412
412
|
}
|
|
@@ -453,7 +453,7 @@ class Operation extends Data_1.Observable {
|
|
|
453
453
|
for (const x of reactions)
|
|
454
454
|
x.runIfNotUpToDate(true, true);
|
|
455
455
|
}
|
|
456
|
-
static markUsed(
|
|
456
|
+
static markUsed(subscription, r, m, h, kind, weak) {
|
|
457
457
|
if (kind !== Options_1.Kind.Transaction) {
|
|
458
458
|
const op = Operation.current;
|
|
459
459
|
if (op && op.options.kind !== Options_1.Kind.Transaction &&
|
|
@@ -462,8 +462,8 @@ class Operation extends Data_1.Observable {
|
|
|
462
462
|
if (ctx !== r.snapshot)
|
|
463
463
|
ctx.bumpBy(r.snapshot.timestamp);
|
|
464
464
|
const t = weak ? -1 : ctx.timestamp;
|
|
465
|
-
if (!op.subscribeTo(
|
|
466
|
-
op.markObsoleteDueTo(
|
|
465
|
+
if (!op.subscribeTo(subscription, r, m, h, t))
|
|
466
|
+
op.markObsoleteDueTo(subscription, m, r.snapshot, h, BOOT_CAUSE, ctx.timestamp, ctx.reactions);
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
469
|
}
|
|
@@ -486,11 +486,11 @@ class Operation extends Data_1.Observable {
|
|
|
486
486
|
if (!r.changes.has(Data_1.Meta.Disposed))
|
|
487
487
|
r.changes.forEach((o, m) => Operation.propagateMemberChangeThroughSubscriptions(false, since, r, m, h, reactions));
|
|
488
488
|
else
|
|
489
|
-
for (const m in r.
|
|
489
|
+
for (const m in r.former.revision.data)
|
|
490
490
|
Operation.propagateMemberChangeThroughSubscriptions(true, since, r, m, h, reactions);
|
|
491
491
|
});
|
|
492
492
|
reactions.sort(compareReactionsByOrder);
|
|
493
|
-
(_a = snapshot.options.journal) === null || _a === void 0 ? void 0 : _a.
|
|
493
|
+
(_a = snapshot.options.journal) === null || _a === void 0 ? void 0 : _a.edited(Journal_1.JournalImpl.buildPatch(snapshot.hint, snapshot.changeset));
|
|
494
494
|
}
|
|
495
495
|
static revokeAllSubscriptions(snapshot) {
|
|
496
496
|
snapshot.changeset.forEach((r, h) => r.changes.forEach((o, m) => Operation.propagateMemberChangeThroughSubscriptions(true, snapshot.timestamp, r, m, h, undefined)));
|
|
@@ -499,45 +499,39 @@ class Operation extends Data_1.Observable {
|
|
|
499
499
|
var _a;
|
|
500
500
|
const curr = r.data[m];
|
|
501
501
|
if (reactions) {
|
|
502
|
-
const
|
|
503
|
-
if (
|
|
502
|
+
const former = r.former.revision.data[m];
|
|
503
|
+
if (former !== undefined && former instanceof Data_1.Subscription) {
|
|
504
504
|
const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
|
|
505
|
-
if (
|
|
506
|
-
if ((
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
505
|
+
if (former instanceof Operation) {
|
|
506
|
+
if ((former.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || former.obsoleteSince <= 0)) {
|
|
507
|
+
former.obsoleteDueTo = why;
|
|
508
|
+
former.obsoleteSince = timestamp;
|
|
509
|
+
former.unsubscribeFromAllSubscriptions();
|
|
510
510
|
}
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
513
|
-
if (
|
|
514
|
-
|
|
511
|
+
const formerSuccessor = former.successor;
|
|
512
|
+
if (formerSuccessor !== curr) {
|
|
513
|
+
if (formerSuccessor && !formerSuccessor.transaction.isFinished)
|
|
514
|
+
formerSuccessor.transaction.cancel(new Error(`T${formerSuccessor.transaction.id}[${formerSuccessor.transaction.hint}] is canceled by T${r.snapshot.id}[${r.snapshot.hint}] and will not run anymore`), null);
|
|
515
515
|
}
|
|
516
516
|
else
|
|
517
|
-
|
|
517
|
+
former.successor = undefined;
|
|
518
518
|
}
|
|
519
|
-
(_a =
|
|
519
|
+
(_a = former.subscribers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, m, r.snapshot, h, why, timestamp, reactions));
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
if (curr instanceof Operation) {
|
|
523
|
-
if (curr.snapshot === r.snapshot && curr.
|
|
523
|
+
if (curr.snapshot === r.snapshot && curr.subscriptions !== undefined) {
|
|
524
524
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
525
|
-
curr.
|
|
525
|
+
curr.subscriptions.forEach((info, v) => {
|
|
526
526
|
if (info.usageCount > Hooks_1.Hooks.repetitiveUsageWarningThreshold)
|
|
527
527
|
Dbg_1.Log.write('', '[!]', `${curr.hint()} uses ${info.memberHint} ${info.usageCount} times (consider remembering it in a local variable)`, 0, ' *** WARNING ***');
|
|
528
528
|
});
|
|
529
529
|
}
|
|
530
530
|
if (unsubscribe)
|
|
531
|
-
curr.
|
|
531
|
+
curr.unsubscribeFromAllSubscriptions();
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
|
-
else if (curr instanceof Data_1.
|
|
535
|
-
curr.observers.forEach(o => {
|
|
536
|
-
o.observables.delete(curr);
|
|
537
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.read)
|
|
538
|
-
Dbg_1.Log.write(Dbg_1.Log.opt.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${o.hint()} is unsubscribed from own-changed ${Snapshot_1.Dump.rev(r, m)}`);
|
|
539
|
-
});
|
|
540
|
-
curr.observers = undefined;
|
|
534
|
+
else if (curr instanceof Data_1.Subscription && curr.subscribers) {
|
|
541
535
|
}
|
|
542
536
|
}
|
|
543
537
|
static enqueueReactionsToRun(reactions) {
|
|
@@ -558,31 +552,31 @@ class Operation extends Data_1.Observable {
|
|
|
558
552
|
}
|
|
559
553
|
Operation.queuedReactions = [];
|
|
560
554
|
}
|
|
561
|
-
|
|
555
|
+
unsubscribeFromAllSubscriptions() {
|
|
562
556
|
var _a;
|
|
563
|
-
(_a = this.
|
|
557
|
+
(_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.forEach((info, value) => {
|
|
564
558
|
var _a;
|
|
565
|
-
value.
|
|
559
|
+
value.subscribers.delete(this);
|
|
566
560
|
if (Dbg_1.Log.isOn && (Dbg_1.Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
567
561
|
Dbg_1.Log.write(Dbg_1.Log.opt.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${info.memberHint}`);
|
|
568
562
|
});
|
|
569
|
-
this.
|
|
563
|
+
this.subscriptions = undefined;
|
|
570
564
|
}
|
|
571
|
-
subscribeTo(
|
|
565
|
+
subscribeTo(subscription, r, m, h, timestamp) {
|
|
572
566
|
var _a, _b, _c;
|
|
573
|
-
const ok = Operation.canSubscribe(
|
|
567
|
+
const ok = Operation.canSubscribe(subscription, r, m, h, timestamp);
|
|
574
568
|
if (ok) {
|
|
575
569
|
let times = 0;
|
|
576
570
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
577
|
-
const existing = this.
|
|
571
|
+
const existing = this.subscriptions.get(subscription);
|
|
578
572
|
times = existing ? existing.usageCount + 1 : 1;
|
|
579
573
|
}
|
|
580
|
-
if (this.
|
|
581
|
-
if (!
|
|
582
|
-
|
|
574
|
+
if (this.subscriptions !== undefined) {
|
|
575
|
+
if (!subscription.subscribers)
|
|
576
|
+
subscription.subscribers = new Set();
|
|
583
577
|
const info = { memberHint: Snapshot_1.Dump.rev2(h, r.snapshot, m), usageCount: times };
|
|
584
|
-
|
|
585
|
-
this.
|
|
578
|
+
subscription.subscribers.add(this);
|
|
579
|
+
this.subscriptions.set(subscription, info);
|
|
586
580
|
if (Dbg_1.Log.isOn && (Dbg_1.Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
587
581
|
Dbg_1.Log.write('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
|
|
588
582
|
}
|
|
@@ -595,10 +589,10 @@ class Operation extends Data_1.Observable {
|
|
|
595
589
|
}
|
|
596
590
|
return ok;
|
|
597
591
|
}
|
|
598
|
-
static canSubscribe(
|
|
599
|
-
let result = !r.snapshot.sealed ||
|
|
592
|
+
static canSubscribe(subscription, r, m, h, timestamp) {
|
|
593
|
+
let result = !r.snapshot.sealed || subscription === h.head.data[m];
|
|
600
594
|
if (result && timestamp !== -1)
|
|
601
|
-
result = !(
|
|
595
|
+
result = !(subscription instanceof Operation && timestamp >= subscription.obsoleteSince);
|
|
602
596
|
return result;
|
|
603
597
|
}
|
|
604
598
|
static createOperation(h, m, options) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Kind, SnapshotOptions } from '../Options';
|
|
2
|
-
import { AbstractSnapshot,
|
|
2
|
+
import { AbstractSnapshot, DataRevision, MemberName, DataHolder, Subscription, Subscriber } from './Data';
|
|
3
3
|
export declare const MAX_TIMESTAMP: number;
|
|
4
4
|
export declare const UNDEFINED_TIMESTAMP: number;
|
|
5
5
|
export declare class Snapshot implements AbstractSnapshot {
|
|
@@ -9,52 +9,52 @@ export declare class Snapshot implements AbstractSnapshot {
|
|
|
9
9
|
private static oldest;
|
|
10
10
|
static garbageCollectionSummaryInterval: number;
|
|
11
11
|
static lastGarbageCollectionSummaryTimestamp: number;
|
|
12
|
-
static
|
|
13
|
-
static
|
|
12
|
+
static totalHolderCount: number;
|
|
13
|
+
static totalRevisionCount: number;
|
|
14
14
|
readonly id: number;
|
|
15
15
|
readonly options: SnapshotOptions;
|
|
16
16
|
get hint(): string;
|
|
17
17
|
get timestamp(): number;
|
|
18
18
|
private stamp;
|
|
19
19
|
private bumper;
|
|
20
|
-
changeset: Map<
|
|
21
|
-
reactions:
|
|
20
|
+
changeset: Map<DataHolder, DataRevision>;
|
|
21
|
+
reactions: Subscriber[];
|
|
22
22
|
sealed: boolean;
|
|
23
23
|
constructor(options: SnapshotOptions | null);
|
|
24
24
|
static current: () => Snapshot;
|
|
25
25
|
static edit: () => Snapshot;
|
|
26
|
-
static markUsed: (
|
|
27
|
-
static markEdited: (oldValue: any, newValue: any, edited: boolean, r:
|
|
26
|
+
static markUsed: (subscription: Subscription, r: DataRevision, m: MemberName, h: DataHolder, kind: Kind, weak: boolean) => void;
|
|
27
|
+
static markEdited: (oldValue: any, newValue: any, edited: boolean, r: DataRevision, m: MemberName, h: DataHolder) => void;
|
|
28
28
|
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
29
|
static propagateAllChangesThroughSubscriptions: (snapshot: Snapshot) => void;
|
|
30
30
|
static revokeAllSubscriptions: (snapshot: Snapshot) => void;
|
|
31
|
-
static enqueueReactionsToRun: (reactions: Array<
|
|
32
|
-
seekRevision(h:
|
|
33
|
-
getCurrentRevision(h:
|
|
34
|
-
getEditableRevision(h:
|
|
31
|
+
static enqueueReactionsToRun: (reactions: Array<Subscriber>) => void;
|
|
32
|
+
seekRevision(h: DataHolder, m: MemberName): DataRevision;
|
|
33
|
+
getCurrentRevision(h: DataHolder, m: MemberName): DataRevision;
|
|
34
|
+
getEditableRevision(h: DataHolder, m: MemberName, value: any, token?: any): DataRevision;
|
|
35
35
|
static takeSnapshot<T>(obj: T): T;
|
|
36
36
|
static dispose(obj: any): void;
|
|
37
|
-
static doDispose(ctx: Snapshot, h:
|
|
37
|
+
static doDispose(ctx: Snapshot, h: DataHolder): DataRevision;
|
|
38
38
|
private isNewRevisionRequired;
|
|
39
39
|
acquire(outer: Snapshot): void;
|
|
40
40
|
bumpBy(timestamp: number): void;
|
|
41
|
-
rebase():
|
|
41
|
+
rebase(): DataRevision[] | undefined;
|
|
42
42
|
private merge;
|
|
43
|
-
applyOrDiscard(error?: any): Array<
|
|
44
|
-
static sealObjectRevision(h:
|
|
45
|
-
static
|
|
46
|
-
static freezeObjectRevision(r:
|
|
43
|
+
applyOrDiscard(error?: any): Array<Subscriber>;
|
|
44
|
+
static sealObjectRevision(h: DataHolder, r: DataRevision): void;
|
|
45
|
+
static sealSubscription(subscription: Subscription | symbol, m: MemberName, typeName: string): void;
|
|
46
|
+
static freezeObjectRevision(r: DataRevision): DataRevision;
|
|
47
47
|
triggerGarbageCollection(): void;
|
|
48
48
|
private unlinkHistory;
|
|
49
49
|
static _init(): void;
|
|
50
50
|
}
|
|
51
51
|
export declare class Dump {
|
|
52
52
|
static valueHint: (value: any, m?: PropertyKey | undefined) => string;
|
|
53
|
-
static obj(h:
|
|
54
|
-
static rev2(h:
|
|
55
|
-
static rev(r:
|
|
56
|
-
static conflicts(conflicts:
|
|
57
|
-
static conflictingMemberHint(m: MemberName, ours:
|
|
53
|
+
static obj(h: DataHolder | undefined, m?: MemberName | undefined, stamp?: number, snapshotId?: number, originSnapshotId?: number, value?: any): string;
|
|
54
|
+
static rev2(h: DataHolder, s: AbstractSnapshot, m?: MemberName, o?: Subscription): string;
|
|
55
|
+
static rev(r: DataRevision, m?: MemberName): string;
|
|
56
|
+
static conflicts(conflicts: DataRevision[]): string;
|
|
57
|
+
static conflictingMemberHint(m: MemberName, ours: DataRevision, theirs: DataRevision): string;
|
|
58
58
|
}
|
|
59
|
-
export declare const ROOT_REV:
|
|
59
|
+
export declare const ROOT_REV: DataRevision;
|
|
60
60
|
export declare const DefaultSnapshotOptions: SnapshotOptions;
|
|
@@ -10,17 +10,17 @@ 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.
|
|
13
|
+
Object.defineProperty(Data_1.DataHolder.prototype, '#this', {
|
|
14
14
|
configurable: false, enumerable: false,
|
|
15
15
|
get() {
|
|
16
16
|
const result = {};
|
|
17
17
|
const data = Snapshot.current().getCurrentRevision(this, '#this').data;
|
|
18
18
|
for (const m in data) {
|
|
19
19
|
const v = data[m];
|
|
20
|
-
if (v instanceof Data_1.
|
|
21
|
-
result[m] = v.
|
|
22
|
-
else if (v === Data_1.Meta.
|
|
23
|
-
result[m] = this.
|
|
20
|
+
if (v instanceof Data_1.Subscription)
|
|
21
|
+
result[m] = v.content;
|
|
22
|
+
else if (v === Data_1.Meta.Nonsubscribing)
|
|
23
|
+
result[m] = this.data[m];
|
|
24
24
|
else
|
|
25
25
|
result[m] = v;
|
|
26
26
|
}
|
|
@@ -51,7 +51,7 @@ class Snapshot {
|
|
|
51
51
|
if (!r) {
|
|
52
52
|
r = h.head;
|
|
53
53
|
while (r !== exports.ROOT_REV && r.snapshot.timestamp > this.timestamp)
|
|
54
|
-
r = r.
|
|
54
|
+
r = r.former.revision;
|
|
55
55
|
}
|
|
56
56
|
return r;
|
|
57
57
|
}
|
|
@@ -64,11 +64,11 @@ class Snapshot {
|
|
|
64
64
|
getEditableRevision(h, m, value, token) {
|
|
65
65
|
let r = this.seekRevision(h, m);
|
|
66
66
|
const existing = r.data[m];
|
|
67
|
-
if (existing !== Data_1.Meta.
|
|
67
|
+
if (existing !== Data_1.Meta.Nonsubscribing) {
|
|
68
68
|
if (this.isNewRevisionRequired(h, r, m, existing, value, token)) {
|
|
69
69
|
const data = Object.assign({}, m === Data_1.Meta.Holder ? value : r.data);
|
|
70
70
|
Reflect.set(data, Data_1.Meta.Holder, h);
|
|
71
|
-
r = new Data_1.
|
|
71
|
+
r = new Data_1.DataRevision(this, r, data);
|
|
72
72
|
this.changeset.set(h, r);
|
|
73
73
|
h.editing = r;
|
|
74
74
|
h.editors++;
|
|
@@ -99,9 +99,9 @@ class Snapshot {
|
|
|
99
99
|
}
|
|
100
100
|
isNewRevisionRequired(h, r, m, existing, value, token) {
|
|
101
101
|
if (this.sealed && r.snapshot !== exports.ROOT_REV.snapshot)
|
|
102
|
-
throw (0, Dbg_1.misuse)(`
|
|
102
|
+
throw (0, Dbg_1.misuse)(`subscribing property ${Dump.obj(h, m)} can only be modified inside transaction`);
|
|
103
103
|
if (m !== Data_1.Meta.Holder && value !== Data_1.Meta.Holder) {
|
|
104
|
-
if (r.snapshot !== this || r.
|
|
104
|
+
if (r.snapshot !== this || r.former.revision !== exports.ROOT_REV) {
|
|
105
105
|
if (this.options.token !== undefined && token !== this.options.token)
|
|
106
106
|
throw (0, Dbg_1.misuse)(`${this.hint} should not have side effects (trying to change ${Dump.rev(r, m)})`);
|
|
107
107
|
}
|
|
@@ -129,7 +129,7 @@ class Snapshot {
|
|
|
129
129
|
let conflicts = undefined;
|
|
130
130
|
if (this.changeset.size > 0) {
|
|
131
131
|
this.changeset.forEach((r, h) => {
|
|
132
|
-
if (r.
|
|
132
|
+
if (r.former.revision !== h.head) {
|
|
133
133
|
const merged = this.merge(h, r);
|
|
134
134
|
if (r.conflicts.size > 0) {
|
|
135
135
|
if (!conflicts)
|
|
@@ -172,7 +172,7 @@ class Snapshot {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
else {
|
|
175
|
-
const conflict = Snapshot.isConflicting(head.data[m], ours.
|
|
175
|
+
const conflict = Snapshot.isConflicting(head.data[m], ours.former.revision.data[m]);
|
|
176
176
|
if (conflict)
|
|
177
177
|
ours.conflicts.set(m, head);
|
|
178
178
|
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.change)
|
|
@@ -180,7 +180,7 @@ class Snapshot {
|
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
182
|
Utils_1.Utils.copyAllMembers(merged, ours.data);
|
|
183
|
-
ours.
|
|
183
|
+
ours.former.revision = head;
|
|
184
184
|
return counter;
|
|
185
185
|
}
|
|
186
186
|
applyOrDiscard(error) {
|
|
@@ -193,9 +193,9 @@ class Snapshot {
|
|
|
193
193
|
if (!error) {
|
|
194
194
|
h.head = r;
|
|
195
195
|
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
196
|
-
Snapshot.
|
|
197
|
-
if (r.
|
|
198
|
-
Snapshot.
|
|
196
|
+
Snapshot.totalRevisionCount++;
|
|
197
|
+
if (r.former.revision === exports.ROOT_REV)
|
|
198
|
+
Snapshot.totalHolderCount++;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
});
|
|
@@ -205,7 +205,7 @@ class Snapshot {
|
|
|
205
205
|
const members = [];
|
|
206
206
|
r.changes.forEach((o, m) => members.push(m.toString()));
|
|
207
207
|
const s = members.join(', ');
|
|
208
|
-
Dbg_1.Log.write('║', '√', `${Dump.rev2(h, r.snapshot)} (${s}) is ${r.
|
|
208
|
+
Dbg_1.Log.write('║', '√', `${Dump.rev2(h, r.snapshot)} (${s}) is ${r.former.revision === exports.ROOT_REV ? 'constructed' : `applied on top of ${Dump.rev2(h, r.former.revision.snapshot)}`}`);
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
if (Dbg_1.Log.opt.transaction)
|
|
@@ -217,20 +217,20 @@ class Snapshot {
|
|
|
217
217
|
}
|
|
218
218
|
static sealObjectRevision(h, r) {
|
|
219
219
|
if (!r.changes.has(Data_1.Meta.Disposed))
|
|
220
|
-
r.changes.forEach((o, m) => Snapshot.
|
|
220
|
+
r.changes.forEach((o, m) => Snapshot.sealSubscription(r.data[m], m, h.proxy.constructor.name));
|
|
221
221
|
else
|
|
222
|
-
for (const m in r.
|
|
222
|
+
for (const m in r.former.revision.data)
|
|
223
223
|
r.data[m] = Data_1.Meta.Disposed;
|
|
224
224
|
if (Dbg_1.Log.isOn)
|
|
225
225
|
Snapshot.freezeObjectRevision(r);
|
|
226
226
|
}
|
|
227
|
-
static
|
|
228
|
-
if (
|
|
229
|
-
const value =
|
|
227
|
+
static sealSubscription(subscription, m, typeName) {
|
|
228
|
+
if (subscription instanceof Data_1.Subscription) {
|
|
229
|
+
const value = subscription.content;
|
|
230
230
|
if (value !== undefined && value !== null) {
|
|
231
231
|
const sealedType = Object.getPrototypeOf(value)[Sealant_1.Sealant.SealedType];
|
|
232
232
|
if (sealedType)
|
|
233
|
-
|
|
233
|
+
subscription.content = Sealant_1.Sealant.seal(value, sealedType, typeName, m);
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
}
|
|
@@ -254,7 +254,7 @@ class Snapshot {
|
|
|
254
254
|
Snapshot.oldest = Snapshot.pending[0];
|
|
255
255
|
const now = Date.now();
|
|
256
256
|
if (now - Snapshot.lastGarbageCollectionSummaryTimestamp > Snapshot.garbageCollectionSummaryInterval) {
|
|
257
|
-
Dbg_1.Log.write('', '[G]', `Total object/revision count: ${Snapshot.
|
|
257
|
+
Dbg_1.Log.write('', '[G]', `Total object/revision count: ${Snapshot.totalHolderCount}/${Snapshot.totalRevisionCount}`);
|
|
258
258
|
Snapshot.lastGarbageCollectionSummaryTimestamp = now;
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -264,15 +264,15 @@ class Snapshot {
|
|
|
264
264
|
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.gc)
|
|
265
265
|
Dbg_1.Log.write('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
|
|
266
266
|
this.changeset.forEach((r, h) => {
|
|
267
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.gc && r.
|
|
268
|
-
Dbg_1.Log.write(' ', ' ', `${Dump.rev2(h, r.
|
|
267
|
+
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.gc && r.former.revision !== exports.ROOT_REV)
|
|
268
|
+
Dbg_1.Log.write(' ', ' ', `${Dump.rev2(h, r.former.revision.snapshot)} is ready for GC because overwritten by ${Dump.rev2(h, r.snapshot)}`);
|
|
269
269
|
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
270
|
-
if (r.
|
|
271
|
-
Snapshot.
|
|
270
|
+
if (r.former.revision !== exports.ROOT_REV)
|
|
271
|
+
Snapshot.totalRevisionCount--;
|
|
272
272
|
if (r.changes.has(Data_1.Meta.Disposed))
|
|
273
|
-
Snapshot.
|
|
273
|
+
Snapshot.totalHolderCount--;
|
|
274
274
|
}
|
|
275
|
-
r.
|
|
275
|
+
r.former.revision = exports.ROOT_REV;
|
|
276
276
|
});
|
|
277
277
|
this.changeset = EMPTY_MAP;
|
|
278
278
|
this.reactions = EMPTY_ARRAY;
|
|
@@ -300,8 +300,8 @@ Snapshot.pending = [];
|
|
|
300
300
|
Snapshot.oldest = undefined;
|
|
301
301
|
Snapshot.garbageCollectionSummaryInterval = Number.MAX_SAFE_INTEGER;
|
|
302
302
|
Snapshot.lastGarbageCollectionSummaryTimestamp = Date.now();
|
|
303
|
-
Snapshot.
|
|
304
|
-
Snapshot.
|
|
303
|
+
Snapshot.totalHolderCount = 0;
|
|
304
|
+
Snapshot.totalRevisionCount = 0;
|
|
305
305
|
Snapshot.current = Utils_1.UNDEF;
|
|
306
306
|
Snapshot.edit = Utils_1.UNDEF;
|
|
307
307
|
Snapshot.markUsed = Utils_1.UNDEF;
|
|
@@ -321,7 +321,7 @@ class Dump {
|
|
|
321
321
|
}
|
|
322
322
|
static rev2(h, s, m, o) {
|
|
323
323
|
var _a;
|
|
324
|
-
return Dump.obj(h, m, s.timestamp, s.id, o === null || o === void 0 ? void 0 : o.originSnapshotId, (_a = o === null || o === void 0 ? void 0 : o.
|
|
324
|
+
return Dump.obj(h, m, s.timestamp, s.id, o === null || o === void 0 ? void 0 : o.originSnapshotId, (_a = o === null || o === void 0 ? void 0 : o.content) !== null && _a !== void 0 ? _a : Data_1.Meta.Undefined);
|
|
325
325
|
}
|
|
326
326
|
static rev(r, m) {
|
|
327
327
|
const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
|
|
@@ -343,7 +343,7 @@ class Dump {
|
|
|
343
343
|
}
|
|
344
344
|
exports.Dump = Dump;
|
|
345
345
|
Dump.valueHint = (value, m) => '???';
|
|
346
|
-
exports.ROOT_REV = new Data_1.
|
|
346
|
+
exports.ROOT_REV = new Data_1.DataRevision(new Snapshot({ hint: '<root>' }), undefined, {});
|
|
347
347
|
exports.DefaultSnapshotOptions = Object.freeze({
|
|
348
348
|
hint: 'noname',
|
|
349
349
|
standalone: false,
|
package/package.json
CHANGED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { ObservableObject } from './Hooks';
|
|
2
|
-
import { ObjectHolder, ObjectRevision, Patch } from './Data';
|
|
3
|
-
export declare abstract class EditJournal extends ObservableObject {
|
|
4
|
-
abstract capacity: number;
|
|
5
|
-
abstract readonly isSaving: boolean;
|
|
6
|
-
abstract readonly edits: ReadonlyArray<Patch>;
|
|
7
|
-
abstract readonly canUndo: boolean;
|
|
8
|
-
abstract readonly canRedo: boolean;
|
|
9
|
-
abstract undo(count?: number): void;
|
|
10
|
-
abstract redo(count?: number): void;
|
|
11
|
-
abstract getUnsaved(): Patch | undefined;
|
|
12
|
-
abstract beginSave(): void;
|
|
13
|
-
abstract endSave(success: boolean): void;
|
|
14
|
-
abstract register(patch: Patch): void;
|
|
15
|
-
static create(): EditJournal;
|
|
16
|
-
}
|
|
17
|
-
export declare class EditJournalImpl extends EditJournal {
|
|
18
|
-
private _capacity;
|
|
19
|
-
private _isSaving;
|
|
20
|
-
private _edits;
|
|
21
|
-
private _position;
|
|
22
|
-
private _saved;
|
|
23
|
-
get capacity(): number;
|
|
24
|
-
set capacity(value: number);
|
|
25
|
-
get isSaving(): boolean;
|
|
26
|
-
get edits(): ReadonlyArray<Patch>;
|
|
27
|
-
get canUndo(): boolean;
|
|
28
|
-
get canRedo(): boolean;
|
|
29
|
-
undo(count?: number): void;
|
|
30
|
-
redo(count?: number): void;
|
|
31
|
-
getUnsaved(): Patch | undefined;
|
|
32
|
-
beginSave(): void;
|
|
33
|
-
endSave(success: boolean): void;
|
|
34
|
-
register(p: Patch): void;
|
|
35
|
-
static buildPatch(hint: string, changeset: Map<ObjectHolder, ObjectRevision>): Patch;
|
|
36
|
-
static applyPatch(patch: Patch, undo: boolean): void;
|
|
37
|
-
}
|