reactronic 0.95.25047 → 0.96.26001
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 +5 -5
- package/build/dist/source/System.d.ts +1 -1
- package/build/dist/source/System.js +1 -1
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/TreeNode.d.ts +12 -12
- package/build/dist/source/core/TreeNode.js +56 -56
- package/build/dist/source/util/LinkedList.d.ts +11 -8
- package/build/dist/source/util/LinkedList.js +44 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ Quick introduction and detailed description is below.
|
|
|
48
48
|
Here is an example of transactional reactive code:
|
|
49
49
|
|
|
50
50
|
``` typescript
|
|
51
|
-
class Demo extends
|
|
51
|
+
class Demo extends RxObject {
|
|
52
52
|
name: string = 'Nezaboodka Software'
|
|
53
53
|
email: string = 'contact@nezaboodka.com'
|
|
54
54
|
|
|
@@ -115,7 +115,7 @@ to track access to their properties, both on reads and
|
|
|
115
115
|
writes.
|
|
116
116
|
|
|
117
117
|
``` typescript
|
|
118
|
-
class MyModel extends
|
|
118
|
+
class MyModel extends RxObject {
|
|
119
119
|
url: string = "https://github.com/nezaboodka/reactronic"
|
|
120
120
|
content: string = "transactional reactive state management"
|
|
121
121
|
timestamp: Date = Date.now()
|
|
@@ -123,7 +123,7 @@ class MyModel extends SignallingObject {
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
In the example above, the class `MyModel` is based on
|
|
126
|
-
Reactronic's `
|
|
126
|
+
Reactronic's `RxObject` class and all its
|
|
127
127
|
properties `url`, `content`, and `timestamp` are hooked.
|
|
128
128
|
|
|
129
129
|
## Transactional Function
|
|
@@ -136,7 +136,7 @@ provide transparent atomicity (by implicit context
|
|
|
136
136
|
switching and isolation).
|
|
137
137
|
|
|
138
138
|
``` typescript
|
|
139
|
-
class MyModel extends
|
|
139
|
+
class MyModel extends RxObject {
|
|
140
140
|
// ...
|
|
141
141
|
@transaction
|
|
142
142
|
async load(url: string): Promise<void> {
|
|
@@ -232,7 +232,7 @@ class Component<P> extends React.Component<P> {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
componentWillUnmount(): void {
|
|
235
|
-
runTransactional(
|
|
235
|
+
runTransactional(disposeRxObject, this)
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
```
|
|
@@ -20,7 +20,7 @@ export declare function runSensitive<T>(sensitivity: boolean, func: F<T>, ...arg
|
|
|
20
20
|
export declare function runContextual<T>(p: Promise<T>): Promise<T>;
|
|
21
21
|
export declare function manageReaction<T>(method: F<T>): Reaction<T>;
|
|
22
22
|
export declare function configureCurrentReaction(options: Partial<ReactivityOptions>): ReactivityOptions;
|
|
23
|
-
export declare function
|
|
23
|
+
export declare function disposeRxObject(obj: any): void;
|
|
24
24
|
export declare function signal(enabled: boolean): (proto: object, prop: PropertyKey) => any;
|
|
25
25
|
export declare function signal<T>(proto: object, prop: PropertyKey): any;
|
|
26
26
|
export declare function transaction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
@@ -47,7 +47,7 @@ export function manageReaction(method) {
|
|
|
47
47
|
export function configureCurrentReaction(options) {
|
|
48
48
|
return ReactionImpl.configureImpl(undefined, options);
|
|
49
49
|
}
|
|
50
|
-
export function
|
|
50
|
+
export function disposeRxObject(obj) {
|
|
51
51
|
Changeset.dispose(obj);
|
|
52
52
|
}
|
|
53
53
|
export function signal(protoOrEnabled, prop) {
|
|
@@ -18,7 +18,7 @@ export { Changeset } from "./core/Changeset.js";
|
|
|
18
18
|
export { Transaction } from "./core/Transaction.js";
|
|
19
19
|
export { Indicator } from "./core/Indicator.js";
|
|
20
20
|
export { Journal } from "./core/Journal.js";
|
|
21
|
-
export { runTransactional, runNonReactive, runSensitive, runContextual, manageReaction, configureCurrentReaction,
|
|
21
|
+
export { runTransactional, runNonReactive, runSensitive, runContextual, manageReaction, configureCurrentReaction, disposeRxObject } from "./System.js";
|
|
22
22
|
export { ReactiveSystem, signal, transaction, reaction, cache, options } from "./System.js";
|
|
23
23
|
export { ReactionEx } from "./OperationEx.js";
|
|
24
24
|
export { declare, derivative, launch, ReactiveTreeNode, BaseDriver, ReactiveTreeVariable } from "./core/TreeNode.js";
|
package/build/dist/source/api.js
CHANGED
|
@@ -14,7 +14,7 @@ export { Changeset } from "./core/Changeset.js";
|
|
|
14
14
|
export { Transaction } from "./core/Transaction.js";
|
|
15
15
|
export { Indicator } from "./core/Indicator.js";
|
|
16
16
|
export { Journal } from "./core/Journal.js";
|
|
17
|
-
export { runTransactional, runNonReactive, runSensitive, runContextual, manageReaction, configureCurrentReaction,
|
|
17
|
+
export { runTransactional, runNonReactive, runSensitive, runContextual, manageReaction, configureCurrentReaction, disposeRxObject } from "./System.js";
|
|
18
18
|
export { ReactiveSystem, signal, transaction, reaction, cache, options } from "./System.js";
|
|
19
19
|
export { ReactionEx } from "./OperationEx.js";
|
|
20
20
|
export { declare, derivative, launch, ReactiveTreeNode, BaseDriver, ReactiveTreeVariable } from "./core/TreeNode.js";
|
|
@@ -6,16 +6,16 @@ import { RxObject } from "../core/Mvcc.js";
|
|
|
6
6
|
export type Script<E> = (this: E, o: E, basis: () => void) => void;
|
|
7
7
|
export type ScriptAsync<E> = (this: E, o: E, basis: () => Promise<void>) => Promise<void>;
|
|
8
8
|
export type Handler<E = unknown, R = void> = (o: E) => R;
|
|
9
|
-
export declare function declare<E = void>(driver: ReactiveTreeNodeDriver<E>,
|
|
9
|
+
export declare function declare<E = void>(driver: ReactiveTreeNodeDriver<E>, body?: Script<E>, bodyTask?: ScriptAsync<E>, key?: string, mode?: Mode, preparation?: Script<E>, preparationAsync?: ScriptAsync<E>, finalization?: Script<E>, signalArgs?: unknown, basis?: ReactiveTreeNodeDecl<E>): ReactiveTreeNode<E>;
|
|
10
10
|
export declare function declare<E = void>(driver: ReactiveTreeNodeDriver<E>, declaration?: ReactiveTreeNodeDecl<E>): ReactiveTreeNode<E>;
|
|
11
|
-
export declare function declare<E = void>(driver: ReactiveTreeNodeDriver<E>,
|
|
11
|
+
export declare function declare<E = void>(driver: ReactiveTreeNodeDriver<E>, bodyOrDeclaration?: Script<E> | ReactiveTreeNodeDecl<E>, bodyTask?: ScriptAsync<E>, key?: string, mode?: Mode, preparation?: Script<E>, preparationAsync?: ScriptAsync<E>, finalization?: Script<E>, signalArgs?: unknown, basis?: ReactiveTreeNodeDecl<E>): ReactiveTreeNode<E>;
|
|
12
12
|
export declare function derivative<E = void>(declaration?: ReactiveTreeNodeDecl<E>, basis?: ReactiveTreeNodeDecl<E>): ReactiveTreeNodeDecl<E>;
|
|
13
|
-
export declare function launch<T>(node: ReactiveTreeNode<T>,
|
|
13
|
+
export declare function launch<T>(node: ReactiveTreeNode<T>, signalArgs?: unknown): ReactiveTreeNode<T>;
|
|
14
14
|
export declare abstract class ReactiveTreeNode<E = unknown> {
|
|
15
15
|
static readonly shortFrameDuration = 16;
|
|
16
16
|
static readonly longFrameDuration = 300;
|
|
17
17
|
static frameDuration: number;
|
|
18
|
-
static
|
|
18
|
+
static currentBodyPriority: Priority;
|
|
19
19
|
abstract readonly key: string;
|
|
20
20
|
abstract readonly driver: ReactiveTreeNodeDriver<E>;
|
|
21
21
|
abstract readonly declaration: Readonly<ReactiveTreeNodeDecl<E>>;
|
|
@@ -35,8 +35,8 @@ export declare abstract class ReactiveTreeNode<E = unknown> {
|
|
|
35
35
|
abstract has(mode: Mode): boolean;
|
|
36
36
|
abstract configureReactivity(options: Partial<ReactivityOptions>): ReactivityOptions;
|
|
37
37
|
static get current(): ReactiveTreeNode;
|
|
38
|
-
static get
|
|
39
|
-
static
|
|
38
|
+
static get isFirstBodyBuild(): boolean;
|
|
39
|
+
static buildBody(node: ReactiveTreeNode<any>, signalArgs: unknown): void;
|
|
40
40
|
static launchFinalization(node: ReactiveTreeNode<any>): void;
|
|
41
41
|
static launchNestedNodesThenDo(action: (error: unknown) => void): void;
|
|
42
42
|
static markAsMounted(node: ReactiveTreeNode<any>, yes: boolean): void;
|
|
@@ -48,14 +48,14 @@ export declare abstract class ReactiveTreeNode<E = unknown> {
|
|
|
48
48
|
static setDefaultLoggingOptions(logging?: LoggingOptions): void;
|
|
49
49
|
}
|
|
50
50
|
export type ReactiveTreeNodeDecl<E = unknown> = {
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
body?: Script<E>;
|
|
52
|
+
bodyTask?: ScriptAsync<E>;
|
|
53
53
|
key?: string;
|
|
54
54
|
mode?: Mode;
|
|
55
55
|
preparation?: Script<E>;
|
|
56
56
|
preparationAsync?: ScriptAsync<E>;
|
|
57
57
|
finalization?: Script<E>;
|
|
58
|
-
|
|
58
|
+
signalArgs?: unknown;
|
|
59
59
|
basis?: ReactiveTreeNodeDecl<E>;
|
|
60
60
|
};
|
|
61
61
|
export type ReactiveTreeNodeDriver<E = unknown> = {
|
|
@@ -66,7 +66,7 @@ export type ReactiveTreeNodeDriver<E = unknown> = {
|
|
|
66
66
|
runPreparation(node: ReactiveTreeNode<E>): void;
|
|
67
67
|
runFinalization(node: ReactiveTreeNode<E>, isLeader: boolean): boolean;
|
|
68
68
|
runMount(node: ReactiveTreeNode<E>): void;
|
|
69
|
-
|
|
69
|
+
buildBody(node: ReactiveTreeNode<E>): void | Promise<void>;
|
|
70
70
|
declareChild(ownerNode: ReactiveTreeNode<E>, childDriver: ReactiveTreeNodeDriver<any>, childDeclaration?: ReactiveTreeNodeDecl<any>, childBasis?: ReactiveTreeNodeDecl<any>): LinkedItem<ReactiveTreeNode> | undefined;
|
|
71
71
|
provideHost(node: ReactiveTreeNode<E>): ReactiveTreeNode<E>;
|
|
72
72
|
};
|
|
@@ -82,7 +82,7 @@ export declare abstract class BaseDriver<E = unknown> implements ReactiveTreeNod
|
|
|
82
82
|
runPreparation(node: ReactiveTreeNode<E>): void | Promise<void>;
|
|
83
83
|
runFinalization(node: ReactiveTreeNode<E>, isLeader: boolean): boolean;
|
|
84
84
|
runMount(node: ReactiveTreeNode<E>): void;
|
|
85
|
-
|
|
85
|
+
buildBody(node: ReactiveTreeNode<E>): void | Promise<void>;
|
|
86
86
|
declareChild(ownerNode: ReactiveTreeNode<E>, childDriver: ReactiveTreeNodeDriver<any>, childDeclaration?: ReactiveTreeNodeDecl<any>, childBasis?: ReactiveTreeNodeDecl<any>): LinkedItem<ReactiveTreeNode> | undefined;
|
|
87
87
|
provideHost(node: ReactiveTreeNode<E>): ReactiveTreeNode<E>;
|
|
88
88
|
}
|
|
@@ -126,7 +126,7 @@ declare class ReactiveTreeNode$<E = unknown> extends ReactiveTreeNode<E> {
|
|
|
126
126
|
set strictOrder(value: boolean);
|
|
127
127
|
get isMoved(): boolean;
|
|
128
128
|
has(mode: Mode): boolean;
|
|
129
|
-
|
|
129
|
+
body(_signalArgs: unknown): void;
|
|
130
130
|
configureReactivity(options: Partial<ReactivityOptions>): ReactivityOptions;
|
|
131
131
|
static get nodeSlot(): LinkedItem<ReactiveTreeNode$>;
|
|
132
132
|
static tryUseTreeVariableValue<T extends Object>(variable: ReactiveTreeVariable<T>): T | undefined;
|
|
@@ -23,31 +23,31 @@ import { emitLetters, flags, getCallerInfo, proceedSyncOrAsync } from "../util/U
|
|
|
23
23
|
import { Priority, Mode, Isolation, Reentrance } from "../Enums.js";
|
|
24
24
|
import { RxObject } from "../core/Mvcc.js";
|
|
25
25
|
import { Transaction } from "../core/Transaction.js";
|
|
26
|
-
import { ReactiveSystem, options, signal, reaction, runTransactional, runNonReactive, manageReaction,
|
|
27
|
-
export function declare(driver,
|
|
26
|
+
import { ReactiveSystem, options, signal, reaction, runTransactional, runNonReactive, manageReaction, disposeRxObject } from "../System.js";
|
|
27
|
+
export function declare(driver, bodyOrDeclaration, bodyTask, key, mode, preparation, preparationAsync, finalization, signalArgs, basis) {
|
|
28
28
|
let result;
|
|
29
29
|
let declaration;
|
|
30
|
-
if (
|
|
30
|
+
if (bodyOrDeclaration instanceof Function) {
|
|
31
31
|
declaration = {
|
|
32
|
-
|
|
33
|
-
preparation, preparationAsync, finalization,
|
|
32
|
+
body: bodyOrDeclaration, bodyTask, key, mode,
|
|
33
|
+
preparation, preparationAsync, finalization, signalArgs, basis,
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
else
|
|
37
|
-
declaration =
|
|
37
|
+
declaration = bodyOrDeclaration !== null && bodyOrDeclaration !== void 0 ? bodyOrDeclaration : {};
|
|
38
38
|
let effectiveKey = declaration.key;
|
|
39
39
|
const owner = gNodeSlot === null || gNodeSlot === void 0 ? void 0 : gNodeSlot.instance;
|
|
40
40
|
if (owner) {
|
|
41
41
|
let existing = owner.driver.declareChild(owner, driver, declaration, declaration.basis);
|
|
42
42
|
const children = owner.children;
|
|
43
|
-
existing !== null && existing !== void 0 ? existing : (existing = children.tryReuse(effectiveKey = effectiveKey || generateKey(owner), undefined, "nested elements can be declared inside '
|
|
43
|
+
existing !== null && existing !== void 0 ? existing : (existing = children.tryReuse(effectiveKey = effectiveKey || generateKey(owner), undefined, "nested elements can be declared inside 'body' only"));
|
|
44
44
|
if (existing) {
|
|
45
45
|
result = existing.instance;
|
|
46
46
|
if (result.driver !== driver && driver !== undefined)
|
|
47
47
|
throw misuse(`changing element driver is not yet supported: "${result.driver.name}" -> "${driver === null || driver === void 0 ? void 0 : driver.name}"`);
|
|
48
|
-
const
|
|
49
|
-
if (signalsAreEqual(declaration.
|
|
50
|
-
declaration.
|
|
48
|
+
const exSignalArgs = result.declaration.signalArgs;
|
|
49
|
+
if (signalsAreEqual(declaration.signalArgs, exSignalArgs))
|
|
50
|
+
declaration.signalArgs = exSignalArgs;
|
|
51
51
|
result.declaration = declaration;
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
@@ -68,23 +68,23 @@ export function derivative(declaration, basis) {
|
|
|
68
68
|
declaration = basis !== null && basis !== void 0 ? basis : {};
|
|
69
69
|
return declaration;
|
|
70
70
|
}
|
|
71
|
-
export function launch(node,
|
|
72
|
-
ReactiveTreeNode.
|
|
71
|
+
export function launch(node, signalArgs) {
|
|
72
|
+
ReactiveTreeNode.buildBody(node, signalArgs);
|
|
73
73
|
return node;
|
|
74
74
|
}
|
|
75
75
|
export class ReactiveTreeNode {
|
|
76
76
|
static get current() {
|
|
77
77
|
return ReactiveTreeNode$.nodeSlot.instance;
|
|
78
78
|
}
|
|
79
|
-
static get
|
|
79
|
+
static get isFirstBodyBuild() {
|
|
80
80
|
return ReactiveTreeNode.current.stamp === 1;
|
|
81
81
|
}
|
|
82
|
-
static
|
|
82
|
+
static buildBody(node, signalArgs) {
|
|
83
83
|
const impl = node;
|
|
84
84
|
const declaration = impl.declaration;
|
|
85
|
-
if (node.stamp >= Number.MAX_SAFE_INTEGER || !signalsAreEqual(
|
|
86
|
-
declaration.
|
|
87
|
-
|
|
85
|
+
if (node.stamp >= Number.MAX_SAFE_INTEGER || !signalsAreEqual(signalArgs, declaration.signalArgs)) {
|
|
86
|
+
declaration.signalArgs = signalArgs;
|
|
87
|
+
buildBodyViaSlot(impl.slot);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
static launchFinalization(node) {
|
|
@@ -140,7 +140,7 @@ export class ReactiveTreeNode {
|
|
|
140
140
|
ReactiveTreeNode.shortFrameDuration = 16;
|
|
141
141
|
ReactiveTreeNode.longFrameDuration = 300;
|
|
142
142
|
ReactiveTreeNode.frameDuration = ReactiveTreeNode.longFrameDuration;
|
|
143
|
-
ReactiveTreeNode.
|
|
143
|
+
ReactiveTreeNode.currentBodyPriority = Priority.realtime;
|
|
144
144
|
export class BaseDriver {
|
|
145
145
|
constructor(name, isPartition, initialize) {
|
|
146
146
|
this.name = name;
|
|
@@ -158,8 +158,8 @@ export class BaseDriver {
|
|
|
158
158
|
}
|
|
159
159
|
runMount(node) {
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
return
|
|
161
|
+
buildBody(node) {
|
|
162
|
+
return invokeBuildBodyUsingBasisChain(node.element, node.declaration);
|
|
163
163
|
}
|
|
164
164
|
declareChild(ownerNode, childDriver, childDeclaration, childBasis) {
|
|
165
165
|
return undefined;
|
|
@@ -196,19 +196,19 @@ export function getModeUsingBasisChain(declaration) {
|
|
|
196
196
|
var _a;
|
|
197
197
|
return (_a = declaration === null || declaration === void 0 ? void 0 : declaration.mode) !== null && _a !== void 0 ? _a : ((declaration === null || declaration === void 0 ? void 0 : declaration.basis) ? getModeUsingBasisChain(declaration === null || declaration === void 0 ? void 0 : declaration.basis) : Mode.default);
|
|
198
198
|
}
|
|
199
|
-
function
|
|
199
|
+
function invokeBuildBodyUsingBasisChain(element, declaration) {
|
|
200
200
|
let result = undefined;
|
|
201
201
|
const basis = declaration.basis;
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
if (
|
|
205
|
-
throw misuse("'
|
|
206
|
-
if (
|
|
207
|
-
result =
|
|
208
|
-
else if (
|
|
209
|
-
result =
|
|
202
|
+
const body = declaration.body;
|
|
203
|
+
const bodyTask = declaration.bodyTask;
|
|
204
|
+
if (body && bodyTask)
|
|
205
|
+
throw misuse("'body' and 'bodyTask' cannot be defined together");
|
|
206
|
+
if (body)
|
|
207
|
+
result = body.call(element, element, basis ? () => invokeBuildBodyUsingBasisChain(element, basis) : NOP);
|
|
208
|
+
else if (bodyTask)
|
|
209
|
+
result = bodyTask.call(element, element, basis ? () => invokeBuildBodyUsingBasisChain(element, basis) : NOP_ASYNC);
|
|
210
210
|
else if (basis)
|
|
211
|
-
result =
|
|
211
|
+
result = invokeBuildBodyUsingBasisChain(element, basis);
|
|
212
212
|
return result;
|
|
213
213
|
}
|
|
214
214
|
function invokePreparationUsingBasisChain(element, declaration) {
|
|
@@ -303,13 +303,13 @@ class ReactiveTreeNode$ extends ReactiveTreeNode {
|
|
|
303
303
|
has(mode) {
|
|
304
304
|
return flags(getModeUsingBasisChain(this.declaration), mode);
|
|
305
305
|
}
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
body(_signalArgs) {
|
|
307
|
+
buildBodyNow(this.slot);
|
|
308
308
|
}
|
|
309
309
|
configureReactivity(options) {
|
|
310
310
|
if (this.stamp < Number.MAX_SAFE_INTEGER - 1 || !this.has(Mode.autonomous))
|
|
311
311
|
throw misuse("reactronic can be configured only for elements with autonomous mode and only during preparation");
|
|
312
|
-
return manageReaction(this.
|
|
312
|
+
return manageReaction(this.body).configure(options);
|
|
313
313
|
}
|
|
314
314
|
static get nodeSlot() {
|
|
315
315
|
if (!gNodeSlot)
|
|
@@ -369,7 +369,7 @@ __decorate([
|
|
|
369
369
|
__metadata("design:type", Function),
|
|
370
370
|
__metadata("design:paramtypes", [Object]),
|
|
371
371
|
__metadata("design:returntype", void 0)
|
|
372
|
-
], ReactiveTreeNode$.prototype, "
|
|
372
|
+
], ReactiveTreeNode$.prototype, "body", null);
|
|
373
373
|
function gatherAuthorityAndPath(node, path, relativeTo) {
|
|
374
374
|
let authority;
|
|
375
375
|
if (node.owner !== node && node.owner !== relativeTo) {
|
|
@@ -409,7 +409,7 @@ function launchNestedNodesThenDoImpl(nodeSlot, error, action) {
|
|
|
409
409
|
mounting = markToMountIfNecessary(mounting, host, child, children, sequential);
|
|
410
410
|
const p = (_a = childNode.priority) !== null && _a !== void 0 ? _a : Priority.realtime;
|
|
411
411
|
if (p === Priority.realtime)
|
|
412
|
-
|
|
412
|
+
buildBodyViaSlot(child);
|
|
413
413
|
else if (p === Priority.normal)
|
|
414
414
|
p1 = push(child, p1);
|
|
415
415
|
else
|
|
@@ -418,7 +418,7 @@ function launchNestedNodesThenDoImpl(nodeSlot, error, action) {
|
|
|
418
418
|
partition = childNode;
|
|
419
419
|
}
|
|
420
420
|
if (!Transaction.isCanceled && (p1 !== undefined || p2 !== undefined))
|
|
421
|
-
promised =
|
|
421
|
+
promised = startIncrementalNestedBodyBuild(nodeSlot, children, p1, p2).then(() => action(error), e => action(e));
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
424
|
finally {
|
|
@@ -441,34 +441,34 @@ function markToMountIfNecessary(mounting, host, nodeSlot, children, sequential)
|
|
|
441
441
|
node.host = host;
|
|
442
442
|
return mounting;
|
|
443
443
|
}
|
|
444
|
-
function
|
|
444
|
+
function startIncrementalNestedBodyBuild(ownerSlot, allChildren, priority1, priority2) {
|
|
445
445
|
return __awaiter(this, void 0, void 0, function* () {
|
|
446
446
|
const stamp = ownerSlot.instance.stamp;
|
|
447
447
|
if (priority1)
|
|
448
|
-
yield
|
|
448
|
+
yield runNestedBodyBuildIncrementally(ownerSlot, stamp, allChildren, priority1, Priority.normal);
|
|
449
449
|
if (priority2)
|
|
450
|
-
yield
|
|
450
|
+
yield runNestedBodyBuildIncrementally(ownerSlot, stamp, allChildren, priority2, Priority.background);
|
|
451
451
|
});
|
|
452
452
|
}
|
|
453
|
-
function
|
|
453
|
+
function runNestedBodyBuildIncrementally(owner, stamp, allChildren, items, priority) {
|
|
454
454
|
return __awaiter(this, void 0, void 0, function* () {
|
|
455
455
|
yield Transaction.requestNextFrame();
|
|
456
456
|
const node = owner.instance;
|
|
457
457
|
if (!Transaction.isCanceled || !Transaction.isFrameOver(1, ReactiveTreeNode$.shortFrameDuration / 3)) {
|
|
458
|
-
let outerPriority = ReactiveTreeNode$.
|
|
459
|
-
ReactiveTreeNode$.
|
|
458
|
+
let outerPriority = ReactiveTreeNode$.currentBodyPriority;
|
|
459
|
+
ReactiveTreeNode$.currentBodyPriority = priority;
|
|
460
460
|
try {
|
|
461
461
|
if (node.childrenShuffling)
|
|
462
462
|
shuffle(items);
|
|
463
463
|
const frameDurationLimit = priority === Priority.background ? ReactiveTreeNode.shortFrameDuration : Infinity;
|
|
464
464
|
let frameDuration = Math.min(frameDurationLimit, Math.max(ReactiveTreeNode.frameDuration / 4, ReactiveTreeNode.shortFrameDuration));
|
|
465
465
|
for (const child of items) {
|
|
466
|
-
|
|
466
|
+
buildBodyViaSlot(child);
|
|
467
467
|
if (Transaction.isFrameOver(1, frameDuration)) {
|
|
468
|
-
ReactiveTreeNode$.
|
|
468
|
+
ReactiveTreeNode$.currentBodyPriority = outerPriority;
|
|
469
469
|
yield Transaction.requestNextFrame(0);
|
|
470
|
-
outerPriority = ReactiveTreeNode$.
|
|
471
|
-
ReactiveTreeNode$.
|
|
470
|
+
outerPriority = ReactiveTreeNode$.currentBodyPriority;
|
|
471
|
+
ReactiveTreeNode$.currentBodyPriority = priority;
|
|
472
472
|
frameDuration = Math.min(4 * frameDuration, Math.min(frameDurationLimit, ReactiveTreeNode.frameDuration));
|
|
473
473
|
}
|
|
474
474
|
if (Transaction.isCanceled && Transaction.isFrameOver(1, ReactiveTreeNode.shortFrameDuration / 3))
|
|
@@ -476,12 +476,12 @@ function runNestedScriptsIncrementally(owner, stamp, allChildren, items, priorit
|
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
finally {
|
|
479
|
-
ReactiveTreeNode$.
|
|
479
|
+
ReactiveTreeNode$.currentBodyPriority = outerPriority;
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
});
|
|
483
483
|
}
|
|
484
|
-
function
|
|
484
|
+
function buildBodyViaSlot(nodeSlot) {
|
|
485
485
|
const node = nodeSlot.instance;
|
|
486
486
|
if (node.stamp >= 0) {
|
|
487
487
|
if (node.has(Mode.autonomous)) {
|
|
@@ -489,17 +489,17 @@ function launchScriptViaSlot(nodeSlot) {
|
|
|
489
489
|
Transaction.outside(() => {
|
|
490
490
|
if (ReactiveSystem.isLogging)
|
|
491
491
|
ReactiveSystem.setLoggingHint(node.element, node.key);
|
|
492
|
-
manageReaction(node.
|
|
492
|
+
manageReaction(node.body).configure({
|
|
493
493
|
order: node.level,
|
|
494
494
|
});
|
|
495
495
|
});
|
|
496
496
|
}
|
|
497
|
-
runNonReactive(node.
|
|
497
|
+
runNonReactive(node.body, node.declaration.signalArgs);
|
|
498
498
|
}
|
|
499
499
|
else if (node.owner !== node)
|
|
500
|
-
|
|
500
|
+
buildBodyNow(nodeSlot);
|
|
501
501
|
else
|
|
502
|
-
runTransactional(() =>
|
|
502
|
+
runTransactional(() => buildBodyNow(nodeSlot));
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
505
|
function mountOrRemountIfNecessary(node) {
|
|
@@ -518,7 +518,7 @@ function mountOrRemountIfNecessary(node) {
|
|
|
518
518
|
else if (node.isMoved && !node.has(Mode.external) && node.host !== node)
|
|
519
519
|
runNonReactive(() => driver.runMount(node));
|
|
520
520
|
}
|
|
521
|
-
function
|
|
521
|
+
function buildBodyNow(nodeSlot) {
|
|
522
522
|
const node = nodeSlot.instance;
|
|
523
523
|
if (node.stamp >= 0) {
|
|
524
524
|
let result = undefined;
|
|
@@ -530,12 +530,12 @@ function runScriptNow(nodeSlot) {
|
|
|
530
530
|
node.numerator = 0;
|
|
531
531
|
node.children.beginReconciliation();
|
|
532
532
|
const driver = node.driver;
|
|
533
|
-
result = driver.
|
|
533
|
+
result = driver.buildBody(node);
|
|
534
534
|
result = proceedSyncOrAsync(result, v => { launchNestedNodesThenDoImpl(nodeSlot, undefined, NOP); return v; }, e => { console.log(e); launchNestedNodesThenDoImpl(nodeSlot, e !== null && e !== void 0 ? e : new Error("unknown error"), NOP); });
|
|
535
535
|
}
|
|
536
536
|
catch (e) {
|
|
537
537
|
launchNestedNodesThenDoImpl(nodeSlot, e, NOP);
|
|
538
|
-
console.log(`Reactive node
|
|
538
|
+
console.log(`Reactive node body build failed: ${node.key}`);
|
|
539
539
|
console.log(`${e}`);
|
|
540
540
|
}
|
|
541
541
|
}
|
|
@@ -574,7 +574,7 @@ function runDisposalLoop() {
|
|
|
574
574
|
while (slot !== undefined) {
|
|
575
575
|
if (Transaction.isFrameOver(500, 5))
|
|
576
576
|
yield Transaction.requestNextFrame();
|
|
577
|
-
|
|
577
|
+
disposeRxObject(slot.instance);
|
|
578
578
|
slot = slot.aux;
|
|
579
579
|
ReactiveTreeNode$.disposableNodeCount--;
|
|
580
580
|
}
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
export type Extractor<T, Result> = (item: T) => Result;
|
|
2
2
|
export type KeyExtractor<T> = Extractor<T, string | undefined>;
|
|
3
3
|
export declare class LinkedList<T extends LinkedItem<T>> {
|
|
4
|
-
readonly
|
|
4
|
+
readonly keyExtractor: KeyExtractor<T>;
|
|
5
5
|
private isStrictOrder$;
|
|
6
6
|
private map;
|
|
7
7
|
items$: LinkedSubList<T>;
|
|
8
|
-
private renovation
|
|
8
|
+
private renovation$;
|
|
9
9
|
constructor(keyExtractor: KeyExtractor<T>, isStrictOrder?: boolean);
|
|
10
10
|
get isStrictOrder(): boolean;
|
|
11
11
|
set isStrictOrder(value: boolean);
|
|
12
|
+
get renovation(): LinkedListRenovation<T>;
|
|
12
13
|
get isRenovationInProgress(): boolean;
|
|
13
14
|
get count(): number;
|
|
14
15
|
items(): Generator<T>;
|
|
15
|
-
|
|
16
|
+
tryLookup(key: string): T | undefined;
|
|
17
|
+
lookup(key: string): T;
|
|
16
18
|
add(item: T, before?: T): void;
|
|
17
19
|
move(item: T, before: T | undefined): void;
|
|
18
20
|
remove(item: T): void;
|
|
19
21
|
beginRenovation(diff?: Array<T>): LinkedListRenovation<T>;
|
|
20
|
-
endRenovation(error?: unknown):
|
|
22
|
+
endRenovation(error?: unknown): LinkedListRenovation<T>;
|
|
23
|
+
extractKey(item: T): string;
|
|
21
24
|
static move$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T, before: T | undefined): void;
|
|
22
25
|
static remove$<T extends LinkedItem<T>>(list: LinkedList<T>, item: T): void;
|
|
23
|
-
static removeKey$<T extends LinkedItem<T>>(list: LinkedList<T>, key: string
|
|
26
|
+
static removeKey$<T extends LinkedItem<T>>(list: LinkedList<T>, key: string): void;
|
|
24
27
|
}
|
|
25
28
|
export declare enum Mark {
|
|
26
|
-
|
|
29
|
+
reaffirmed = 0,
|
|
27
30
|
added = 1,
|
|
28
31
|
modified = 2,
|
|
29
32
|
removed = 3
|
|
@@ -59,8 +62,8 @@ export declare class LinkedListRenovation<T extends LinkedItem<T>> {
|
|
|
59
62
|
private expected;
|
|
60
63
|
private absent;
|
|
61
64
|
constructor(list: LinkedList<T>, former: LinkedSubList<T>, diff?: Array<T>);
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
tryLookup(key: string): T | undefined;
|
|
66
|
+
tryReaffirm(key: string, resolution?: {
|
|
64
67
|
isDuplicate: boolean;
|
|
65
68
|
}, error?: string): T | undefined;
|
|
66
69
|
thisIsAdded(item: T, before?: T): T;
|
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
import { misuse } from "./Dbg.js";
|
|
2
2
|
export class LinkedList {
|
|
3
3
|
constructor(keyExtractor, isStrictOrder = false) {
|
|
4
|
-
this.
|
|
4
|
+
this.keyExtractor = keyExtractor;
|
|
5
5
|
this.isStrictOrder$ = isStrictOrder;
|
|
6
6
|
this.map = new Map();
|
|
7
7
|
this.items$ = new LinkedSubList();
|
|
8
|
-
this.renovation = undefined;
|
|
8
|
+
this.renovation$ = undefined;
|
|
9
9
|
}
|
|
10
10
|
get isStrictOrder() { return this.isStrictOrder$; }
|
|
11
11
|
set isStrictOrder(value) {
|
|
12
|
-
if (this.renovation !== undefined)
|
|
12
|
+
if (this.renovation$ !== undefined)
|
|
13
13
|
throw misuse("cannot change strict mode in the middle of renovation");
|
|
14
14
|
this.isStrictOrder$ = value;
|
|
15
15
|
}
|
|
16
|
+
get renovation() {
|
|
17
|
+
const r = this.renovation$;
|
|
18
|
+
if (r === undefined)
|
|
19
|
+
throw misuse("renovation is not in progress");
|
|
20
|
+
return r;
|
|
21
|
+
}
|
|
16
22
|
get isRenovationInProgress() {
|
|
17
|
-
return this.renovation !== undefined;
|
|
23
|
+
return this.renovation$ !== undefined;
|
|
18
24
|
}
|
|
19
25
|
get count() {
|
|
20
26
|
var _a, _b;
|
|
21
|
-
return this.items$.count + ((_b = (_a = this.renovation) === null || _a === void 0 ? void 0 : _a.lostItemCount) !== null && _b !== void 0 ? _b : 0);
|
|
27
|
+
return this.items$.count + ((_b = (_a = this.renovation$) === null || _a === void 0 ? void 0 : _a.lostItemCount) !== null && _b !== void 0 ? _b : 0);
|
|
22
28
|
}
|
|
23
29
|
items() {
|
|
24
30
|
return this.items$.items();
|
|
25
31
|
}
|
|
26
|
-
|
|
32
|
+
tryLookup(key) {
|
|
27
33
|
return this.map.get(key);
|
|
28
34
|
}
|
|
35
|
+
lookup(key) {
|
|
36
|
+
const result = this.tryLookup(key);
|
|
37
|
+
if (result === undefined)
|
|
38
|
+
throw misuse(`item with given key doesn't exist: ${key}`);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
29
41
|
add(item, before) {
|
|
30
|
-
const key = this.
|
|
42
|
+
const key = this.extractKey(item);
|
|
31
43
|
if (this.map.get(key) !== undefined)
|
|
32
44
|
throw misuse(`item with given key already exists: ${key}`);
|
|
33
45
|
this.map.set(key, item);
|
|
@@ -48,23 +60,23 @@ export class LinkedList {
|
|
|
48
60
|
LinkedList.remove$(this, item);
|
|
49
61
|
}
|
|
50
62
|
beginRenovation(diff) {
|
|
51
|
-
if (this.renovation !== undefined)
|
|
63
|
+
if (this.renovation$ !== undefined)
|
|
52
64
|
throw misuse("renovation is in progress already");
|
|
53
65
|
const former = this.items$;
|
|
54
66
|
const renovation = new LinkedListRenovation(this, former, diff);
|
|
55
67
|
this.items$ = new LinkedSubList();
|
|
56
|
-
this.renovation = renovation;
|
|
68
|
+
this.renovation$ = renovation;
|
|
57
69
|
return renovation;
|
|
58
70
|
}
|
|
59
71
|
endRenovation(error) {
|
|
60
|
-
const renovation = this.renovation
|
|
72
|
+
const renovation = this.renovation$;
|
|
61
73
|
if (renovation === undefined)
|
|
62
74
|
throw misuse("renovation is ended already");
|
|
63
75
|
const items = this.items$;
|
|
64
76
|
if (error === undefined) {
|
|
65
77
|
for (const x of renovation.lostItems()) {
|
|
66
78
|
if (!x.isManagedExternally) {
|
|
67
|
-
LinkedList.removeKey$(this, this.
|
|
79
|
+
LinkedList.removeKey$(this, this.extractKey(x));
|
|
68
80
|
LinkedItem.setStatus$(x, Mark.removed, 0);
|
|
69
81
|
}
|
|
70
82
|
else
|
|
@@ -74,16 +86,24 @@ export class LinkedList {
|
|
|
74
86
|
else {
|
|
75
87
|
for (const x of renovation.lostItems()) {
|
|
76
88
|
LinkedItem.link$(items, x, undefined);
|
|
77
|
-
LinkedItem.setStatus$(x, Mark.
|
|
89
|
+
LinkedItem.setStatus$(x, Mark.reaffirmed, items.count);
|
|
78
90
|
}
|
|
79
91
|
}
|
|
80
|
-
this.renovation = undefined;
|
|
92
|
+
this.renovation$ = undefined;
|
|
93
|
+
return renovation;
|
|
94
|
+
}
|
|
95
|
+
extractKey(item) {
|
|
96
|
+
const result = this.keyExtractor(item);
|
|
97
|
+
if (result === undefined)
|
|
98
|
+
throw misuse("given item has no key");
|
|
99
|
+
return result;
|
|
81
100
|
}
|
|
82
101
|
static move$(list, item, before) {
|
|
83
102
|
LinkedItem.link$(list.items$, item, before);
|
|
84
103
|
}
|
|
85
104
|
static remove$(list, item) {
|
|
86
|
-
|
|
105
|
+
const key = list.extractKey(item);
|
|
106
|
+
LinkedList.removeKey$(list, key);
|
|
87
107
|
LinkedItem.link$(undefined, item, undefined);
|
|
88
108
|
}
|
|
89
109
|
static removeKey$(list, key) {
|
|
@@ -92,7 +112,7 @@ export class LinkedList {
|
|
|
92
112
|
}
|
|
93
113
|
export var Mark;
|
|
94
114
|
(function (Mark) {
|
|
95
|
-
Mark[Mark["
|
|
115
|
+
Mark[Mark["reaffirmed"] = 0] = "reaffirmed";
|
|
96
116
|
Mark[Mark["added"] = 1] = "added";
|
|
97
117
|
Mark[Mark["modified"] = 2] = "modified";
|
|
98
118
|
Mark[Mark["removed"] = 3] = "removed";
|
|
@@ -215,12 +235,12 @@ export class LinkedListRenovation {
|
|
|
215
235
|
this.expected = former.first;
|
|
216
236
|
this.absent = undefined;
|
|
217
237
|
}
|
|
218
|
-
|
|
238
|
+
tryLookup(key) {
|
|
219
239
|
let result = undefined;
|
|
220
240
|
if (key !== undefined && key !== this.absent) {
|
|
221
|
-
result = this.list.
|
|
241
|
+
result = this.list.tryLookup(key);
|
|
222
242
|
if (result !== undefined) {
|
|
223
|
-
if (this.list.
|
|
243
|
+
if (this.list.keyExtractor(result) !== key) {
|
|
224
244
|
this.absent = key;
|
|
225
245
|
result = undefined;
|
|
226
246
|
}
|
|
@@ -230,14 +250,14 @@ export class LinkedListRenovation {
|
|
|
230
250
|
}
|
|
231
251
|
return result;
|
|
232
252
|
}
|
|
233
|
-
|
|
253
|
+
tryReaffirm(key, resolution, error) {
|
|
234
254
|
var _a, _b;
|
|
235
255
|
const list = this.list;
|
|
236
256
|
if (!list.isRenovationInProgress)
|
|
237
257
|
throw misuse(error !== null && error !== void 0 ? error : "renovation is no longer in progress");
|
|
238
258
|
let x = this.expected;
|
|
239
|
-
if (key !== (x ? list.
|
|
240
|
-
x = this.
|
|
259
|
+
if (key !== (x ? list.keyExtractor(x) : undefined))
|
|
260
|
+
x = this.tryLookup(key);
|
|
241
261
|
if (x !== undefined) {
|
|
242
262
|
const result = this.list.items$;
|
|
243
263
|
if (x.list !== result) {
|
|
@@ -249,7 +269,7 @@ export class LinkedListRenovation {
|
|
|
249
269
|
(_b = this.diff) === null || _b === void 0 ? void 0 : _b.push(x);
|
|
250
270
|
}
|
|
251
271
|
else
|
|
252
|
-
LinkedItem.setStatus$(x, Mark.
|
|
272
|
+
LinkedItem.setStatus$(x, Mark.reaffirmed, result.count);
|
|
253
273
|
this.expected = next;
|
|
254
274
|
if (resolution)
|
|
255
275
|
resolution.isDuplicate = false;
|
|
@@ -274,9 +294,9 @@ export class LinkedListRenovation {
|
|
|
274
294
|
}
|
|
275
295
|
thisIsModified(item) {
|
|
276
296
|
if (item.list !== this.list.items$)
|
|
277
|
-
throw misuse("only
|
|
297
|
+
throw misuse("only reaffirmed items can be marked as modified");
|
|
278
298
|
const m = item.mark;
|
|
279
|
-
if (m === Mark.
|
|
299
|
+
if (m === Mark.reaffirmed)
|
|
280
300
|
LinkedItem.setStatus$(item, Mark.modified, item.rank);
|
|
281
301
|
else if (m !== Mark.modified)
|
|
282
302
|
throw misuse("item is renovated already and cannot be marked as modified");
|