reactronic 0.22.206 → 0.22.210
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 +3 -3
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +3 -3
- package/build/dist/source/impl/Data.d.ts +3 -8
- package/build/dist/source/impl/Data.js +2 -2
- package/build/dist/source/impl/Hooks.d.ts +2 -2
- package/build/dist/source/impl/Hooks.js +2 -2
- package/build/dist/source/impl/{EditJournal.d.ts → Journal.d.ts} +13 -19
- package/build/dist/source/impl/Journal.js +138 -0
- package/build/dist/source/impl/Operation.d.ts +1 -1
- package/build/dist/source/impl/Operation.js +25 -25
- package/build/dist/source/impl/Snapshot.js +12 -12
- package/package.json +1 -1
- package/build/dist/source/impl/EditJournal.js +0 -135
package/README.md
CHANGED
|
@@ -310,7 +310,7 @@ function sensitive<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
|
|
|
310
310
|
export interface SnapshotOptions {
|
|
311
311
|
readonly hint?: string
|
|
312
312
|
readonly standalone?: StandaloneMode
|
|
313
|
-
readonly journal?:
|
|
313
|
+
readonly journal?: Journal
|
|
314
314
|
readonly logging?: Partial<LoggingOptions>
|
|
315
315
|
readonly token?: any
|
|
316
316
|
}
|
|
@@ -323,7 +323,7 @@ interface MemberOptions {
|
|
|
323
323
|
readonly triggeringArgs: boolean
|
|
324
324
|
readonly throttling: number // milliseconds, -1 is immediately, Number.MAX_SAFE_INTEGER is never
|
|
325
325
|
readonly reentrance: Reentrance
|
|
326
|
-
readonly journal:
|
|
326
|
+
readonly journal: Journal | undefined
|
|
327
327
|
readonly monitor: Monitor | null
|
|
328
328
|
readonly logging?: Partial<LoggingOptions>
|
|
329
329
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { LoggingOptions } from './Logging';
|
|
2
2
|
import { StandaloneMode } from './impl/Data';
|
|
3
3
|
export { LoggingOptions, ProfilingOptions, LoggingLevel } from './Logging';
|
|
4
|
-
import {
|
|
4
|
+
import { Journal } from './impl/Journal';
|
|
5
5
|
import { Monitor } from './impl/Monitor';
|
|
6
6
|
export interface SnapshotOptions {
|
|
7
7
|
readonly hint?: string;
|
|
8
8
|
readonly standalone?: StandaloneMode;
|
|
9
|
-
readonly journal?:
|
|
9
|
+
readonly journal?: Journal;
|
|
10
10
|
readonly logging?: Partial<LoggingOptions>;
|
|
11
11
|
readonly token?: any;
|
|
12
12
|
}
|
|
@@ -18,7 +18,7 @@ export interface MemberOptions {
|
|
|
18
18
|
readonly triggeringArgs: boolean;
|
|
19
19
|
readonly throttling: number;
|
|
20
20
|
readonly reentrance: Reentrance;
|
|
21
|
-
readonly journal:
|
|
21
|
+
readonly journal: Journal | undefined;
|
|
22
22
|
readonly monitor: Monitor | null;
|
|
23
23
|
readonly logging?: Partial<LoggingOptions>;
|
|
24
24
|
}
|
|
@@ -10,5 +10,5 @@ export { ObservableObject } from './impl/Hooks';
|
|
|
10
10
|
export { Snapshot } from './impl/Snapshot';
|
|
11
11
|
export { Transaction } from './impl/Transaction';
|
|
12
12
|
export { Monitor } from './impl/Monitor';
|
|
13
|
-
export {
|
|
13
|
+
export { Journal } from './impl/Journal';
|
|
14
14
|
export { Rx, nonreactive, sensitive, unobservable, transaction, reaction, cached, options } from './Rx';
|
package/build/dist/source/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nonreactive = exports.Rx = exports.
|
|
3
|
+
exports.options = exports.cached = exports.reaction = exports.transaction = exports.unobservable = exports.sensitive = exports.nonreactive = exports.Rx = exports.Journal = exports.Monitor = exports.Transaction = exports.Snapshot = exports.ObservableObject = exports.ToggleRef = exports.Ref = exports.Controller = exports.LoggingLevel = exports.Reentrance = exports.Kind = exports.SealedSet = exports.SealedMap = exports.SealedArray = exports.pause = exports.all = void 0;
|
|
4
4
|
var Utils_1 = require("./util/Utils");
|
|
5
5
|
Object.defineProperty(exports, "all", { enumerable: true, get: function () { return Utils_1.all; } });
|
|
6
6
|
Object.defineProperty(exports, "pause", { enumerable: true, get: function () { return Utils_1.pause; } });
|
|
@@ -27,8 +27,8 @@ var Transaction_1 = require("./impl/Transaction");
|
|
|
27
27
|
Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return Transaction_1.Transaction; } });
|
|
28
28
|
var Monitor_1 = require("./impl/Monitor");
|
|
29
29
|
Object.defineProperty(exports, "Monitor", { enumerable: true, get: function () { return Monitor_1.Monitor; } });
|
|
30
|
-
var
|
|
31
|
-
Object.defineProperty(exports, "
|
|
30
|
+
var Journal_1 = require("./impl/Journal");
|
|
31
|
+
Object.defineProperty(exports, "Journal", { enumerable: true, get: function () { return Journal_1.Journal; } });
|
|
32
32
|
var Rx_1 = require("./Rx");
|
|
33
33
|
Object.defineProperty(exports, "Rx", { enumerable: true, get: function () { return Rx_1.Rx; } });
|
|
34
34
|
Object.defineProperty(exports, "nonreactive", { enumerable: true, get: function () { return Rx_1.nonreactive; } });
|
|
@@ -28,13 +28,13 @@ export interface ObservableInfo {
|
|
|
28
28
|
}
|
|
29
29
|
export declare class ObjectRevision {
|
|
30
30
|
readonly snapshot: AbstractSnapshot;
|
|
31
|
-
readonly
|
|
31
|
+
readonly former: {
|
|
32
32
|
revision: ObjectRevision;
|
|
33
33
|
};
|
|
34
34
|
readonly data: any;
|
|
35
35
|
readonly changes: Set<MemberName>;
|
|
36
36
|
readonly conflicts: Map<MemberName, ObjectRevision>;
|
|
37
|
-
constructor(snapshot: AbstractSnapshot,
|
|
37
|
+
constructor(snapshot: AbstractSnapshot, former: ObjectRevision | undefined, data: object);
|
|
38
38
|
}
|
|
39
39
|
export declare class ObjectHolder {
|
|
40
40
|
private static generator;
|
|
@@ -53,11 +53,6 @@ export interface Patch {
|
|
|
53
53
|
objects: Map<object, ObjectPatch>;
|
|
54
54
|
}
|
|
55
55
|
export interface ObjectPatch {
|
|
56
|
-
|
|
56
|
+
data: any;
|
|
57
57
|
former: any;
|
|
58
58
|
}
|
|
59
|
-
export interface DataRequest {
|
|
60
|
-
holder: ObjectHolder;
|
|
61
|
-
member: MemberName;
|
|
62
|
-
revision: ObjectRevision;
|
|
63
|
-
}
|
|
@@ -12,9 +12,9 @@ class Observable {
|
|
|
12
12
|
}
|
|
13
13
|
exports.Observable = Observable;
|
|
14
14
|
class ObjectRevision {
|
|
15
|
-
constructor(snapshot,
|
|
15
|
+
constructor(snapshot, former, data) {
|
|
16
16
|
this.snapshot = snapshot;
|
|
17
|
-
this.
|
|
17
|
+
this.former = { revision: former || this };
|
|
18
18
|
this.data = data;
|
|
19
19
|
this.changes = new Set();
|
|
20
20
|
this.conflicts = new Map();
|
|
@@ -2,7 +2,7 @@ import { F } from '../util/Utils';
|
|
|
2
2
|
import { MemberOptions, Kind, Reentrance } from '../Options';
|
|
3
3
|
import { LoggingOptions, ProfilingOptions } from '../Logging';
|
|
4
4
|
import { MemberName, ObjectHolder, StandaloneMode } from './Data';
|
|
5
|
-
import {
|
|
5
|
+
import { Journal } from './Journal';
|
|
6
6
|
import { Monitor } from './Monitor';
|
|
7
7
|
export declare abstract class ObservableObject {
|
|
8
8
|
constructor();
|
|
@@ -18,7 +18,7 @@ export declare class OptionsImpl implements MemberOptions {
|
|
|
18
18
|
readonly triggeringArgs: boolean;
|
|
19
19
|
readonly throttling: number;
|
|
20
20
|
readonly reentrance: Reentrance;
|
|
21
|
-
readonly journal:
|
|
21
|
+
readonly journal: Journal | undefined;
|
|
22
22
|
readonly monitor: Monitor | null;
|
|
23
23
|
readonly logging?: Partial<LoggingOptions>;
|
|
24
24
|
static readonly INITIAL: Readonly<OptionsImpl>;
|
|
@@ -76,10 +76,10 @@ class Hooks {
|
|
|
76
76
|
const r = Snapshot_1.Snapshot.edit().getEditableRevision(h, m, value);
|
|
77
77
|
if (r !== Snapshot_1.ROOT_REV) {
|
|
78
78
|
let curr = r.data[m];
|
|
79
|
-
if (curr !== undefined || (r.
|
|
79
|
+
if (curr !== undefined || (r.former.revision.snapshot === Snapshot_1.ROOT_REV.snapshot && (m in h.unobservable) === false)) {
|
|
80
80
|
if (curr === undefined || curr.value !== value || Hooks.sensitivity) {
|
|
81
81
|
const old = curr === null || curr === void 0 ? void 0 : curr.value;
|
|
82
|
-
if (r.
|
|
82
|
+
if (r.former.revision.data[m] === curr) {
|
|
83
83
|
curr = r.data[m] = new Data_1.Observable(value);
|
|
84
84
|
Snapshot_1.Snapshot.markEdited(old, value, true, r, m, h);
|
|
85
85
|
}
|
|
@@ -1,40 +1,34 @@
|
|
|
1
1
|
import { ObservableObject } from './Hooks';
|
|
2
2
|
import { ObjectHolder, ObjectRevision, Patch } from './Data';
|
|
3
|
-
export declare
|
|
3
|
+
export declare type Saver = (patch: Patch) => Promise<void>;
|
|
4
|
+
export declare abstract class Journal extends ObservableObject {
|
|
4
5
|
abstract capacity: number;
|
|
5
|
-
abstract autoSave: boolean;
|
|
6
|
-
abstract readonly isSaving: boolean;
|
|
7
6
|
abstract readonly edits: ReadonlyArray<Patch>;
|
|
7
|
+
abstract readonly unsaved: Patch;
|
|
8
8
|
abstract readonly canUndo: boolean;
|
|
9
9
|
abstract readonly canRedo: boolean;
|
|
10
|
+
abstract edited(patch: Patch): void;
|
|
11
|
+
abstract saved(patch: Patch): void;
|
|
10
12
|
abstract undo(count?: number): void;
|
|
11
13
|
abstract redo(count?: number): void;
|
|
12
|
-
|
|
13
|
-
abstract register(patch: Patch): void;
|
|
14
|
-
static create(): EditJournal;
|
|
14
|
+
static create(): Journal;
|
|
15
15
|
}
|
|
16
|
-
export declare class
|
|
16
|
+
export declare class JournalImpl extends Journal {
|
|
17
17
|
private _capacity;
|
|
18
|
-
private _autoSave;
|
|
19
|
-
private _isSaving;
|
|
20
18
|
private _edits;
|
|
19
|
+
private _unsaved;
|
|
21
20
|
private _position;
|
|
22
|
-
private _saved;
|
|
23
21
|
get capacity(): number;
|
|
24
22
|
set capacity(value: number);
|
|
25
|
-
get autoSave(): boolean;
|
|
26
|
-
set autoSave(value: boolean);
|
|
27
|
-
get isSaving(): boolean;
|
|
28
23
|
get edits(): ReadonlyArray<Patch>;
|
|
24
|
+
get unsaved(): Patch;
|
|
29
25
|
get canUndo(): boolean;
|
|
30
26
|
get canRedo(): boolean;
|
|
27
|
+
edited(p: Patch): void;
|
|
28
|
+
saved(patch: Patch): void;
|
|
31
29
|
undo(count?: number): void;
|
|
32
30
|
redo(count?: number): void;
|
|
33
|
-
save(): void;
|
|
34
|
-
getUnsaved(): Patch | undefined;
|
|
35
|
-
beginSave(): void;
|
|
36
|
-
endSave(success: boolean): void;
|
|
37
|
-
register(p: Patch): void;
|
|
38
31
|
static buildPatch(hint: string, changeset: Map<ObjectHolder, ObjectRevision>): Patch;
|
|
39
|
-
static applyPatch(patch: Patch,
|
|
32
|
+
static applyPatch(patch: Patch, undoing: boolean): void;
|
|
33
|
+
mergePatchToUnsaved(patch: Patch, undoing: boolean): void;
|
|
40
34
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JournalImpl = exports.Journal = void 0;
|
|
4
|
+
const Hooks_1 = require("./Hooks");
|
|
5
|
+
const Data_1 = require("./Data");
|
|
6
|
+
const Snapshot_1 = require("./Snapshot");
|
|
7
|
+
const Transaction_1 = require("./Transaction");
|
|
8
|
+
const Sealant_1 = require("../util/Sealant");
|
|
9
|
+
class Journal extends Hooks_1.ObservableObject {
|
|
10
|
+
static create() { return new JournalImpl(); }
|
|
11
|
+
}
|
|
12
|
+
exports.Journal = Journal;
|
|
13
|
+
class JournalImpl extends Journal {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this._capacity = 5;
|
|
17
|
+
this._edits = [];
|
|
18
|
+
this._unsaved = { hint: 'unsaved', objects: new Map() };
|
|
19
|
+
this._position = 0;
|
|
20
|
+
}
|
|
21
|
+
get capacity() { return this._capacity; }
|
|
22
|
+
set capacity(value) { this._capacity = value; if (value < this._edits.length)
|
|
23
|
+
this._edits.splice(0, this._edits.length - value); }
|
|
24
|
+
get edits() { return this._edits; }
|
|
25
|
+
get unsaved() { return this._unsaved; }
|
|
26
|
+
get canUndo() { return this._edits.length > 0 && this._position > 0; }
|
|
27
|
+
get canRedo() { return this._position < this._edits.length; }
|
|
28
|
+
edited(p) {
|
|
29
|
+
Transaction_1.Transaction.run({ hint: 'EditJournal.edited', standalone: 'isolated' }, () => {
|
|
30
|
+
const items = this._edits = this._edits.toMutable();
|
|
31
|
+
if (items.length >= this._capacity)
|
|
32
|
+
items.shift();
|
|
33
|
+
else
|
|
34
|
+
items.splice(this._position);
|
|
35
|
+
this.mergePatchToUnsaved(p, false);
|
|
36
|
+
items.push(p);
|
|
37
|
+
this._position = items.length;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
saved(patch) {
|
|
41
|
+
if (this._unsaved === patch)
|
|
42
|
+
this._unsaved = { hint: 'unsaved', objects: new Map() };
|
|
43
|
+
else
|
|
44
|
+
throw new Error('not implemented');
|
|
45
|
+
}
|
|
46
|
+
undo(count = 1) {
|
|
47
|
+
Transaction_1.Transaction.run({ hint: 'Journal.undo', standalone: 'isolated' }, () => {
|
|
48
|
+
let i = this._position - 1;
|
|
49
|
+
while (i >= 0 && count > 0) {
|
|
50
|
+
const patch = this._edits[i];
|
|
51
|
+
JournalImpl.applyPatch(patch, true);
|
|
52
|
+
this.mergePatchToUnsaved(patch, true);
|
|
53
|
+
i--, count--;
|
|
54
|
+
}
|
|
55
|
+
this._position = i + 1;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
redo(count = 1) {
|
|
59
|
+
Transaction_1.Transaction.run({ hint: 'Journal.redo', standalone: 'isolated' }, () => {
|
|
60
|
+
let i = this._position;
|
|
61
|
+
while (i < this._edits.length && count > 0) {
|
|
62
|
+
const patch = this._edits[i];
|
|
63
|
+
JournalImpl.applyPatch(patch, false);
|
|
64
|
+
this.mergePatchToUnsaved(patch, false);
|
|
65
|
+
i++, count--;
|
|
66
|
+
}
|
|
67
|
+
this._position = i;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
static buildPatch(hint, changeset) {
|
|
71
|
+
const patch = { hint, objects: new Map() };
|
|
72
|
+
changeset.forEach((r, h) => {
|
|
73
|
+
const op = { data: {}, former: {} };
|
|
74
|
+
const former = r.former.revision !== Snapshot_1.ROOT_REV ? r.former.revision.data : undefined;
|
|
75
|
+
r.changes.forEach(m => {
|
|
76
|
+
op.data[m] = unseal(r.data[m]);
|
|
77
|
+
if (former)
|
|
78
|
+
op.former[m] = unseal(former[m]);
|
|
79
|
+
});
|
|
80
|
+
if (!former) {
|
|
81
|
+
delete op.data[Data_1.Meta.Disposed];
|
|
82
|
+
op.former[Data_1.Meta.Disposed] = Data_1.Meta.Disposed;
|
|
83
|
+
}
|
|
84
|
+
patch.objects.set(h.proxy, op);
|
|
85
|
+
});
|
|
86
|
+
return patch;
|
|
87
|
+
}
|
|
88
|
+
static applyPatch(patch, undoing) {
|
|
89
|
+
const ctx = Snapshot_1.Snapshot.edit();
|
|
90
|
+
patch.objects.forEach((op, obj) => {
|
|
91
|
+
const h = Data_1.Meta.get(obj, Data_1.Meta.Holder);
|
|
92
|
+
const data = undoing ? op.former : op.data;
|
|
93
|
+
if (data[Data_1.Meta.Disposed] === undefined) {
|
|
94
|
+
for (const m in data) {
|
|
95
|
+
const value = data[m];
|
|
96
|
+
const r = ctx.getEditableRevision(h, m, value);
|
|
97
|
+
if (r.snapshot === ctx) {
|
|
98
|
+
r.data[m] = new Data_1.Observable(value);
|
|
99
|
+
const v = r.former.revision.data[m];
|
|
100
|
+
Snapshot_1.Snapshot.markEdited(v, value, v !== value, r, m, h);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
Snapshot_1.Snapshot.doDispose(ctx, h);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
mergePatchToUnsaved(patch, undoing) {
|
|
109
|
+
const unsaved = this._unsaved;
|
|
110
|
+
patch.objects.forEach((op, obj) => {
|
|
111
|
+
let merged = unsaved.objects.get(obj);
|
|
112
|
+
if (!merged)
|
|
113
|
+
unsaved.objects.set(obj, merged = { data: {}, former: {} });
|
|
114
|
+
const data = undoing ? op.former : op.data;
|
|
115
|
+
const former = undoing ? op.data : op.former;
|
|
116
|
+
for (const m in data) {
|
|
117
|
+
const value = data[m];
|
|
118
|
+
if (value !== merged.former[m]) {
|
|
119
|
+
merged.data[m] = value;
|
|
120
|
+
if (m in merged.former === false)
|
|
121
|
+
merged.former[m] = former[m];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
delete merged.data[m];
|
|
125
|
+
delete merged.former[m];
|
|
126
|
+
if (Object.keys(merged.data).length === 0)
|
|
127
|
+
unsaved.objects.delete(obj);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.JournalImpl = JournalImpl;
|
|
134
|
+
function unseal(observable) {
|
|
135
|
+
const result = observable.value;
|
|
136
|
+
const createCopy = result === null || result === void 0 ? void 0 : result[Sealant_1.Sealant.CreateCopy];
|
|
137
|
+
return createCopy !== undefined ? createCopy.call(result) : result;
|
|
138
|
+
}
|
|
@@ -50,7 +50,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
50
50
|
obsoleteDueTo: string | undefined;
|
|
51
51
|
obsoleteSince: number;
|
|
52
52
|
successor: Operation | undefined;
|
|
53
|
-
constructor(controller: OperationController, snapshot: AbstractSnapshot,
|
|
53
|
+
constructor(controller: OperationController, snapshot: AbstractSnapshot, former: Operation | OptionsImpl);
|
|
54
54
|
get isOperation(): boolean;
|
|
55
55
|
get originSnapshotId(): number;
|
|
56
56
|
hint(): string;
|
|
@@ -9,7 +9,7 @@ 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
15
|
const ROOT_HOLDER = new Data_1.ObjectHolder(undefined, undefined, Hooks_1.Hooks.proxy, Snapshot_1.ROOT_REV, '<root>');
|
|
@@ -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);
|
|
@@ -205,20 +205,20 @@ class OperationController extends Controller_1.Controller {
|
|
|
205
205
|
}
|
|
206
206
|
exports.OperationController = OperationController;
|
|
207
207
|
class Operation extends Data_1.Observable {
|
|
208
|
-
constructor(controller, snapshot,
|
|
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
214
|
this.observables = new Map();
|
|
215
|
-
if (
|
|
216
|
-
this.options =
|
|
217
|
-
this.args =
|
|
218
|
-
this.cause =
|
|
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
|
}
|
|
@@ -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,24 +499,24 @@ 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.Observable) {
|
|
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.unsubscribeFromAllObservables();
|
|
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.observers) === null || _a === void 0 ? void 0 : _a.forEach(c => c.markObsoleteDueTo(former, m, r.snapshot, h, why, timestamp, reactions));
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
if (curr instanceof Operation) {
|
|
@@ -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
|
}
|
|
@@ -101,7 +101,7 @@ class Snapshot {
|
|
|
101
101
|
if (this.sealed && r.snapshot !== exports.ROOT_REV.snapshot)
|
|
102
102
|
throw (0, Dbg_1.misuse)(`observable 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) {
|
|
@@ -194,7 +194,7 @@ class Snapshot {
|
|
|
194
194
|
h.head = r;
|
|
195
195
|
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
196
196
|
Snapshot.totalObjectRevisionCount++;
|
|
197
|
-
if (r.
|
|
197
|
+
if (r.former.revision === exports.ROOT_REV)
|
|
198
198
|
Snapshot.totalObjectHolderCount++;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
@@ -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)
|
|
@@ -219,7 +219,7 @@ class Snapshot {
|
|
|
219
219
|
if (!r.changes.has(Data_1.Meta.Disposed))
|
|
220
220
|
r.changes.forEach((o, m) => Snapshot.sealObservable(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);
|
|
@@ -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.
|
|
270
|
+
if (r.former.revision !== exports.ROOT_REV)
|
|
271
271
|
Snapshot.totalObjectRevisionCount--;
|
|
272
272
|
if (r.changes.has(Data_1.Meta.Disposed))
|
|
273
273
|
Snapshot.totalObjectHolderCount--;
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EditJournalImpl = exports.EditJournal = void 0;
|
|
4
|
-
const Hooks_1 = require("./Hooks");
|
|
5
|
-
const Data_1 = require("./Data");
|
|
6
|
-
const Snapshot_1 = require("./Snapshot");
|
|
7
|
-
const Transaction_1 = require("./Transaction");
|
|
8
|
-
const Sealant_1 = require("../util/Sealant");
|
|
9
|
-
class EditJournal extends Hooks_1.ObservableObject {
|
|
10
|
-
static create() { return new EditJournalImpl(); }
|
|
11
|
-
}
|
|
12
|
-
exports.EditJournal = EditJournal;
|
|
13
|
-
class EditJournalImpl extends EditJournal {
|
|
14
|
-
constructor() {
|
|
15
|
-
super(...arguments);
|
|
16
|
-
this._capacity = 5;
|
|
17
|
-
this._autoSave = false;
|
|
18
|
-
this._isSaving = false;
|
|
19
|
-
this._edits = [];
|
|
20
|
-
this._position = 0;
|
|
21
|
-
this._saved = 0;
|
|
22
|
-
}
|
|
23
|
-
get capacity() { return this._capacity; }
|
|
24
|
-
set capacity(value) { this._capacity = value; if (value < this._edits.length)
|
|
25
|
-
this._edits.splice(0, this._edits.length - value); }
|
|
26
|
-
get autoSave() { return this._autoSave; }
|
|
27
|
-
set autoSave(value) { this._autoSave = value; }
|
|
28
|
-
get isSaving() { return this._isSaving; }
|
|
29
|
-
get edits() { return this._edits; }
|
|
30
|
-
get canUndo() { return this._edits.length > 0 && this._position > 0; }
|
|
31
|
-
get canRedo() { return this._position < this._edits.length; }
|
|
32
|
-
undo(count = 1) {
|
|
33
|
-
Transaction_1.Transaction.run({ hint: 'EditJournal.undo', standalone: 'isolated' }, () => {
|
|
34
|
-
let i = this._position - 1;
|
|
35
|
-
while (i >= 0 && count > 0) {
|
|
36
|
-
const patch = this._edits[i];
|
|
37
|
-
EditJournalImpl.applyPatch(patch, true);
|
|
38
|
-
i--, count--;
|
|
39
|
-
}
|
|
40
|
-
this._position = i + 1;
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
redo(count = 1) {
|
|
44
|
-
Transaction_1.Transaction.run({ hint: 'EditJournal.redo', standalone: 'isolated' }, () => {
|
|
45
|
-
let i = this._position;
|
|
46
|
-
while (i < this._edits.length && count > 0) {
|
|
47
|
-
const patch = this._edits[i];
|
|
48
|
-
EditJournalImpl.applyPatch(patch, false);
|
|
49
|
-
i++, count--;
|
|
50
|
-
}
|
|
51
|
-
this._position = i;
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
save() {
|
|
55
|
-
}
|
|
56
|
-
getUnsaved() {
|
|
57
|
-
let result = undefined;
|
|
58
|
-
const length = Math.abs(this._position - this._saved);
|
|
59
|
-
if (length !== 0) {
|
|
60
|
-
result = { hint: 'unsaved changes', objects: new Map() };
|
|
61
|
-
const direction = Math.sign(this._position - this._saved);
|
|
62
|
-
let i = 0;
|
|
63
|
-
while (i < length) {
|
|
64
|
-
const patch = this._edits[this._position + direction * (i + 1)];
|
|
65
|
-
patch.objects.forEach((p, obj) => {
|
|
66
|
-
});
|
|
67
|
-
i++;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return result;
|
|
71
|
-
}
|
|
72
|
-
beginSave() {
|
|
73
|
-
this._isSaving = true;
|
|
74
|
-
}
|
|
75
|
-
endSave(success) {
|
|
76
|
-
if (success)
|
|
77
|
-
this._saved = this._position;
|
|
78
|
-
this._isSaving = false;
|
|
79
|
-
}
|
|
80
|
-
register(p) {
|
|
81
|
-
Transaction_1.Transaction.run({ hint: 'EditJournal.remember', standalone: 'isolated' }, () => {
|
|
82
|
-
const items = this._edits = this._edits.toMutable();
|
|
83
|
-
if (items.length >= this._capacity)
|
|
84
|
-
items.shift();
|
|
85
|
-
else
|
|
86
|
-
items.splice(this._position);
|
|
87
|
-
items.push(p);
|
|
88
|
-
this._position = items.length;
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
static buildPatch(hint, changeset) {
|
|
92
|
-
const patch = { hint, objects: new Map() };
|
|
93
|
-
changeset.forEach((r, h) => {
|
|
94
|
-
const p = { current: {}, former: {} };
|
|
95
|
-
const old = r.prev.revision !== Snapshot_1.ROOT_REV ? r.prev.revision.data : undefined;
|
|
96
|
-
r.changes.forEach((episode, m) => {
|
|
97
|
-
p.current[m] = unseal(r.data[m]);
|
|
98
|
-
if (old)
|
|
99
|
-
p.former[m] = unseal(old[m]);
|
|
100
|
-
});
|
|
101
|
-
if (!old) {
|
|
102
|
-
delete p.current[Data_1.Meta.Disposed];
|
|
103
|
-
p.former[Data_1.Meta.Disposed] = Data_1.Meta.Disposed;
|
|
104
|
-
}
|
|
105
|
-
patch.objects.set(h.proxy, p);
|
|
106
|
-
});
|
|
107
|
-
return patch;
|
|
108
|
-
}
|
|
109
|
-
static applyPatch(patch, undo) {
|
|
110
|
-
const ctx = Snapshot_1.Snapshot.edit();
|
|
111
|
-
patch.objects.forEach((p, obj) => {
|
|
112
|
-
const h = Data_1.Meta.get(obj, Data_1.Meta.Holder);
|
|
113
|
-
const data = undo ? p.former : p.current;
|
|
114
|
-
if (data[Data_1.Meta.Disposed] === undefined) {
|
|
115
|
-
for (const m in data) {
|
|
116
|
-
const value = data[m];
|
|
117
|
-
const r = ctx.getEditableRevision(h, m, value);
|
|
118
|
-
if (r.snapshot === ctx) {
|
|
119
|
-
r.data[m] = new Data_1.Observable(value);
|
|
120
|
-
const v = r.prev.revision.data[m];
|
|
121
|
-
Snapshot_1.Snapshot.markEdited(v, value, v !== value, r, m, h);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else
|
|
126
|
-
Snapshot_1.Snapshot.doDispose(ctx, h);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
exports.EditJournalImpl = EditJournalImpl;
|
|
131
|
-
function unseal(observable) {
|
|
132
|
-
const result = observable.value;
|
|
133
|
-
const createCopy = result === null || result === void 0 ? void 0 : result[Sealant_1.Sealant.CreateCopy];
|
|
134
|
-
return createCopy !== undefined ? createCopy.call(result) : result;
|
|
135
|
-
}
|