reactronic 0.92.25014 → 0.92.25020
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 +26 -25
- package/build/dist/source/Pipe.d.ts +2 -2
- package/build/dist/source/Pipe.js +2 -2
- package/build/dist/source/ReactiveLoop.d.ts +2 -2
- package/build/dist/source/ReactiveLoop.js +2 -2
- package/build/dist/source/ReactiveSystem.d.ts +2 -2
- package/build/dist/source/ReactiveSystem.js +8 -5
- package/build/dist/source/api.d.ts +4 -4
- package/build/dist/source/api.js +4 -4
- package/build/dist/source/core/Changeset.js +1 -1
- package/build/dist/source/core/Data.d.ts +2 -2
- package/build/dist/source/core/Indicator.d.ts +2 -2
- package/build/dist/source/core/Indicator.js +2 -2
- package/build/dist/source/core/Journal.d.ts +2 -2
- package/build/dist/source/core/Journal.js +2 -2
- package/build/dist/source/core/Mvcc.d.ts +7 -7
- package/build/dist/source/core/Mvcc.js +15 -15
- package/build/dist/source/core/MvccArray.d.ts +2 -2
- package/build/dist/source/core/MvccArray.js +3 -3
- package/build/dist/source/core/MvccMap.d.ts +2 -2
- package/build/dist/source/core/MvccMap.js +3 -3
- package/build/dist/source/core/MvccMergeList.d.ts +2 -2
- package/build/dist/source/core/MvccMergeList.js +2 -2
- package/build/dist/source/core/Operation.d.ts +3 -3
- package/build/dist/source/core/Operation.js +34 -34
- package/build/dist/source/core/ReactiveNode.js +5 -5
- package/build/dist/source/core/Transaction.js +36 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,19 +19,20 @@ atomically applied, are **consistently propagated** to
|
|
|
19
19
|
corresponding visual components for (re)rendering. All
|
|
20
20
|
that is done in automatic, seamless, and fine-grained
|
|
21
21
|
way. Reactronic **takes full care of tracking dependencies**
|
|
22
|
-
between visual components (
|
|
23
|
-
(
|
|
22
|
+
between visual components (reactive functions) and
|
|
23
|
+
application state (triggering objects).
|
|
24
24
|
|
|
25
25
|
Transactional reactivity is based on four fundamental
|
|
26
26
|
concepts:
|
|
27
27
|
|
|
28
|
-
- **
|
|
29
|
-
data of an application (state)
|
|
28
|
+
- **Triggering Objects** - a set of objects that store
|
|
29
|
+
data of an application (state) and cause reactions
|
|
30
|
+
upon their changes;
|
|
30
31
|
- **Atomic Function** - a function that makes changes in
|
|
31
|
-
|
|
32
|
+
triggering objects in atomic way ("all or nothing");
|
|
32
33
|
- **Reactive Function** - a function that is
|
|
33
|
-
(re-)executed in response to changes made
|
|
34
|
-
actions;
|
|
34
|
+
(re-)executed in response to changes made in
|
|
35
|
+
triggering objects by atomic actions;
|
|
35
36
|
- **Cached Function** - a function which result is
|
|
36
37
|
remembered and, if becomes obsolete, causes function
|
|
37
38
|
to re-execute on-demand.
|
|
@@ -46,7 +47,7 @@ Quick introduction and detailed description is below.
|
|
|
46
47
|
Here is an example of transactional reactive code:
|
|
47
48
|
|
|
48
49
|
``` typescript
|
|
49
|
-
class Demo extends
|
|
50
|
+
class Demo extends TriggeringObject {
|
|
50
51
|
name: string = 'Nezaboodka Software'
|
|
51
52
|
email: string = 'contact@nezaboodka.com'
|
|
52
53
|
|
|
@@ -66,7 +67,7 @@ class Demo extends ObservableObject {
|
|
|
66
67
|
}
|
|
67
68
|
```
|
|
68
69
|
|
|
69
|
-
In the example above, `Demo` is
|
|
70
|
+
In the example above, `Demo` is a triggering object,
|
|
70
71
|
meaning that access to its fields are seamlessly tracked
|
|
71
72
|
to determine dependent reactive and cached functions.
|
|
72
73
|
Reactive function `printContact` reads `name` and `email`
|
|
@@ -78,7 +79,7 @@ Here is an example of a cached result that is
|
|
|
78
79
|
(re-)computed on-demand:
|
|
79
80
|
|
|
80
81
|
``` typescript
|
|
81
|
-
class Demo extends
|
|
82
|
+
class Demo extends TriggeringObject {
|
|
82
83
|
name: string = 'Nezaboodka Software'
|
|
83
84
|
email: string = 'contact@nezaboodka.com'
|
|
84
85
|
|
|
@@ -105,15 +106,15 @@ thus causing execution of depending reactive function
|
|
|
105
106
|
`printContact` runs it reads `contact` and causes its
|
|
106
107
|
re-computation.
|
|
107
108
|
|
|
108
|
-
##
|
|
109
|
+
## Triggering Objects
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
application. All such objects are transparently hooked
|
|
111
|
+
Triggering objects (triggers) are aimed to store data of
|
|
112
|
+
an application. All such objects are transparently hooked
|
|
112
113
|
to track access to their properties, both on reads and
|
|
113
114
|
writes.
|
|
114
115
|
|
|
115
116
|
``` typescript
|
|
116
|
-
class MyModel extends
|
|
117
|
+
class MyModel extends TriggeringObject {
|
|
117
118
|
url: string = "https://github.com/nezaboodka/reactronic"
|
|
118
119
|
content: string = "transactional reactive state management"
|
|
119
120
|
timestamp: Date = Date.now()
|
|
@@ -121,19 +122,19 @@ class MyModel extends ObservableObject {
|
|
|
121
122
|
```
|
|
122
123
|
|
|
123
124
|
In the example above, the class `MyModel` is based on
|
|
124
|
-
Reactronic's `
|
|
125
|
+
Reactronic's `TriggeringObject` class and all its
|
|
125
126
|
properties `url`, `content`, and `timestamp` are hooked.
|
|
126
127
|
|
|
127
128
|
## Atomic Function
|
|
128
129
|
|
|
129
|
-
Atomic function makes changes in
|
|
130
|
+
Atomic function makes changes in triggering objects
|
|
130
131
|
in atomic (transactional) way, thus provoking execution
|
|
131
132
|
of dependent reactive and cached functions. Atomic
|
|
132
133
|
function is instrumented with hooks to provide transparent atomicity
|
|
133
134
|
(by implicit context switching and isolation).
|
|
134
135
|
|
|
135
136
|
``` typescript
|
|
136
|
-
class MyModel extends
|
|
137
|
+
class MyModel extends TriggeringObject {
|
|
137
138
|
// ...
|
|
138
139
|
@atomic
|
|
139
140
|
async load(url: string): Promise<void> {
|
|
@@ -180,12 +181,12 @@ chain of asynchronous operations is fully completed.
|
|
|
180
181
|
## Reactive & Cached Functions
|
|
181
182
|
|
|
182
183
|
Reactive function is automatically and immediately called
|
|
183
|
-
in response to changes in
|
|
184
|
+
in response to changes in triggering objects made by
|
|
184
185
|
atomic functions. Cached function is called on-demand to
|
|
185
186
|
renew the result if it was marked as obsolete due to
|
|
186
187
|
changes made by an atomic functions. Reactive and cached
|
|
187
188
|
functions are instrumented with hooks to seamlessly
|
|
188
|
-
subscribe to those
|
|
189
|
+
subscribe to those triggering objects and other cached
|
|
189
190
|
functions (dependencies), which are used during their
|
|
190
191
|
execution.
|
|
191
192
|
|
|
@@ -248,14 +249,14 @@ cached value.
|
|
|
248
249
|
|
|
249
250
|
In general case, all reactive and cached functions
|
|
250
251
|
are automatically and immediately marked as obsolete
|
|
251
|
-
when changes are made in those
|
|
252
|
+
when changes are made in those triggering objects and
|
|
252
253
|
other cached results that were used during their
|
|
253
254
|
execution. And once marked, the functions are
|
|
254
255
|
automatically executed again, either immediately (for
|
|
255
256
|
reactive functions) or on-demand (for cached functions).
|
|
256
257
|
|
|
257
258
|
Reactronic takes full care of tracking dependencies
|
|
258
|
-
between all the
|
|
259
|
+
between all the triggering objects and reactive/cached
|
|
259
260
|
functions. With Reactronic, you no longer need to create
|
|
260
261
|
data change events in one set of objects, subscribe to
|
|
261
262
|
these events in other objects, and manually maintain
|
|
@@ -301,7 +302,7 @@ Key Reactronic principles and differentiators:
|
|
|
301
302
|
|
|
302
303
|
- No compromises on consistency, clarity, and simplicity;
|
|
303
304
|
- Minimalism and zero boilerplating (it's not a framework bloating your code);
|
|
304
|
-
-
|
|
305
|
+
- Async, patches, undo/redo, conflict resolving are provided out of the box;
|
|
305
306
|
- Seamless integration with transactional reactive object-oriented databases like [Nezaboodka](https://nezaboodka.com/#products);
|
|
306
307
|
- Compact dependency-free implementation consisting of less than 2K lines of code.
|
|
307
308
|
|
|
@@ -322,12 +323,12 @@ NPM: `npm install reactronic`
|
|
|
322
323
|
// Classes
|
|
323
324
|
|
|
324
325
|
class TransactionalObject { }
|
|
325
|
-
class
|
|
326
|
+
class TriggeringObject { }
|
|
326
327
|
|
|
327
328
|
// Decorators & Operators
|
|
328
329
|
|
|
329
|
-
function
|
|
330
|
-
function
|
|
330
|
+
function trigger(boolean) // field only
|
|
331
|
+
function trigger(proto, prop) // field only
|
|
331
332
|
function atomic(proto, prop, pd) // method only
|
|
332
333
|
function reactive(proto, prop, pd) // method only
|
|
333
334
|
function cached(proto, prop, pd) // method only
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare abstract class Pipe<T> extends
|
|
1
|
+
import { TriggeringObject } from "./core/Mvcc.js";
|
|
2
|
+
export declare abstract class Pipe<T> extends TriggeringObject {
|
|
3
3
|
abstract readonly capacity: number;
|
|
4
4
|
abstract readonly count: number;
|
|
5
5
|
abstract put(...items: T[]): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export class Pipe extends
|
|
1
|
+
import { TriggeringObject } from "./core/Mvcc.js";
|
|
2
|
+
export class Pipe extends TriggeringObject {
|
|
3
3
|
static create(hint, capacity) { throw new Error("not implemented"); }
|
|
4
4
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F } from "./util/Utils.js";
|
|
2
|
-
import {
|
|
3
|
-
export declare class ReactiveLoop<T> extends
|
|
2
|
+
import { TriggeringObject } from "./core/Mvcc.js";
|
|
3
|
+
export declare class ReactiveLoop<T> extends TriggeringObject {
|
|
4
4
|
protected reactiveFunction: F<T>;
|
|
5
5
|
constructor(reactiveFunction: F<T>);
|
|
6
6
|
protected launch(): T;
|
|
@@ -7,9 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { TriggeringObject } from "./core/Mvcc.js";
|
|
11
11
|
import { reactive } from "./ReactiveSystem.js";
|
|
12
|
-
export class ReactiveLoop extends
|
|
12
|
+
export class ReactiveLoop extends TriggeringObject {
|
|
13
13
|
constructor(reactiveFunction) {
|
|
14
14
|
super();
|
|
15
15
|
this.reactiveFunction = reactiveFunction;
|
|
@@ -22,8 +22,8 @@ export declare function atomicRun<T>(options: SnapshotOptions, func: F<T>, ...ar
|
|
|
22
22
|
export declare function nonReactiveRun<T>(func: F<T>, ...args: any[]): T;
|
|
23
23
|
export declare function sensitiveRun<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
24
24
|
export declare function contextualRun<T>(p: Promise<T>): Promise<T>;
|
|
25
|
-
export declare function
|
|
26
|
-
export declare function
|
|
25
|
+
export declare function trigger(enabled: boolean): (proto: object, prop: PropertyKey) => any;
|
|
26
|
+
export declare function trigger<T>(proto: object, prop: PropertyKey): any;
|
|
27
27
|
export declare function atomic(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
28
28
|
export declare function reactive(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
29
29
|
export declare function cached(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
@@ -45,11 +45,14 @@ export function sensitiveRun(sensitivity, func, ...args) {
|
|
|
45
45
|
export function contextualRun(p) {
|
|
46
46
|
throw new Error("not implemented yet");
|
|
47
47
|
}
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
export function trigger(protoOrEnabled, prop) {
|
|
49
|
+
if (typeof (protoOrEnabled) === "boolean") {
|
|
50
|
+
return (proto, prop) => {
|
|
51
|
+
return Mvcc.decorateData(protoOrEnabled, proto, prop);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
return Mvcc.decorateData(true, protoOrEnabled, prop);
|
|
53
56
|
}
|
|
54
57
|
export function atomic(proto, prop, pd) {
|
|
55
58
|
const opts = {
|
|
@@ -9,15 +9,15 @@ export type { Operation, MemberOptions, SnapshotOptions, LoggingOptions, Profili
|
|
|
9
9
|
export type { Worker } from "./Worker.js";
|
|
10
10
|
export { Ref, ToggleRef, refs, toggleRefs, customToggleRefs } from "./Ref.js";
|
|
11
11
|
export type { BoolOnly, GivenTypeOnly } from "./Ref.js";
|
|
12
|
-
export { TransactionalObject,
|
|
13
|
-
export { TransactionalArray,
|
|
14
|
-
export { TransactionalMap,
|
|
12
|
+
export { TransactionalObject, TriggeringObject } from "./core/Mvcc.js";
|
|
13
|
+
export { TransactionalArray, TriggeringArray } from "./core/MvccArray.js";
|
|
14
|
+
export { TransactionalMap, TriggeringMap } from "./core/MvccMap.js";
|
|
15
15
|
export { Changeset } from "./core/Changeset.js";
|
|
16
16
|
export { Transaction } from "./core/Transaction.js";
|
|
17
17
|
export { Indicator } from "./core/Indicator.js";
|
|
18
18
|
export { Journal } from "./core/Journal.js";
|
|
19
19
|
export { atomicRun, nonReactiveRun, sensitiveRun, contextualRun } from "./ReactiveSystem.js";
|
|
20
|
-
export { ReactiveSystem,
|
|
20
|
+
export { ReactiveSystem, trigger, atomic, reactive, cached, options } from "./ReactiveSystem.js";
|
|
21
21
|
export { ReactiveLoop } from "./ReactiveLoop.js";
|
|
22
22
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
23
23
|
export type { Script, ScriptAsync, Handler, ReactiveNodeDecl, ReactiveNodeDriver, ReactiveNodeContext } from "./core/ReactiveNode.js";
|
package/build/dist/source/api.js
CHANGED
|
@@ -5,14 +5,14 @@ export { SealedMap } from "./util/SealedMap.js";
|
|
|
5
5
|
export { SealedSet } from "./util/SealedSet.js";
|
|
6
6
|
export { Kind, Reentrance, Isolation, LoggingLevel } from "./Options.js";
|
|
7
7
|
export { Ref, ToggleRef, refs, toggleRefs, customToggleRefs } from "./Ref.js";
|
|
8
|
-
export { TransactionalObject,
|
|
9
|
-
export { TransactionalArray,
|
|
10
|
-
export { TransactionalMap,
|
|
8
|
+
export { TransactionalObject, TriggeringObject } from "./core/Mvcc.js";
|
|
9
|
+
export { TransactionalArray, TriggeringArray } from "./core/MvccArray.js";
|
|
10
|
+
export { TransactionalMap, TriggeringMap } from "./core/MvccMap.js";
|
|
11
11
|
export { Changeset } from "./core/Changeset.js";
|
|
12
12
|
export { Transaction } from "./core/Transaction.js";
|
|
13
13
|
export { Indicator } from "./core/Indicator.js";
|
|
14
14
|
export { Journal } from "./core/Journal.js";
|
|
15
15
|
export { atomicRun, nonReactiveRun, sensitiveRun, contextualRun } from "./ReactiveSystem.js";
|
|
16
|
-
export { ReactiveSystem,
|
|
16
|
+
export { ReactiveSystem, trigger, atomic, reactive, cached, options } from "./ReactiveSystem.js";
|
|
17
17
|
export { ReactiveLoop } from "./ReactiveLoop.js";
|
|
18
18
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
@@ -125,7 +125,7 @@ export class Changeset {
|
|
|
125
125
|
}
|
|
126
126
|
isNewObjectVersionRequired(h, ov, fk, existing, value, token) {
|
|
127
127
|
if (this.sealed && ov.changeset !== EMPTY_OBJECT_VERSION.changeset)
|
|
128
|
-
throw misuse(`
|
|
128
|
+
throw misuse(`triggering property ${Dump.obj(h, fk)} can only be modified inside transaction`);
|
|
129
129
|
if (fk !== Meta.Handle) {
|
|
130
130
|
if (value !== Meta.Handle) {
|
|
131
131
|
if (ov.changeset !== this || ov.former.objectVersion !== EMPTY_OBJECT_VERSION) {
|
|
@@ -14,10 +14,10 @@ export declare class FieldVersion<T = any> {
|
|
|
14
14
|
}
|
|
15
15
|
export type Observer = {
|
|
16
16
|
readonly order: number;
|
|
17
|
-
readonly
|
|
17
|
+
readonly triggers: Map<FieldVersion, Subscription> | undefined;
|
|
18
18
|
readonly obsoleteSince: number;
|
|
19
19
|
hint(nop?: boolean): string;
|
|
20
|
-
markObsoleteDueTo(
|
|
20
|
+
markObsoleteDueTo(trigger: FieldVersion, fk: FieldKey, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Array<Observer>): void;
|
|
21
21
|
relaunchIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
22
22
|
};
|
|
23
23
|
export type FieldKey = PropertyKey;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Worker } from "../Worker.js";
|
|
2
|
-
import {
|
|
3
|
-
export declare abstract class Indicator extends
|
|
2
|
+
import { TriggeringObject } from "./Mvcc.js";
|
|
3
|
+
export declare abstract class Indicator extends TriggeringObject {
|
|
4
4
|
abstract readonly isBusy: boolean;
|
|
5
5
|
abstract readonly counter: number;
|
|
6
6
|
abstract readonly workers: ReadonlySet<Worker>;
|
|
@@ -8,9 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { Isolation } from "../Options.js";
|
|
11
|
-
import {
|
|
11
|
+
import { TriggeringObject, Mvcc } from "./Mvcc.js";
|
|
12
12
|
import { Transaction } from "./Transaction.js";
|
|
13
|
-
export class Indicator extends
|
|
13
|
+
export class Indicator extends TriggeringObject {
|
|
14
14
|
static create(hint, activationDelay, deactivationDelay, durationResolution) {
|
|
15
15
|
return IndicatorImpl.createImpl(hint, activationDelay, deactivationDelay, durationResolution);
|
|
16
16
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TriggeringObject } from "./Mvcc.js";
|
|
2
2
|
import { ObjectHandle, ObjectVersion, PatchSet } from "./Data.js";
|
|
3
3
|
export type Saver = (patch: PatchSet) => Promise<void>;
|
|
4
|
-
export declare abstract class Journal extends
|
|
4
|
+
export declare abstract class Journal extends TriggeringObject {
|
|
5
5
|
abstract capacity: number;
|
|
6
6
|
abstract readonly edits: ReadonlyArray<PatchSet>;
|
|
7
7
|
abstract readonly unsaved: PatchSet;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Isolation } from "../Options.js";
|
|
2
|
-
import {
|
|
2
|
+
import { TriggeringObject } from "./Mvcc.js";
|
|
3
3
|
import { Meta, FieldVersion } from "./Data.js";
|
|
4
4
|
import { Changeset, EMPTY_OBJECT_VERSION } from "./Changeset.js";
|
|
5
5
|
import { Transaction } from "./Transaction.js";
|
|
6
6
|
import { Sealant } from "../util/Sealant.js";
|
|
7
|
-
export class Journal extends
|
|
7
|
+
export class Journal extends TriggeringObject {
|
|
8
8
|
static create() { return new JournalImpl(); }
|
|
9
9
|
}
|
|
10
10
|
export class JournalImpl extends Journal {
|
|
@@ -5,13 +5,13 @@ import { FieldKey, ObjectHandle } from "./Data.js";
|
|
|
5
5
|
import { Journal } from "./Journal.js";
|
|
6
6
|
import { Indicator } from "./Indicator.js";
|
|
7
7
|
export declare abstract class MvccObject {
|
|
8
|
-
protected constructor(
|
|
8
|
+
protected constructor(isTriggering: boolean);
|
|
9
9
|
[Symbol.toStringTag](): string;
|
|
10
10
|
}
|
|
11
11
|
export declare abstract class TransactionalObject extends MvccObject {
|
|
12
12
|
constructor();
|
|
13
13
|
}
|
|
14
|
-
export declare abstract class
|
|
14
|
+
export declare abstract class TriggeringObject extends MvccObject {
|
|
15
15
|
constructor();
|
|
16
16
|
}
|
|
17
17
|
export declare class OptionsImpl implements MemberOptions {
|
|
@@ -38,9 +38,9 @@ export declare class Mvcc implements ProxyHandler<ObjectHandle> {
|
|
|
38
38
|
static asyncActionDurationWarningThreshold: number;
|
|
39
39
|
static sensitivity: boolean;
|
|
40
40
|
static readonly transactional: Mvcc;
|
|
41
|
-
static readonly
|
|
42
|
-
readonly
|
|
43
|
-
constructor(
|
|
41
|
+
static readonly triggering: Mvcc;
|
|
42
|
+
readonly isTriggering: boolean;
|
|
43
|
+
constructor(isTriggering: boolean);
|
|
44
44
|
getPrototypeOf(h: ObjectHandle): object | null;
|
|
45
45
|
get(h: ObjectHandle, fk: FieldKey, receiver: any): any;
|
|
46
46
|
set(h: ObjectHandle, fk: FieldKey, value: any, receiver: any): boolean;
|
|
@@ -48,11 +48,11 @@ export declare class Mvcc implements ProxyHandler<ObjectHandle> {
|
|
|
48
48
|
defineProperty?(h: ObjectHandle, name: string | symbol, attributes: PropertyDescriptor): boolean;
|
|
49
49
|
getOwnPropertyDescriptor(h: ObjectHandle, fk: FieldKey): PropertyDescriptor | undefined;
|
|
50
50
|
ownKeys(h: ObjectHandle): Array<string | symbol>;
|
|
51
|
-
static decorateData(
|
|
51
|
+
static decorateData(isTrigger: boolean, proto: any, fk: FieldKey): any;
|
|
52
52
|
static decorateOperation(implicit: boolean, decorator: Function, options: Partial<MemberOptions>, proto: any, member: FieldKey, pd: PropertyDescriptor | undefined): any;
|
|
53
53
|
static decorateOperationParametrized(decorator: Function, options: Partial<MemberOptions>): F<any>;
|
|
54
54
|
static acquireHandle(obj: any): ObjectHandle;
|
|
55
|
-
static createHandleForMvccObject(proto: any, data: any, blank: any, hint: string,
|
|
55
|
+
static createHandleForMvccObject(proto: any, data: any, blank: any, hint: string, isTriggering: boolean): ObjectHandle;
|
|
56
56
|
static setProfilingMode(isOn: boolean, options?: Partial<ProfilingOptions>): void;
|
|
57
57
|
static sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
58
58
|
static setHint<T>(obj: T, hint: string | undefined): T;
|
|
@@ -4,10 +4,10 @@ import { Kind, Reentrance, Isolation } from "../Options.js";
|
|
|
4
4
|
import { ObjectVersion, ObjectHandle, FieldVersion, Meta } from "./Data.js";
|
|
5
5
|
import { Changeset, Dump, EMPTY_OBJECT_VERSION } from "./Changeset.js";
|
|
6
6
|
export class MvccObject {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(isTriggering) {
|
|
8
8
|
const proto = new.target.prototype;
|
|
9
9
|
const initial = Meta.getFrom(proto, Meta.Initial);
|
|
10
|
-
const h = Mvcc.createHandleForMvccObject(proto, this, initial, new.target.name,
|
|
10
|
+
const h = Mvcc.createHandleForMvccObject(proto, this, initial, new.target.name, isTriggering);
|
|
11
11
|
return h.proxy;
|
|
12
12
|
}
|
|
13
13
|
[Symbol.toStringTag]() {
|
|
@@ -20,7 +20,7 @@ export class TransactionalObject extends MvccObject {
|
|
|
20
20
|
super(false);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
export class
|
|
23
|
+
export class TriggeringObject extends MvccObject {
|
|
24
24
|
constructor() {
|
|
25
25
|
super(true);
|
|
26
26
|
}
|
|
@@ -62,8 +62,8 @@ function merge(def, existing, patch, implicit) {
|
|
|
62
62
|
return patch !== undefined && (existing === def || !implicit) ? patch : existing;
|
|
63
63
|
}
|
|
64
64
|
export class Mvcc {
|
|
65
|
-
constructor(
|
|
66
|
-
this.
|
|
65
|
+
constructor(isTriggering) {
|
|
66
|
+
this.isTriggering = isTriggering;
|
|
67
67
|
}
|
|
68
68
|
getPrototypeOf(h) {
|
|
69
69
|
return Reflect.getPrototypeOf(h.data);
|
|
@@ -75,7 +75,7 @@ export class Mvcc {
|
|
|
75
75
|
const ov = cs.getObjectVersion(h, fk);
|
|
76
76
|
result = ov.data[fk];
|
|
77
77
|
if (result instanceof FieldVersion && !result.isLaunch) {
|
|
78
|
-
if (this.
|
|
78
|
+
if (this.isTriggering)
|
|
79
79
|
Changeset.markUsed(result, ov, fk, h, Kind.plain, false);
|
|
80
80
|
result = result.content;
|
|
81
81
|
}
|
|
@@ -122,16 +122,16 @@ export class Mvcc {
|
|
|
122
122
|
}
|
|
123
123
|
return result;
|
|
124
124
|
}
|
|
125
|
-
static decorateData(
|
|
126
|
-
if (
|
|
125
|
+
static decorateData(isTrigger, proto, fk) {
|
|
126
|
+
if (isTrigger) {
|
|
127
127
|
Meta.acquire(proto, Meta.Initial)[fk] = new FieldVersion(undefined, 0);
|
|
128
128
|
const get = function () {
|
|
129
129
|
const h = Mvcc.acquireHandle(this);
|
|
130
|
-
return Mvcc.
|
|
130
|
+
return Mvcc.triggering.get(h, fk, this);
|
|
131
131
|
};
|
|
132
132
|
const set = function (value) {
|
|
133
133
|
const h = Mvcc.acquireHandle(this);
|
|
134
|
-
return Mvcc.
|
|
134
|
+
return Mvcc.triggering.set(h, fk, value, this);
|
|
135
135
|
};
|
|
136
136
|
const enumerable = true;
|
|
137
137
|
const configurable = false;
|
|
@@ -177,19 +177,19 @@ export class Mvcc {
|
|
|
177
177
|
let h = obj[Meta.Handle];
|
|
178
178
|
if (!h) {
|
|
179
179
|
if (obj !== Object(obj) || Array.isArray(obj))
|
|
180
|
-
throw misuse("only objects can be
|
|
180
|
+
throw misuse("only objects can be triggering");
|
|
181
181
|
const initial = Meta.getFrom(Object.getPrototypeOf(obj), Meta.Initial);
|
|
182
182
|
const ov = new ObjectVersion(EMPTY_OBJECT_VERSION.changeset, EMPTY_OBJECT_VERSION, Object.assign({}, initial));
|
|
183
|
-
h = new ObjectHandle(obj, obj, Mvcc.
|
|
183
|
+
h = new ObjectHandle(obj, obj, Mvcc.triggering, ov, obj.constructor.name);
|
|
184
184
|
Meta.set(ov.data, Meta.Handle, h);
|
|
185
185
|
Meta.set(obj, Meta.Handle, h);
|
|
186
186
|
Meta.set(ov.data, Meta.Revision, new FieldVersion(1, 0));
|
|
187
187
|
}
|
|
188
188
|
return h;
|
|
189
189
|
}
|
|
190
|
-
static createHandleForMvccObject(proto, data, blank, hint,
|
|
190
|
+
static createHandleForMvccObject(proto, data, blank, hint, isTriggering) {
|
|
191
191
|
const ctx = Changeset.edit();
|
|
192
|
-
const mvcc =
|
|
192
|
+
const mvcc = isTriggering ? Mvcc.triggering : Mvcc.transactional;
|
|
193
193
|
const h = new ObjectHandle(data, undefined, mvcc, EMPTY_OBJECT_VERSION, hint);
|
|
194
194
|
ctx.getEditableObjectVersion(h, Meta.Handle, blank);
|
|
195
195
|
if (!Mvcc.reactivityAutoStartDisabled)
|
|
@@ -239,7 +239,7 @@ Mvcc.mainThreadBlockingWarningThreshold = Number.MAX_SAFE_INTEGER;
|
|
|
239
239
|
Mvcc.asyncActionDurationWarningThreshold = Number.MAX_SAFE_INTEGER;
|
|
240
240
|
Mvcc.sensitivity = false;
|
|
241
241
|
Mvcc.transactional = new Mvcc(false);
|
|
242
|
-
Mvcc.
|
|
242
|
+
Mvcc.triggering = new Mvcc(true);
|
|
243
243
|
Mvcc.createOperation = function (h, fk, options) {
|
|
244
244
|
throw misuse("this implementation of createOperation should never be called");
|
|
245
245
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MvccObject } from "./Mvcc.js";
|
|
2
2
|
export declare class MvccArray<T> extends MvccObject {
|
|
3
3
|
private impl;
|
|
4
|
-
constructor(
|
|
4
|
+
constructor(isTriggering: boolean, array: Array<T>);
|
|
5
5
|
get length(): number;
|
|
6
6
|
set length(n: number);
|
|
7
7
|
getItem(n: number): T;
|
|
@@ -53,7 +53,7 @@ export declare class TransactionalArray<T> extends MvccArray<T> {
|
|
|
53
53
|
constructor(arrayLength?: number);
|
|
54
54
|
constructor(...items: T[]);
|
|
55
55
|
}
|
|
56
|
-
export declare class
|
|
56
|
+
export declare class TriggeringArray<T> extends MvccArray<T> {
|
|
57
57
|
constructor();
|
|
58
58
|
constructor(arrayLength: number);
|
|
59
59
|
constructor(arrayLength?: number);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Sealant } from "../util/Sealant.js";
|
|
2
2
|
import { MvccObject } from "./Mvcc.js";
|
|
3
3
|
export class MvccArray extends MvccObject {
|
|
4
|
-
constructor(
|
|
5
|
-
super(
|
|
4
|
+
constructor(isTriggering, array) {
|
|
5
|
+
super(isTriggering);
|
|
6
6
|
this.impl = array;
|
|
7
7
|
}
|
|
8
8
|
get length() { return this.impl.length; }
|
|
@@ -51,7 +51,7 @@ export class TransactionalArray extends MvccArray {
|
|
|
51
51
|
super(false, new Array(...args));
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
export class
|
|
54
|
+
export class TriggeringArray extends MvccArray {
|
|
55
55
|
constructor(...args) {
|
|
56
56
|
super(true, new Array(...args));
|
|
57
57
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MvccObject } from "./Mvcc.js";
|
|
2
2
|
export declare class MvccMap<K, V> extends MvccObject {
|
|
3
3
|
private impl;
|
|
4
|
-
constructor(
|
|
4
|
+
constructor(isTriggering: boolean, map: Map<K, V>);
|
|
5
5
|
clear(): void;
|
|
6
6
|
delete(key: K): boolean;
|
|
7
7
|
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
|
|
@@ -19,7 +19,7 @@ export declare class TransactionalMap<K, V> extends MvccMap<K, V> {
|
|
|
19
19
|
constructor();
|
|
20
20
|
constructor(iterable?: Iterable<readonly [K, V]> | null);
|
|
21
21
|
}
|
|
22
|
-
export declare class
|
|
22
|
+
export declare class TriggeringMap<K, V> extends MvccMap<K, V> {
|
|
23
23
|
constructor();
|
|
24
24
|
constructor(iterable?: Iterable<readonly [K, V]> | null);
|
|
25
25
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Sealant } from "../util/Sealant.js";
|
|
2
2
|
import { MvccObject } from "./Mvcc.js";
|
|
3
3
|
export class MvccMap extends MvccObject {
|
|
4
|
-
constructor(
|
|
5
|
-
super(
|
|
4
|
+
constructor(isTriggering, map) {
|
|
5
|
+
super(isTriggering);
|
|
6
6
|
this.impl = map;
|
|
7
7
|
}
|
|
8
8
|
clear() { this.mutable.clear(); }
|
|
@@ -28,7 +28,7 @@ export class TransactionalMap extends MvccMap {
|
|
|
28
28
|
super(false, args !== undefined ? new Map(args) : new Map());
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
export class
|
|
31
|
+
export class TriggeringMap extends MvccMap {
|
|
32
32
|
constructor(args) {
|
|
33
33
|
super(true, args !== undefined ? new Map(args) : new Map());
|
|
34
34
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MergeList, MergedItem, MergeListReader } from "../util/MergeList.js";
|
|
2
|
-
import {
|
|
3
|
-
export declare abstract class
|
|
2
|
+
import { TriggeringObject } from "./Mvcc.js";
|
|
3
|
+
export declare abstract class TriggeringMergeList<T> extends TriggeringObject implements MergeListReader<T> {
|
|
4
4
|
protected abstract impl: MergeList<T>;
|
|
5
5
|
get isStrict(): boolean;
|
|
6
6
|
get count(): number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export class
|
|
1
|
+
import { TriggeringObject } from "./Mvcc.js";
|
|
2
|
+
export class TriggeringMergeList extends TriggeringObject {
|
|
3
3
|
get isStrict() { return this.impl.isStrict; }
|
|
4
4
|
get count() { return this.impl.count; }
|
|
5
5
|
get addedCount() { return this.impl.addedCount; }
|
|
@@ -39,7 +39,7 @@ declare class Launch extends FieldVersion implements Observer {
|
|
|
39
39
|
readonly transaction: Transaction;
|
|
40
40
|
readonly operation: OperationImpl;
|
|
41
41
|
readonly changeset: AbstractChangeset;
|
|
42
|
-
|
|
42
|
+
triggers: Map<FieldVersion, Subscription> | undefined;
|
|
43
43
|
options: OptionsImpl;
|
|
44
44
|
cause: string | undefined;
|
|
45
45
|
args: any[];
|
|
@@ -60,7 +60,7 @@ declare class Launch extends FieldVersion implements Observer {
|
|
|
60
60
|
dependencies(): string[];
|
|
61
61
|
wrap<T>(func: F<T>): F<T>;
|
|
62
62
|
proceed(proxy: any, args: any[] | undefined): void;
|
|
63
|
-
markObsoleteDueTo(
|
|
63
|
+
markObsoleteDueTo(trigger: FieldVersion, fk: FieldKey, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, obsolete: Observer[]): void;
|
|
64
64
|
relaunchIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
65
65
|
isNotUpToDate(): boolean;
|
|
66
66
|
reenterOver(head: Launch): this;
|
|
@@ -81,7 +81,7 @@ declare class Launch extends FieldVersion implements Observer {
|
|
|
81
81
|
private static enqueueReactiveFunctionsToRun;
|
|
82
82
|
private static migrateFieldVersion;
|
|
83
83
|
private static processQueuedReactiveOperations;
|
|
84
|
-
private
|
|
84
|
+
private unsubscribeFromAllTriggers;
|
|
85
85
|
private subscribeTo;
|
|
86
86
|
private static canSubscribeTo;
|
|
87
87
|
private static createOperation;
|
|
@@ -8,7 +8,7 @@ import { Mvcc, OptionsImpl } from "./Mvcc.js";
|
|
|
8
8
|
import { JournalImpl } from "./Journal.js";
|
|
9
9
|
const BOOT_ARGS = [];
|
|
10
10
|
const BOOT_CAUSE = "<boot>";
|
|
11
|
-
const EMPTY_HANDLE = new ObjectHandle(undefined, undefined, Mvcc.
|
|
11
|
+
const EMPTY_HANDLE = new ObjectHandle(undefined, undefined, Mvcc.triggering, EMPTY_OBJECT_VERSION, "<boot>");
|
|
12
12
|
export class OperationImpl {
|
|
13
13
|
configure(options) { return OperationImpl.configureImpl(this, options); }
|
|
14
14
|
get options() { return this.peek(undefined).launch.options; }
|
|
@@ -201,7 +201,7 @@ class Launch extends FieldVersion {
|
|
|
201
201
|
this.transaction = transaction;
|
|
202
202
|
this.operation = operation;
|
|
203
203
|
this.changeset = changeset;
|
|
204
|
-
this.
|
|
204
|
+
this.triggers = new Map();
|
|
205
205
|
if (former instanceof Launch) {
|
|
206
206
|
this.options = former.options;
|
|
207
207
|
this.cause = former.obsoleteDueTo;
|
|
@@ -287,13 +287,13 @@ class Launch extends FieldVersion {
|
|
|
287
287
|
else
|
|
288
288
|
this.result = Promise.reject(this.error);
|
|
289
289
|
}
|
|
290
|
-
markObsoleteDueTo(
|
|
290
|
+
markObsoleteDueTo(trigger, fk, changeset, h, outer, since, obsolete) {
|
|
291
291
|
var _a, _b, _c;
|
|
292
|
-
if (this.
|
|
293
|
-
const skip = !
|
|
292
|
+
if (this.triggers !== undefined) {
|
|
293
|
+
const skip = !trigger.isLaunch &&
|
|
294
294
|
changeset.id === this.lastEditorChangesetId;
|
|
295
295
|
if (!skip) {
|
|
296
|
-
const why = `${Dump.snapshot2(h, changeset, fk,
|
|
296
|
+
const why = `${Dump.snapshot2(h, changeset, fk, trigger)} ◀◀ ${outer}`;
|
|
297
297
|
const isReactive = this.options.kind === Kind.reactive;
|
|
298
298
|
this.obsoleteDueTo = why;
|
|
299
299
|
this.obsoleteSince = since;
|
|
@@ -301,7 +301,7 @@ class Launch extends FieldVersion {
|
|
|
301
301
|
Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", isReactive ? "█" : "▒", isReactive && changeset === EMPTY_OBJECT_VERSION.changeset
|
|
302
302
|
? `${this.hint()} is reactive and will run automatically (order ${this.options.order})`
|
|
303
303
|
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, fk)} since s${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ""}`);
|
|
304
|
-
this.
|
|
304
|
+
this.unsubscribeFromAllTriggers();
|
|
305
305
|
if (isReactive)
|
|
306
306
|
obsolete.push(this);
|
|
307
307
|
else
|
|
@@ -309,11 +309,11 @@ class Launch extends FieldVersion {
|
|
|
309
309
|
const tran = this.transaction;
|
|
310
310
|
if (tran.changeset === changeset) {
|
|
311
311
|
}
|
|
312
|
-
else if (!tran.isFinished && this !==
|
|
312
|
+
else if (!tran.isFinished && this !== trigger && !this.options.allowObsoleteToFinish)
|
|
313
313
|
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Dump.snapshot2(h, changeset, fk)} changed by T${changeset.id}[${changeset.hint}]`), null);
|
|
314
314
|
}
|
|
315
315
|
else if (Log.isOn && (Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
316
|
-
Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk,
|
|
316
|
+
Log.write(" ", "x", `${this.hint()} is not obsolete due to its own change to ${Dump.snapshot2(h, changeset, fk, trigger)}`);
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
relaunchIfNotUpToDate(now, nothrow) {
|
|
@@ -468,7 +468,7 @@ class Launch extends FieldVersion {
|
|
|
468
468
|
for (const x of deferred)
|
|
469
469
|
x.relaunchIfNotUpToDate(true, true);
|
|
470
470
|
}
|
|
471
|
-
static markUsed(
|
|
471
|
+
static markUsed(trigger, ov, fk, h, kind, weak) {
|
|
472
472
|
if (kind !== Kind.atomic) {
|
|
473
473
|
const launch = Launch.current;
|
|
474
474
|
if (launch && launch.options.kind !== Kind.atomic &&
|
|
@@ -477,8 +477,8 @@ class Launch extends FieldVersion {
|
|
|
477
477
|
if (ctx !== ov.changeset)
|
|
478
478
|
ctx.bumpBy(ov.changeset.timestamp);
|
|
479
479
|
const t = weak ? -1 : ctx.timestamp;
|
|
480
|
-
if (!launch.subscribeTo(
|
|
481
|
-
launch.markObsoleteDueTo(
|
|
480
|
+
if (!launch.subscribeTo(trigger, ov, fk, h, t))
|
|
481
|
+
launch.markObsoleteDueTo(trigger, fk, h.applied.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.obsolete);
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
}
|
|
@@ -534,7 +534,7 @@ class Launch extends FieldVersion {
|
|
|
534
534
|
if ((former.obsoleteSince === MAX_REVISION || former.obsoleteSince <= 0)) {
|
|
535
535
|
former.obsoleteDueTo = why;
|
|
536
536
|
former.obsoleteSince = timestamp;
|
|
537
|
-
former.
|
|
537
|
+
former.unsubscribeFromAllTriggers();
|
|
538
538
|
}
|
|
539
539
|
const formerSuccessor = former.successor;
|
|
540
540
|
if (formerSuccessor !== curr) {
|
|
@@ -552,15 +552,15 @@ class Launch extends FieldVersion {
|
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
if (curr instanceof Launch) {
|
|
555
|
-
if (curr.changeset === ov.changeset && curr.
|
|
555
|
+
if (curr.changeset === ov.changeset && curr.triggers !== undefined) {
|
|
556
556
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
557
|
-
curr.
|
|
557
|
+
curr.triggers.forEach((info, v) => {
|
|
558
558
|
if (info.usageCount > Mvcc.repetitiveUsageWarningThreshold)
|
|
559
559
|
Log.write("", "[!]", `${curr.hint()} uses ${info.memberHint} ${info.usageCount} times (consider remembering it in a local variable)`, 0, " *** WARNING ***");
|
|
560
560
|
});
|
|
561
561
|
}
|
|
562
562
|
if (unsubscribe)
|
|
563
|
-
curr.
|
|
563
|
+
curr.unsubscribeFromAllTriggers();
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
566
|
else if (curr instanceof FieldVersion && curr.observers) {
|
|
@@ -592,50 +592,50 @@ class Launch extends FieldVersion {
|
|
|
592
592
|
}
|
|
593
593
|
Launch.queuedReactiveOperations = [];
|
|
594
594
|
}
|
|
595
|
-
|
|
595
|
+
unsubscribeFromAllTriggers() {
|
|
596
596
|
var _a;
|
|
597
|
-
(_a = this.
|
|
597
|
+
(_a = this.triggers) === null || _a === void 0 ? void 0 : _a.forEach((info, value) => {
|
|
598
598
|
var _a;
|
|
599
599
|
value.observers.delete(this);
|
|
600
600
|
if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
601
601
|
Log.write(Log.opt.transaction && !Changeset.current().sealed ? "║" : " ", "-", `${this.hint()} is unsubscribed from ${info.memberHint}`);
|
|
602
602
|
});
|
|
603
|
-
this.
|
|
603
|
+
this.triggers = undefined;
|
|
604
604
|
}
|
|
605
|
-
subscribeTo(
|
|
605
|
+
subscribeTo(trigger, ov, fk, h, timestamp) {
|
|
606
606
|
var _a, _b, _c;
|
|
607
607
|
const parent = this.transaction.changeset.parent;
|
|
608
|
-
const ok = Launch.canSubscribeTo(
|
|
608
|
+
const ok = Launch.canSubscribeTo(trigger, ov, parent, fk, h, timestamp);
|
|
609
609
|
if (ok) {
|
|
610
610
|
let times = 0;
|
|
611
611
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
612
|
-
const existing = this.
|
|
612
|
+
const existing = this.triggers.get(trigger);
|
|
613
613
|
times = existing ? existing.usageCount + 1 : 1;
|
|
614
614
|
}
|
|
615
|
-
if (this.
|
|
616
|
-
if (!
|
|
617
|
-
|
|
615
|
+
if (this.triggers !== undefined) {
|
|
616
|
+
if (!trigger.observers)
|
|
617
|
+
trigger.observers = new Set();
|
|
618
618
|
const subscription = { memberHint: Dump.snapshot2(h, ov.changeset, fk), usageCount: times };
|
|
619
|
-
|
|
620
|
-
this.
|
|
619
|
+
trigger.observers.add(this);
|
|
620
|
+
this.triggers.set(trigger, subscription);
|
|
621
621
|
if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
622
|
-
Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk,
|
|
622
|
+
Log.write("║", " ∞", `${this.hint()} is subscribed to ${Dump.snapshot2(h, ov.changeset, fk, trigger)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ""}`);
|
|
623
623
|
}
|
|
624
624
|
else if (Log.isOn && (Log.opt.read || ((_b = this.options.logging) === null || _b === void 0 ? void 0 : _b.read)))
|
|
625
|
-
Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk,
|
|
625
|
+
Log.write("║", " x", `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, ov.changeset, fk, trigger)}`);
|
|
626
626
|
}
|
|
627
627
|
else {
|
|
628
628
|
if (Log.isOn && (Log.opt.read || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.read)))
|
|
629
|
-
Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk,
|
|
629
|
+
Log.write("║", " x", `${this.hint()} is NOT subscribed to already obsolete ${Dump.snapshot2(h, ov.changeset, fk, trigger)}`);
|
|
630
630
|
}
|
|
631
631
|
return ok;
|
|
632
632
|
}
|
|
633
|
-
static canSubscribeTo(
|
|
633
|
+
static canSubscribeTo(trigger, ov, parent, fk, h, timestamp) {
|
|
634
634
|
const parentSnapshot = parent ? parent.lookupObjectVersion(h, fk, false) : h.applied;
|
|
635
|
-
const
|
|
636
|
-
let result =
|
|
635
|
+
const parentTrigger = parentSnapshot.data[fk];
|
|
636
|
+
let result = trigger === parentTrigger || (!ov.changeset.sealed && ov.former.objectVersion.data[fk] === parentTrigger);
|
|
637
637
|
if (result && timestamp !== -1)
|
|
638
|
-
result = !(
|
|
638
|
+
result = !(trigger instanceof Launch && timestamp >= trigger.obsoleteSince);
|
|
639
639
|
return result;
|
|
640
640
|
}
|
|
641
641
|
static createOperation(h, fk, options) {
|
|
@@ -20,9 +20,9 @@ import { misuse } from "../util/Dbg.js";
|
|
|
20
20
|
import { MergeList } from "../util/MergeList.js";
|
|
21
21
|
import { emitLetters, getCallerInfo, proceedSyncOrAsync } from "../util/Utils.js";
|
|
22
22
|
import { Isolation, Reentrance } from "../Options.js";
|
|
23
|
-
import {
|
|
23
|
+
import { TriggeringObject } from "../core/Mvcc.js";
|
|
24
24
|
import { Transaction } from "../core/Transaction.js";
|
|
25
|
-
import { ReactiveSystem, options,
|
|
25
|
+
import { ReactiveSystem, options, trigger, reactive, atomicRun, nonReactiveRun } from "../ReactiveSystem.js";
|
|
26
26
|
export var Mode;
|
|
27
27
|
(function (Mode) {
|
|
28
28
|
Mode[Mode["default"] = 0] = "default";
|
|
@@ -250,7 +250,7 @@ function invokeFinalizationUsingBasisChain(element, declaration) {
|
|
|
250
250
|
else if (basis)
|
|
251
251
|
invokeFinalizationUsingBasisChain(element, basis);
|
|
252
252
|
}
|
|
253
|
-
class ReactiveNodeContextImpl extends
|
|
253
|
+
class ReactiveNodeContextImpl extends TriggeringObject {
|
|
254
254
|
constructor(variable, value) {
|
|
255
255
|
super();
|
|
256
256
|
this.next = undefined;
|
|
@@ -259,11 +259,11 @@ class ReactiveNodeContextImpl extends ObservableObject {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
__decorate([
|
|
262
|
-
|
|
262
|
+
trigger(false),
|
|
263
263
|
__metadata("design:type", Object)
|
|
264
264
|
], ReactiveNodeContextImpl.prototype, "next", void 0);
|
|
265
265
|
__decorate([
|
|
266
|
-
|
|
266
|
+
trigger(false),
|
|
267
267
|
__metadata("design:type", ReactiveNodeVariable)
|
|
268
268
|
], ReactiveNodeContextImpl.prototype, "variable", void 0);
|
|
269
269
|
class ReactiveNodeImpl extends ReactiveNode {
|
|
@@ -363,10 +363,10 @@ export class TransactionImpl extends Transaction {
|
|
|
363
363
|
if (observers) {
|
|
364
364
|
const migratedObservers = migrated.observers = new Set();
|
|
365
365
|
observers.forEach(o => {
|
|
366
|
-
|
|
367
|
-
const sub =
|
|
368
|
-
|
|
369
|
-
|
|
366
|
+
const conformingTriggers = o.triggers;
|
|
367
|
+
const sub = conformingTriggers.get(fvParent);
|
|
368
|
+
conformingTriggers.delete(fvParent);
|
|
369
|
+
conformingTriggers.set(migrated, sub);
|
|
370
370
|
migratedObservers.add(o);
|
|
371
371
|
});
|
|
372
372
|
fvParent.observers = undefined;
|
|
@@ -377,24 +377,24 @@ export class TransactionImpl extends Transaction {
|
|
|
377
377
|
if (migratedObservers === undefined)
|
|
378
378
|
migratedObservers = migrated.observers = new Set();
|
|
379
379
|
observers.forEach(o => {
|
|
380
|
-
|
|
381
|
-
const sub =
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
migratedObservers
|
|
380
|
+
const conformingTriggers = o.triggers;
|
|
381
|
+
const sub = conformingTriggers.get(fv);
|
|
382
|
+
conformingTriggers.delete(fv);
|
|
383
|
+
conformingTriggers.set(migrated, sub);
|
|
384
|
+
migratedObservers.add(o);
|
|
385
385
|
});
|
|
386
386
|
fv.observers = undefined;
|
|
387
387
|
}
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
388
|
+
const triggers = fv.triggers;
|
|
389
|
+
const migratedTriggers = migrated.triggers;
|
|
390
|
+
if (triggers) {
|
|
391
|
+
triggers.forEach((s, o) => {
|
|
392
|
+
const conformingObservers = o.observers;
|
|
393
|
+
conformingObservers.delete(fv);
|
|
394
|
+
conformingObservers.add(migrated);
|
|
395
|
+
migratedTriggers.set(o, s);
|
|
396
396
|
});
|
|
397
|
-
|
|
397
|
+
triggers.clear();
|
|
398
398
|
}
|
|
399
399
|
ovParent.data[fk] = migrated;
|
|
400
400
|
}
|
|
@@ -403,24 +403,24 @@ export class TransactionImpl extends Transaction {
|
|
|
403
403
|
if (observers) {
|
|
404
404
|
const migratedObservers = migrated.observers = new Set();
|
|
405
405
|
observers.forEach(o => {
|
|
406
|
-
|
|
407
|
-
const sub =
|
|
408
|
-
|
|
409
|
-
|
|
406
|
+
const conformingTriggers = o.triggers;
|
|
407
|
+
const sub = conformingTriggers.get(fv);
|
|
408
|
+
conformingTriggers.delete(fv);
|
|
409
|
+
conformingTriggers.set(migrated, sub);
|
|
410
410
|
migratedObservers.add(o);
|
|
411
411
|
});
|
|
412
412
|
fv.observers = undefined;
|
|
413
413
|
}
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
if (
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
414
|
+
const triggers = fv.triggers;
|
|
415
|
+
const migratedTriggers = migrated.triggers;
|
|
416
|
+
if (triggers) {
|
|
417
|
+
triggers.forEach((s, o) => {
|
|
418
|
+
const conformingObservers = o.observers;
|
|
419
|
+
conformingObservers.delete(fv);
|
|
420
|
+
conformingObservers.add(migrated);
|
|
421
|
+
migratedTriggers.set(o, s);
|
|
422
422
|
});
|
|
423
|
-
|
|
423
|
+
triggers.clear();
|
|
424
424
|
}
|
|
425
425
|
ovParent.data[fk] = migrated;
|
|
426
426
|
}
|
|
@@ -436,11 +436,11 @@ export class TransactionImpl extends Transaction {
|
|
|
436
436
|
if (fvParent.observers === undefined)
|
|
437
437
|
fvParent.observers = new Set();
|
|
438
438
|
observers.forEach(o => {
|
|
439
|
-
|
|
440
|
-
const sub =
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
439
|
+
const conformingTriggers = o.triggers;
|
|
440
|
+
const sub = conformingTriggers.get(fv);
|
|
441
|
+
conformingTriggers.delete(fv);
|
|
442
|
+
conformingTriggers.set(fvParent, sub);
|
|
443
|
+
fvParent.observers.add(o);
|
|
444
444
|
});
|
|
445
445
|
}
|
|
446
446
|
}
|