@opendaw/lib-box 0.0.6
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 +1 -0
- package/dist/address.d.ts +47 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +133 -0
- package/dist/array.d.ts +19 -0
- package/dist/array.d.ts.map +1 -0
- package/dist/array.js +32 -0
- package/dist/box.d.ts +51 -0
- package/dist/box.d.ts.map +1 -0
- package/dist/box.js +122 -0
- package/dist/dispatchers.d.ts +16 -0
- package/dist/dispatchers.d.ts.map +1 -0
- package/dist/dispatchers.js +127 -0
- package/dist/editing.d.ts +21 -0
- package/dist/editing.d.ts.map +1 -0
- package/dist/editing.js +131 -0
- package/dist/field.d.ts +42 -0
- package/dist/field.d.ts.map +1 -0
- package/dist/field.js +80 -0
- package/dist/graph-edges.d.ts +16 -0
- package/dist/graph-edges.d.ts.map +1 -0
- package/dist/graph-edges.js +109 -0
- package/dist/graph.d.ts +55 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +262 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/object.d.ts +17 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/object.js +19 -0
- package/dist/pointer-hub.d.ts +26 -0
- package/dist/pointer-hub.d.ts.map +1 -0
- package/dist/pointer-hub.js +110 -0
- package/dist/pointer.d.ts +32 -0
- package/dist/pointer.d.ts.map +1 -0
- package/dist/pointer.js +82 -0
- package/dist/primitive.d.ts +110 -0
- package/dist/primitive.d.ts.map +1 -0
- package/dist/primitive.js +152 -0
- package/dist/serializer.d.ts +7 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +29 -0
- package/dist/sync-source.d.ts +11 -0
- package/dist/sync-source.d.ts.map +1 -0
- package/dist/sync-source.js +72 -0
- package/dist/sync-target.d.ts +5 -0
- package/dist/sync-target.d.ts.map +1 -0
- package/dist/sync-target.js +40 -0
- package/dist/sync.d.ts +24 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +1 -0
- package/dist/updates.d.ts +70 -0
- package/dist/updates.d.ts.map +1 -0
- package/dist/updates.js +178 -0
- package/dist/vertex.d.ts +41 -0
- package/dist/vertex.d.ts.map +1 -0
- package/dist/vertex.js +1 -0
- package/package.json +33 -0
package/dist/editing.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Arrays, assert, Option } from "@opendaw/lib-std";
|
|
2
|
+
class EditingStep {
|
|
3
|
+
updates;
|
|
4
|
+
constructor(updates) {
|
|
5
|
+
this.updates = updates;
|
|
6
|
+
}
|
|
7
|
+
undo(graph) {
|
|
8
|
+
for (const update of this.updates.toReversed()) {
|
|
9
|
+
update.inverse(graph);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
redo(graph) {
|
|
13
|
+
for (const update of this.updates) {
|
|
14
|
+
update.forward(graph);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class Editing {
|
|
19
|
+
#graph;
|
|
20
|
+
#pending = [];
|
|
21
|
+
#history = [];
|
|
22
|
+
#modifying = false;
|
|
23
|
+
#historyIndex = 0;
|
|
24
|
+
constructor(graph) {
|
|
25
|
+
this.#graph = graph;
|
|
26
|
+
}
|
|
27
|
+
get graph() { return this.#graph; }
|
|
28
|
+
isEmpty() { return this.#history.length === 0 && this.#pending.length === 0; }
|
|
29
|
+
clear() {
|
|
30
|
+
assert(!this.#modifying, "Already modifying");
|
|
31
|
+
Arrays.clear(this.#pending);
|
|
32
|
+
Arrays.clear(this.#history);
|
|
33
|
+
this.#historyIndex = 0;
|
|
34
|
+
}
|
|
35
|
+
undo() {
|
|
36
|
+
if (this.#pending.length > 0) {
|
|
37
|
+
this.mark();
|
|
38
|
+
}
|
|
39
|
+
if (this.#historyIndex === 0) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
this.#graph.beginTransaction();
|
|
43
|
+
const editingStep = this.#history[--this.#historyIndex];
|
|
44
|
+
editingStep.undo(this.#graph);
|
|
45
|
+
this.#graph.endTransaction();
|
|
46
|
+
this.#graph.edges().validateRequirements();
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
redo() {
|
|
50
|
+
if (this.#historyIndex === this.#history.length) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (this.#pending.length > 0) {
|
|
54
|
+
console.warn("redo while having pending updates?");
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
this.#graph.beginTransaction();
|
|
58
|
+
this.#history[this.#historyIndex++].redo(this.#graph);
|
|
59
|
+
this.#graph.endTransaction();
|
|
60
|
+
this.#graph.edges().validateRequirements();
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// TODO This is an option to clarify, if user actions meant to be run by a modifier or not.
|
|
64
|
+
// See ParameterWrapper. Not the nicest solution. Probably coming back to this sooner or later.
|
|
65
|
+
canModify() { return !this.#graph.inTransaction(); }
|
|
66
|
+
modify(modifier, mark = true) {
|
|
67
|
+
if (this.#modifying) {
|
|
68
|
+
// we just keep adding new updates to the running modifier
|
|
69
|
+
return Option.wrap(modifier());
|
|
70
|
+
}
|
|
71
|
+
if (mark && this.#pending.length > 0) {
|
|
72
|
+
this.mark();
|
|
73
|
+
}
|
|
74
|
+
const result = Option.wrap(this.#modify(modifier));
|
|
75
|
+
if (mark) {
|
|
76
|
+
this.mark();
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
beginModification() {
|
|
81
|
+
this.#graph.beginTransaction();
|
|
82
|
+
this.#modifying = true;
|
|
83
|
+
const subscription = this.#graph.subscribeToAllUpdates({
|
|
84
|
+
onUpdate: (update) => this.#pending.push(update)
|
|
85
|
+
});
|
|
86
|
+
const complete = () => {
|
|
87
|
+
this.#graph.endTransaction();
|
|
88
|
+
subscription.terminate();
|
|
89
|
+
this.#modifying = false;
|
|
90
|
+
this.#graph.edges().validateRequirements();
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
approve: () => { complete(); },
|
|
94
|
+
revert: () => {
|
|
95
|
+
this.clearPending();
|
|
96
|
+
complete();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
#modify(modifier) {
|
|
101
|
+
assert(!this.#modifying, "Already modifying");
|
|
102
|
+
this.#modifying = true;
|
|
103
|
+
const subscription = this.#graph.subscribeToAllUpdates({
|
|
104
|
+
onUpdate: (update) => this.#pending.push(update)
|
|
105
|
+
});
|
|
106
|
+
this.#graph.beginTransaction();
|
|
107
|
+
const result = modifier();
|
|
108
|
+
this.#graph.endTransaction();
|
|
109
|
+
subscription.terminate();
|
|
110
|
+
this.#modifying = false;
|
|
111
|
+
this.#graph.edges().validateRequirements();
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
mark() {
|
|
115
|
+
if (this.#pending.length === 0) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (this.#history.length - this.#historyIndex > 0) {
|
|
119
|
+
this.#history.splice(this.#historyIndex);
|
|
120
|
+
}
|
|
121
|
+
this.#history.push(new EditingStep(this.#pending.splice(0)));
|
|
122
|
+
this.#historyIndex = this.#history.length;
|
|
123
|
+
}
|
|
124
|
+
clearPending() {
|
|
125
|
+
if (this.#pending.length === 0) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
this.#pending.reverse().forEach(update => update.inverse(this.#graph));
|
|
129
|
+
this.#pending.length = 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DataInput, DataOutput, Nullish, Option, short } from "@opendaw/lib-std";
|
|
2
|
+
import { Address } from "./address";
|
|
3
|
+
import { Box } from "./box";
|
|
4
|
+
import { PointerRules, Vertex, VertexVisitor } from "./vertex";
|
|
5
|
+
import { PointerTypes } from "./pointer";
|
|
6
|
+
import { PointerHub } from "./pointer-hub";
|
|
7
|
+
import { BoxGraph } from "./graph";
|
|
8
|
+
export type FieldKey = number;
|
|
9
|
+
export type FieldKeys = Readonly<Int16Array>;
|
|
10
|
+
export type Fields = Record<FieldKey, Field>;
|
|
11
|
+
export type FieldConstruct<T extends PointerTypes> = {
|
|
12
|
+
parent: Vertex;
|
|
13
|
+
fieldKey: FieldKey;
|
|
14
|
+
fieldName: string;
|
|
15
|
+
pointerRules: PointerRules<T>;
|
|
16
|
+
};
|
|
17
|
+
export declare class Field<P extends PointerTypes = PointerTypes, F extends Fields = Fields> implements Vertex<P, F> {
|
|
18
|
+
#private;
|
|
19
|
+
static hook<P extends PointerTypes>(construct: FieldConstruct<P>): Field<P, Fields>;
|
|
20
|
+
protected constructor({ parent, fieldKey, fieldName, pointerRules }: FieldConstruct<P>);
|
|
21
|
+
accept<RETURN>(visitor: VertexVisitor<RETURN>): Nullish<RETURN>;
|
|
22
|
+
get box(): Box;
|
|
23
|
+
get graph(): BoxGraph;
|
|
24
|
+
get parent(): Vertex;
|
|
25
|
+
get fieldKey(): short;
|
|
26
|
+
get fieldName(): string;
|
|
27
|
+
get pointerRules(): PointerRules<P>;
|
|
28
|
+
get pointerHub(): PointerHub;
|
|
29
|
+
get address(): Address;
|
|
30
|
+
get debugPath(): string;
|
|
31
|
+
isBox(): this is Box;
|
|
32
|
+
isField(): this is Field;
|
|
33
|
+
isAttached(): boolean;
|
|
34
|
+
fields(): Iterable<Field>;
|
|
35
|
+
getField(_key: keyof F): F[keyof F];
|
|
36
|
+
optField(_key: keyof F): Option<F[keyof F]>;
|
|
37
|
+
read(_input: DataInput): void;
|
|
38
|
+
write(_output: DataOutput): void;
|
|
39
|
+
disconnect(): void;
|
|
40
|
+
toString(): string;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,UAAU,EAAmB,OAAO,EAAE,MAAM,EAAsB,KAAK,EAAC,MAAM,kBAAkB,CAAA;AACnH,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAC,MAAM,UAAU,CAAA;AAC5D,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAA;AAEhC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAA;AAC7B,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAA;AAC5C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;AAC5C,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,YAAY,IAAI;IACjD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAA;CAChC,CAAA;AAED,qBAAa,KAAK,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,YAAW,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;IACxG,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,YAAY,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC;IAShE,SAAS,aAAa,EAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IASpF,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/D,IAAI,GAAG,IAAI,GAAG,CAA0B;IACxC,IAAI,KAAK,IAAI,QAAQ,CAA4B;IACjD,IAAI,MAAM,IAAI,MAAM,CAAsB;IAC1C,IAAI,QAAQ,IAAI,KAAK,CAAwB;IAC7C,IAAI,SAAS,IAAI,MAAM,CAAyB;IAChD,IAAI,YAAY,IAAI,YAAY,CAAC,CAAC,CAAC,CAA4B;IAE/D,IACI,UAAU,IAAI,UAAU,CAA8B;IAE1D,IACI,OAAO,IAAI,OAAO,CAAqD;IAE3E,IACI,SAAS,IAAI,MAAM,CAEtB;IAED,KAAK,IAAI,IAAI,IAAI,GAAG;IACpB,OAAO,IAAI,IAAI,IAAI,KAAK;IACxB,UAAU,IAAI,OAAO;IACrB,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAC7B,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAChC,UAAU,IAAI,IAAI;IAUlB,QAAQ,IAAI,MAAM;CACrB"}
|
package/dist/field.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Iterables, Lazy, Option, panic, safeExecute } from "@opendaw/lib-std";
|
|
11
|
+
import { Address } from "./address";
|
|
12
|
+
import { PointerHub } from "./pointer-hub";
|
|
13
|
+
export class Field {
|
|
14
|
+
static hook(construct) {
|
|
15
|
+
return new Field(construct);
|
|
16
|
+
}
|
|
17
|
+
#parent;
|
|
18
|
+
#fieldKey;
|
|
19
|
+
#fieldName;
|
|
20
|
+
#pointerRules;
|
|
21
|
+
constructor({ parent, fieldKey, fieldName, pointerRules }) {
|
|
22
|
+
this.#parent = parent;
|
|
23
|
+
this.#fieldKey = fieldKey;
|
|
24
|
+
this.#fieldName = fieldName;
|
|
25
|
+
this.#pointerRules = pointerRules;
|
|
26
|
+
if (pointerRules.mandatory) {
|
|
27
|
+
this.graph.edges().watchVertex(this);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
accept(visitor) {
|
|
31
|
+
return safeExecute(visitor.visitField, this);
|
|
32
|
+
}
|
|
33
|
+
get box() { return this.#parent.box; }
|
|
34
|
+
get graph() { return this.#parent.graph; }
|
|
35
|
+
get parent() { return this.#parent; }
|
|
36
|
+
get fieldKey() { return this.#fieldKey; }
|
|
37
|
+
get fieldName() { return this.#fieldName; }
|
|
38
|
+
get pointerRules() { return this.#pointerRules; }
|
|
39
|
+
get pointerHub() { return new PointerHub(this); }
|
|
40
|
+
get address() { return this.#parent.address.append(this.#fieldKey); }
|
|
41
|
+
get debugPath() {
|
|
42
|
+
return `${this.box.name}:${this.box.mapFields(field => field.fieldName, ...this.address.fieldKeys).join("/")}`;
|
|
43
|
+
}
|
|
44
|
+
isBox() { return false; }
|
|
45
|
+
isField() { return true; }
|
|
46
|
+
isAttached() { return this.graph.findBox(this.address.uuid).nonEmpty(); }
|
|
47
|
+
fields() { return Iterables.empty(); }
|
|
48
|
+
getField(_key) { return panic(); }
|
|
49
|
+
optField(_key) { return Option.None; }
|
|
50
|
+
read(_input) { }
|
|
51
|
+
write(_output) { }
|
|
52
|
+
disconnect() {
|
|
53
|
+
if (this.pointerHub.isEmpty()) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const incoming = this.pointerHub.incoming();
|
|
57
|
+
incoming.forEach(pointer => {
|
|
58
|
+
pointer.defer();
|
|
59
|
+
if (pointer.mandatory || (this.pointerRules.mandatory && incoming.length === 1)) {
|
|
60
|
+
pointer.box.delete();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
toString() { return `{${this.box.constructor.name}:${this.constructor.name} (${this.fieldName}) ${this.address.toString()}`; }
|
|
65
|
+
}
|
|
66
|
+
__decorate([
|
|
67
|
+
Lazy,
|
|
68
|
+
__metadata("design:type", PointerHub),
|
|
69
|
+
__metadata("design:paramtypes", [])
|
|
70
|
+
], Field.prototype, "pointerHub", null);
|
|
71
|
+
__decorate([
|
|
72
|
+
Lazy,
|
|
73
|
+
__metadata("design:type", Address),
|
|
74
|
+
__metadata("design:paramtypes", [])
|
|
75
|
+
], Field.prototype, "address", null);
|
|
76
|
+
__decorate([
|
|
77
|
+
Lazy,
|
|
78
|
+
__metadata("design:type", String),
|
|
79
|
+
__metadata("design:paramtypes", [])
|
|
80
|
+
], Field.prototype, "debugPath", null);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PointerField } from "./pointer";
|
|
2
|
+
import { Vertex } from "./vertex";
|
|
3
|
+
import { Box } from "./box";
|
|
4
|
+
export declare class GraphEdges {
|
|
5
|
+
#private;
|
|
6
|
+
constructor();
|
|
7
|
+
watchVertex(vertex: Vertex | PointerField): void;
|
|
8
|
+
unwatchVerticesOf(...boxes: ReadonlyArray<Box>): void;
|
|
9
|
+
connect(source: PointerField, target: Vertex): void;
|
|
10
|
+
disconnect(source: PointerField): void;
|
|
11
|
+
outgoingEdgesOf(box: Box): ReadonlyArray<[PointerField, Vertex]>;
|
|
12
|
+
incomingEdgesOf(vertex: Box | Vertex): ReadonlyArray<PointerField>;
|
|
13
|
+
validateRequirements(): void;
|
|
14
|
+
verifyPointers(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=graph-edges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-edges.d.ts","sourceRoot":"","sources":["../src/graph-edges.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAA;AACtC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAA;AAC/B,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAA;AAEzB,qBAAa,UAAU;;;IAanB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAchD,iBAAiB,CAAC,GAAG,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAoBrD,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQnD,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAOtC,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,aAAa,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAIhE,eAAe,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC;IASlE,oBAAoB,IAAI,IAAI;IAqB5B,cAAc,IAAI,IAAI;CAczB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Arrays, assert, isDefined, isInstanceOf, panic } from "@opendaw/lib-std";
|
|
2
|
+
import { Address } from "./address";
|
|
3
|
+
import { PointerField } from "./pointer";
|
|
4
|
+
export class GraphEdges {
|
|
5
|
+
#requiresTarget;
|
|
6
|
+
#requiresPointer;
|
|
7
|
+
#incoming;
|
|
8
|
+
#outgoing;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.#requiresTarget = Address.newSet(source => source.address);
|
|
11
|
+
this.#requiresPointer = Address.newSet(vertex => vertex.address);
|
|
12
|
+
this.#incoming = Address.newSet(([vertex]) => vertex.address);
|
|
13
|
+
this.#outgoing = Address.newSet(([source]) => source.address);
|
|
14
|
+
}
|
|
15
|
+
watchVertex(vertex) {
|
|
16
|
+
if (isInstanceOf(vertex, PointerField)) {
|
|
17
|
+
if (!vertex.mandatory) {
|
|
18
|
+
return panic("watchVertex called but has no edge requirement");
|
|
19
|
+
}
|
|
20
|
+
this.#requiresTarget.add(vertex);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
if (!vertex.pointerRules.mandatory) {
|
|
24
|
+
return panic("watchVertex called but has no edge requirement");
|
|
25
|
+
}
|
|
26
|
+
this.#requiresPointer.add(vertex);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
unwatchVerticesOf(...boxes) {
|
|
30
|
+
const map = ({ box: { address: { uuid } } }) => uuid;
|
|
31
|
+
for (const { address: { uuid } } of boxes) {
|
|
32
|
+
this.#removeSameBox(this.#requiresTarget, uuid, map);
|
|
33
|
+
this.#removeSameBox(this.#requiresPointer, uuid, map);
|
|
34
|
+
}
|
|
35
|
+
for (const box of boxes) {
|
|
36
|
+
const outgoingLinks = this.outgoingEdgesOf(box);
|
|
37
|
+
if (outgoingLinks.length > 0) {
|
|
38
|
+
return panic(`${box} has outgoing edges: ${outgoingLinks.map(([source, target]) => `[${source.toString()}, ${target.toString()}]`)}`);
|
|
39
|
+
}
|
|
40
|
+
const incomingPointers = this.incomingEdgesOf(box);
|
|
41
|
+
if (incomingPointers.length > 0) {
|
|
42
|
+
return panic(`${box} has incoming edges from: ${incomingPointers.map((source) => source.toString())}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
connect(source, target) {
|
|
47
|
+
this.#outgoing.add([source, target]);
|
|
48
|
+
this.#incoming.opt(target.address).match({
|
|
49
|
+
none: () => this.#incoming.add([target, [source]]),
|
|
50
|
+
some: ([, sources]) => sources.push(source)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
disconnect(source) {
|
|
54
|
+
const [, target] = this.#outgoing.removeByKey(source.address);
|
|
55
|
+
const [, sources] = this.#incoming.get(target.address);
|
|
56
|
+
Arrays.remove(sources, source);
|
|
57
|
+
if (sources.length === 0) {
|
|
58
|
+
this.#incoming.removeByKey(target.address);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
outgoingEdgesOf(box) {
|
|
62
|
+
return this.#collectSameBox(this.#outgoing, box.address.uuid, ([{ box: { address: { uuid } } }]) => uuid);
|
|
63
|
+
}
|
|
64
|
+
incomingEdgesOf(vertex) {
|
|
65
|
+
if (vertex.isBox()) {
|
|
66
|
+
return this.#collectSameBox(this.#incoming, vertex.address.uuid, ([{ address: { uuid } }]) => uuid)
|
|
67
|
+
.flatMap(([_, pointers]) => pointers);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return this.#incoming.opt(vertex.address).mapOr(([_, pointers]) => pointers, Arrays.empty());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
validateRequirements() {
|
|
74
|
+
this.#requiresTarget.forEach(pointer => {
|
|
75
|
+
if (pointer.isEmpty()) {
|
|
76
|
+
if (pointer.mandatory) {
|
|
77
|
+
return panic(`Pointer ${pointer.toString()} requires an edge.`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return panic(`Illegal state: ${pointer} has no edge requirements.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
this.#requiresPointer.forEach(target => {
|
|
85
|
+
if (target.pointerHub.isEmpty()) {
|
|
86
|
+
if (target.pointerRules.mandatory) {
|
|
87
|
+
return panic(`Target ${target.toString()} requires an edge.`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
return panic(`Illegal state: ${target} has no edge requirements.`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
verifyPointers() {
|
|
96
|
+
this.#requiresTarget.forEach(pointer => assert(pointer.isAttached(), `${pointer.address.toString()} is not attached`));
|
|
97
|
+
this.#requiresPointer.forEach(pointer => assert(pointer.isAttached(), `${pointer.address.toString()} is not attached`));
|
|
98
|
+
}
|
|
99
|
+
#collectSameBox(set, id, map) {
|
|
100
|
+
const range = Address.boxRange(set, id, map);
|
|
101
|
+
return isDefined(range) ? set.values().slice(range[0], range[1]) : Arrays.empty();
|
|
102
|
+
}
|
|
103
|
+
#removeSameBox(set, id, map) {
|
|
104
|
+
const range = Address.boxRange(set, id, map);
|
|
105
|
+
if (isDefined(range)) {
|
|
106
|
+
set.removeRange(range[0], range[1]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
package/dist/graph.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Exec, int, Option, Procedure, Subscription, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { Vertex } from "./vertex";
|
|
3
|
+
import { Box } from "./box";
|
|
4
|
+
import { Address } from "./address";
|
|
5
|
+
import { PointerField } from "./pointer";
|
|
6
|
+
import { PrimitiveField, PrimitiveValues } from "./primitive";
|
|
7
|
+
import { Propagation } from "./dispatchers";
|
|
8
|
+
import { Update } from "./updates";
|
|
9
|
+
import { GraphEdges } from "./graph-edges";
|
|
10
|
+
export type BoxFactory<BoxMap> = (name: keyof BoxMap, graph: BoxGraph<BoxMap>, uuid: UUID.Format, constructor: Procedure<Box>) => Box;
|
|
11
|
+
export interface TransactionListener {
|
|
12
|
+
onBeginTransaction(): void;
|
|
13
|
+
onEndTransaction(): void;
|
|
14
|
+
}
|
|
15
|
+
export interface UpdateListener {
|
|
16
|
+
onUpdate(update: Update): void;
|
|
17
|
+
}
|
|
18
|
+
export type Dependencies = {
|
|
19
|
+
boxes: Iterable<Box>;
|
|
20
|
+
pointers: Iterable<PointerField>;
|
|
21
|
+
};
|
|
22
|
+
export declare class BoxGraph<BoxMap = any> {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(boxFactory?: Option<BoxFactory<BoxMap>>);
|
|
25
|
+
beginTransaction(): void;
|
|
26
|
+
endTransaction(): void;
|
|
27
|
+
inTransaction(): boolean;
|
|
28
|
+
constructingBox(): boolean;
|
|
29
|
+
resolvePointers(): void;
|
|
30
|
+
createBox(name: keyof BoxMap, uuid: UUID.Format, constructor: Procedure<Box>): void;
|
|
31
|
+
stageBox<B extends Box>(box: B, constructor?: Procedure<B>): B;
|
|
32
|
+
subscribeTransaction(listener: TransactionListener): Subscription;
|
|
33
|
+
subscribeToAllUpdates(listener: UpdateListener): Subscription;
|
|
34
|
+
subscribeToAllUpdatesImmediate(listener: UpdateListener): Subscription;
|
|
35
|
+
subscribeVertexUpdates(propagation: Propagation, address: Address, procedure: Procedure<Update>): Subscription;
|
|
36
|
+
subscribeEndTransaction(observer: Exec): void;
|
|
37
|
+
unstageBox(box: Box): void;
|
|
38
|
+
findBox<B extends Box = Box>(uuid: UUID.Format): Option<B>;
|
|
39
|
+
findVertex(address: Address): Option<Vertex>;
|
|
40
|
+
boxes(): ReadonlyArray<Box>;
|
|
41
|
+
edges(): GraphEdges;
|
|
42
|
+
checksum(): Int8Array;
|
|
43
|
+
onPrimitiveValueUpdate<V extends PrimitiveValues>(field: PrimitiveField<V, any>, oldValue: V, newValue: V): void;
|
|
44
|
+
onPointerAddressUpdated(pointerField: PointerField, oldValue: Option<Address>, newValue: Option<Address>): void;
|
|
45
|
+
dependenciesOf(box: Box): Dependencies;
|
|
46
|
+
verifyPointers(): {
|
|
47
|
+
count: int;
|
|
48
|
+
};
|
|
49
|
+
debugBoxes(): void;
|
|
50
|
+
debugDependencies(): void;
|
|
51
|
+
addressToDebugPath(address: Option<Address>): Option<string>;
|
|
52
|
+
toArrayBuffer(): ArrayBufferLike;
|
|
53
|
+
fromArrayBuffer(arrayBuffer: ArrayBuffer): void;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|