reactronic 0.94.25034 → 0.94.25037
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/api.d.ts +2 -2
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/MvccReconciliationList.d.ts +27 -0
- package/build/dist/source/core/MvccReconciliationList.js +25 -0
- package/build/dist/source/core/TreeNode.d.ts +8 -8
- package/build/dist/source/core/TreeNode.js +13 -13
- package/build/dist/source/util/ReconciliationList.d.ts +64 -0
- package/build/dist/source/util/{MergeList.js → ReconciliationList.js} +45 -45
- package/package.json +1 -1
- package/build/dist/source/core/MvccMergeList.d.ts +0 -27
- package/build/dist/source/core/MvccMergeList.js +0 -25
- package/build/dist/source/util/MergeList.d.ts +0 -64
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { all, pause, proceedSyncOrAsync } from "./util/Utils.js";
|
|
2
2
|
export { Uri } from "./util/Uri.js";
|
|
3
|
-
export {
|
|
4
|
-
export type {
|
|
3
|
+
export { ReconciliationList } from "./util/ReconciliationList.js";
|
|
4
|
+
export type { LinkedItem, ReconciliationListReader } from "./util/ReconciliationList.js";
|
|
5
5
|
export { SealedArray } from "./util/SealedArray.js";
|
|
6
6
|
export { SealedMap } from "./util/SealedMap.js";
|
|
7
7
|
export { SealedSet } from "./util/SealedSet.js";
|
package/build/dist/source/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { all, pause, proceedSyncOrAsync } from "./util/Utils.js";
|
|
2
2
|
export { Uri } from "./util/Uri.js";
|
|
3
|
-
export {
|
|
3
|
+
export { ReconciliationList } from "./util/ReconciliationList.js";
|
|
4
4
|
export { SealedArray } from "./util/SealedArray.js";
|
|
5
5
|
export { SealedMap } from "./util/SealedMap.js";
|
|
6
6
|
export { SealedSet } from "./util/SealedSet.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReconciliationList, LinkedItem, ReconciliationListReader } from "../util/ReconciliationList.js";
|
|
2
|
+
import { ObservableObject } from "./Mvcc.js";
|
|
3
|
+
export declare abstract class ObservableReconciliationList<T> extends ObservableObject implements ReconciliationListReader<T> {
|
|
4
|
+
protected abstract impl: ReconciliationList<T>;
|
|
5
|
+
get isStrict(): boolean;
|
|
6
|
+
get count(): number;
|
|
7
|
+
get countOfAdded(): number;
|
|
8
|
+
get countOfRemoved(): number;
|
|
9
|
+
get isReconciliationInProgress(): boolean;
|
|
10
|
+
lookup(key: string): LinkedItem<T> | undefined;
|
|
11
|
+
tryMergeAsExisting(key: string): LinkedItem<T> | undefined;
|
|
12
|
+
mergeAsAdded(instance: T): LinkedItem<T>;
|
|
13
|
+
mergeAsRemoved(item: LinkedItem<T>): void;
|
|
14
|
+
move(item: LinkedItem<T>, after: LinkedItem<T>): void;
|
|
15
|
+
beginMerge(): void;
|
|
16
|
+
endMerge(error?: unknown): void;
|
|
17
|
+
resetAddedAndRemovedLists(): void;
|
|
18
|
+
firstItem(): LinkedItem<T> | undefined;
|
|
19
|
+
lastItem(): LinkedItem<T> | undefined;
|
|
20
|
+
items(): Generator<LinkedItem<T>>;
|
|
21
|
+
itemsAdded(reset?: boolean): Generator<LinkedItem<T>>;
|
|
22
|
+
itemsRemoved(reset?: boolean): Generator<LinkedItem<T>>;
|
|
23
|
+
isAdded(item: LinkedItem<T>): boolean;
|
|
24
|
+
isMoved(item: LinkedItem<T>): boolean;
|
|
25
|
+
isRemoved(item: LinkedItem<T>): boolean;
|
|
26
|
+
isFresh(item: LinkedItem<T>): boolean;
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ObservableObject } from "./Mvcc.js";
|
|
2
|
+
export class ObservableReconciliationList extends ObservableObject {
|
|
3
|
+
get isStrict() { return this.impl.isStrict; }
|
|
4
|
+
get count() { return this.impl.count; }
|
|
5
|
+
get countOfAdded() { return this.impl.countOfAdded; }
|
|
6
|
+
get countOfRemoved() { return this.impl.countOfRemoved; }
|
|
7
|
+
get isReconciliationInProgress() { return this.impl.isReconciliationInProgress; }
|
|
8
|
+
lookup(key) { return this.impl.lookup(key); }
|
|
9
|
+
tryMergeAsExisting(key) { return this.impl.tryReuse(key); }
|
|
10
|
+
mergeAsAdded(instance) { return this.impl.add(instance); }
|
|
11
|
+
mergeAsRemoved(item) { return this.impl.remove(item); }
|
|
12
|
+
move(item, after) { this.impl.move(item, after); }
|
|
13
|
+
beginMerge() { this.impl.beginReconciliation(); }
|
|
14
|
+
endMerge(error) { this.impl.endReconciliation(error); }
|
|
15
|
+
resetAddedAndRemovedLists() { this.impl.resetAddedAndRemovedLists(); }
|
|
16
|
+
firstItem() { return this.impl.firstItem(); }
|
|
17
|
+
lastItem() { return this.impl.lastItem(); }
|
|
18
|
+
items() { return this.impl.items(); }
|
|
19
|
+
itemsAdded(reset) { return this.impl.itemsAdded(reset); }
|
|
20
|
+
itemsRemoved(reset) { return this.impl.itemsRemoved(reset); }
|
|
21
|
+
isAdded(item) { return this.impl.isAdded(item); }
|
|
22
|
+
isMoved(item) { return this.impl.isMoved(item); }
|
|
23
|
+
isRemoved(item) { return this.impl.isRemoved(item); }
|
|
24
|
+
isFresh(item) { return this.impl.isFresh(item); }
|
|
25
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LoggingOptions } from "../Logging.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ReconciliationList, ReconciliationListReader, LinkedItem } from "../util/ReconciliationList.js";
|
|
3
3
|
import { Priority, Mode } from "../Enums.js";
|
|
4
4
|
import { ReactivityOptions } from "../Options.js";
|
|
5
5
|
import { ObservableObject } from "../core/Mvcc.js";
|
|
@@ -23,8 +23,8 @@ export declare abstract class ReactiveTreeNode<E = unknown> {
|
|
|
23
23
|
abstract readonly owner: ReactiveTreeNode;
|
|
24
24
|
abstract element: E;
|
|
25
25
|
abstract readonly host: ReactiveTreeNode;
|
|
26
|
-
abstract readonly children:
|
|
27
|
-
abstract readonly slot:
|
|
26
|
+
abstract readonly children: ReconciliationListReader<ReactiveTreeNode>;
|
|
27
|
+
abstract readonly slot: LinkedItem<ReactiveTreeNode<E>> | undefined;
|
|
28
28
|
abstract readonly stamp: number;
|
|
29
29
|
abstract readonly outer: ReactiveTreeNode;
|
|
30
30
|
abstract readonly context: ReactiveTreeNodeContext | undefined;
|
|
@@ -67,7 +67,7 @@ export type ReactiveTreeNodeDriver<E = unknown> = {
|
|
|
67
67
|
runFinalization(node: ReactiveTreeNode<E>, isLeader: boolean): boolean;
|
|
68
68
|
runMount(node: ReactiveTreeNode<E>): void;
|
|
69
69
|
runScript(node: ReactiveTreeNode<E>): void | Promise<void>;
|
|
70
|
-
declareChild(ownerNode: ReactiveTreeNode<E>, childDriver: ReactiveTreeNodeDriver<any>, childDeclaration?: ReactiveTreeNodeDecl<any>, childBasis?: ReactiveTreeNodeDecl<any>):
|
|
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
|
};
|
|
73
73
|
export type ReactiveTreeNodeContext<T extends Object = Object> = {
|
|
@@ -83,7 +83,7 @@ export declare abstract class BaseDriver<E = unknown> implements ReactiveTreeNod
|
|
|
83
83
|
runFinalization(node: ReactiveTreeNode<E>, isLeader: boolean): boolean;
|
|
84
84
|
runMount(node: ReactiveTreeNode<E>): void;
|
|
85
85
|
runScript(node: ReactiveTreeNode<E>): void | Promise<void>;
|
|
86
|
-
declareChild(ownerNode: ReactiveTreeNode<E>, childDriver: ReactiveTreeNodeDriver<any>, childDeclaration?: ReactiveTreeNodeDecl<any>, childBasis?: ReactiveTreeNodeDecl<any>):
|
|
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
|
}
|
|
89
89
|
export declare class ReactiveTreeVariable<T extends Object = Object> {
|
|
@@ -112,8 +112,8 @@ declare class ReactiveTreeNodeImpl<E = unknown> extends ReactiveTreeNode<E> {
|
|
|
112
112
|
readonly owner: ReactiveTreeNodeImpl;
|
|
113
113
|
readonly element: E;
|
|
114
114
|
host: ReactiveTreeNodeImpl;
|
|
115
|
-
readonly children:
|
|
116
|
-
slot:
|
|
115
|
+
readonly children: ReconciliationList<ReactiveTreeNodeImpl>;
|
|
116
|
+
slot: LinkedItem<ReactiveTreeNodeImpl<E>> | undefined;
|
|
117
117
|
stamp: number;
|
|
118
118
|
outer: ReactiveTreeNodeImpl;
|
|
119
119
|
context: ReactiveTreeNodeContextImpl<any> | undefined;
|
|
@@ -128,7 +128,7 @@ declare class ReactiveTreeNodeImpl<E = unknown> extends ReactiveTreeNode<E> {
|
|
|
128
128
|
has(mode: Mode): boolean;
|
|
129
129
|
script(_triggers: unknown): void;
|
|
130
130
|
configureReactivity(options: Partial<ReactivityOptions>): ReactivityOptions;
|
|
131
|
-
static get nodeSlot():
|
|
131
|
+
static get nodeSlot(): LinkedItem<ReactiveTreeNodeImpl>;
|
|
132
132
|
static tryUseTreeVariableValue<T extends Object>(variable: ReactiveTreeVariable<T>): T | undefined;
|
|
133
133
|
static useTreeVariableValue<T extends Object>(variable: ReactiveTreeVariable<T>): T;
|
|
134
134
|
static setTreeVariableValue<T extends Object>(variable: ReactiveTreeVariable<T>, value: T | undefined): void;
|
|
@@ -18,7 +18,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
18
18
|
};
|
|
19
19
|
import { misuse } from "../util/Dbg.js";
|
|
20
20
|
import { Uri } from "../util/Uri.js";
|
|
21
|
-
import {
|
|
21
|
+
import { ReconciliationList } from "../util/ReconciliationList.js";
|
|
22
22
|
import { emitLetters, flags, getCallerInfo, proceedSyncOrAsync } from "../util/Utils.js";
|
|
23
23
|
import { Priority, Mode, Isolation, Reentrance } from "../Enums.js";
|
|
24
24
|
import { ObservableObject } from "../core/Mvcc.js";
|
|
@@ -40,7 +40,7 @@ export function declare(driver, scriptOrDeclaration, scriptAsync, key, mode, pre
|
|
|
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.
|
|
43
|
+
existing !== null && existing !== void 0 ? existing : (existing = children.tryReuse(effectiveKey = effectiveKey || generateKey(owner), undefined, "nested elements can be declared inside 'script' only"));
|
|
44
44
|
if (existing) {
|
|
45
45
|
result = existing.instance;
|
|
46
46
|
if (result.driver !== driver && driver !== undefined)
|
|
@@ -52,12 +52,12 @@ export function declare(driver, scriptOrDeclaration, scriptAsync, key, mode, pre
|
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
54
|
result = new ReactiveTreeNodeImpl(effectiveKey || generateKey(owner), driver, declaration, owner);
|
|
55
|
-
result.slot = children.
|
|
55
|
+
result.slot = children.add(result);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
59
|
result = new ReactiveTreeNodeImpl(effectiveKey || generateKey(owner), driver, declaration, owner);
|
|
60
|
-
result.slot =
|
|
60
|
+
result.slot = ReconciliationList.createItem(result);
|
|
61
61
|
}
|
|
62
62
|
return result;
|
|
63
63
|
}
|
|
@@ -89,7 +89,7 @@ export class ReactiveTreeNode {
|
|
|
89
89
|
}
|
|
90
90
|
static launchFinalization(node) {
|
|
91
91
|
const impl = node;
|
|
92
|
-
|
|
92
|
+
launchFinalizationViaSlot(impl.slot, true, true);
|
|
93
93
|
}
|
|
94
94
|
static launchNestedNodesThenDo(action) {
|
|
95
95
|
launchNestedNodesThenDoImpl(ReactiveTreeNodeImpl.nodeSlot, undefined, action);
|
|
@@ -270,7 +270,7 @@ class ReactiveTreeNodeImpl extends ReactiveTreeNode {
|
|
|
270
270
|
}
|
|
271
271
|
this.element = driver.create(this);
|
|
272
272
|
this.host = thisAsUnknown;
|
|
273
|
-
this.children = new
|
|
273
|
+
this.children = new ReconciliationList(getNodeKey, true);
|
|
274
274
|
this.slot = undefined;
|
|
275
275
|
this.stamp = Number.MAX_SAFE_INTEGER;
|
|
276
276
|
this.context = undefined;
|
|
@@ -388,12 +388,12 @@ function launchNestedNodesThenDoImpl(nodeSlot, error, action) {
|
|
|
388
388
|
var _a;
|
|
389
389
|
const owner = nodeSlot.instance;
|
|
390
390
|
const children = owner.children;
|
|
391
|
-
if (children.
|
|
391
|
+
if (children.isReconciliationInProgress) {
|
|
392
392
|
let promised = undefined;
|
|
393
393
|
try {
|
|
394
|
-
children.
|
|
395
|
-
for (const child of children.
|
|
396
|
-
|
|
394
|
+
children.endReconciliation(error);
|
|
395
|
+
for (const child of children.itemsRemoved(true))
|
|
396
|
+
launchFinalizationViaSlot(child, true, true);
|
|
397
397
|
if (!error) {
|
|
398
398
|
const sequential = children.isStrict;
|
|
399
399
|
let p1 = undefined;
|
|
@@ -528,7 +528,7 @@ function runScriptNow(nodeSlot) {
|
|
|
528
528
|
try {
|
|
529
529
|
node.stamp++;
|
|
530
530
|
node.numerator = 0;
|
|
531
|
-
node.children.
|
|
531
|
+
node.children.beginReconciliation();
|
|
532
532
|
const driver = node.driver;
|
|
533
533
|
result = driver.runScript(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); });
|
|
@@ -542,7 +542,7 @@ function runScriptNow(nodeSlot) {
|
|
|
542
542
|
});
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
|
-
function
|
|
545
|
+
function launchFinalizationViaSlot(nodeSlot, isLeader, individual) {
|
|
546
546
|
const node = nodeSlot.instance;
|
|
547
547
|
if (node.stamp >= 0) {
|
|
548
548
|
const driver = node.driver;
|
|
@@ -563,7 +563,7 @@ function launchFinalization(nodeSlot, isLeader, individual) {
|
|
|
563
563
|
});
|
|
564
564
|
}
|
|
565
565
|
for (const child of node.children.items())
|
|
566
|
-
|
|
566
|
+
launchFinalizationViaSlot(child, childrenAreLeaders, false);
|
|
567
567
|
ReactiveTreeNodeImpl.grandNodeCount--;
|
|
568
568
|
}
|
|
569
569
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type GetListItemKey<T = unknown> = (item: T) => string | undefined;
|
|
2
|
+
export type ReconciliationListReader<T> = {
|
|
3
|
+
readonly isStrict: boolean;
|
|
4
|
+
readonly count: number;
|
|
5
|
+
readonly countOfAdded: number;
|
|
6
|
+
readonly countOfRemoved: number;
|
|
7
|
+
readonly isReconciliationInProgress: boolean;
|
|
8
|
+
lookup(key: string): LinkedItem<T> | undefined;
|
|
9
|
+
firstItem(): LinkedItem<T> | undefined;
|
|
10
|
+
lastItem(): LinkedItem<T> | undefined;
|
|
11
|
+
items(onlyAfter?: LinkedItem<T>): Generator<LinkedItem<T>>;
|
|
12
|
+
itemsAdded(reset?: boolean): Generator<LinkedItem<T>>;
|
|
13
|
+
itemsRemoved(reset?: boolean): Generator<LinkedItem<T>>;
|
|
14
|
+
isAdded(item: LinkedItem<T>): boolean;
|
|
15
|
+
isMoved(item: LinkedItem<T>): boolean;
|
|
16
|
+
isRemoved(item: LinkedItem<T>): boolean;
|
|
17
|
+
isFresh(item: LinkedItem<T>): boolean;
|
|
18
|
+
};
|
|
19
|
+
export type LinkedItem<T> = {
|
|
20
|
+
readonly instance: T;
|
|
21
|
+
readonly index: number;
|
|
22
|
+
readonly next?: LinkedItem<T>;
|
|
23
|
+
readonly prev?: LinkedItem<T>;
|
|
24
|
+
aux?: LinkedItem<T>;
|
|
25
|
+
};
|
|
26
|
+
export declare class ReconciliationList<T> implements ReconciliationListReader<T> {
|
|
27
|
+
readonly getKey: GetListItemKey<T>;
|
|
28
|
+
private strict;
|
|
29
|
+
private map;
|
|
30
|
+
private tag;
|
|
31
|
+
private fresh;
|
|
32
|
+
private added;
|
|
33
|
+
private removed;
|
|
34
|
+
private lastNotFoundKey;
|
|
35
|
+
private strictNextItem?;
|
|
36
|
+
constructor(getKey: GetListItemKey<T>, strict?: boolean);
|
|
37
|
+
get isStrict(): boolean;
|
|
38
|
+
set isStrict(value: boolean);
|
|
39
|
+
get count(): number;
|
|
40
|
+
get countOfAdded(): number;
|
|
41
|
+
get countOfRemoved(): number;
|
|
42
|
+
get isReconciliationInProgress(): boolean;
|
|
43
|
+
lookup(key: string | undefined): LinkedItem<T> | undefined;
|
|
44
|
+
tryReuse(key: string, resolution?: {
|
|
45
|
+
isDuplicate: boolean;
|
|
46
|
+
}, error?: string): LinkedItem<T> | undefined;
|
|
47
|
+
add(instance: T): LinkedItem<T>;
|
|
48
|
+
remove(item: LinkedItem<T>): void;
|
|
49
|
+
move(item: LinkedItem<T>, after: LinkedItem<T>): void;
|
|
50
|
+
beginReconciliation(): void;
|
|
51
|
+
endReconciliation(error?: unknown): void;
|
|
52
|
+
resetAddedAndRemovedLists(): void;
|
|
53
|
+
firstItem(): LinkedItem<T> | undefined;
|
|
54
|
+
lastItem(): LinkedItem<T> | undefined;
|
|
55
|
+
items(onlyAfter?: LinkedItem<T>): Generator<LinkedItem<T>>;
|
|
56
|
+
itemsAdded(reset?: boolean): Generator<LinkedItem<T>>;
|
|
57
|
+
itemsRemoved(reset?: boolean): Generator<LinkedItem<T>>;
|
|
58
|
+
isAdded(item: LinkedItem<T>): boolean;
|
|
59
|
+
isMoved(item: LinkedItem<T>): boolean;
|
|
60
|
+
isRemoved(item: LinkedItem<T>): boolean;
|
|
61
|
+
isFresh(item: LinkedItem<T>): boolean;
|
|
62
|
+
markAsMoved(item: LinkedItem<T>): void;
|
|
63
|
+
static createItem<T>(instance: T): LinkedItem<T>;
|
|
64
|
+
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { misuse } from "./Dbg.js";
|
|
2
|
-
export class
|
|
2
|
+
export class ReconciliationList {
|
|
3
3
|
constructor(getKey, strict = false) {
|
|
4
4
|
this.getKey = getKey;
|
|
5
5
|
this.strict = strict;
|
|
6
6
|
this.map = new Map();
|
|
7
7
|
this.tag = ~0;
|
|
8
|
-
this.
|
|
9
|
-
this.added = new
|
|
10
|
-
this.removed = new
|
|
8
|
+
this.fresh = new LinkedItemChain();
|
|
9
|
+
this.added = new LinkedItemChain();
|
|
10
|
+
this.removed = new LinkedItemChain();
|
|
11
11
|
this.lastNotFoundKey = undefined;
|
|
12
12
|
this.strictNextItem = undefined;
|
|
13
13
|
}
|
|
14
14
|
get isStrict() { return this.strict; }
|
|
15
15
|
set isStrict(value) {
|
|
16
|
-
if (this.
|
|
17
|
-
throw misuse("cannot change strict mode in the middle of
|
|
16
|
+
if (this.isReconciliationInProgress && this.fresh.count > 0)
|
|
17
|
+
throw misuse("cannot change strict mode in the middle of reconciliation");
|
|
18
18
|
this.strict = value;
|
|
19
19
|
}
|
|
20
20
|
get count() {
|
|
21
|
-
return this.
|
|
21
|
+
return this.fresh.count;
|
|
22
22
|
}
|
|
23
|
-
get
|
|
23
|
+
get countOfAdded() {
|
|
24
24
|
return this.added.count;
|
|
25
25
|
}
|
|
26
|
-
get
|
|
26
|
+
get countOfRemoved() {
|
|
27
27
|
return this.removed.count;
|
|
28
28
|
}
|
|
29
|
-
get
|
|
29
|
+
get isReconciliationInProgress() {
|
|
30
30
|
return this.tag > 0;
|
|
31
31
|
}
|
|
32
32
|
lookup(key) {
|
|
@@ -44,10 +44,10 @@ export class MergeList {
|
|
|
44
44
|
}
|
|
45
45
|
return result;
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
tryReuse(key, resolution, error) {
|
|
48
48
|
const tag = this.tag;
|
|
49
49
|
if (tag < 0)
|
|
50
|
-
throw misuse(error !== null && error !== void 0 ? error : "
|
|
50
|
+
throw misuse(error !== null && error !== void 0 ? error : "reconciliation is not in progress");
|
|
51
51
|
let item = this.strictNextItem;
|
|
52
52
|
if (key !== (item ? this.getKey(item.instance) : undefined))
|
|
53
53
|
item = this.lookup(key);
|
|
@@ -58,8 +58,8 @@ export class MergeList {
|
|
|
58
58
|
item.status = tag;
|
|
59
59
|
this.strictNextItem = item.next;
|
|
60
60
|
this.removed.exclude(item);
|
|
61
|
-
item.index = this.
|
|
62
|
-
this.
|
|
61
|
+
item.index = this.fresh.count;
|
|
62
|
+
this.fresh.include(item);
|
|
63
63
|
if (resolution)
|
|
64
64
|
resolution.isDuplicate = false;
|
|
65
65
|
}
|
|
@@ -72,7 +72,7 @@ export class MergeList {
|
|
|
72
72
|
resolution.isDuplicate = false;
|
|
73
73
|
return item;
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
add(instance) {
|
|
76
76
|
const key = this.getKey(instance);
|
|
77
77
|
if (this.lookup(key) !== undefined)
|
|
78
78
|
throw misuse(`key is already in use: ${key}`);
|
|
@@ -81,19 +81,19 @@ export class MergeList {
|
|
|
81
81
|
tag = ~this.tag + 1;
|
|
82
82
|
this.tag = ~tag;
|
|
83
83
|
}
|
|
84
|
-
const item = new
|
|
84
|
+
const item = new LinkedItemImpl(instance, tag);
|
|
85
85
|
this.map.set(key, item);
|
|
86
86
|
this.lastNotFoundKey = undefined;
|
|
87
87
|
this.strictNextItem = undefined;
|
|
88
|
-
item.index = this.
|
|
89
|
-
this.
|
|
88
|
+
item.index = this.fresh.count;
|
|
89
|
+
this.fresh.include(item);
|
|
90
90
|
this.added.aux(item);
|
|
91
91
|
return item;
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
remove(item) {
|
|
94
94
|
const t = item;
|
|
95
95
|
if (!this.isRemoved(t)) {
|
|
96
|
-
this.
|
|
96
|
+
this.fresh.exclude(t);
|
|
97
97
|
this.removed.include(t);
|
|
98
98
|
t.tag--;
|
|
99
99
|
}
|
|
@@ -101,30 +101,30 @@ export class MergeList {
|
|
|
101
101
|
move(item, after) {
|
|
102
102
|
throw misuse("not implemented");
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
if (this.
|
|
106
|
-
throw misuse("
|
|
104
|
+
beginReconciliation() {
|
|
105
|
+
if (this.isReconciliationInProgress)
|
|
106
|
+
throw misuse("reconciliation is in progress already");
|
|
107
107
|
this.tag = ~this.tag + 1;
|
|
108
|
-
this.strictNextItem = this.
|
|
109
|
-
this.removed.grab(this.
|
|
108
|
+
this.strictNextItem = this.fresh.first;
|
|
109
|
+
this.removed.grab(this.fresh, false);
|
|
110
110
|
this.added.reset();
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
if (!this.
|
|
114
|
-
throw misuse("
|
|
112
|
+
endReconciliation(error) {
|
|
113
|
+
if (!this.isReconciliationInProgress)
|
|
114
|
+
throw misuse("reconciliation is ended already");
|
|
115
115
|
this.tag = ~this.tag;
|
|
116
116
|
if (error === undefined) {
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
117
|
+
const freshCount = this.fresh.count;
|
|
118
|
+
if (freshCount > 0) {
|
|
119
119
|
const getKey = this.getKey;
|
|
120
|
-
if (
|
|
120
|
+
if (freshCount > this.removed.count) {
|
|
121
121
|
const map = this.map;
|
|
122
122
|
for (const x of this.removed.items())
|
|
123
123
|
map.delete(getKey(x.instance));
|
|
124
124
|
}
|
|
125
125
|
else {
|
|
126
126
|
const map = this.map = new Map();
|
|
127
|
-
for (const x of this.
|
|
127
|
+
for (const x of this.fresh.items())
|
|
128
128
|
map.set(getKey(x.instance), x);
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -132,11 +132,11 @@ export class MergeList {
|
|
|
132
132
|
this.map = new Map();
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
|
-
this.
|
|
135
|
+
this.fresh.grab(this.removed, true);
|
|
136
136
|
const getKey = this.getKey;
|
|
137
137
|
for (const x of this.added.itemsViaAux()) {
|
|
138
138
|
this.map.delete(getKey(x.instance));
|
|
139
|
-
this.
|
|
139
|
+
this.fresh.exclude(x);
|
|
140
140
|
}
|
|
141
141
|
this.added.reset();
|
|
142
142
|
}
|
|
@@ -145,22 +145,22 @@ export class MergeList {
|
|
|
145
145
|
this.removed.reset();
|
|
146
146
|
this.added.reset();
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
return this.
|
|
148
|
+
firstItem() {
|
|
149
|
+
return this.fresh.first;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
return this.
|
|
151
|
+
lastItem() {
|
|
152
|
+
return this.fresh.last;
|
|
153
153
|
}
|
|
154
154
|
*items(onlyAfter) {
|
|
155
155
|
var _a;
|
|
156
|
-
let x = (_a = onlyAfter === null || onlyAfter === void 0 ? void 0 : onlyAfter.next) !== null && _a !== void 0 ? _a : this.
|
|
156
|
+
let x = (_a = onlyAfter === null || onlyAfter === void 0 ? void 0 : onlyAfter.next) !== null && _a !== void 0 ? _a : this.fresh.first;
|
|
157
157
|
while (x !== undefined) {
|
|
158
158
|
const next = x.next;
|
|
159
159
|
yield x;
|
|
160
160
|
x = next;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
*
|
|
163
|
+
*itemsAdded(reset) {
|
|
164
164
|
let x = this.added.first;
|
|
165
165
|
while (x !== undefined) {
|
|
166
166
|
const next = x.aux;
|
|
@@ -171,7 +171,7 @@ export class MergeList {
|
|
|
171
171
|
if (reset)
|
|
172
172
|
this.added.reset();
|
|
173
173
|
}
|
|
174
|
-
*
|
|
174
|
+
*itemsRemoved(reset) {
|
|
175
175
|
let x = this.removed.first;
|
|
176
176
|
while (x !== undefined) {
|
|
177
177
|
const next = x.next;
|
|
@@ -200,7 +200,7 @@ export class MergeList {
|
|
|
200
200
|
const tag = this.tag;
|
|
201
201
|
return tag > 0 ? t.tag < tag : t.tag < tag - 1;
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
isFresh(item) {
|
|
204
204
|
const t = item;
|
|
205
205
|
return t.tag === this.tag;
|
|
206
206
|
}
|
|
@@ -210,10 +210,10 @@ export class MergeList {
|
|
|
210
210
|
t.status = t.tag;
|
|
211
211
|
}
|
|
212
212
|
static createItem(instance) {
|
|
213
|
-
return new
|
|
213
|
+
return new LinkedItemImpl(instance, 0);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
|
-
class
|
|
216
|
+
class LinkedItemImpl {
|
|
217
217
|
constructor(instance, tag) {
|
|
218
218
|
this.instance = instance;
|
|
219
219
|
this.index = -1;
|
|
@@ -224,7 +224,7 @@ class MergedItemImpl {
|
|
|
224
224
|
this.aux = undefined;
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
|
-
class
|
|
227
|
+
class LinkedItemChain {
|
|
228
228
|
constructor() {
|
|
229
229
|
this.count = 0;
|
|
230
230
|
this.first = undefined;
|
package/package.json
CHANGED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { MergeList, MergedItem, MergeListReader } from "../util/MergeList.js";
|
|
2
|
-
import { ObservableObject } from "./Mvcc.js";
|
|
3
|
-
export declare abstract class ObservableMergeList<T> extends ObservableObject implements MergeListReader<T> {
|
|
4
|
-
protected abstract impl: MergeList<T>;
|
|
5
|
-
get isStrict(): boolean;
|
|
6
|
-
get count(): number;
|
|
7
|
-
get addedCount(): number;
|
|
8
|
-
get removedCount(): number;
|
|
9
|
-
get isMergeInProgress(): boolean;
|
|
10
|
-
lookup(key: string): MergedItem<T> | undefined;
|
|
11
|
-
tryMergeAsExisting(key: string): MergedItem<T> | undefined;
|
|
12
|
-
mergeAsAdded(instance: T): MergedItem<T>;
|
|
13
|
-
mergeAsRemoved(item: MergedItem<T>): void;
|
|
14
|
-
move(item: MergedItem<T>, after: MergedItem<T>): void;
|
|
15
|
-
beginMerge(): void;
|
|
16
|
-
endMerge(error?: unknown): void;
|
|
17
|
-
resetAddedAndRemovedLists(): void;
|
|
18
|
-
firstMergedItem(): MergedItem<T> | undefined;
|
|
19
|
-
lastMergedItem(): MergedItem<T> | undefined;
|
|
20
|
-
items(): Generator<MergedItem<T>>;
|
|
21
|
-
addedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
22
|
-
removedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
23
|
-
isAdded(item: MergedItem<T>): boolean;
|
|
24
|
-
isMoved(item: MergedItem<T>): boolean;
|
|
25
|
-
isRemoved(item: MergedItem<T>): boolean;
|
|
26
|
-
isActual(item: MergedItem<T>): boolean;
|
|
27
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { ObservableObject } from "./Mvcc.js";
|
|
2
|
-
export class ObservableMergeList extends ObservableObject {
|
|
3
|
-
get isStrict() { return this.impl.isStrict; }
|
|
4
|
-
get count() { return this.impl.count; }
|
|
5
|
-
get addedCount() { return this.impl.addedCount; }
|
|
6
|
-
get removedCount() { return this.impl.removedCount; }
|
|
7
|
-
get isMergeInProgress() { return this.impl.isMergeInProgress; }
|
|
8
|
-
lookup(key) { return this.impl.lookup(key); }
|
|
9
|
-
tryMergeAsExisting(key) { return this.impl.tryMergeAsExisting(key); }
|
|
10
|
-
mergeAsAdded(instance) { return this.impl.mergeAsAdded(instance); }
|
|
11
|
-
mergeAsRemoved(item) { return this.impl.mergeAsRemoved(item); }
|
|
12
|
-
move(item, after) { this.impl.move(item, after); }
|
|
13
|
-
beginMerge() { this.impl.beginMerge(); }
|
|
14
|
-
endMerge(error) { this.impl.endMerge(error); }
|
|
15
|
-
resetAddedAndRemovedLists() { this.impl.resetAddedAndRemovedLists(); }
|
|
16
|
-
firstMergedItem() { return this.impl.firstMergedItem(); }
|
|
17
|
-
lastMergedItem() { return this.impl.lastMergedItem(); }
|
|
18
|
-
items() { return this.impl.items(); }
|
|
19
|
-
addedItems(reset) { return this.impl.addedItems(reset); }
|
|
20
|
-
removedItems(reset) { return this.impl.removedItems(reset); }
|
|
21
|
-
isAdded(item) { return this.impl.isAdded(item); }
|
|
22
|
-
isMoved(item) { return this.impl.isMoved(item); }
|
|
23
|
-
isRemoved(item) { return this.impl.isRemoved(item); }
|
|
24
|
-
isActual(item) { return this.impl.isActual(item); }
|
|
25
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
export type GetMergedItemKey<T = unknown> = (item: T) => string | undefined;
|
|
2
|
-
export type MergeListReader<T> = {
|
|
3
|
-
readonly isStrict: boolean;
|
|
4
|
-
readonly count: number;
|
|
5
|
-
readonly addedCount: number;
|
|
6
|
-
readonly removedCount: number;
|
|
7
|
-
readonly isMergeInProgress: boolean;
|
|
8
|
-
lookup(key: string): MergedItem<T> | undefined;
|
|
9
|
-
firstMergedItem(): MergedItem<T> | undefined;
|
|
10
|
-
lastMergedItem(): MergedItem<T> | undefined;
|
|
11
|
-
items(onlyAfter?: MergedItem<T>): Generator<MergedItem<T>>;
|
|
12
|
-
addedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
13
|
-
removedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
14
|
-
isAdded(item: MergedItem<T>): boolean;
|
|
15
|
-
isMoved(item: MergedItem<T>): boolean;
|
|
16
|
-
isRemoved(item: MergedItem<T>): boolean;
|
|
17
|
-
isActual(item: MergedItem<T>): boolean;
|
|
18
|
-
};
|
|
19
|
-
export type MergedItem<T> = {
|
|
20
|
-
readonly instance: T;
|
|
21
|
-
readonly index: number;
|
|
22
|
-
readonly next?: MergedItem<T>;
|
|
23
|
-
readonly prev?: MergedItem<T>;
|
|
24
|
-
aux?: MergedItem<T>;
|
|
25
|
-
};
|
|
26
|
-
export declare class MergeList<T> implements MergeListReader<T> {
|
|
27
|
-
readonly getKey: GetMergedItemKey<T>;
|
|
28
|
-
private strict;
|
|
29
|
-
private map;
|
|
30
|
-
private tag;
|
|
31
|
-
private current;
|
|
32
|
-
private added;
|
|
33
|
-
private removed;
|
|
34
|
-
private lastNotFoundKey;
|
|
35
|
-
private strictNextItem?;
|
|
36
|
-
constructor(getKey: GetMergedItemKey<T>, strict?: boolean);
|
|
37
|
-
get isStrict(): boolean;
|
|
38
|
-
set isStrict(value: boolean);
|
|
39
|
-
get count(): number;
|
|
40
|
-
get addedCount(): number;
|
|
41
|
-
get removedCount(): number;
|
|
42
|
-
get isMergeInProgress(): boolean;
|
|
43
|
-
lookup(key: string | undefined): MergedItem<T> | undefined;
|
|
44
|
-
tryMergeAsExisting(key: string, resolution?: {
|
|
45
|
-
isDuplicate: boolean;
|
|
46
|
-
}, error?: string): MergedItem<T> | undefined;
|
|
47
|
-
mergeAsAdded(instance: T): MergedItem<T>;
|
|
48
|
-
mergeAsRemoved(item: MergedItem<T>): void;
|
|
49
|
-
move(item: MergedItem<T>, after: MergedItem<T>): void;
|
|
50
|
-
beginMerge(): void;
|
|
51
|
-
endMerge(error?: unknown): void;
|
|
52
|
-
resetAddedAndRemovedLists(): void;
|
|
53
|
-
firstMergedItem(): MergedItem<T> | undefined;
|
|
54
|
-
lastMergedItem(): MergedItem<T> | undefined;
|
|
55
|
-
items(onlyAfter?: MergedItem<T>): Generator<MergedItem<T>>;
|
|
56
|
-
addedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
57
|
-
removedItems(reset?: boolean): Generator<MergedItem<T>>;
|
|
58
|
-
isAdded(item: MergedItem<T>): boolean;
|
|
59
|
-
isMoved(item: MergedItem<T>): boolean;
|
|
60
|
-
isRemoved(item: MergedItem<T>): boolean;
|
|
61
|
-
isActual(item: MergedItem<T>): boolean;
|
|
62
|
-
markAsMoved(item: MergedItem<T>): void;
|
|
63
|
-
static createItem<T>(instance: T): MergedItem<T>;
|
|
64
|
-
}
|