reactronic 0.22.210 → 0.22.302
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 +20 -20
- package/build/dist/source/Buffer.d.ts +2 -2
- package/build/dist/source/Buffer.js +1 -1
- package/build/dist/source/Ref.d.ts +1 -1
- package/build/dist/source/Ref.js +1 -1
- package/build/dist/source/Rx.d.ts +1 -1
- package/build/dist/source/Rx.js +4 -4
- package/build/dist/source/api.d.ts +2 -2
- package/build/dist/source/api.js +3 -3
- package/build/dist/source/impl/Data.d.ts +20 -20
- package/build/dist/source/impl/Data.js +12 -12
- package/build/dist/source/impl/Hooks.d.ts +13 -13
- package/build/dist/source/impl/Hooks.js +34 -34
- package/build/dist/source/impl/Journal.d.ts +15 -15
- package/build/dist/source/impl/Journal.js +11 -11
- 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 +8 -8
- package/build/dist/source/impl/Operation.js +40 -40
- package/build/dist/source/impl/Snapshot.d.ts +23 -23
- package/build/dist/source/impl/Snapshot.js +22 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,13 +19,13 @@ isolated data snapshot and then, once atomically applied, are
|
|
|
19
19
|
**consistently propagated** to corresponding visual components for
|
|
20
20
|
(re)rendering. All that is done in automatic, seamless, and fine-grained
|
|
21
21
|
way, because reactronic **takes full care of tracking dependencies**
|
|
22
|
-
between visual components (
|
|
22
|
+
between visual components (subscribers) and state (reactive objects).
|
|
23
23
|
|
|
24
24
|
Transactional reactivity is based on four fundamental concepts:
|
|
25
25
|
|
|
26
|
-
- **
|
|
27
|
-
application (state);
|
|
28
|
-
- **Transaction** - a function that makes changes in
|
|
26
|
+
- **Reactive Objects** - a set of objects that store data of an
|
|
27
|
+
application (state) and maintain subscription lists;
|
|
28
|
+
- **Transaction** - a function that makes changes in reactive
|
|
29
29
|
objects in transactional (atomic) way;
|
|
30
30
|
- **Reaction** - a function that is executed automatically in
|
|
31
31
|
response to changes made by a transaction;
|
|
@@ -39,11 +39,11 @@ Quick introduction and detailed description is below.
|
|
|
39
39
|
|
|
40
40
|
## Quick Introduction
|
|
41
41
|
|
|
42
|
-
Here is an example of transactional reactive code with
|
|
43
|
-
object, transaction and reaction:
|
|
42
|
+
Here is an example of transactional reactive code with
|
|
43
|
+
reactive object, transaction and reaction:
|
|
44
44
|
|
|
45
45
|
``` typescript
|
|
46
|
-
class Demo extends
|
|
46
|
+
class Demo extends ReactiveObject {
|
|
47
47
|
name: string = 'Nezaboodka Software'
|
|
48
48
|
email: string = 'contact@nezaboodka.com'
|
|
49
49
|
|
|
@@ -70,7 +70,7 @@ to changes of these fields made by `saveContact` transaction.
|
|
|
70
70
|
Here is an example of if cached value computed on-demand:
|
|
71
71
|
|
|
72
72
|
``` typescript
|
|
73
|
-
class Demo extends
|
|
73
|
+
class Demo extends ReactiveObject {
|
|
74
74
|
name: string = 'Nezaboodka Software'
|
|
75
75
|
email: string = 'contact@nezaboodka.com'
|
|
76
76
|
|
|
@@ -95,14 +95,14 @@ invalidated, thus causing execution of depending reaction
|
|
|
95
95
|
`printContact`. Then `printContact` reaction causes `contact`
|
|
96
96
|
re-computation on the first use.
|
|
97
97
|
|
|
98
|
-
##
|
|
98
|
+
## Reactive Objects
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
Reactive objects store data of an application. All such objects
|
|
101
101
|
are transparently hooked to track access to their properties,
|
|
102
102
|
both on reads and writes.
|
|
103
103
|
|
|
104
104
|
``` typescript
|
|
105
|
-
class MyModel extends
|
|
105
|
+
class MyModel extends ReactiveObject {
|
|
106
106
|
url: string = "https://github.com/nezaboodka/reactronic"
|
|
107
107
|
content: string = "transactional reactive state management"
|
|
108
108
|
timestamp: Date = Date.now()
|
|
@@ -110,18 +110,18 @@ class MyModel extends ObservableObject {
|
|
|
110
110
|
```
|
|
111
111
|
|
|
112
112
|
In the example above, the class `MyModel` is based on Reactronic's
|
|
113
|
-
`
|
|
113
|
+
`ReactiveObject` class and all its properties `url`, `content`,
|
|
114
114
|
and `timestamp` are hooked.
|
|
115
115
|
|
|
116
116
|
## Transaction
|
|
117
117
|
|
|
118
|
-
Transaction is a function that makes changes in
|
|
118
|
+
Transaction is a function that makes changes in reactive objects
|
|
119
119
|
in transactional (atomic) way. Such a function is instrumented with hooks
|
|
120
120
|
to provide transparent atomicity (by implicit context switching
|
|
121
121
|
and isolation).
|
|
122
122
|
|
|
123
123
|
``` typescript
|
|
124
|
-
class MyModel extends
|
|
124
|
+
class MyModel extends ReactiveObject {
|
|
125
125
|
// ...
|
|
126
126
|
@transaction
|
|
127
127
|
async load(url: string): Promise<void> {
|
|
@@ -164,12 +164,12 @@ of asynchronous operations is fully completed.
|
|
|
164
164
|
## Reaction & Cache
|
|
165
165
|
|
|
166
166
|
Reaction is an code block that is immediately called in response to
|
|
167
|
-
changes made by a transaction in
|
|
167
|
+
changes made by a transaction in reactive objects. Cache is a
|
|
168
168
|
computed value having an associated function that is called
|
|
169
169
|
on-demand to renew the value if it was marked as obsolete due to changes
|
|
170
170
|
made by a transaction. Reactive and cached functions are
|
|
171
171
|
instrumented with hooks to seamlessly subscribe to those
|
|
172
|
-
|
|
172
|
+
reactive objects and other cached functions (dependencies),
|
|
173
173
|
which are used during their execution.
|
|
174
174
|
|
|
175
175
|
``` tsx
|
|
@@ -223,14 +223,14 @@ function enqueues re-rendering request to React, which calls
|
|
|
223
223
|
`render` function causing it to renew its cached value.
|
|
224
224
|
|
|
225
225
|
In general case, all reactions and caches are automatically and
|
|
226
|
-
immediately marked as obsolete when changes are made in those
|
|
226
|
+
immediately marked as obsolete when changes are made in those reactive
|
|
227
227
|
objects and cached functions that were used during their execution.
|
|
228
228
|
And once marked, the functions are automatically executed again,
|
|
229
229
|
either immediately (for @reactive functions) or on-demand
|
|
230
230
|
(for @cached functions).
|
|
231
231
|
|
|
232
232
|
Reactronic takes full care of tracking dependencies between
|
|
233
|
-
all the
|
|
233
|
+
all the reactive objects and reactions/caches.
|
|
234
234
|
With Reactronic, you no longer need to create data change events
|
|
235
235
|
in one set of objects, subscribe to these events in other objects,
|
|
236
236
|
and manually maintain switching from the previous object version
|
|
@@ -292,11 +292,11 @@ NPM: `npm install reactronic`
|
|
|
292
292
|
|
|
293
293
|
// Classes
|
|
294
294
|
|
|
295
|
-
class
|
|
295
|
+
class ReactiveObject { }
|
|
296
296
|
|
|
297
297
|
// Decorators & Operators
|
|
298
298
|
|
|
299
|
-
function
|
|
299
|
+
function isnonreactive(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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare abstract class Buffer<T> extends
|
|
1
|
+
import { ReactiveObject } from './impl/Hooks';
|
|
2
|
+
export declare abstract class Buffer<T> extends ReactiveObject {
|
|
3
3
|
abstract readonly capacity: number;
|
|
4
4
|
abstract readonly count: number;
|
|
5
5
|
abstract put(...items: T[]): void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Buffer = void 0;
|
|
4
4
|
const Hooks_1 = require("./impl/Hooks");
|
|
5
|
-
class Buffer extends Hooks_1.
|
|
5
|
+
class Buffer extends Hooks_1.ReactiveObject {
|
|
6
6
|
static create(hint, capacity) { throw new Error('not implemented'); }
|
|
7
7
|
}
|
|
8
8
|
exports.Buffer = Buffer;
|
|
@@ -11,7 +11,7 @@ export declare class Ref<T = any> {
|
|
|
11
11
|
constructor(owner: any, name: string, index?: number);
|
|
12
12
|
get value(): T;
|
|
13
13
|
set value(value: T);
|
|
14
|
-
|
|
14
|
+
nonreactive(): T;
|
|
15
15
|
observe(): T;
|
|
16
16
|
unobserve(): T;
|
|
17
17
|
static to<O extends object = object>(owner: O): {
|
package/build/dist/source/Ref.js
CHANGED
|
@@ -19,7 +19,7 @@ export declare class Rx {
|
|
|
19
19
|
}
|
|
20
20
|
export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
|
|
21
21
|
export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
22
|
-
export declare function
|
|
22
|
+
export declare function isnonreactive(proto: object, prop: PropertyKey): any;
|
|
23
23
|
export declare function transaction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
24
24
|
export declare function reaction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
25
25
|
export declare function cached(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
package/build/dist/source/Rx.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.
|
|
3
|
+
exports.options = exports.cached = exports.reaction = exports.transaction = exports.isnonreactive = exports.sensitive = exports.nonreactive = exports.Rx = void 0;
|
|
4
4
|
const Dbg_1 = require("./util/Dbg");
|
|
5
5
|
const Options_1 = require("./Options");
|
|
6
6
|
const Data_1 = require("./impl/Data");
|
|
@@ -20,7 +20,7 @@ class Rx {
|
|
|
20
20
|
static get loggingOptions() { return Dbg_1.Log.opt; }
|
|
21
21
|
static setLoggingMode(isOn, options) { Dbg_1.Log.setMode(isOn, options); }
|
|
22
22
|
static setLoggingHint(obj, name) { Hooks_1.Hooks.setHint(obj, name); }
|
|
23
|
-
static getLoggingHint(obj, full = false) { return Data_1.
|
|
23
|
+
static getLoggingHint(obj, full = false) { return Data_1.DataHolder.getHint(obj, full); }
|
|
24
24
|
static setProfilingMode(isOn, options) { Hooks_1.Hooks.setProfilingMode(isOn, options); }
|
|
25
25
|
}
|
|
26
26
|
exports.Rx = Rx;
|
|
@@ -32,10 +32,10 @@ function sensitive(sensitivity, func, ...args) {
|
|
|
32
32
|
return Hooks_1.Hooks.sensitive(sensitivity, func, ...args);
|
|
33
33
|
}
|
|
34
34
|
exports.sensitive = sensitive;
|
|
35
|
-
function
|
|
35
|
+
function isnonreactive(proto, prop) {
|
|
36
36
|
return Hooks_1.Hooks.decorateData(false, proto, prop);
|
|
37
37
|
}
|
|
38
|
-
exports.
|
|
38
|
+
exports.isnonreactive = isnonreactive;
|
|
39
39
|
function transaction(proto, prop, pd) {
|
|
40
40
|
const opts = { kind: Options_1.Kind.Transaction };
|
|
41
41
|
return Hooks_1.Hooks.decorateOperation(true, transaction, opts, proto, prop, pd);
|
|
@@ -6,9 +6,9 @@ export { MemberOptions, SnapshotOptions, Kind, Reentrance, LoggingOptions, Profi
|
|
|
6
6
|
export { Worker } from './Worker';
|
|
7
7
|
export { Controller } from './Controller';
|
|
8
8
|
export { Ref, ToggleRef, BoolOnly, GivenTypeOnly } from './Ref';
|
|
9
|
-
export {
|
|
9
|
+
export { ReactiveObject } 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
13
|
export { Journal } from './impl/Journal';
|
|
14
|
-
export { Rx, nonreactive, sensitive,
|
|
14
|
+
export { Rx, nonreactive, sensitive, isnonreactive, 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.
|
|
3
|
+
exports.options = exports.cached = exports.reaction = exports.transaction = exports.isnonreactive = exports.sensitive = exports.nonreactive = exports.Rx = exports.Journal = exports.Monitor = exports.Transaction = exports.Snapshot = exports.ReactiveObject = 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; } });
|
|
@@ -20,7 +20,7 @@ var Ref_1 = require("./Ref");
|
|
|
20
20
|
Object.defineProperty(exports, "Ref", { enumerable: true, get: function () { return Ref_1.Ref; } });
|
|
21
21
|
Object.defineProperty(exports, "ToggleRef", { enumerable: true, get: function () { return Ref_1.ToggleRef; } });
|
|
22
22
|
var Hooks_1 = require("./impl/Hooks");
|
|
23
|
-
Object.defineProperty(exports, "
|
|
23
|
+
Object.defineProperty(exports, "ReactiveObject", { enumerable: true, get: function () { return Hooks_1.ReactiveObject; } });
|
|
24
24
|
var Snapshot_1 = require("./impl/Snapshot");
|
|
25
25
|
Object.defineProperty(exports, "Snapshot", { enumerable: true, get: function () { return Snapshot_1.Snapshot; } });
|
|
26
26
|
var Transaction_1 = require("./impl/Transaction");
|
|
@@ -33,7 +33,7 @@ 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; } });
|
|
35
35
|
Object.defineProperty(exports, "sensitive", { enumerable: true, get: function () { return Rx_1.sensitive; } });
|
|
36
|
-
Object.defineProperty(exports, "
|
|
36
|
+
Object.defineProperty(exports, "isnonreactive", { enumerable: true, get: function () { return Rx_1.isnonreactive; } });
|
|
37
37
|
Object.defineProperty(exports, "transaction", { enumerable: true, get: function () { return Rx_1.transaction; } });
|
|
38
38
|
Object.defineProperty(exports, "reaction", { enumerable: true, get: function () { return Rx_1.reaction; } });
|
|
39
39
|
Object.defineProperty(exports, "cached", { enumerable: true, get: function () { return Rx_1.cached; } });
|
|
@@ -5,54 +5,54 @@ export interface AbstractSnapshot {
|
|
|
5
5
|
readonly timestamp: number;
|
|
6
6
|
readonly sealed: boolean;
|
|
7
7
|
}
|
|
8
|
-
export declare class
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
export declare class Subscription {
|
|
9
|
+
content: any;
|
|
10
|
+
subscribers?: Set<Subscriber>;
|
|
11
11
|
get isOperation(): boolean;
|
|
12
12
|
get originSnapshotId(): number | undefined;
|
|
13
|
-
constructor(
|
|
13
|
+
constructor(content: any);
|
|
14
14
|
}
|
|
15
15
|
export declare type StandaloneMode = boolean | 'isolated' | 'disposal';
|
|
16
|
-
export interface
|
|
16
|
+
export interface Subscriber {
|
|
17
17
|
readonly order: number;
|
|
18
|
-
readonly
|
|
18
|
+
readonly subscriptions: Map<Subscription, SubscriptionInfo> | undefined;
|
|
19
19
|
readonly obsoleteSince: number;
|
|
20
20
|
hint(nop?: boolean): string;
|
|
21
|
-
markObsoleteDueTo(
|
|
21
|
+
markObsoleteDueTo(subscription: Subscription, memberName: MemberName, snapshot: AbstractSnapshot, holder: DataHolder, outer: string, since: number, reactions: Array<Subscriber>): void;
|
|
22
22
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
23
23
|
}
|
|
24
24
|
export declare type MemberName = PropertyKey;
|
|
25
|
-
export interface
|
|
25
|
+
export interface SubscriptionInfo {
|
|
26
26
|
readonly memberHint: string;
|
|
27
27
|
readonly usageCount: number;
|
|
28
28
|
}
|
|
29
|
-
export declare class
|
|
29
|
+
export declare class DataRevision {
|
|
30
30
|
readonly snapshot: AbstractSnapshot;
|
|
31
31
|
readonly former: {
|
|
32
|
-
revision:
|
|
32
|
+
revision: DataRevision;
|
|
33
33
|
};
|
|
34
34
|
readonly data: any;
|
|
35
35
|
readonly changes: Set<MemberName>;
|
|
36
|
-
readonly conflicts: Map<MemberName,
|
|
37
|
-
constructor(snapshot: AbstractSnapshot, former:
|
|
36
|
+
readonly conflicts: Map<MemberName, DataRevision>;
|
|
37
|
+
constructor(snapshot: AbstractSnapshot, former: DataRevision | undefined, data: object);
|
|
38
38
|
}
|
|
39
|
-
export declare class
|
|
39
|
+
export declare class DataHolder {
|
|
40
40
|
private static generator;
|
|
41
41
|
readonly id: number;
|
|
42
|
-
readonly
|
|
42
|
+
readonly data: any;
|
|
43
43
|
readonly proxy: any;
|
|
44
|
-
head:
|
|
45
|
-
editing?:
|
|
44
|
+
head: DataRevision;
|
|
45
|
+
editing?: DataRevision;
|
|
46
46
|
editors: number;
|
|
47
47
|
hint: string;
|
|
48
|
-
constructor(
|
|
48
|
+
constructor(data: any, proxy: any, handler: ProxyHandler<DataHolder>, head: DataRevision, hint: string);
|
|
49
49
|
static getHint(obj: object, full: boolean): string | undefined;
|
|
50
50
|
}
|
|
51
|
-
export interface
|
|
51
|
+
export interface PatchSet {
|
|
52
52
|
hint: string;
|
|
53
|
-
objects: Map<object,
|
|
53
|
+
objects: Map<object, DataPatch>;
|
|
54
54
|
}
|
|
55
|
-
export interface
|
|
55
|
+
export interface DataPatch {
|
|
56
56
|
data: any;
|
|
57
57
|
former: any;
|
|
58
58
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.DataHolder = exports.DataRevision = exports.Subscription = exports.Meta = void 0;
|
|
4
4
|
const Dbg_1 = require("../util/Dbg");
|
|
5
5
|
const Meta_1 = require("./Meta");
|
|
6
6
|
var Meta_2 = require("./Meta");
|
|
7
7
|
Object.defineProperty(exports, "Meta", { enumerable: true, get: function () { return Meta_2.Meta; } });
|
|
8
|
-
class
|
|
9
|
-
constructor(
|
|
8
|
+
class Subscription {
|
|
9
|
+
constructor(content) { this.content = content; }
|
|
10
10
|
get isOperation() { return false; }
|
|
11
11
|
get originSnapshotId() { return 0; }
|
|
12
12
|
}
|
|
13
|
-
exports.
|
|
14
|
-
class
|
|
13
|
+
exports.Subscription = Subscription;
|
|
14
|
+
class DataRevision {
|
|
15
15
|
constructor(snapshot, former, data) {
|
|
16
16
|
this.snapshot = snapshot;
|
|
17
17
|
this.former = { revision: former || this };
|
|
@@ -22,11 +22,11 @@ class ObjectRevision {
|
|
|
22
22
|
Object.freeze(this);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
exports.
|
|
26
|
-
class
|
|
27
|
-
constructor(
|
|
28
|
-
this.id = ++
|
|
29
|
-
this.
|
|
25
|
+
exports.DataRevision = DataRevision;
|
|
26
|
+
class DataHolder {
|
|
27
|
+
constructor(data, proxy, handler, head, hint) {
|
|
28
|
+
this.id = ++DataHolder.generator;
|
|
29
|
+
this.data = data;
|
|
30
30
|
this.proxy = proxy || new Proxy(this, handler);
|
|
31
31
|
this.head = head;
|
|
32
32
|
this.editing = undefined;
|
|
@@ -38,5 +38,5 @@ class ObjectHolder {
|
|
|
38
38
|
return h !== undefined ? (full ? `${h.hint}#${h.id}` : h.hint) : undefined;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
exports.
|
|
42
|
-
|
|
41
|
+
exports.DataHolder = DataHolder;
|
|
42
|
+
DataHolder.generator = 19;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { F } from '../util/Utils';
|
|
2
2
|
import { MemberOptions, Kind, Reentrance } from '../Options';
|
|
3
3
|
import { LoggingOptions, ProfilingOptions } from '../Logging';
|
|
4
|
-
import { MemberName,
|
|
4
|
+
import { MemberName, DataHolder, StandaloneMode } from './Data';
|
|
5
5
|
import { Journal } from './Journal';
|
|
6
6
|
import { Monitor } from './Monitor';
|
|
7
|
-
export declare abstract class
|
|
7
|
+
export declare abstract class ReactiveObject {
|
|
8
8
|
constructor();
|
|
9
9
|
[Symbol.toStringTag](): string;
|
|
10
10
|
}
|
|
@@ -24,27 +24,27 @@ export declare class OptionsImpl implements MemberOptions {
|
|
|
24
24
|
static readonly INITIAL: Readonly<OptionsImpl>;
|
|
25
25
|
constructor(getter: Function | undefined, setter: Function | undefined, existing: OptionsImpl, patch: Partial<OptionsImpl>, implicit: boolean);
|
|
26
26
|
}
|
|
27
|
-
export declare class Hooks implements ProxyHandler<
|
|
27
|
+
export declare class Hooks implements ProxyHandler<DataHolder> {
|
|
28
28
|
static reactionsAutoStartDisabled: boolean;
|
|
29
29
|
static repetitiveUsageWarningThreshold: number;
|
|
30
30
|
static mainThreadBlockingWarningThreshold: number;
|
|
31
31
|
static asyncActionDurationWarningThreshold: number;
|
|
32
32
|
static sensitivity: boolean;
|
|
33
33
|
static readonly proxy: Hooks;
|
|
34
|
-
getPrototypeOf(h:
|
|
35
|
-
get(h:
|
|
36
|
-
set(h:
|
|
37
|
-
has(h:
|
|
38
|
-
getOwnPropertyDescriptor(h:
|
|
39
|
-
ownKeys(h:
|
|
40
|
-
static decorateData(
|
|
34
|
+
getPrototypeOf(h: DataHolder): object | null;
|
|
35
|
+
get(h: DataHolder, m: MemberName, receiver: any): any;
|
|
36
|
+
set(h: DataHolder, m: MemberName, value: any, receiver: any): boolean;
|
|
37
|
+
has(h: DataHolder, m: MemberName): boolean;
|
|
38
|
+
getOwnPropertyDescriptor(h: DataHolder, m: MemberName): PropertyDescriptor | undefined;
|
|
39
|
+
ownKeys(h: DataHolder): Array<string | symbol>;
|
|
40
|
+
static decorateData(reactive: boolean, proto: any, m: MemberName): any;
|
|
41
41
|
static decorateOperation(implicit: boolean, decorator: Function, options: Partial<MemberOptions>, proto: any, member: MemberName, pd: PropertyDescriptor | undefined): any;
|
|
42
42
|
static decorateOperationParametrized(decorator: Function, options: Partial<MemberOptions>): F<any>;
|
|
43
|
-
static
|
|
44
|
-
static
|
|
43
|
+
static acquireDataHolder(obj: any): DataHolder;
|
|
44
|
+
static createDataHolderForReactiveObject(proto: any, data: any, blank: any, hint: string): DataHolder;
|
|
45
45
|
static setProfilingMode(isOn: boolean, options?: Partial<ProfilingOptions>): void;
|
|
46
46
|
static sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
47
47
|
static setHint<T>(obj: T, hint: string | undefined): T;
|
|
48
|
-
static createOperation: (h:
|
|
48
|
+
static createOperation: (h: DataHolder, m: MemberName, options: OptionsImpl) => F<any>;
|
|
49
49
|
static rememberOperationOptions: (proto: any, m: MemberName, getter: Function | undefined, setter: Function | undefined, enumerable: boolean, configurable: boolean, options: Partial<MemberOptions>, implicit: boolean) => OptionsImpl;
|
|
50
50
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Hooks = exports.OptionsImpl = exports.
|
|
3
|
+
exports.Hooks = exports.OptionsImpl = exports.ReactiveObject = void 0;
|
|
4
4
|
const Utils_1 = require("../util/Utils");
|
|
5
5
|
const Dbg_1 = require("../util/Dbg");
|
|
6
6
|
const Options_1 = require("../Options");
|
|
7
7
|
const Data_1 = require("./Data");
|
|
8
8
|
const Snapshot_1 = require("./Snapshot");
|
|
9
|
-
class
|
|
9
|
+
class ReactiveObject {
|
|
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.
|
|
13
|
+
const h = Hooks.createDataHolderForReactiveObject(proto, this, initial, new.target.name);
|
|
14
14
|
return h.proxy;
|
|
15
15
|
}
|
|
16
16
|
[Symbol.toStringTag]() {
|
|
@@ -18,7 +18,7 @@ class ObservableObject {
|
|
|
18
18
|
return Snapshot_1.Dump.obj(h);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
exports.
|
|
21
|
+
exports.ReactiveObject = ReactiveObject;
|
|
22
22
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
23
23
|
kind: Options_1.Kind.Plain,
|
|
24
24
|
standalone: false,
|
|
@@ -56,49 +56,49 @@ function merge(def, existing, patch, implicit) {
|
|
|
56
56
|
}
|
|
57
57
|
class Hooks {
|
|
58
58
|
getPrototypeOf(h) {
|
|
59
|
-
return Reflect.getPrototypeOf(h.
|
|
59
|
+
return Reflect.getPrototypeOf(h.data);
|
|
60
60
|
}
|
|
61
61
|
get(h, m, receiver) {
|
|
62
62
|
let result;
|
|
63
63
|
const r = Snapshot_1.Snapshot.current().getCurrentRevision(h, m);
|
|
64
64
|
result = r.data[m];
|
|
65
|
-
if (result instanceof Data_1.
|
|
65
|
+
if (result instanceof Data_1.Subscription && !result.isOperation) {
|
|
66
66
|
Snapshot_1.Snapshot.markUsed(result, r, m, h, Options_1.Kind.Plain, false);
|
|
67
|
-
result = result.
|
|
67
|
+
result = result.content;
|
|
68
68
|
}
|
|
69
69
|
else if (m === Data_1.Meta.Holder) {
|
|
70
70
|
}
|
|
71
71
|
else
|
|
72
|
-
result = Reflect.get(h.
|
|
72
|
+
result = Reflect.get(h.data, m, receiver);
|
|
73
73
|
return result;
|
|
74
74
|
}
|
|
75
75
|
set(h, m, value, receiver) {
|
|
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.former.revision.snapshot === Snapshot_1.ROOT_REV.snapshot && (m in h.
|
|
80
|
-
if (curr === undefined || curr.
|
|
81
|
-
const
|
|
79
|
+
if (curr !== undefined || (r.former.revision.snapshot === Snapshot_1.ROOT_REV.snapshot && (m in h.data) === false)) {
|
|
80
|
+
if (curr === undefined || curr.content !== value || Hooks.sensitivity) {
|
|
81
|
+
const existing = curr === null || curr === void 0 ? void 0 : curr.content;
|
|
82
82
|
if (r.former.revision.data[m] === curr) {
|
|
83
|
-
curr = r.data[m] = new Data_1.
|
|
84
|
-
Snapshot_1.Snapshot.markEdited(
|
|
83
|
+
curr = r.data[m] = new Data_1.Subscription(value);
|
|
84
|
+
Snapshot_1.Snapshot.markEdited(existing, value, true, r, m, h);
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
|
-
curr.
|
|
88
|
-
Snapshot_1.Snapshot.markEdited(
|
|
87
|
+
curr.content = value;
|
|
88
|
+
Snapshot_1.Snapshot.markEdited(existing, value, true, r, m, h);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
else
|
|
93
|
-
Reflect.set(h.
|
|
93
|
+
Reflect.set(h.data, m, value, receiver);
|
|
94
94
|
}
|
|
95
95
|
else
|
|
96
|
-
h.
|
|
96
|
+
h.data[m] = value;
|
|
97
97
|
return true;
|
|
98
98
|
}
|
|
99
99
|
has(h, m) {
|
|
100
100
|
const r = Snapshot_1.Snapshot.current().getCurrentRevision(h, m);
|
|
101
|
-
return m in r.data || m in h.
|
|
101
|
+
return m in r.data || m in h.data;
|
|
102
102
|
}
|
|
103
103
|
getOwnPropertyDescriptor(h, m) {
|
|
104
104
|
const r = Snapshot_1.Snapshot.current().getCurrentRevision(h, m);
|
|
@@ -112,19 +112,19 @@ class Hooks {
|
|
|
112
112
|
const result = [];
|
|
113
113
|
for (const m of Object.getOwnPropertyNames(r.data)) {
|
|
114
114
|
const value = r.data[m];
|
|
115
|
-
if (!(value instanceof Data_1.
|
|
115
|
+
if (!(value instanceof Data_1.Subscription) || !value.isOperation)
|
|
116
116
|
result.push(m);
|
|
117
117
|
}
|
|
118
118
|
return result;
|
|
119
119
|
}
|
|
120
|
-
static decorateData(
|
|
121
|
-
if (
|
|
120
|
+
static decorateData(reactive, proto, m) {
|
|
121
|
+
if (reactive) {
|
|
122
122
|
const get = function () {
|
|
123
|
-
const h = Hooks.
|
|
123
|
+
const h = Hooks.acquireDataHolder(this);
|
|
124
124
|
return Hooks.proxy.get(h, m, this);
|
|
125
125
|
};
|
|
126
126
|
const set = function (value) {
|
|
127
|
-
const h = Hooks.
|
|
127
|
+
const h = Hooks.acquireDataHolder(this);
|
|
128
128
|
return Hooks.proxy.set(h, m, value, this);
|
|
129
129
|
};
|
|
130
130
|
const enumerable = true;
|
|
@@ -132,7 +132,7 @@ class Hooks {
|
|
|
132
132
|
return Object.defineProperty(proto, m, { get, set, enumerable, configurable });
|
|
133
133
|
}
|
|
134
134
|
else
|
|
135
|
-
Data_1.Meta.acquire(proto, Data_1.Meta.Initial)[m] = Data_1.Meta.
|
|
135
|
+
Data_1.Meta.acquire(proto, Data_1.Meta.Initial)[m] = Data_1.Meta.Nonreactive;
|
|
136
136
|
}
|
|
137
137
|
static decorateOperation(implicit, decorator, options, proto, member, pd) {
|
|
138
138
|
var _a, _b, _c, _d;
|
|
@@ -143,18 +143,18 @@ class Hooks {
|
|
|
143
143
|
const opts = Hooks.rememberOperationOptions(proto, member, (_c = pd.value) !== null && _c !== void 0 ? _c : pd.get, (_d = pd.value) !== null && _d !== void 0 ? _d : pd.set, true, configurable, options, implicit);
|
|
144
144
|
if (opts.getter === opts.setter) {
|
|
145
145
|
const bootstrap = function () {
|
|
146
|
-
const h = Hooks.
|
|
146
|
+
const h = Hooks.acquireDataHolder(this);
|
|
147
147
|
const operation = Hooks.createOperation(h, member, opts);
|
|
148
|
-
Object.defineProperty(h.
|
|
148
|
+
Object.defineProperty(h.data, member, { value: operation, enumerable, configurable });
|
|
149
149
|
return operation;
|
|
150
150
|
};
|
|
151
151
|
return Object.defineProperty(proto, member, { get: bootstrap, enumerable, configurable: true });
|
|
152
152
|
}
|
|
153
153
|
else if (opts.setter === Utils_1.UNDEF) {
|
|
154
154
|
const bootstrap = function () {
|
|
155
|
-
const h = Hooks.
|
|
155
|
+
const h = Hooks.acquireDataHolder(this);
|
|
156
156
|
const operation = Hooks.createOperation(h, member, opts);
|
|
157
|
-
Object.defineProperty(h.
|
|
157
|
+
Object.defineProperty(h.data, member, { get: operation, enumerable, configurable });
|
|
158
158
|
return operation.call(this);
|
|
159
159
|
};
|
|
160
160
|
return Object.defineProperty(proto, member, { get: bootstrap, enumerable, configurable: true });
|
|
@@ -167,22 +167,22 @@ class Hooks {
|
|
|
167
167
|
return Hooks.decorateOperation(false, decorator, options, proto, prop, pd);
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
|
-
static
|
|
170
|
+
static acquireDataHolder(obj) {
|
|
171
171
|
let h = obj[Data_1.Meta.Holder];
|
|
172
172
|
if (!h) {
|
|
173
173
|
if (obj !== Object(obj) || Array.isArray(obj))
|
|
174
174
|
throw (0, Dbg_1.misuse)('only objects can be reactive');
|
|
175
175
|
const initial = Data_1.Meta.getFrom(Object.getPrototypeOf(obj), Data_1.Meta.Initial);
|
|
176
|
-
const rev = new Data_1.
|
|
176
|
+
const rev = new Data_1.DataRevision(Snapshot_1.ROOT_REV.snapshot, Snapshot_1.ROOT_REV, Object.assign({}, initial));
|
|
177
177
|
Data_1.Meta.set(rev.data, Data_1.Meta.Holder, h);
|
|
178
|
-
h = new Data_1.
|
|
178
|
+
h = new Data_1.DataHolder(obj, obj, Hooks.proxy, rev, obj.constructor.name);
|
|
179
179
|
Data_1.Meta.set(obj, Data_1.Meta.Holder, h);
|
|
180
180
|
}
|
|
181
181
|
return h;
|
|
182
182
|
}
|
|
183
|
-
static
|
|
183
|
+
static createDataHolderForReactiveObject(proto, data, blank, hint) {
|
|
184
184
|
const ctx = Snapshot_1.Snapshot.edit();
|
|
185
|
-
const h = new Data_1.
|
|
185
|
+
const h = new Data_1.DataHolder(data, undefined, Hooks.proxy, Snapshot_1.ROOT_REV, hint);
|
|
186
186
|
ctx.getEditableRevision(h, Data_1.Meta.Holder, blank);
|
|
187
187
|
if (!Hooks.reactionsAutoStartDisabled)
|
|
188
188
|
for (const m in Data_1.Meta.getFrom(proto, Data_1.Meta.Reactions))
|
|
@@ -215,7 +215,7 @@ class Hooks {
|
|
|
215
215
|
}
|
|
216
216
|
static setHint(obj, hint) {
|
|
217
217
|
if (hint) {
|
|
218
|
-
const h = Hooks.
|
|
218
|
+
const h = Hooks.acquireDataHolder(obj);
|
|
219
219
|
h.hint = hint;
|
|
220
220
|
}
|
|
221
221
|
return obj;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export declare type Saver = (patch:
|
|
4
|
-
export declare abstract class Journal extends
|
|
1
|
+
import { ReactiveObject } from './Hooks';
|
|
2
|
+
import { DataHolder, DataRevision, PatchSet } from './Data';
|
|
3
|
+
export declare type Saver = (patch: PatchSet) => Promise<void>;
|
|
4
|
+
export declare abstract class Journal extends ReactiveObject {
|
|
5
5
|
abstract capacity: number;
|
|
6
|
-
abstract readonly edits: ReadonlyArray<
|
|
7
|
-
abstract readonly unsaved:
|
|
6
|
+
abstract readonly edits: ReadonlyArray<PatchSet>;
|
|
7
|
+
abstract readonly unsaved: PatchSet;
|
|
8
8
|
abstract readonly canUndo: boolean;
|
|
9
9
|
abstract readonly canRedo: boolean;
|
|
10
|
-
abstract edited(patch:
|
|
11
|
-
abstract saved(patch:
|
|
10
|
+
abstract edited(patch: PatchSet): void;
|
|
11
|
+
abstract saved(patch: PatchSet): void;
|
|
12
12
|
abstract undo(count?: number): void;
|
|
13
13
|
abstract redo(count?: number): void;
|
|
14
14
|
static create(): Journal;
|
|
@@ -20,15 +20,15 @@ export declare class JournalImpl extends Journal {
|
|
|
20
20
|
private _position;
|
|
21
21
|
get capacity(): number;
|
|
22
22
|
set capacity(value: number);
|
|
23
|
-
get edits(): ReadonlyArray<
|
|
24
|
-
get unsaved():
|
|
23
|
+
get edits(): ReadonlyArray<PatchSet>;
|
|
24
|
+
get unsaved(): PatchSet;
|
|
25
25
|
get canUndo(): boolean;
|
|
26
26
|
get canRedo(): boolean;
|
|
27
|
-
edited(p:
|
|
28
|
-
saved(patch:
|
|
27
|
+
edited(p: PatchSet): void;
|
|
28
|
+
saved(patch: PatchSet): void;
|
|
29
29
|
undo(count?: number): void;
|
|
30
30
|
redo(count?: number): void;
|
|
31
|
-
static buildPatch(hint: string, changeset: Map<
|
|
32
|
-
static applyPatch(patch:
|
|
33
|
-
mergePatchToUnsaved(patch:
|
|
31
|
+
static buildPatch(hint: string, changeset: Map<DataHolder, DataRevision>): PatchSet;
|
|
32
|
+
static applyPatch(patch: PatchSet, undoing: boolean): void;
|
|
33
|
+
mergePatchToUnsaved(patch: PatchSet, undoing: boolean): void;
|
|
34
34
|
}
|
|
@@ -6,7 +6,7 @@ const Data_1 = require("./Data");
|
|
|
6
6
|
const Snapshot_1 = require("./Snapshot");
|
|
7
7
|
const Transaction_1 = require("./Transaction");
|
|
8
8
|
const Sealant_1 = require("../util/Sealant");
|
|
9
|
-
class Journal extends Hooks_1.
|
|
9
|
+
class Journal extends Hooks_1.ReactiveObject {
|
|
10
10
|
static create() { return new JournalImpl(); }
|
|
11
11
|
}
|
|
12
12
|
exports.Journal = Journal;
|
|
@@ -87,17 +87,17 @@ class JournalImpl extends Journal {
|
|
|
87
87
|
}
|
|
88
88
|
static applyPatch(patch, undoing) {
|
|
89
89
|
const ctx = Snapshot_1.Snapshot.edit();
|
|
90
|
-
patch.objects.forEach((
|
|
90
|
+
patch.objects.forEach((dp, obj) => {
|
|
91
91
|
const h = Data_1.Meta.get(obj, Data_1.Meta.Holder);
|
|
92
|
-
const data = undoing ?
|
|
92
|
+
const data = undoing ? dp.former : dp.data;
|
|
93
93
|
if (data[Data_1.Meta.Disposed] === undefined) {
|
|
94
94
|
for (const m in data) {
|
|
95
95
|
const value = data[m];
|
|
96
96
|
const r = ctx.getEditableRevision(h, m, value);
|
|
97
97
|
if (r.snapshot === ctx) {
|
|
98
|
-
r.data[m] = new Data_1.
|
|
99
|
-
const
|
|
100
|
-
Snapshot_1.Snapshot.markEdited(
|
|
98
|
+
r.data[m] = new Data_1.Subscription(value);
|
|
99
|
+
const existing = r.former.revision.data[m];
|
|
100
|
+
Snapshot_1.Snapshot.markEdited(existing, value, existing !== value, r, m, h);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
}
|
|
@@ -107,12 +107,12 @@ class JournalImpl extends Journal {
|
|
|
107
107
|
}
|
|
108
108
|
mergePatchToUnsaved(patch, undoing) {
|
|
109
109
|
const unsaved = this._unsaved;
|
|
110
|
-
patch.objects.forEach((
|
|
110
|
+
patch.objects.forEach((dp, obj) => {
|
|
111
111
|
let merged = unsaved.objects.get(obj);
|
|
112
112
|
if (!merged)
|
|
113
113
|
unsaved.objects.set(obj, merged = { data: {}, former: {} });
|
|
114
|
-
const data = undoing ?
|
|
115
|
-
const former = undoing ?
|
|
114
|
+
const data = undoing ? dp.former : dp.data;
|
|
115
|
+
const former = undoing ? dp.data : dp.former;
|
|
116
116
|
for (const m in data) {
|
|
117
117
|
const value = data[m];
|
|
118
118
|
if (value !== merged.former[m]) {
|
|
@@ -131,8 +131,8 @@ class JournalImpl extends Journal {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
exports.JournalImpl = JournalImpl;
|
|
134
|
-
function unseal(
|
|
135
|
-
const result =
|
|
134
|
+
function unseal(subscription) {
|
|
135
|
+
const result = subscription.content;
|
|
136
136
|
const createCopy = result === null || result === void 0 ? void 0 : result[Sealant_1.Sealant.CreateCopy];
|
|
137
137
|
return createCopy !== undefined ? createCopy.call(result) : result;
|
|
138
138
|
}
|
|
@@ -4,7 +4,7 @@ export declare abstract class Meta {
|
|
|
4
4
|
static readonly Disposed: unique symbol;
|
|
5
5
|
static readonly Initial: unique symbol;
|
|
6
6
|
static readonly Reactions: unique symbol;
|
|
7
|
-
static readonly
|
|
7
|
+
static readonly Nonreactive: unique symbol;
|
|
8
8
|
static readonly Undefined: unique symbol;
|
|
9
9
|
static get<T>(obj: any, sym: symbol): T;
|
|
10
10
|
static set(obj: any, sym: symbol, value: any): any;
|
|
@@ -29,5 +29,5 @@ Meta.Controller = Symbol('rxController');
|
|
|
29
29
|
Meta.Disposed = Symbol('rxDisposed');
|
|
30
30
|
Meta.Initial = Symbol('rxInitial');
|
|
31
31
|
Meta.Reactions = Symbol('rxReactions');
|
|
32
|
-
Meta.
|
|
32
|
+
Meta.Nonreactive = Symbol('rxNonreactive');
|
|
33
33
|
Meta.Undefined = Symbol('rxUndefined');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Worker } from '../Worker';
|
|
2
|
-
import {
|
|
3
|
-
export declare abstract class Monitor extends
|
|
2
|
+
import { ReactiveObject } from './Hooks';
|
|
3
|
+
export declare abstract class Monitor extends ReactiveObject {
|
|
4
4
|
abstract readonly isActive: boolean;
|
|
5
5
|
abstract readonly counter: number;
|
|
6
6
|
abstract readonly workers: ReadonlySet<Worker>;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MonitorImpl = exports.Monitor = void 0;
|
|
4
4
|
const Hooks_1 = require("./Hooks");
|
|
5
5
|
const Transaction_1 = require("./Transaction");
|
|
6
|
-
class Monitor extends Hooks_1.
|
|
6
|
+
class Monitor extends Hooks_1.ReactiveObject {
|
|
7
7
|
static create(hint, activationDelay, deactivationDelay, durationResolution) {
|
|
8
8
|
return MonitorImpl.create(hint, activationDelay, deactivationDelay, durationResolution);
|
|
9
9
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { F } from '../util/Utils';
|
|
2
2
|
import { MemberOptions } from '../Options';
|
|
3
3
|
import { Controller } from '../Controller';
|
|
4
|
-
import { MemberName,
|
|
4
|
+
import { MemberName, DataHolder, Subscription, Subscriber, SubscriptionInfo, AbstractSnapshot } from './Data';
|
|
5
5
|
import { Transaction } from './Transaction';
|
|
6
6
|
import { OptionsImpl } from './Hooks';
|
|
7
7
|
export declare class OperationController extends Controller<any> {
|
|
8
|
-
readonly ownHolder:
|
|
8
|
+
readonly ownHolder: DataHolder;
|
|
9
9
|
readonly memberName: MemberName;
|
|
10
10
|
configure(options: Partial<MemberOptions>): MemberOptions;
|
|
11
11
|
get options(): MemberOptions;
|
|
@@ -17,7 +17,7 @@ export declare class OperationController extends Controller<any> {
|
|
|
17
17
|
get isUpToDate(): boolean;
|
|
18
18
|
markObsolete(): void;
|
|
19
19
|
pullLastResult(args?: any[]): any;
|
|
20
|
-
constructor(ownHolder:
|
|
20
|
+
constructor(ownHolder: DataHolder, memberName: MemberName);
|
|
21
21
|
useOrRun(weak: boolean, args: any[] | undefined): Operation;
|
|
22
22
|
static of(method: F<any>): Controller<any>;
|
|
23
23
|
static configureImpl(self: OperationController | undefined, options: Partial<MemberOptions>): MemberOptions;
|
|
@@ -32,15 +32,15 @@ export declare class OperationController extends Controller<any> {
|
|
|
32
32
|
private run;
|
|
33
33
|
private static markObsolete;
|
|
34
34
|
}
|
|
35
|
-
declare class Operation extends
|
|
35
|
+
declare class Operation extends Subscription implements Subscriber {
|
|
36
36
|
static current?: Operation;
|
|
37
|
-
static queuedReactions: Array<
|
|
37
|
+
static queuedReactions: Array<Subscriber>;
|
|
38
38
|
static deferredReactions: Array<Operation>;
|
|
39
39
|
readonly margin: number;
|
|
40
40
|
readonly transaction: Transaction;
|
|
41
41
|
readonly controller: OperationController;
|
|
42
42
|
readonly snapshot: AbstractSnapshot;
|
|
43
|
-
|
|
43
|
+
subscriptions: Map<Subscription, SubscriptionInfo> | undefined;
|
|
44
44
|
options: OptionsImpl;
|
|
45
45
|
cause: string | undefined;
|
|
46
46
|
args: any[];
|
|
@@ -61,7 +61,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
61
61
|
dependencies(): string[];
|
|
62
62
|
wrap<T>(func: F<T>): F<T>;
|
|
63
63
|
run(proxy: any, args: any[] | undefined): void;
|
|
64
|
-
markObsoleteDueTo(
|
|
64
|
+
markObsoleteDueTo(subscription: Subscription, memberName: MemberName, snapshot: AbstractSnapshot, holder: DataHolder, outer: string, since: number, reactions: Subscriber[]): void;
|
|
65
65
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
66
66
|
isNotUpToDate(): boolean;
|
|
67
67
|
reenterOver(head: Operation): this;
|
|
@@ -81,7 +81,7 @@ declare class Operation extends Observable implements Observer {
|
|
|
81
81
|
private static propagateMemberChangeThroughSubscriptions;
|
|
82
82
|
private static enqueueReactionsToRun;
|
|
83
83
|
private static runQueuedReactionsLoop;
|
|
84
|
-
private
|
|
84
|
+
private unsubscribeFromAllSubscriptions;
|
|
85
85
|
private subscribeTo;
|
|
86
86
|
private static canSubscribe;
|
|
87
87
|
private static createOperation;
|
|
@@ -12,7 +12,7 @@ const Hooks_1 = require("./Hooks");
|
|
|
12
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 nonreactive() { return this.peek(undefined).operation.
|
|
24
|
+
get nonreactive() { 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);
|
|
@@ -204,14 +204,14 @@ class OperationController extends Controller_1.Controller {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
exports.OperationController = OperationController;
|
|
207
|
-
class Operation extends Data_1.
|
|
207
|
+
class Operation extends Data_1.Subscription {
|
|
208
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.
|
|
214
|
+
this.subscriptions = new Map();
|
|
215
215
|
if (former instanceof Operation) {
|
|
216
216
|
this.options = former.options;
|
|
217
217
|
this.args = former.args;
|
|
@@ -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
|
}
|
|
@@ -500,13 +500,13 @@ class Operation extends Data_1.Observable {
|
|
|
500
500
|
const curr = r.data[m];
|
|
501
501
|
if (reactions) {
|
|
502
502
|
const former = r.former.revision.data[m];
|
|
503
|
-
if (former !== undefined && former instanceof Data_1.
|
|
503
|
+
if (former !== undefined && former instanceof Data_1.Subscription) {
|
|
504
504
|
const why = `T${r.snapshot.id}[${r.snapshot.hint}]`;
|
|
505
505
|
if (former instanceof Operation) {
|
|
506
506
|
if ((former.obsoleteSince === Snapshot_1.MAX_TIMESTAMP || former.obsoleteSince <= 0)) {
|
|
507
507
|
former.obsoleteDueTo = why;
|
|
508
508
|
former.obsoleteSince = timestamp;
|
|
509
|
-
former.
|
|
509
|
+
former.unsubscribeFromAllSubscriptions();
|
|
510
510
|
}
|
|
511
511
|
const formerSuccessor = former.successor;
|
|
512
512
|
if (formerSuccessor !== curr) {
|
|
@@ -516,22 +516,22 @@ class Operation extends Data_1.Observable {
|
|
|
516
516
|
else
|
|
517
517
|
former.successor = undefined;
|
|
518
518
|
}
|
|
519
|
-
(_a = former.
|
|
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.
|
|
534
|
+
else if (curr instanceof Data_1.Subscription && curr.subscribers) {
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
static enqueueReactionsToRun(reactions) {
|
|
@@ -552,31 +552,31 @@ class Operation extends Data_1.Observable {
|
|
|
552
552
|
}
|
|
553
553
|
Operation.queuedReactions = [];
|
|
554
554
|
}
|
|
555
|
-
|
|
555
|
+
unsubscribeFromAllSubscriptions() {
|
|
556
556
|
var _a;
|
|
557
|
-
(_a = this.
|
|
557
|
+
(_a = this.subscriptions) === null || _a === void 0 ? void 0 : _a.forEach((info, value) => {
|
|
558
558
|
var _a;
|
|
559
|
-
value.
|
|
559
|
+
value.subscribers.delete(this);
|
|
560
560
|
if (Dbg_1.Log.isOn && (Dbg_1.Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
561
561
|
Dbg_1.Log.write(Dbg_1.Log.opt.transaction && !Snapshot_1.Snapshot.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${info.memberHint}`);
|
|
562
562
|
});
|
|
563
|
-
this.
|
|
563
|
+
this.subscriptions = undefined;
|
|
564
564
|
}
|
|
565
|
-
subscribeTo(
|
|
565
|
+
subscribeTo(subscription, r, m, h, timestamp) {
|
|
566
566
|
var _a, _b, _c;
|
|
567
|
-
const ok = Operation.canSubscribe(
|
|
567
|
+
const ok = Operation.canSubscribe(subscription, r, m, h, timestamp);
|
|
568
568
|
if (ok) {
|
|
569
569
|
let times = 0;
|
|
570
570
|
if (Hooks_1.Hooks.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
571
|
-
const existing = this.
|
|
571
|
+
const existing = this.subscriptions.get(subscription);
|
|
572
572
|
times = existing ? existing.usageCount + 1 : 1;
|
|
573
573
|
}
|
|
574
|
-
if (this.
|
|
575
|
-
if (!
|
|
576
|
-
|
|
574
|
+
if (this.subscriptions !== undefined) {
|
|
575
|
+
if (!subscription.subscribers)
|
|
576
|
+
subscription.subscribers = new Set();
|
|
577
577
|
const info = { memberHint: Snapshot_1.Dump.rev2(h, r.snapshot, m), usageCount: times };
|
|
578
|
-
|
|
579
|
-
this.
|
|
578
|
+
subscription.subscribers.add(this);
|
|
579
|
+
this.subscriptions.set(subscription, info);
|
|
580
580
|
if (Dbg_1.Log.isOn && (Dbg_1.Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
581
581
|
Dbg_1.Log.write('║', ' ∞ ', `${this.hint()} is subscribed to ${Snapshot_1.Dump.rev2(h, r.snapshot, m)}${info.usageCount > 1 ? ` (${info.usageCount} times)` : ''}`);
|
|
582
582
|
}
|
|
@@ -589,10 +589,10 @@ class Operation extends Data_1.Observable {
|
|
|
589
589
|
}
|
|
590
590
|
return ok;
|
|
591
591
|
}
|
|
592
|
-
static canSubscribe(
|
|
593
|
-
let result = !r.snapshot.sealed ||
|
|
592
|
+
static canSubscribe(subscription, r, m, h, timestamp) {
|
|
593
|
+
let result = !r.snapshot.sealed || subscription === h.head.data[m];
|
|
594
594
|
if (result && timestamp !== -1)
|
|
595
|
-
result = !(
|
|
595
|
+
result = !(subscription instanceof Operation && timestamp >= subscription.obsoleteSince);
|
|
596
596
|
return result;
|
|
597
597
|
}
|
|
598
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.Nonreactive)
|
|
23
|
+
result[m] = this.data[m];
|
|
24
24
|
else
|
|
25
25
|
result[m] = v;
|
|
26
26
|
}
|
|
@@ -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.Nonreactive) {
|
|
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,7 +99,7 @@ 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)(`reactive 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
104
|
if (r.snapshot !== this || r.former.revision !== exports.ROOT_REV) {
|
|
105
105
|
if (this.options.token !== undefined && token !== this.options.token)
|
|
@@ -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.
|
|
196
|
+
Snapshot.totalRevisionCount++;
|
|
197
197
|
if (r.former.revision === exports.ROOT_REV)
|
|
198
|
-
Snapshot.
|
|
198
|
+
Snapshot.totalHolderCount++;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
});
|
|
@@ -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
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
|
}
|
|
@@ -268,9 +268,9 @@ class Snapshot {
|
|
|
268
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
270
|
if (r.former.revision !== exports.ROOT_REV)
|
|
271
|
-
Snapshot.
|
|
271
|
+
Snapshot.totalRevisionCount--;
|
|
272
272
|
if (r.changes.has(Data_1.Meta.Disposed))
|
|
273
|
-
Snapshot.
|
|
273
|
+
Snapshot.totalHolderCount--;
|
|
274
274
|
}
|
|
275
275
|
r.former.revision = exports.ROOT_REV;
|
|
276
276
|
});
|
|
@@ -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,
|