reactronic 0.22.503 → 0.22.505
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/dist/source/Rx.d.ts +1 -0
- package/build/dist/source/Rx.js +3 -0
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/impl/Changeset.d.ts +7 -7
- package/build/dist/source/impl/Changeset.js +8 -8
- package/build/dist/source/impl/Data.d.ts +6 -6
- package/build/dist/source/impl/Data.js +1 -1
- package/build/dist/source/impl/Journal.js +4 -4
- package/build/dist/source/impl/Mvcc.d.ts +1 -1
- package/build/dist/source/impl/Mvcc.js +11 -10
- package/build/dist/source/impl/Operation.d.ts +6 -6
- package/build/dist/source/impl/Operation.js +37 -37
- package/build/dist/source/util/Collection.d.ts +1 -1
- package/build/dist/source/util/Collection.js +3 -3
- package/package.json +3 -3
|
@@ -21,6 +21,7 @@ export declare class Rx {
|
|
|
21
21
|
export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
|
|
22
22
|
export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
23
23
|
export declare function raw(proto: object, prop: PropertyKey): any;
|
|
24
|
+
export declare function observable(proto: object, prop: PropertyKey): any;
|
|
24
25
|
export declare function transactional(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
25
26
|
export declare function reactive(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
26
27
|
export declare function cached(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
package/build/dist/source/Rx.js
CHANGED
|
@@ -30,6 +30,9 @@ export function sensitive(sensitivity, func, ...args) {
|
|
|
30
30
|
export function raw(proto, prop) {
|
|
31
31
|
return Mvcc.decorateData(false, proto, prop);
|
|
32
32
|
}
|
|
33
|
+
export function observable(proto, prop) {
|
|
34
|
+
return Mvcc.decorateData(true, proto, prop);
|
|
35
|
+
}
|
|
33
36
|
export function transactional(proto, prop, pd) {
|
|
34
37
|
const opts = { kind: Kind.Transactional };
|
|
35
38
|
return Mvcc.decorateOperation(true, transactional, opts, proto, prop, pd);
|
|
@@ -17,4 +17,4 @@ export { Changeset } from './impl/Changeset';
|
|
|
17
17
|
export { Transaction } from './impl/Transaction';
|
|
18
18
|
export { Monitor } from './impl/Monitor';
|
|
19
19
|
export { Journal } from './impl/Journal';
|
|
20
|
-
export { Rx, raw, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
|
20
|
+
export { Rx, raw, observable, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
package/build/dist/source/api.js
CHANGED
|
@@ -13,4 +13,4 @@ export { Changeset } from './impl/Changeset';
|
|
|
13
13
|
export { Transaction } from './impl/Transaction';
|
|
14
14
|
export { Monitor } from './impl/Monitor';
|
|
15
15
|
export { Journal } from './impl/Journal';
|
|
16
|
-
export { Rx, raw, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
|
16
|
+
export { Rx, raw, observable, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Kind, SnapshotOptions } from '../Options';
|
|
2
|
-
import { AbstractChangeset, ObjectSnapshot, MemberName, ObjectHandle,
|
|
2
|
+
import { AbstractChangeset, ObjectSnapshot, MemberName, ObjectHandle, Observable, Observer } from './Data';
|
|
3
3
|
export declare const MAX_REVISION: number;
|
|
4
4
|
export declare const UNDEFINED_REVISION: number;
|
|
5
5
|
export declare class Changeset implements AbstractChangeset {
|
|
@@ -18,17 +18,17 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
18
18
|
private revision;
|
|
19
19
|
private bumper;
|
|
20
20
|
items: Map<ObjectHandle, ObjectSnapshot>;
|
|
21
|
-
reactive:
|
|
21
|
+
reactive: Observer[];
|
|
22
22
|
sealed: boolean;
|
|
23
23
|
constructor(options: SnapshotOptions | null);
|
|
24
24
|
static current: () => Changeset;
|
|
25
25
|
static edit: () => Changeset;
|
|
26
|
-
static markUsed: (
|
|
26
|
+
static markUsed: (observable: Observable, os: ObjectSnapshot, m: MemberName, h: ObjectHandle, kind: Kind, weak: boolean) => void;
|
|
27
27
|
static markEdited: (oldValue: any, newValue: any, edited: boolean, os: ObjectSnapshot, m: MemberName, h: ObjectHandle) => void;
|
|
28
28
|
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
29
|
static propagateAllChangesThroughSubscriptions: (changeset: Changeset) => void;
|
|
30
30
|
static revokeAllSubscriptions: (changeset: Changeset) => void;
|
|
31
|
-
static enqueueReactiveFunctionsToRun: (reactive: Array<
|
|
31
|
+
static enqueueReactiveFunctionsToRun: (reactive: Array<Observer>) => void;
|
|
32
32
|
lookupObjectSnapshot(h: ObjectHandle, m: MemberName): ObjectSnapshot;
|
|
33
33
|
getObjectSnapshot(h: ObjectHandle, m: MemberName): ObjectSnapshot;
|
|
34
34
|
getEditableObjectSnapshot(h: ObjectHandle, m: MemberName, value: any, token?: any): ObjectSnapshot;
|
|
@@ -40,9 +40,9 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
40
40
|
bumpBy(timestamp: number): void;
|
|
41
41
|
rebase(): ObjectSnapshot[] | undefined;
|
|
42
42
|
private merge;
|
|
43
|
-
applyOrDiscard(error?: any): Array<
|
|
43
|
+
applyOrDiscard(error?: any): Array<Observer>;
|
|
44
44
|
static sealObjectSnapshot(h: ObjectHandle, os: ObjectSnapshot): void;
|
|
45
|
-
static
|
|
45
|
+
static sealObservable(o: Observable | symbol, m: MemberName, typeName: string): void;
|
|
46
46
|
static freezeObjectSnapshot(os: ObjectSnapshot): ObjectSnapshot;
|
|
47
47
|
triggerGarbageCollection(): void;
|
|
48
48
|
private unlinkHistory;
|
|
@@ -51,7 +51,7 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
51
51
|
export declare class Dump {
|
|
52
52
|
static valueHint: (value: any, m?: MemberName) => string;
|
|
53
53
|
static obj(h: ObjectHandle | undefined, m?: MemberName | undefined, stamp?: number, snapshotId?: number, originSnapshotId?: number, value?: any): string;
|
|
54
|
-
static snapshot2(h: ObjectHandle, s: AbstractChangeset, m?: MemberName, o?:
|
|
54
|
+
static snapshot2(h: ObjectHandle, s: AbstractChangeset, m?: MemberName, o?: Observable): string;
|
|
55
55
|
static snapshot(os: ObjectSnapshot, m?: MemberName): string;
|
|
56
56
|
static conflicts(conflicts: ObjectSnapshot[]): string;
|
|
57
57
|
static conflictingMemberHint(m: MemberName, ours: ObjectSnapshot, theirs: ObjectSnapshot): string;
|
|
@@ -4,7 +4,7 @@ import { Sealant } from '../util/Sealant';
|
|
|
4
4
|
import { SealedArray } from '../util/SealedArray';
|
|
5
5
|
import { SealedMap } from '../util/SealedMap';
|
|
6
6
|
import { SealedSet } from '../util/SealedSet';
|
|
7
|
-
import { ObjectSnapshot, ObjectHandle,
|
|
7
|
+
import { ObjectSnapshot, ObjectHandle, Observable, Meta } from './Data';
|
|
8
8
|
export const MAX_REVISION = Number.MAX_SAFE_INTEGER;
|
|
9
9
|
export const UNDEFINED_REVISION = MAX_REVISION - 1;
|
|
10
10
|
Object.defineProperty(ObjectHandle.prototype, '#this#', {
|
|
@@ -14,7 +14,7 @@ Object.defineProperty(ObjectHandle.prototype, '#this#', {
|
|
|
14
14
|
const data = Changeset.current().getObjectSnapshot(this, '#this#').data;
|
|
15
15
|
for (const m in data) {
|
|
16
16
|
const v = data[m];
|
|
17
|
-
if (v instanceof
|
|
17
|
+
if (v instanceof Observable)
|
|
18
18
|
result[m] = v.content;
|
|
19
19
|
else if (v === Meta.Raw)
|
|
20
20
|
result[m] = this.data[m];
|
|
@@ -67,7 +67,7 @@ export class Changeset {
|
|
|
67
67
|
const revision = m === Meta.Handle ? 1 : os.revision + 1;
|
|
68
68
|
const data = Object.assign({}, m === Meta.Handle ? value : os.data);
|
|
69
69
|
Meta.set(data, Meta.Handle, h);
|
|
70
|
-
Meta.set(data, Meta.Revision, new
|
|
70
|
+
Meta.set(data, Meta.Revision, new Observable(revision));
|
|
71
71
|
os = new ObjectSnapshot(this, os, data);
|
|
72
72
|
this.items.set(h, os);
|
|
73
73
|
h.editing = os;
|
|
@@ -218,20 +218,20 @@ export class Changeset {
|
|
|
218
218
|
}
|
|
219
219
|
static sealObjectSnapshot(h, os) {
|
|
220
220
|
if (!os.disposed)
|
|
221
|
-
os.changes.forEach((o, m) => Changeset.
|
|
221
|
+
os.changes.forEach((o, m) => Changeset.sealObservable(os.data[m], m, h.proxy.constructor.name));
|
|
222
222
|
else
|
|
223
223
|
for (const m in os.former.snapshot.data)
|
|
224
224
|
os.data[m] = Meta.Undefined;
|
|
225
225
|
if (Log.isOn)
|
|
226
226
|
Changeset.freezeObjectSnapshot(os);
|
|
227
227
|
}
|
|
228
|
-
static
|
|
229
|
-
if (
|
|
230
|
-
const value =
|
|
228
|
+
static sealObservable(o, m, typeName) {
|
|
229
|
+
if (o instanceof Observable) {
|
|
230
|
+
const value = o.content;
|
|
231
231
|
if (value !== undefined && value !== null) {
|
|
232
232
|
const sealedType = Object.getPrototypeOf(value)[Sealant.SealedType];
|
|
233
233
|
if (sealedType)
|
|
234
|
-
|
|
234
|
+
o.content = Sealant.seal(value, sealedType, typeName, m);
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
}
|
|
@@ -5,24 +5,24 @@ export interface AbstractChangeset {
|
|
|
5
5
|
readonly timestamp: number;
|
|
6
6
|
readonly sealed: boolean;
|
|
7
7
|
}
|
|
8
|
-
export declare class
|
|
8
|
+
export declare class Observable {
|
|
9
9
|
content: any;
|
|
10
|
-
|
|
10
|
+
observers?: Set<Observer>;
|
|
11
11
|
get isOperation(): boolean;
|
|
12
12
|
get originSnapshotId(): number | undefined;
|
|
13
13
|
constructor(content: any);
|
|
14
14
|
}
|
|
15
15
|
export declare type SeparationMode = boolean | 'isolated' | 'disposal';
|
|
16
|
-
export interface
|
|
16
|
+
export interface Observer {
|
|
17
17
|
readonly order: number;
|
|
18
|
-
readonly
|
|
18
|
+
readonly observables: Map<Observable, Subscription> | undefined;
|
|
19
19
|
readonly obsoleteSince: number;
|
|
20
20
|
hint(nop?: boolean): string;
|
|
21
|
-
markObsoleteDueTo(
|
|
21
|
+
markObsoleteDueTo(observable: Observable, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Array<Observer>): void;
|
|
22
22
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
23
23
|
}
|
|
24
24
|
export declare type MemberName = PropertyKey;
|
|
25
|
-
export interface
|
|
25
|
+
export interface Subscription {
|
|
26
26
|
readonly memberHint: string;
|
|
27
27
|
readonly usageCount: number;
|
|
28
28
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Log } from '../util/Dbg';
|
|
2
2
|
import { Meta } from './Meta';
|
|
3
3
|
export { Meta } from './Meta';
|
|
4
|
-
export class
|
|
4
|
+
export class Observable {
|
|
5
5
|
constructor(content) { this.content = content; }
|
|
6
6
|
get isOperation() { return false; }
|
|
7
7
|
get originSnapshotId() { return 0; }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ObservableObject } from './Mvcc';
|
|
2
|
-
import { Meta,
|
|
2
|
+
import { Meta, Observable } from './Data';
|
|
3
3
|
import { Changeset, EMPTY_SNAPSHOT } from './Changeset';
|
|
4
4
|
import { Transaction } from './Transaction';
|
|
5
5
|
import { Sealant } from '../util/Sealant';
|
|
@@ -99,7 +99,7 @@ export class JournalImpl extends Journal {
|
|
|
99
99
|
const value = undoing ? vp.formerValue : vp.freshValue;
|
|
100
100
|
const os = ctx.getEditableObjectSnapshot(h, m, value);
|
|
101
101
|
if (os.changeset === ctx) {
|
|
102
|
-
os.data[m] = new
|
|
102
|
+
os.data[m] = new Observable(value);
|
|
103
103
|
const existing = os.former.snapshot.data[m];
|
|
104
104
|
Changeset.markEdited(existing, value, existing !== value, os, m, h);
|
|
105
105
|
}
|
|
@@ -137,8 +137,8 @@ export class JournalImpl extends Journal {
|
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
function unseal(
|
|
141
|
-
const result =
|
|
140
|
+
function unseal(o) {
|
|
141
|
+
const result = o.content;
|
|
142
142
|
const createCopy = result === null || result === void 0 ? void 0 : result[Sealant.CreateCopy];
|
|
143
143
|
return createCopy !== undefined ? createCopy.call(result) : result;
|
|
144
144
|
}
|
|
@@ -46,7 +46,7 @@ export declare class Mvcc implements ProxyHandler<ObjectHandle> {
|
|
|
46
46
|
has(h: ObjectHandle, m: MemberName): boolean;
|
|
47
47
|
getOwnPropertyDescriptor(h: ObjectHandle, m: MemberName): PropertyDescriptor | undefined;
|
|
48
48
|
ownKeys(h: ObjectHandle): Array<string | symbol>;
|
|
49
|
-
static decorateData(isObservable: boolean, proto: any,
|
|
49
|
+
static decorateData(isObservable: boolean, proto: any, member: MemberName): any;
|
|
50
50
|
static decorateOperation(implicit: boolean, decorator: Function, options: Partial<MemberOptions>, proto: any, member: MemberName, pd: PropertyDescriptor | undefined): any;
|
|
51
51
|
static decorateOperationParametrized(decorator: Function, options: Partial<MemberOptions>): F<any>;
|
|
52
52
|
static acquireHandle(obj: any): ObjectHandle;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UNDEF } from '../util/Utils';
|
|
2
2
|
import { Log, misuse } from '../util/Dbg';
|
|
3
3
|
import { Kind, Reentrance } from '../Options';
|
|
4
|
-
import { ObjectSnapshot, ObjectHandle,
|
|
4
|
+
import { ObjectSnapshot, ObjectHandle, Observable, Meta } from './Data';
|
|
5
5
|
import { Changeset, Dump, EMPTY_SNAPSHOT } from './Changeset';
|
|
6
6
|
export class MvccObject {
|
|
7
7
|
constructor(observable) {
|
|
@@ -72,7 +72,7 @@ export class Mvcc {
|
|
|
72
72
|
const cs = Changeset.current();
|
|
73
73
|
const os = cs.getObjectSnapshot(h, m);
|
|
74
74
|
result = os.data[m];
|
|
75
|
-
if (result instanceof
|
|
75
|
+
if (result instanceof Observable && !result.isOperation) {
|
|
76
76
|
if (this.isObservable)
|
|
77
77
|
Changeset.markUsed(result, os, m, h, Kind.Plain, false);
|
|
78
78
|
result = result.content;
|
|
@@ -92,7 +92,7 @@ export class Mvcc {
|
|
|
92
92
|
if (curr === undefined || curr.content !== value || Mvcc.sensitivity) {
|
|
93
93
|
const existing = curr === null || curr === void 0 ? void 0 : curr.content;
|
|
94
94
|
if (os.former.snapshot.data[m] === curr) {
|
|
95
|
-
curr = os.data[m] = new
|
|
95
|
+
curr = os.data[m] = new Observable(value);
|
|
96
96
|
Changeset.markEdited(existing, value, true, os, m, h);
|
|
97
97
|
}
|
|
98
98
|
else {
|
|
@@ -124,27 +124,28 @@ export class Mvcc {
|
|
|
124
124
|
const result = [];
|
|
125
125
|
for (const m of Object.getOwnPropertyNames(os.data)) {
|
|
126
126
|
const value = os.data[m];
|
|
127
|
-
if (!(value instanceof
|
|
127
|
+
if (!(value instanceof Observable) || !value.isOperation)
|
|
128
128
|
result.push(m);
|
|
129
129
|
}
|
|
130
130
|
return result;
|
|
131
131
|
}
|
|
132
|
-
static decorateData(isObservable, proto,
|
|
132
|
+
static decorateData(isObservable, proto, member) {
|
|
133
133
|
if (isObservable) {
|
|
134
|
+
Meta.acquire(proto, Meta.Initial)[member] = new Observable(undefined);
|
|
134
135
|
const get = function () {
|
|
135
136
|
const h = Mvcc.acquireHandle(this);
|
|
136
|
-
return Mvcc.observable.get(h,
|
|
137
|
+
return Mvcc.observable.get(h, member, this);
|
|
137
138
|
};
|
|
138
139
|
const set = function (value) {
|
|
139
140
|
const h = Mvcc.acquireHandle(this);
|
|
140
|
-
return Mvcc.observable.set(h,
|
|
141
|
+
return Mvcc.observable.set(h, member, value, this);
|
|
141
142
|
};
|
|
142
143
|
const enumerable = true;
|
|
143
144
|
const configurable = false;
|
|
144
|
-
return Object.defineProperty(proto,
|
|
145
|
+
return Object.defineProperty(proto, member, { get, set, enumerable, configurable });
|
|
145
146
|
}
|
|
146
147
|
else
|
|
147
|
-
Meta.acquire(proto, Meta.Initial)[
|
|
148
|
+
Meta.acquire(proto, Meta.Initial)[member] = Meta.Raw;
|
|
148
149
|
}
|
|
149
150
|
static decorateOperation(implicit, decorator, options, proto, member, pd) {
|
|
150
151
|
var _a, _b, _c, _d;
|
|
@@ -189,7 +190,7 @@ export class Mvcc {
|
|
|
189
190
|
h = new ObjectHandle(obj, obj, Mvcc.observable, os, obj.constructor.name);
|
|
190
191
|
Meta.set(os.data, Meta.Handle, h);
|
|
191
192
|
Meta.set(obj, Meta.Handle, h);
|
|
192
|
-
Meta.set(os.data, Meta.Revision, new
|
|
193
|
+
Meta.set(os.data, Meta.Revision, new Observable(1));
|
|
193
194
|
}
|
|
194
195
|
return h;
|
|
195
196
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { F } from '../util/Utils';
|
|
2
2
|
import { MemberOptions } from '../Options';
|
|
3
3
|
import { Controller } from '../Controller';
|
|
4
|
-
import { MemberName, ObjectHandle,
|
|
4
|
+
import { MemberName, ObjectHandle, Observable, Observer, Subscription, AbstractChangeset } from './Data';
|
|
5
5
|
import { Transaction } from './Transaction';
|
|
6
6
|
import { OptionsImpl } from './Mvcc';
|
|
7
7
|
export declare class OperationController extends Controller<any> {
|
|
@@ -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 Observable implements Observer {
|
|
36
36
|
static current?: Operation;
|
|
37
|
-
static queuedReactiveFunctions: Array<
|
|
37
|
+
static queuedReactiveFunctions: Array<Observer>;
|
|
38
38
|
static deferredReactiveFunctions: Array<Operation>;
|
|
39
39
|
readonly margin: number;
|
|
40
40
|
readonly transaction: Transaction;
|
|
41
41
|
readonly controller: OperationController;
|
|
42
42
|
readonly changeset: AbstractChangeset;
|
|
43
|
-
|
|
43
|
+
observables: Map<Observable, Subscription> | undefined;
|
|
44
44
|
options: OptionsImpl;
|
|
45
45
|
cause: string | undefined;
|
|
46
46
|
args: any[];
|
|
@@ -61,7 +61,7 @@ declare class Operation extends Subscription implements Subscriber {
|
|
|
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(observable: Observable, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Observer[]): 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 Subscription implements Subscriber {
|
|
|
81
81
|
private static propagateMemberChangeThroughSubscriptions;
|
|
82
82
|
private static enqueueReactiveFunctionsToRun;
|
|
83
83
|
private static runQueuedReactiveLoop;
|
|
84
|
-
private
|
|
84
|
+
private unsubscribeFromAllObservables;
|
|
85
85
|
private subscribeTo;
|
|
86
86
|
private static canSubscribe;
|
|
87
87
|
private static createOperation;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Log, misuse } from '../util/Dbg';
|
|
2
2
|
import { Kind, Reentrance } from '../Options';
|
|
3
3
|
import { Controller } from '../Controller';
|
|
4
|
-
import { ObjectHandle,
|
|
4
|
+
import { ObjectHandle, Observable, Meta } from './Data';
|
|
5
5
|
import { Changeset, Dump, EMPTY_SNAPSHOT, MAX_REVISION } from './Changeset';
|
|
6
6
|
import { Transaction } from './Transaction';
|
|
7
7
|
import { MonitorImpl } from './Monitor';
|
|
@@ -199,14 +199,14 @@ export class OperationController extends Controller {
|
|
|
199
199
|
oc.operation.markObsoleteDueTo(oc.operation, self.memberName, EMPTY_SNAPSHOT.changeset, EMPTY_HANDLE, BOOT_CAUSE, ctx.timestamp, ctx.reactive);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
class Operation extends
|
|
202
|
+
class Operation extends Observable {
|
|
203
203
|
constructor(controller, changeset, former) {
|
|
204
204
|
super(undefined);
|
|
205
205
|
this.margin = Operation.current ? Operation.current.margin + 1 : 1;
|
|
206
206
|
this.transaction = Transaction.current;
|
|
207
207
|
this.controller = controller;
|
|
208
208
|
this.changeset = changeset;
|
|
209
|
-
this.
|
|
209
|
+
this.observables = new Map();
|
|
210
210
|
if (former instanceof Operation) {
|
|
211
211
|
this.options = former.options;
|
|
212
212
|
this.args = former.args;
|
|
@@ -269,13 +269,13 @@ class Operation extends Subscription {
|
|
|
269
269
|
else
|
|
270
270
|
this.result = Promise.reject(this.error);
|
|
271
271
|
}
|
|
272
|
-
markObsoleteDueTo(
|
|
272
|
+
markObsoleteDueTo(observable, m, changeset, h, outer, since, reactive) {
|
|
273
273
|
var _a, _b, _c;
|
|
274
|
-
if (this.
|
|
275
|
-
const skip = !
|
|
274
|
+
if (this.observables !== undefined) {
|
|
275
|
+
const skip = !observable.isOperation &&
|
|
276
276
|
changeset === this.changeset;
|
|
277
277
|
if (!skip) {
|
|
278
|
-
const why = `${Dump.snapshot2(h, changeset, m,
|
|
278
|
+
const why = `${Dump.snapshot2(h, changeset, m, observable)} << ${outer}`;
|
|
279
279
|
const isReactive = this.options.kind === Kind.Reactive;
|
|
280
280
|
this.obsoleteDueTo = why;
|
|
281
281
|
this.obsoleteSince = since;
|
|
@@ -283,15 +283,15 @@ class Operation extends Subscription {
|
|
|
283
283
|
Log.write(Log.opt.transaction && !Changeset.current().sealed ? '║' : ' ', isReactive ? '█' : '▒', isReactive && changeset === EMPTY_SNAPSHOT.changeset
|
|
284
284
|
? `${this.hint()} is a reactive and will run automatically (order ${this.options.order})`
|
|
285
285
|
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, m)} since v${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ''}`);
|
|
286
|
-
this.
|
|
286
|
+
this.unsubscribeFromAllObservables();
|
|
287
287
|
if (isReactive)
|
|
288
288
|
reactive.push(this);
|
|
289
289
|
else
|
|
290
|
-
(_b = this.
|
|
290
|
+
(_b = this.observers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.controller.memberName, this.changeset, this.controller.objectHandle, why, since, reactive));
|
|
291
291
|
const tran = this.transaction;
|
|
292
292
|
if (tran.changeset === changeset) {
|
|
293
293
|
}
|
|
294
|
-
else if (!tran.isFinished && this !==
|
|
294
|
+
else if (!tran.isFinished && this !== observable)
|
|
295
295
|
tran.cancel(new Error(`T${tran.id}[${tran.hint}] is canceled due to obsolete ${Dump.snapshot2(h, changeset, m)} changed by T${changeset.id}[${changeset.hint}]`), null);
|
|
296
296
|
}
|
|
297
297
|
else if (Log.isOn && (Log.opt.obsolete || ((_c = this.options.logging) === null || _c === void 0 ? void 0 : _c.obsolete)))
|
|
@@ -448,7 +448,7 @@ class Operation extends Subscription {
|
|
|
448
448
|
for (const x of deferred)
|
|
449
449
|
x.runIfNotUpToDate(true, true);
|
|
450
450
|
}
|
|
451
|
-
static markUsed(
|
|
451
|
+
static markUsed(observable, os, m, h, kind, weak) {
|
|
452
452
|
if (kind !== Kind.Transactional) {
|
|
453
453
|
const op = Operation.current;
|
|
454
454
|
if (op && op.options.kind !== Kind.Transactional &&
|
|
@@ -457,8 +457,8 @@ class Operation extends Subscription {
|
|
|
457
457
|
if (ctx !== os.changeset)
|
|
458
458
|
ctx.bumpBy(os.changeset.timestamp);
|
|
459
459
|
const t = weak ? -1 : ctx.timestamp;
|
|
460
|
-
if (!op.subscribeTo(
|
|
461
|
-
op.markObsoleteDueTo(
|
|
460
|
+
if (!op.subscribeTo(observable, os, m, h, t))
|
|
461
|
+
op.markObsoleteDueTo(observable, m, os.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.reactive);
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
464
|
}
|
|
@@ -499,13 +499,13 @@ class Operation extends Subscription {
|
|
|
499
499
|
const curr = os.data[m];
|
|
500
500
|
if (reactive) {
|
|
501
501
|
const former = os.former.snapshot.data[m];
|
|
502
|
-
if (former !== undefined && former instanceof
|
|
502
|
+
if (former !== undefined && former instanceof Observable) {
|
|
503
503
|
const why = `T${os.changeset.id}[${os.changeset.hint}]`;
|
|
504
504
|
if (former instanceof Operation) {
|
|
505
505
|
if ((former.obsoleteSince === MAX_REVISION || former.obsoleteSince <= 0)) {
|
|
506
506
|
former.obsoleteDueTo = why;
|
|
507
507
|
former.obsoleteSince = timestamp;
|
|
508
|
-
former.
|
|
508
|
+
former.unsubscribeFromAllObservables();
|
|
509
509
|
}
|
|
510
510
|
const formerSuccessor = former.successor;
|
|
511
511
|
if (formerSuccessor !== curr) {
|
|
@@ -515,22 +515,22 @@ class Operation extends Subscription {
|
|
|
515
515
|
else
|
|
516
516
|
former.successor = undefined;
|
|
517
517
|
}
|
|
518
|
-
(_a = former.
|
|
518
|
+
(_a = former.observers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, m, os.changeset, h, why, timestamp, reactive));
|
|
519
519
|
}
|
|
520
520
|
}
|
|
521
521
|
if (curr instanceof Operation) {
|
|
522
|
-
if (curr.changeset === os.changeset && curr.
|
|
522
|
+
if (curr.changeset === os.changeset && curr.observables !== undefined) {
|
|
523
523
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
524
|
-
curr.
|
|
524
|
+
curr.observables.forEach((info, v) => {
|
|
525
525
|
if (info.usageCount > Mvcc.repetitiveUsageWarningThreshold)
|
|
526
526
|
Log.write('', '[!]', `${curr.hint()} uses ${info.memberHint} ${info.usageCount} times (consider remembering it in a local variable)`, 0, ' *** WARNING ***');
|
|
527
527
|
});
|
|
528
528
|
}
|
|
529
529
|
if (unsubscribe)
|
|
530
|
-
curr.
|
|
530
|
+
curr.unsubscribeFromAllObservables();
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
|
-
else if (curr instanceof
|
|
533
|
+
else if (curr instanceof Observable && curr.observers) {
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
536
|
static enqueueReactiveFunctionsToRun(reactive) {
|
|
@@ -551,33 +551,33 @@ class Operation extends Subscription {
|
|
|
551
551
|
}
|
|
552
552
|
Operation.queuedReactiveFunctions = [];
|
|
553
553
|
}
|
|
554
|
-
|
|
554
|
+
unsubscribeFromAllObservables() {
|
|
555
555
|
var _a;
|
|
556
|
-
(_a = this.
|
|
556
|
+
(_a = this.observables) === null || _a === void 0 ? void 0 : _a.forEach((info, value) => {
|
|
557
557
|
var _a;
|
|
558
|
-
value.
|
|
558
|
+
value.observers.delete(this);
|
|
559
559
|
if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
560
560
|
Log.write(Log.opt.transaction && !Changeset.current().sealed ? '║' : ' ', '-', `${this.hint()} is unsubscribed from ${info.memberHint}`);
|
|
561
561
|
});
|
|
562
|
-
this.
|
|
562
|
+
this.observables = undefined;
|
|
563
563
|
}
|
|
564
|
-
subscribeTo(
|
|
564
|
+
subscribeTo(observable, os, m, h, timestamp) {
|
|
565
565
|
var _a, _b, _c;
|
|
566
|
-
const ok = Operation.canSubscribe(
|
|
566
|
+
const ok = Operation.canSubscribe(observable, os, m, h, timestamp);
|
|
567
567
|
if (ok) {
|
|
568
568
|
let times = 0;
|
|
569
569
|
if (Mvcc.repetitiveUsageWarningThreshold < Number.MAX_SAFE_INTEGER) {
|
|
570
|
-
const existing = this.
|
|
570
|
+
const existing = this.observables.get(observable);
|
|
571
571
|
times = existing ? existing.usageCount + 1 : 1;
|
|
572
572
|
}
|
|
573
|
-
if (this.
|
|
574
|
-
if (!
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
this.
|
|
573
|
+
if (this.observables !== undefined) {
|
|
574
|
+
if (!observable.observers)
|
|
575
|
+
observable.observers = new Set();
|
|
576
|
+
const subscription = { memberHint: Dump.snapshot2(h, os.changeset, m), usageCount: times };
|
|
577
|
+
observable.observers.add(this);
|
|
578
|
+
this.observables.set(observable, subscription);
|
|
579
579
|
if (Log.isOn && (Log.opt.read || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.read)))
|
|
580
|
-
Log.write('║', ' ∞ ', `${this.hint()} is subscribed to ${Dump.snapshot2(h, os.changeset, m)}${
|
|
580
|
+
Log.write('║', ' ∞ ', `${this.hint()} is subscribed to ${Dump.snapshot2(h, os.changeset, m)}${subscription.usageCount > 1 ? ` (${subscription.usageCount} times)` : ''}`);
|
|
581
581
|
}
|
|
582
582
|
else if (Log.isOn && (Log.opt.read || ((_b = this.options.logging) === null || _b === void 0 ? void 0 : _b.read)))
|
|
583
583
|
Log.write('║', ' x ', `${this.hint()} is obsolete and is NOT subscribed to ${Dump.snapshot2(h, os.changeset, m)}`);
|
|
@@ -588,10 +588,10 @@ class Operation extends Subscription {
|
|
|
588
588
|
}
|
|
589
589
|
return ok;
|
|
590
590
|
}
|
|
591
|
-
static canSubscribe(
|
|
592
|
-
let result = !os.changeset.sealed ||
|
|
591
|
+
static canSubscribe(observable, os, m, h, timestamp) {
|
|
592
|
+
let result = !os.changeset.sealed || observable === h.head.data[m];
|
|
593
593
|
if (result && timestamp !== -1)
|
|
594
|
-
result = !(
|
|
594
|
+
result = !(observable instanceof Operation && timestamp >= observable.obsoleteSince);
|
|
595
595
|
return result;
|
|
596
596
|
}
|
|
597
597
|
static createOperation(h, m, options) {
|
|
@@ -45,7 +45,7 @@ export declare class Collection<T> implements CollectionReader<T> {
|
|
|
45
45
|
lookup(key: string | undefined): Item<T> | undefined;
|
|
46
46
|
claim(key: string, resolution?: {
|
|
47
47
|
isDuplicate: boolean;
|
|
48
|
-
}): Item<T> | undefined;
|
|
48
|
+
}, error?: string): Item<T> | undefined;
|
|
49
49
|
add(instance: T): Item<T>;
|
|
50
50
|
remove(item: Item<T>): void;
|
|
51
51
|
move(item: Item<T>, after: Item<T>): void;
|
|
@@ -37,10 +37,10 @@ export class Collection {
|
|
|
37
37
|
}
|
|
38
38
|
return result;
|
|
39
39
|
}
|
|
40
|
-
claim(key, resolution) {
|
|
40
|
+
claim(key, resolution, error) {
|
|
41
41
|
const tag = this.tag;
|
|
42
42
|
if (tag < 0)
|
|
43
|
-
throw new Error('merge is not in progress');
|
|
43
|
+
throw new Error(error !== null && error !== void 0 ? error : 'merge is not in progress');
|
|
44
44
|
let item = this.strictNextItem;
|
|
45
45
|
if (key !== (item ? this.getKey(item.instance) : undefined))
|
|
46
46
|
item = this.lookup(key);
|
|
@@ -58,7 +58,7 @@ export class Collection {
|
|
|
58
58
|
else if (resolution)
|
|
59
59
|
resolution.isDuplicate = true;
|
|
60
60
|
else
|
|
61
|
-
throw new Error(`duplicate item: ${key}`);
|
|
61
|
+
throw new Error(`duplicate collection item: ${key}`);
|
|
62
62
|
}
|
|
63
63
|
else if (resolution)
|
|
64
64
|
resolution.isDuplicate = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reactronic",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.505",
|
|
4
4
|
"description": "Reactronic - Transactional Reactive State Management",
|
|
5
5
|
"publisher": "Nezaboodka Software",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "18.11.9",
|
|
35
35
|
"@types/react": "18.0.25",
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "5.42.
|
|
37
|
-
"@typescript-eslint/parser": "5.42.
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "5.42.1",
|
|
37
|
+
"@typescript-eslint/parser": "5.42.1",
|
|
38
38
|
"ava": "4.3.3",
|
|
39
39
|
"c8": "7.12.0",
|
|
40
40
|
"eslint": "8.27.0",
|