reactronic 0.22.302 → 0.22.303
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/build/dist/source/Logging.d.ts +6 -6
- package/build/dist/source/Rx.d.ts +1 -0
- package/build/dist/source/Rx.js +5 -4
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +3 -3
- package/build/dist/source/impl/Changeset.d.ts +60 -0
- package/build/dist/source/impl/Changeset.js +361 -0
- package/build/dist/source/impl/Data.d.ts +20 -15
- package/build/dist/source/impl/Data.js +20 -11
- package/build/dist/source/impl/Hooks.d.ts +41 -12
- package/build/dist/source/impl/Hooks.js +84 -44
- package/build/dist/source/impl/Journal.d.ts +2 -2
- package/build/dist/source/impl/Journal.js +56 -45
- package/build/dist/source/impl/Meta.d.ts +2 -2
- package/build/dist/source/impl/Meta.js +7 -7
- package/build/dist/source/impl/Operation.d.ts +7 -7
- package/build/dist/source/impl/Operation.js +123 -122
- package/build/dist/source/impl/Transaction.d.ts +2 -2
- package/build/dist/source/impl/Transaction.js +23 -23
- package/package.json +1 -1
- package/build/dist/source/impl/Snapshot.d.ts +0 -60
- package/build/dist/source/impl/Snapshot.js +0 -353
|
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.Transaction = void 0;
|
|
13
13
|
const Utils_1 = require("../util/Utils");
|
|
14
14
|
const Dbg_1 = require("../util/Dbg");
|
|
15
|
-
const
|
|
15
|
+
const Changeset_1 = require("./Changeset");
|
|
16
16
|
class Transaction {
|
|
17
17
|
static get current() { return TransactionImpl.current; }
|
|
18
18
|
whenFinished() {
|
|
@@ -31,7 +31,7 @@ class TransactionImpl extends Transaction {
|
|
|
31
31
|
constructor(options) {
|
|
32
32
|
super();
|
|
33
33
|
this.margin = TransactionImpl.curr !== undefined ? TransactionImpl.curr.margin + 1 : -1;
|
|
34
|
-
this.
|
|
34
|
+
this.changeset = new Changeset_1.Changeset(options);
|
|
35
35
|
this.pending = 0;
|
|
36
36
|
this.sealed = false;
|
|
37
37
|
this.canceled = undefined;
|
|
@@ -41,10 +41,10 @@ class TransactionImpl extends Transaction {
|
|
|
41
41
|
this.reject = Utils_1.UNDEF;
|
|
42
42
|
}
|
|
43
43
|
static get current() { return TransactionImpl.curr; }
|
|
44
|
-
get id() { return this.
|
|
45
|
-
get hint() { return this.
|
|
46
|
-
get options() { return this.
|
|
47
|
-
get timestamp() { return this.
|
|
44
|
+
get id() { return this.changeset.id; }
|
|
45
|
+
get hint() { return this.changeset.hint; }
|
|
46
|
+
get options() { return this.changeset.options; }
|
|
47
|
+
get timestamp() { return this.changeset.timestamp; }
|
|
48
48
|
get error() { return this.canceled; }
|
|
49
49
|
run(func, ...args) {
|
|
50
50
|
this.guard();
|
|
@@ -181,8 +181,8 @@ class TransactionImpl extends Transaction {
|
|
|
181
181
|
const options = {
|
|
182
182
|
hint: `${this.hint} - restart after T${this.after.id}`,
|
|
183
183
|
standalone: this.options.standalone === 'isolated' ? 'isolated' : true,
|
|
184
|
-
logging: this.
|
|
185
|
-
token: this.
|
|
184
|
+
logging: this.changeset.options.logging,
|
|
185
|
+
token: this.changeset.options.token,
|
|
186
186
|
};
|
|
187
187
|
return TransactionImpl.run(options, func, ...args);
|
|
188
188
|
}
|
|
@@ -211,7 +211,7 @@ class TransactionImpl extends Transaction {
|
|
|
211
211
|
}
|
|
212
212
|
TransactionImpl.curr = this;
|
|
213
213
|
this.pending++;
|
|
214
|
-
this.
|
|
214
|
+
this.changeset.acquire(outer.changeset);
|
|
215
215
|
result = func(...args);
|
|
216
216
|
if (this.sealed && this.pending === 1) {
|
|
217
217
|
if (!this.canceled)
|
|
@@ -230,7 +230,7 @@ class TransactionImpl extends Transaction {
|
|
|
230
230
|
if (this.sealed && this.pending === 0) {
|
|
231
231
|
const reactions = this.applyOrDiscard();
|
|
232
232
|
TransactionImpl.curr = outer;
|
|
233
|
-
TransactionImpl.off(
|
|
233
|
+
TransactionImpl.off(Changeset_1.Changeset.enqueueReactionsToRun, reactions);
|
|
234
234
|
}
|
|
235
235
|
else
|
|
236
236
|
TransactionImpl.curr = outer;
|
|
@@ -246,25 +246,25 @@ class TransactionImpl extends Transaction {
|
|
|
246
246
|
if (after && after !== TransactionImpl.none)
|
|
247
247
|
Dbg_1.Log.write('║', ' [!]', `T${t.id}[${t.hint}] will be restarted${t !== after ? ` after T${after.id}[${after.hint}]` : ''}`);
|
|
248
248
|
}
|
|
249
|
-
|
|
249
|
+
Changeset_1.Changeset.revokeAllSubscriptions(t.changeset);
|
|
250
250
|
}
|
|
251
251
|
t.sealed = true;
|
|
252
252
|
}
|
|
253
253
|
checkForConflicts() {
|
|
254
|
-
const conflicts = this.
|
|
254
|
+
const conflicts = this.changeset.rebase();
|
|
255
255
|
if (conflicts)
|
|
256
256
|
this.tryResolveConflicts(conflicts);
|
|
257
257
|
}
|
|
258
258
|
tryResolveConflicts(conflicts) {
|
|
259
|
-
throw (0, Dbg_1.error)(`T${this.id}[${this.hint}] conflicts with: ${
|
|
259
|
+
throw (0, Dbg_1.error)(`T${this.id}[${this.hint}] conflicts with: ${Changeset_1.Dump.conflicts(conflicts)}`, undefined);
|
|
260
260
|
}
|
|
261
261
|
applyOrDiscard() {
|
|
262
262
|
let reactions;
|
|
263
263
|
try {
|
|
264
264
|
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.change)
|
|
265
265
|
Dbg_1.Log.write('╠═', '', '', undefined, 'changes');
|
|
266
|
-
reactions = this.
|
|
267
|
-
this.
|
|
266
|
+
reactions = this.changeset.applyOrDiscard(this.canceled);
|
|
267
|
+
this.changeset.triggerGarbageCollection();
|
|
268
268
|
if (this.promise) {
|
|
269
269
|
if (this.canceled && !this.after)
|
|
270
270
|
this.reject(this.canceled);
|
|
@@ -289,20 +289,20 @@ class TransactionImpl extends Transaction {
|
|
|
289
289
|
}
|
|
290
290
|
return this.promise;
|
|
291
291
|
}
|
|
292
|
-
static
|
|
293
|
-
return TransactionImpl.curr.
|
|
292
|
+
static getCurrentChangeset() {
|
|
293
|
+
return TransactionImpl.curr.changeset;
|
|
294
294
|
}
|
|
295
|
-
static
|
|
295
|
+
static getEditableChangeset() {
|
|
296
296
|
if (TransactionImpl.inspection)
|
|
297
297
|
throw (0, Dbg_1.misuse)('cannot make changes during transaction inspection');
|
|
298
|
-
return TransactionImpl.curr.
|
|
298
|
+
return TransactionImpl.curr.changeset;
|
|
299
299
|
}
|
|
300
300
|
static _init() {
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
Changeset_1.Changeset.current = TransactionImpl.getCurrentChangeset;
|
|
302
|
+
Changeset_1.Changeset.edit = TransactionImpl.getEditableChangeset;
|
|
303
303
|
TransactionImpl.none.sealed = true;
|
|
304
|
-
TransactionImpl.none.
|
|
305
|
-
|
|
304
|
+
TransactionImpl.none.changeset.applyOrDiscard();
|
|
305
|
+
Changeset_1.Changeset._init();
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
TransactionImpl.none = new TransactionImpl({ hint: 'Transaction.off' });
|
package/package.json
CHANGED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Kind, SnapshotOptions } from '../Options';
|
|
2
|
-
import { AbstractSnapshot, DataRevision, MemberName, DataHolder, Subscription, Subscriber } from './Data';
|
|
3
|
-
export declare const MAX_TIMESTAMP: number;
|
|
4
|
-
export declare const UNDEFINED_TIMESTAMP: number;
|
|
5
|
-
export declare class Snapshot implements AbstractSnapshot {
|
|
6
|
-
static idGen: number;
|
|
7
|
-
private static stampGen;
|
|
8
|
-
private static pending;
|
|
9
|
-
private static oldest;
|
|
10
|
-
static garbageCollectionSummaryInterval: number;
|
|
11
|
-
static lastGarbageCollectionSummaryTimestamp: number;
|
|
12
|
-
static totalHolderCount: number;
|
|
13
|
-
static totalRevisionCount: number;
|
|
14
|
-
readonly id: number;
|
|
15
|
-
readonly options: SnapshotOptions;
|
|
16
|
-
get hint(): string;
|
|
17
|
-
get timestamp(): number;
|
|
18
|
-
private stamp;
|
|
19
|
-
private bumper;
|
|
20
|
-
changeset: Map<DataHolder, DataRevision>;
|
|
21
|
-
reactions: Subscriber[];
|
|
22
|
-
sealed: boolean;
|
|
23
|
-
constructor(options: SnapshotOptions | null);
|
|
24
|
-
static current: () => Snapshot;
|
|
25
|
-
static edit: () => Snapshot;
|
|
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
|
-
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
|
-
static propagateAllChangesThroughSubscriptions: (snapshot: Snapshot) => void;
|
|
30
|
-
static revokeAllSubscriptions: (snapshot: Snapshot) => void;
|
|
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
|
-
static takeSnapshot<T>(obj: T): T;
|
|
36
|
-
static dispose(obj: any): void;
|
|
37
|
-
static doDispose(ctx: Snapshot, h: DataHolder): DataRevision;
|
|
38
|
-
private isNewRevisionRequired;
|
|
39
|
-
acquire(outer: Snapshot): void;
|
|
40
|
-
bumpBy(timestamp: number): void;
|
|
41
|
-
rebase(): DataRevision[] | undefined;
|
|
42
|
-
private merge;
|
|
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
|
-
triggerGarbageCollection(): void;
|
|
48
|
-
private unlinkHistory;
|
|
49
|
-
static _init(): void;
|
|
50
|
-
}
|
|
51
|
-
export declare class Dump {
|
|
52
|
-
static valueHint: (value: any, m?: PropertyKey | undefined) => string;
|
|
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
|
-
}
|
|
59
|
-
export declare const ROOT_REV: DataRevision;
|
|
60
|
-
export declare const DefaultSnapshotOptions: SnapshotOptions;
|
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DefaultSnapshotOptions = exports.ROOT_REV = exports.Dump = exports.Snapshot = exports.UNDEFINED_TIMESTAMP = exports.MAX_TIMESTAMP = void 0;
|
|
4
|
-
const Utils_1 = require("../util/Utils");
|
|
5
|
-
const Dbg_1 = require("../util/Dbg");
|
|
6
|
-
const Sealant_1 = require("../util/Sealant");
|
|
7
|
-
const SealedArray_1 = require("../util/SealedArray");
|
|
8
|
-
const SealedMap_1 = require("../util/SealedMap");
|
|
9
|
-
const SealedSet_1 = require("../util/SealedSet");
|
|
10
|
-
const Data_1 = require("./Data");
|
|
11
|
-
exports.MAX_TIMESTAMP = Number.MAX_SAFE_INTEGER;
|
|
12
|
-
exports.UNDEFINED_TIMESTAMP = exports.MAX_TIMESTAMP - 1;
|
|
13
|
-
Object.defineProperty(Data_1.DataHolder.prototype, '#this', {
|
|
14
|
-
configurable: false, enumerable: false,
|
|
15
|
-
get() {
|
|
16
|
-
const result = {};
|
|
17
|
-
const data = Snapshot.current().getCurrentRevision(this, '#this').data;
|
|
18
|
-
for (const m in data) {
|
|
19
|
-
const v = data[m];
|
|
20
|
-
if (v instanceof Data_1.Subscription)
|
|
21
|
-
result[m] = v.content;
|
|
22
|
-
else if (v === Data_1.Meta.Nonreactive)
|
|
23
|
-
result[m] = this.data[m];
|
|
24
|
-
else
|
|
25
|
-
result[m] = v;
|
|
26
|
-
}
|
|
27
|
-
return result;
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
const EMPTY_ARRAY = Object.freeze([]);
|
|
31
|
-
const EMPTY_MAP = Utils_1.Utils.freezeMap(new Map());
|
|
32
|
-
class Snapshot {
|
|
33
|
-
constructor(options) {
|
|
34
|
-
this.id = ++Snapshot.idGen;
|
|
35
|
-
this.options = options !== null && options !== void 0 ? options : exports.DefaultSnapshotOptions;
|
|
36
|
-
this.stamp = exports.UNDEFINED_TIMESTAMP;
|
|
37
|
-
this.bumper = 100;
|
|
38
|
-
this.changeset = new Map();
|
|
39
|
-
this.reactions = [];
|
|
40
|
-
this.sealed = false;
|
|
41
|
-
}
|
|
42
|
-
get hint() { var _a; return (_a = this.options.hint) !== null && _a !== void 0 ? _a : 'noname'; }
|
|
43
|
-
get timestamp() { return this.stamp; }
|
|
44
|
-
seekRevision(h, m) {
|
|
45
|
-
let r = h.editing;
|
|
46
|
-
if (r && r.snapshot !== this) {
|
|
47
|
-
r = this.changeset.get(h);
|
|
48
|
-
if (r)
|
|
49
|
-
h.editing = r;
|
|
50
|
-
}
|
|
51
|
-
if (!r) {
|
|
52
|
-
r = h.head;
|
|
53
|
-
while (r !== exports.ROOT_REV && r.snapshot.timestamp > this.timestamp)
|
|
54
|
-
r = r.former.revision;
|
|
55
|
-
}
|
|
56
|
-
return r;
|
|
57
|
-
}
|
|
58
|
-
getCurrentRevision(h, m) {
|
|
59
|
-
const r = this.seekRevision(h, m);
|
|
60
|
-
if (r === exports.ROOT_REV)
|
|
61
|
-
throw (0, Dbg_1.misuse)(`object ${Dump.obj(h)} doesn't exist in snapshot v${this.stamp} (${this.hint})`);
|
|
62
|
-
return r;
|
|
63
|
-
}
|
|
64
|
-
getEditableRevision(h, m, value, token) {
|
|
65
|
-
let r = this.seekRevision(h, m);
|
|
66
|
-
const existing = r.data[m];
|
|
67
|
-
if (existing !== Data_1.Meta.Nonreactive) {
|
|
68
|
-
if (this.isNewRevisionRequired(h, r, m, existing, value, token)) {
|
|
69
|
-
const data = Object.assign({}, m === Data_1.Meta.Holder ? value : r.data);
|
|
70
|
-
Reflect.set(data, Data_1.Meta.Holder, h);
|
|
71
|
-
r = new Data_1.DataRevision(this, r, data);
|
|
72
|
-
this.changeset.set(h, r);
|
|
73
|
-
h.editing = r;
|
|
74
|
-
h.editors++;
|
|
75
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.write)
|
|
76
|
-
Dbg_1.Log.write('║', ' ⎘', `${Dump.obj(h)} is cloned`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else
|
|
80
|
-
r = exports.ROOT_REV;
|
|
81
|
-
return r;
|
|
82
|
-
}
|
|
83
|
-
static takeSnapshot(obj) {
|
|
84
|
-
return obj[Data_1.Meta.Holder]['#this'];
|
|
85
|
-
}
|
|
86
|
-
static dispose(obj) {
|
|
87
|
-
const ctx = Snapshot.edit();
|
|
88
|
-
const h = Data_1.Meta.get(obj, Data_1.Meta.Holder);
|
|
89
|
-
if (h !== undefined)
|
|
90
|
-
Snapshot.doDispose(ctx, h);
|
|
91
|
-
}
|
|
92
|
-
static doDispose(ctx, h) {
|
|
93
|
-
const r = ctx.getEditableRevision(h, Data_1.Meta.Disposed, Data_1.Meta.Disposed);
|
|
94
|
-
if (r !== exports.ROOT_REV) {
|
|
95
|
-
r.data[Data_1.Meta.Disposed] = Data_1.Meta.Disposed;
|
|
96
|
-
Snapshot.markEdited(Data_1.Meta.Disposed, Data_1.Meta.Disposed, true, r, Data_1.Meta.Disposed, h);
|
|
97
|
-
}
|
|
98
|
-
return r;
|
|
99
|
-
}
|
|
100
|
-
isNewRevisionRequired(h, r, m, existing, value, token) {
|
|
101
|
-
if (this.sealed && r.snapshot !== exports.ROOT_REV.snapshot)
|
|
102
|
-
throw (0, Dbg_1.misuse)(`reactive property ${Dump.obj(h, m)} can only be modified inside transaction`);
|
|
103
|
-
if (m !== Data_1.Meta.Holder && value !== Data_1.Meta.Holder) {
|
|
104
|
-
if (r.snapshot !== this || r.former.revision !== exports.ROOT_REV) {
|
|
105
|
-
if (this.options.token !== undefined && token !== this.options.token)
|
|
106
|
-
throw (0, Dbg_1.misuse)(`${this.hint} should not have side effects (trying to change ${Dump.rev(r, m)})`);
|
|
107
|
-
}
|
|
108
|
-
if (r === exports.ROOT_REV)
|
|
109
|
-
throw (0, Dbg_1.misuse)(`member ${Dump.rev(r, m)} doesn't exist in snapshot v${this.stamp} (${this.hint})`);
|
|
110
|
-
}
|
|
111
|
-
return r.snapshot !== this && !this.sealed;
|
|
112
|
-
}
|
|
113
|
-
acquire(outer) {
|
|
114
|
-
if (!this.sealed && this.stamp === exports.UNDEFINED_TIMESTAMP) {
|
|
115
|
-
const ahead = this.options.token === undefined || outer.stamp === exports.UNDEFINED_TIMESTAMP;
|
|
116
|
-
this.stamp = ahead ? Snapshot.stampGen : outer.stamp;
|
|
117
|
-
Snapshot.pending.push(this);
|
|
118
|
-
if (Snapshot.oldest === undefined)
|
|
119
|
-
Snapshot.oldest = this;
|
|
120
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.transaction)
|
|
121
|
-
Dbg_1.Log.write('╔══', `v${this.stamp}`, `${this.hint}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
bumpBy(timestamp) {
|
|
125
|
-
if (timestamp > this.bumper)
|
|
126
|
-
this.bumper = timestamp;
|
|
127
|
-
}
|
|
128
|
-
rebase() {
|
|
129
|
-
let conflicts = undefined;
|
|
130
|
-
if (this.changeset.size > 0) {
|
|
131
|
-
this.changeset.forEach((r, h) => {
|
|
132
|
-
if (r.former.revision !== h.head) {
|
|
133
|
-
const merged = this.merge(h, r);
|
|
134
|
-
if (r.conflicts.size > 0) {
|
|
135
|
-
if (!conflicts)
|
|
136
|
-
conflicts = [];
|
|
137
|
-
conflicts.push(r);
|
|
138
|
-
}
|
|
139
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.transaction)
|
|
140
|
-
Dbg_1.Log.write('╠╝', '', `${Dump.rev2(h, r.snapshot)} is merged with ${Dump.rev2(h, h.head.snapshot)} among ${merged} properties with ${r.conflicts.size} conflicts.`);
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
if (this.options.token === undefined) {
|
|
144
|
-
if (this.bumper > 100) {
|
|
145
|
-
this.bumper = this.stamp;
|
|
146
|
-
this.stamp = ++Snapshot.stampGen;
|
|
147
|
-
}
|
|
148
|
-
else
|
|
149
|
-
this.stamp = this.bumper + 1;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
this.stamp = this.bumper;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return conflicts;
|
|
156
|
-
}
|
|
157
|
-
merge(h, ours) {
|
|
158
|
-
let counter = 0;
|
|
159
|
-
const head = h.head;
|
|
160
|
-
const headDisposed = head.changes.has(Data_1.Meta.Disposed);
|
|
161
|
-
const merged = Object.assign({}, head.data);
|
|
162
|
-
ours.changes.forEach((o, m) => {
|
|
163
|
-
counter++;
|
|
164
|
-
merged[m] = ours.data[m];
|
|
165
|
-
if (headDisposed || m === Data_1.Meta.Disposed) {
|
|
166
|
-
if (headDisposed !== (m === Data_1.Meta.Disposed)) {
|
|
167
|
-
if (headDisposed || this.options.standalone !== 'disposal') {
|
|
168
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.change)
|
|
169
|
-
Dbg_1.Log.write('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} <> ${Dump.rev2(h, head.snapshot, m)}`, 0, ' *** CONFLICT ***');
|
|
170
|
-
ours.conflicts.set(m, head);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
const conflict = Snapshot.isConflicting(head.data[m], ours.former.revision.data[m]);
|
|
176
|
-
if (conflict)
|
|
177
|
-
ours.conflicts.set(m, head);
|
|
178
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.change)
|
|
179
|
-
Dbg_1.Log.write('║╠', '', `${Dump.rev2(h, ours.snapshot, m)} ${conflict ? '<>' : '=='} ${Dump.rev2(h, head.snapshot, m)}`, 0, conflict ? ' *** CONFLICT ***' : undefined);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
Utils_1.Utils.copyAllMembers(merged, ours.data);
|
|
183
|
-
ours.former.revision = head;
|
|
184
|
-
return counter;
|
|
185
|
-
}
|
|
186
|
-
applyOrDiscard(error) {
|
|
187
|
-
this.sealed = true;
|
|
188
|
-
this.changeset.forEach((r, h) => {
|
|
189
|
-
Snapshot.sealObjectRevision(h, r);
|
|
190
|
-
h.editors--;
|
|
191
|
-
if (h.editors === 0)
|
|
192
|
-
h.editing = undefined;
|
|
193
|
-
if (!error) {
|
|
194
|
-
h.head = r;
|
|
195
|
-
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
196
|
-
Snapshot.totalRevisionCount++;
|
|
197
|
-
if (r.former.revision === exports.ROOT_REV)
|
|
198
|
-
Snapshot.totalHolderCount++;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
if (Dbg_1.Log.isOn) {
|
|
203
|
-
if (Dbg_1.Log.opt.change && !error) {
|
|
204
|
-
this.changeset.forEach((r, h) => {
|
|
205
|
-
const members = [];
|
|
206
|
-
r.changes.forEach((o, m) => members.push(m.toString()));
|
|
207
|
-
const s = members.join(', ');
|
|
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
|
-
});
|
|
210
|
-
}
|
|
211
|
-
if (Dbg_1.Log.opt.transaction)
|
|
212
|
-
Dbg_1.Log.write(this.stamp < exports.UNDEFINED_TIMESTAMP ? '╚══' : '═══', `v${this.stamp}`, `${this.hint} - ${error ? 'CANCEL' : 'APPLY'}(${this.changeset.size})${error ? ` - ${error}` : ''}`);
|
|
213
|
-
}
|
|
214
|
-
if (!error)
|
|
215
|
-
Snapshot.propagateAllChangesThroughSubscriptions(this);
|
|
216
|
-
return this.reactions;
|
|
217
|
-
}
|
|
218
|
-
static sealObjectRevision(h, r) {
|
|
219
|
-
if (!r.changes.has(Data_1.Meta.Disposed))
|
|
220
|
-
r.changes.forEach((o, m) => Snapshot.sealSubscription(r.data[m], m, h.proxy.constructor.name));
|
|
221
|
-
else
|
|
222
|
-
for (const m in r.former.revision.data)
|
|
223
|
-
r.data[m] = Data_1.Meta.Disposed;
|
|
224
|
-
if (Dbg_1.Log.isOn)
|
|
225
|
-
Snapshot.freezeObjectRevision(r);
|
|
226
|
-
}
|
|
227
|
-
static sealSubscription(subscription, m, typeName) {
|
|
228
|
-
if (subscription instanceof Data_1.Subscription) {
|
|
229
|
-
const value = subscription.content;
|
|
230
|
-
if (value !== undefined && value !== null) {
|
|
231
|
-
const sealedType = Object.getPrototypeOf(value)[Sealant_1.Sealant.SealedType];
|
|
232
|
-
if (sealedType)
|
|
233
|
-
subscription.content = Sealant_1.Sealant.seal(value, sealedType, typeName, m);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
static freezeObjectRevision(r) {
|
|
238
|
-
Object.freeze(r.data);
|
|
239
|
-
Utils_1.Utils.freezeSet(r.changes);
|
|
240
|
-
Utils_1.Utils.freezeMap(r.conflicts);
|
|
241
|
-
return r;
|
|
242
|
-
}
|
|
243
|
-
triggerGarbageCollection() {
|
|
244
|
-
if (this.stamp !== 0) {
|
|
245
|
-
if (this === Snapshot.oldest) {
|
|
246
|
-
const p = Snapshot.pending;
|
|
247
|
-
p.sort((a, b) => a.stamp - b.stamp);
|
|
248
|
-
let i = 0;
|
|
249
|
-
while (i < p.length && p[i].sealed) {
|
|
250
|
-
p[i].unlinkHistory();
|
|
251
|
-
i++;
|
|
252
|
-
}
|
|
253
|
-
Snapshot.pending = p.slice(i);
|
|
254
|
-
Snapshot.oldest = Snapshot.pending[0];
|
|
255
|
-
const now = Date.now();
|
|
256
|
-
if (now - Snapshot.lastGarbageCollectionSummaryTimestamp > Snapshot.garbageCollectionSummaryInterval) {
|
|
257
|
-
Dbg_1.Log.write('', '[G]', `Total object/revision count: ${Snapshot.totalHolderCount}/${Snapshot.totalRevisionCount}`);
|
|
258
|
-
Snapshot.lastGarbageCollectionSummaryTimestamp = now;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
unlinkHistory() {
|
|
264
|
-
if (Dbg_1.Log.isOn && Dbg_1.Log.opt.gc)
|
|
265
|
-
Dbg_1.Log.write('', '[G]', `Dismiss history below v${this.stamp}t${this.id} (${this.hint})`);
|
|
266
|
-
this.changeset.forEach((r, h) => {
|
|
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
|
-
if (Snapshot.garbageCollectionSummaryInterval < Number.MAX_SAFE_INTEGER) {
|
|
270
|
-
if (r.former.revision !== exports.ROOT_REV)
|
|
271
|
-
Snapshot.totalRevisionCount--;
|
|
272
|
-
if (r.changes.has(Data_1.Meta.Disposed))
|
|
273
|
-
Snapshot.totalHolderCount--;
|
|
274
|
-
}
|
|
275
|
-
r.former.revision = exports.ROOT_REV;
|
|
276
|
-
});
|
|
277
|
-
this.changeset = EMPTY_MAP;
|
|
278
|
-
this.reactions = EMPTY_ARRAY;
|
|
279
|
-
if (Dbg_1.Log.isOn)
|
|
280
|
-
Object.freeze(this);
|
|
281
|
-
}
|
|
282
|
-
static _init() {
|
|
283
|
-
const boot = exports.ROOT_REV.snapshot;
|
|
284
|
-
boot.acquire(boot);
|
|
285
|
-
boot.applyOrDiscard();
|
|
286
|
-
boot.triggerGarbageCollection();
|
|
287
|
-
Snapshot.freezeObjectRevision(exports.ROOT_REV);
|
|
288
|
-
Snapshot.idGen = 100;
|
|
289
|
-
Snapshot.stampGen = 101;
|
|
290
|
-
Snapshot.oldest = undefined;
|
|
291
|
-
SealedArray_1.SealedArray.prototype;
|
|
292
|
-
SealedMap_1.SealedMap.prototype;
|
|
293
|
-
SealedSet_1.SealedSet.prototype;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
exports.Snapshot = Snapshot;
|
|
297
|
-
Snapshot.idGen = -1;
|
|
298
|
-
Snapshot.stampGen = 1;
|
|
299
|
-
Snapshot.pending = [];
|
|
300
|
-
Snapshot.oldest = undefined;
|
|
301
|
-
Snapshot.garbageCollectionSummaryInterval = Number.MAX_SAFE_INTEGER;
|
|
302
|
-
Snapshot.lastGarbageCollectionSummaryTimestamp = Date.now();
|
|
303
|
-
Snapshot.totalHolderCount = 0;
|
|
304
|
-
Snapshot.totalRevisionCount = 0;
|
|
305
|
-
Snapshot.current = Utils_1.UNDEF;
|
|
306
|
-
Snapshot.edit = Utils_1.UNDEF;
|
|
307
|
-
Snapshot.markUsed = Utils_1.UNDEF;
|
|
308
|
-
Snapshot.markEdited = Utils_1.UNDEF;
|
|
309
|
-
Snapshot.isConflicting = Utils_1.UNDEF;
|
|
310
|
-
Snapshot.propagateAllChangesThroughSubscriptions = (snapshot) => { };
|
|
311
|
-
Snapshot.revokeAllSubscriptions = (snapshot) => { };
|
|
312
|
-
Snapshot.enqueueReactionsToRun = (reactions) => { };
|
|
313
|
-
class Dump {
|
|
314
|
-
static obj(h, m, stamp, snapshotId, originSnapshotId, value) {
|
|
315
|
-
const member = m !== undefined ? `.${m.toString()}` : '';
|
|
316
|
-
return h === undefined
|
|
317
|
-
? `boot${member}`
|
|
318
|
-
: stamp === undefined
|
|
319
|
-
? `${h.hint}${member}${value !== undefined ? `[=${Dump.valueHint(value)}]` : ''} #${h.id}`
|
|
320
|
-
: `${h.hint}${member}${value !== undefined ? `[=${Dump.valueHint(value)}]` : ''} #${h.id}t${snapshotId}v${stamp}${originSnapshotId !== undefined && originSnapshotId !== 0 ? `t${originSnapshotId}` : ''}`;
|
|
321
|
-
}
|
|
322
|
-
static rev2(h, s, m, o) {
|
|
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.content) !== null && _a !== void 0 ? _a : Data_1.Meta.Undefined);
|
|
325
|
-
}
|
|
326
|
-
static rev(r, m) {
|
|
327
|
-
const h = Data_1.Meta.get(r.data, Data_1.Meta.Holder);
|
|
328
|
-
const value = m !== undefined ? r.data[m] : undefined;
|
|
329
|
-
return Dump.obj(h, m, r.snapshot.timestamp, r.snapshot.id, value === null || value === void 0 ? void 0 : value.originSnapshotId);
|
|
330
|
-
}
|
|
331
|
-
static conflicts(conflicts) {
|
|
332
|
-
return conflicts.map(ours => {
|
|
333
|
-
const items = [];
|
|
334
|
-
ours.conflicts.forEach((theirs, m) => {
|
|
335
|
-
items.push(Dump.conflictingMemberHint(m, ours, theirs));
|
|
336
|
-
});
|
|
337
|
-
return items.join(', ');
|
|
338
|
-
}).join(', ');
|
|
339
|
-
}
|
|
340
|
-
static conflictingMemberHint(m, ours, theirs) {
|
|
341
|
-
return `${theirs.snapshot.hint} (${Dump.rev(theirs, m)})`;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
exports.Dump = Dump;
|
|
345
|
-
Dump.valueHint = (value, m) => '???';
|
|
346
|
-
exports.ROOT_REV = new Data_1.DataRevision(new Snapshot({ hint: '<root>' }), undefined, {});
|
|
347
|
-
exports.DefaultSnapshotOptions = Object.freeze({
|
|
348
|
-
hint: 'noname',
|
|
349
|
-
standalone: false,
|
|
350
|
-
journal: undefined,
|
|
351
|
-
logging: undefined,
|
|
352
|
-
token: undefined,
|
|
353
|
-
});
|