@genome-spy/core 0.29.0 → 0.30.2
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/dist/index.es.js +16373 -0
- package/dist/index.js +43 -43
- package/package.json +10 -7
- package/src/data/collector.js +0 -183
- package/src/data/collector.test.js +0 -84
- package/src/data/dataFlow.js +0 -148
- package/src/data/dataFlow.test.js +0 -5
- package/src/data/facetNode.js +0 -17
- package/src/data/flow.test.js +0 -72
- package/src/data/flowBatch.d.ts +0 -40
- package/src/data/flowNode.js +0 -283
- package/src/data/flowNode.test.js +0 -50
- package/src/data/flowOptimizer.js +0 -123
- package/src/data/flowOptimizer.test.js +0 -193
- package/src/data/flowTestUtils.js +0 -63
- package/src/data/formats/fasta.js +0 -32
- package/src/data/formats/fasta.test.js +0 -27
- package/src/data/sources/dataSource.js +0 -22
- package/src/data/sources/dataSourceFactory.js +0 -24
- package/src/data/sources/dataUtils.js +0 -78
- package/src/data/sources/dynamicCallbackSource.js +0 -57
- package/src/data/sources/dynamicSource.js +0 -37
- package/src/data/sources/inlineSource.js +0 -67
- package/src/data/sources/inlineSource.test.js +0 -56
- package/src/data/sources/namedSource.js +0 -79
- package/src/data/sources/sequenceSource.js +0 -46
- package/src/data/sources/sequenceSource.test.js +0 -46
- package/src/data/sources/urlSource.js +0 -74
- package/src/data/transforms/aggregate.js +0 -70
- package/src/data/transforms/clone.js +0 -40
- package/src/data/transforms/clone.test.js +0 -11
- package/src/data/transforms/coverage.js +0 -187
- package/src/data/transforms/coverage.test.js +0 -123
- package/src/data/transforms/filter.js +0 -37
- package/src/data/transforms/filter.test.js +0 -18
- package/src/data/transforms/filterScoredLabels.js +0 -134
- package/src/data/transforms/flattenCompressedExons.js +0 -57
- package/src/data/transforms/flattenDelimited.js +0 -74
- package/src/data/transforms/flattenDelimited.test.js +0 -87
- package/src/data/transforms/flattenSequence.js +0 -39
- package/src/data/transforms/flattenSequence.test.js +0 -34
- package/src/data/transforms/formula.js +0 -39
- package/src/data/transforms/formula.test.js +0 -19
- package/src/data/transforms/identifier.js +0 -108
- package/src/data/transforms/identifier.test.js +0 -83
- package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
- package/src/data/transforms/measureText.js +0 -44
- package/src/data/transforms/pileup.js +0 -128
- package/src/data/transforms/pileup.test.js +0 -70
- package/src/data/transforms/project.js +0 -41
- package/src/data/transforms/project.test.js +0 -32
- package/src/data/transforms/regexExtract.js +0 -61
- package/src/data/transforms/regexExtract.test.js +0 -67
- package/src/data/transforms/regexFold.js +0 -141
- package/src/data/transforms/regexFold.test.js +0 -160
- package/src/data/transforms/sample.js +0 -101
- package/src/data/transforms/sample.test.js +0 -38
- package/src/data/transforms/stack.js +0 -137
- package/src/data/transforms/stack.test.js +0 -91
- package/src/data/transforms/transformFactory.js +0 -60
- package/src/embedApi.d.ts +0 -67
- package/src/encoder/accessor.js +0 -82
- package/src/encoder/accessor.test.js +0 -47
- package/src/encoder/encoder.js +0 -394
- package/src/encoder/encoder.test.js +0 -98
- package/src/fonts/Lato-Regular.json +0 -1267
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +0 -93
- package/src/fonts/README.md +0 -3
- package/src/fonts/bmFont.d.ts +0 -58
- package/src/fonts/bmFontManager.js +0 -357
- package/src/fonts/bmFontMetrics.js +0 -108
- package/src/genome/genome.js +0 -317
- package/src/genome/genome.test.js +0 -188
- package/src/genome/genomeStore.js +0 -54
- package/src/genome/locusFormat.js +0 -31
- package/src/genome/scaleIndex.d.ts +0 -38
- package/src/genome/scaleIndex.js +0 -166
- package/src/genome/scaleIndex.test.js +0 -78
- package/src/genome/scaleLocus.d.ts +0 -11
- package/src/genome/scaleLocus.js +0 -108
- package/src/genome/scaleLocus.test.js +0 -4
- package/src/genomeSpy.js +0 -784
- package/src/gl/arrayBuilder.js +0 -199
- package/src/gl/dataToVertices.js +0 -636
- package/src/gl/includes/common.glsl +0 -63
- package/src/gl/includes/picking.fragment.glsl +0 -1
- package/src/gl/includes/picking.vertex.glsl +0 -27
- package/src/gl/includes/sampleFacet.glsl +0 -107
- package/src/gl/includes/scales.glsl +0 -112
- package/src/gl/link.fragment.glsl +0 -18
- package/src/gl/link.vertex.glsl +0 -111
- package/src/gl/point.fragment.glsl +0 -123
- package/src/gl/point.vertex.glsl +0 -129
- package/src/gl/rect.fragment.glsl +0 -51
- package/src/gl/rect.vertex.glsl +0 -114
- package/src/gl/rule.fragment.glsl +0 -52
- package/src/gl/rule.vertex.glsl +0 -89
- package/src/gl/text.fragment.glsl +0 -31
- package/src/gl/text.vertex.glsl +0 -246
- package/src/gl/webGLHelper.js +0 -489
- package/src/img/bowtie.svg +0 -1
- package/src/img/genomespy-favicon.svg +0 -34
- package/src/index.html +0 -11
- package/src/index.js +0 -128
- package/src/marks/link.js +0 -175
- package/src/marks/mark.js +0 -975
- package/src/marks/markUtils.js +0 -125
- package/src/marks/pointMark.js +0 -251
- package/src/marks/rectMark.js +0 -241
- package/src/marks/rule.js +0 -250
- package/src/marks/text.js +0 -278
- package/src/node_modules/.vitest/results.json +0 -1
- package/src/scale/colorUtils.js +0 -184
- package/src/scale/glslScaleGenerator.js +0 -488
- package/src/scale/scale.js +0 -451
- package/src/scale/scale.test.js +0 -324
- package/src/scale/ticks.js +0 -203
- package/src/scale/ticks.test.js +0 -40
- package/src/singlePageApp.js +0 -13
- package/src/spec/axis.d.ts +0 -296
- package/src/spec/channel.d.ts +0 -430
- package/src/spec/data.d.ts +0 -196
- package/src/spec/font.d.ts +0 -15
- package/src/spec/genome.d.ts +0 -35
- package/src/spec/mark.d.ts +0 -429
- package/src/spec/root.d.ts +0 -17
- package/src/spec/sampleView.d.ts +0 -180
- package/src/spec/scale.d.ts +0 -273
- package/src/spec/title.d.ts +0 -102
- package/src/spec/tooltip.d.ts +0 -9
- package/src/spec/transform.d.ts +0 -479
- package/src/spec/view.d.ts +0 -201
- package/src/styles/genome-spy.scss +0 -153
- package/src/tooltip/dataTooltipHandler.js +0 -64
- package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
- package/src/tooltip/tooltipHandler.ts +0 -12
- package/src/types/filetypes.d.ts +0 -14
- package/src/types/flatqueue.d.ts +0 -53
- package/src/types/glsl.d.ts +0 -4
- package/src/types/internmap.d.ts +0 -22
- package/src/types/object.d.ts +0 -21
- package/src/types/vega-loader.d.ts +0 -1
- package/src/types/vega-scale.d.ts +0 -60
- package/src/utils/addBaseUrl.js +0 -19
- package/src/utils/addBaseUrl.test.js +0 -22
- package/src/utils/animator.js +0 -83
- package/src/utils/arrayUtils.js +0 -61
- package/src/utils/binnedIndex.js +0 -167
- package/src/utils/binnedIndex.test.js +0 -155
- package/src/utils/clamp.js +0 -8
- package/src/utils/cloner.js +0 -34
- package/src/utils/cloner.test.js +0 -24
- package/src/utils/coalesce.js +0 -11
- package/src/utils/coalesce.test.js +0 -16
- package/src/utils/concatIterables.js +0 -26
- package/src/utils/concatIterables.test.js +0 -8
- package/src/utils/debounce.js +0 -37
- package/src/utils/domainArray.js +0 -216
- package/src/utils/domainArray.test.js +0 -130
- package/src/utils/eerp.js +0 -13
- package/src/utils/expression.js +0 -32
- package/src/utils/field.js +0 -28
- package/src/utils/formatObject.js +0 -31
- package/src/utils/indexer.js +0 -43
- package/src/utils/indexer.test.js +0 -47
- package/src/utils/inertia.js +0 -124
- package/src/utils/interactionEvent.js +0 -33
- package/src/utils/iterateNestedMaps.js +0 -21
- package/src/utils/iterateNestedMaps.test.js +0 -33
- package/src/utils/kWayMerge.js +0 -42
- package/src/utils/kWayMerge.test.js +0 -26
- package/src/utils/layout/flexLayout.js +0 -368
- package/src/utils/layout/flexLayout.test.js +0 -311
- package/src/utils/layout/grid.js +0 -95
- package/src/utils/layout/grid.test.js +0 -71
- package/src/utils/layout/padding.js +0 -120
- package/src/utils/layout/point.js +0 -23
- package/src/utils/layout/rectangle.js +0 -288
- package/src/utils/layout/rectangle.test.js +0 -172
- package/src/utils/mergeObjects.js +0 -99
- package/src/utils/mergeObjects.test.js +0 -42
- package/src/utils/numberExtractor.js +0 -24
- package/src/utils/numberExtractor.test.js +0 -6
- package/src/utils/point.js +0 -14
- package/src/utils/propertyCacher.js +0 -70
- package/src/utils/propertyCacher.test.js +0 -85
- package/src/utils/propertyCoalescer.js +0 -42
- package/src/utils/propertyCoalescer.test.js +0 -22
- package/src/utils/reservationMap.js +0 -103
- package/src/utils/reservationMap.test.js +0 -20
- package/src/utils/scaleNull.js +0 -19
- package/src/utils/setOperations.js +0 -75
- package/src/utils/smoothstep.js +0 -10
- package/src/utils/throttle.js +0 -34
- package/src/utils/topK.js +0 -76
- package/src/utils/topK.test.js +0 -64
- package/src/utils/transition.js +0 -74
- package/src/utils/ui/tooltip.js +0 -189
- package/src/utils/url.js +0 -22
- package/src/utils/variableTools.js +0 -24
- package/src/utils/variableTools.test.js +0 -13
- package/src/view/axisResolution.js +0 -140
- package/src/view/axisResolution.test.js +0 -201
- package/src/view/axisView.js +0 -747
- package/src/view/concatView.js +0 -45
- package/src/view/containerView.js +0 -159
- package/src/view/facetView.js +0 -491
- package/src/view/flowBuilder.js +0 -367
- package/src/view/flowBuilder.test.js +0 -125
- package/src/view/gridView.js +0 -786
- package/src/view/implicitRootView.js +0 -14
- package/src/view/importView.js +0 -19
- package/src/view/layerView.js +0 -74
- package/src/view/rendering.d.ts +0 -44
- package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
- package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
- package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
- package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
- package/src/view/renderingContext/viewRenderingContext.js +0 -41
- package/src/view/scaleResolution.js +0 -791
- package/src/view/scaleResolution.test.js +0 -572
- package/src/view/scaleResolutionApi.d.ts +0 -40
- package/src/view/testUtils.js +0 -51
- package/src/view/title.js +0 -165
- package/src/view/unitView.js +0 -382
- package/src/view/view.js +0 -612
- package/src/view/view.test.js +0 -214
- package/src/view/viewContext.d.ts +0 -62
- package/src/view/viewFactory.js +0 -181
- package/src/view/viewFactory.test.js +0 -17
- package/src/view/viewUtils.js +0 -327
- package/src/view/zoom.js +0 -89
package/src/data/flowNode.js
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { range } from "d3-array";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The FlowNode clones the data objects passing through or creates entirely
|
|
5
|
-
* new objects.
|
|
6
|
-
*/
|
|
7
|
-
export const BEHAVIOR_CLONES = 1 << 0;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* FlowNode modifies the objects that pass through. Creating defensive copies
|
|
11
|
-
* (clones) in an upstream node may be appropriate, depending on branching.
|
|
12
|
-
*/
|
|
13
|
-
export const BEHAVIOR_MODIFIES = 1 << 1;
|
|
14
|
-
|
|
15
|
-
const ROOT_CONTEXT_OBJECT = {};
|
|
16
|
-
/**
|
|
17
|
-
* This is heavily inspired by Vega's and Vega-Lite's data flow system.
|
|
18
|
-
*
|
|
19
|
-
* @typedef {import("./flowBatch").FlowBatch} FlowBatch
|
|
20
|
-
*
|
|
21
|
-
* @typedef {Record<string, any>} Datum
|
|
22
|
-
* @typedef {Datum[]} Data
|
|
23
|
-
*/
|
|
24
|
-
export default class FlowNode {
|
|
25
|
-
get behavior() {
|
|
26
|
-
return 0;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
/** @type {FlowNode[]} */
|
|
31
|
-
this.children = [];
|
|
32
|
-
|
|
33
|
-
/** @type {FlowNode} */
|
|
34
|
-
this.parent = undefined;
|
|
35
|
-
|
|
36
|
-
/** True if all data have been processed */
|
|
37
|
-
this.completed = false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Resets the node and all its descendants to their initial state, i.e., preparing
|
|
42
|
-
* for a new batch of data.
|
|
43
|
-
*/
|
|
44
|
-
reset() {
|
|
45
|
-
this.completed = false;
|
|
46
|
-
|
|
47
|
-
for (const child of this.children) {
|
|
48
|
-
child.reset();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Allows for doing final initialization after the flow structure has been
|
|
54
|
-
* built and optimized. Must be called before any data are to be propagated.
|
|
55
|
-
*/
|
|
56
|
-
initialize() {
|
|
57
|
-
// override
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Dynamically updates the propagator method to allow the JavaScript engine
|
|
62
|
-
* to employ optimizations such as inlining.
|
|
63
|
-
*/
|
|
64
|
-
_updatePropagator() {
|
|
65
|
-
this._propagate = Function(
|
|
66
|
-
"children",
|
|
67
|
-
range(this.children.length)
|
|
68
|
-
.map((i) => `const child${i} = children[${i}];`)
|
|
69
|
-
.join("\n") +
|
|
70
|
-
`return function propagate(datum) {${range(this.children.length)
|
|
71
|
-
.map((i) => `child${i}.handle(datum);`)
|
|
72
|
-
.join("\n")}}`
|
|
73
|
-
)(this.children);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
*
|
|
78
|
-
* @param {FlowNode} parent
|
|
79
|
-
*/
|
|
80
|
-
setParent(parent) {
|
|
81
|
-
this.parent = parent;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
*
|
|
86
|
-
* @param {FlowNode} child
|
|
87
|
-
*/
|
|
88
|
-
addChild(child) {
|
|
89
|
-
if (child.parent) {
|
|
90
|
-
throw new Error("Cannot add the child! It already has a parent.");
|
|
91
|
-
}
|
|
92
|
-
this.children.push(child);
|
|
93
|
-
child.setParent(this);
|
|
94
|
-
this._updatePropagator();
|
|
95
|
-
return this;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @param {FlowNode} node
|
|
100
|
-
*/
|
|
101
|
-
adopt(node) {
|
|
102
|
-
if (node.parent) {
|
|
103
|
-
node.parent.removeChild(node);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
this.addChild(node);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @param {FlowNode} otherParent
|
|
111
|
-
*/
|
|
112
|
-
adoptChildrenOf(otherParent) {
|
|
113
|
-
for (const child of otherParent.children) {
|
|
114
|
-
this.adopt(child);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @param {FlowNode} newParent
|
|
120
|
-
*/
|
|
121
|
-
insertAsParent(newParent) {
|
|
122
|
-
if (this.isRoot()) {
|
|
123
|
-
// Root should always be a data source
|
|
124
|
-
throw new Error("Cannot insert a new parent for a root node!");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
newParent.parent = this.parent;
|
|
128
|
-
this.parent.children[this.parent.children.indexOf(this)] = newParent;
|
|
129
|
-
this.parent._updatePropagator();
|
|
130
|
-
this.parent = undefined;
|
|
131
|
-
newParent.addChild(this);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
*
|
|
136
|
-
* @param {FlowNode} child
|
|
137
|
-
*/
|
|
138
|
-
removeChild(child) {
|
|
139
|
-
const index = this.children.indexOf(child);
|
|
140
|
-
if (index > -1) {
|
|
141
|
-
this.children.splice(index, 1);
|
|
142
|
-
child.parent = undefined;
|
|
143
|
-
this._updatePropagator();
|
|
144
|
-
} else {
|
|
145
|
-
throw new Error("Trying to remove an unknown child node!");
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Removes this node and ligates (connects) the preceding and succeeding nodes.
|
|
151
|
-
*/
|
|
152
|
-
excise() {
|
|
153
|
-
if (this.isRoot()) {
|
|
154
|
-
// TODO: Implement
|
|
155
|
-
throw new Error("Cannot excise root node!");
|
|
156
|
-
} else if (this.isTerminal()) {
|
|
157
|
-
this.parent.removeChild(this);
|
|
158
|
-
} else if (this.children.length == 1) {
|
|
159
|
-
const child = this.children[0];
|
|
160
|
-
child.setParent(this.parent);
|
|
161
|
-
this.parent.children[this.parent.children.indexOf(this)] = child;
|
|
162
|
-
this.parent._updatePropagator();
|
|
163
|
-
this.setParent(undefined);
|
|
164
|
-
this.children.length = 0;
|
|
165
|
-
} else {
|
|
166
|
-
// TODO: Implement
|
|
167
|
-
throw new Error("Cannot excise a node that has multiple children!");
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
isRoot() {
|
|
172
|
-
return !this.parent;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
isBranching() {
|
|
176
|
-
return this.children.length > 1;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
isTerminal() {
|
|
180
|
-
return this.children.length == 0;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Visits child nodes in depth-first order.
|
|
185
|
-
*
|
|
186
|
-
* @param {(function(FlowNode):void) & { afterChildren?: function(FlowNode):void}} visitor
|
|
187
|
-
*/
|
|
188
|
-
visit(visitor) {
|
|
189
|
-
// pre-order
|
|
190
|
-
visitor(this);
|
|
191
|
-
|
|
192
|
-
for (const child of this.children) {
|
|
193
|
-
child.visit(visitor);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// post-oder
|
|
197
|
-
if (visitor.afterChildren) {
|
|
198
|
-
visitor.afterChildren(this);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* @param {number} [depth]
|
|
204
|
-
* @returns {string}
|
|
205
|
-
*/
|
|
206
|
-
subtreeToString(depth = 0) {
|
|
207
|
-
const childTree = this.children
|
|
208
|
-
.map((child) => child.subtreeToString(depth + 1))
|
|
209
|
-
.join("");
|
|
210
|
-
return (
|
|
211
|
-
" ".repeat(depth * 2) +
|
|
212
|
-
"* " +
|
|
213
|
-
/^class ([A-Za-z0-9_]+)/.exec("" + this.constructor)?.[1] +
|
|
214
|
-
"\n" +
|
|
215
|
-
childTree
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* The global object for expressions (in formula and filter transforms).
|
|
221
|
-
* Nodes in the hierarchy may extend the object using Object.create to
|
|
222
|
-
* introduce variables that are visible downstream the flow.
|
|
223
|
-
*
|
|
224
|
-
* @returns {Record<string, any>}
|
|
225
|
-
*/
|
|
226
|
-
getGlobalObject() {
|
|
227
|
-
return this.parent
|
|
228
|
-
? this.parent.getGlobalObject()
|
|
229
|
-
: ROOT_CONTEXT_OBJECT;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
*
|
|
234
|
-
* @param {Datum} datum
|
|
235
|
-
*/
|
|
236
|
-
handle(datum) {
|
|
237
|
-
// Default implementation just passes through
|
|
238
|
-
this._propagate(datum);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
complete() {
|
|
242
|
-
this.completed = true;
|
|
243
|
-
|
|
244
|
-
for (const child of this.children) {
|
|
245
|
-
child.complete();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Signals that a new batch of data will be propagated.
|
|
251
|
-
*
|
|
252
|
-
* @param {FlowBatch} flowBatch
|
|
253
|
-
*/
|
|
254
|
-
beginBatch(flowBatch) {
|
|
255
|
-
for (const child of this.children) {
|
|
256
|
-
child.beginBatch(flowBatch);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
*
|
|
262
|
-
* @param {any} datum
|
|
263
|
-
*/
|
|
264
|
-
_propagate(datum) {
|
|
265
|
-
// Implementation is set dynamically in add/removeChild
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* @param {FlowBatch} flowBatch
|
|
271
|
-
* @returns {flowBatch is import("./flowBatch").FileBatch}
|
|
272
|
-
*/
|
|
273
|
-
export function isFileBatch(flowBatch) {
|
|
274
|
-
return flowBatch.type == "file";
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @param {FlowBatch} flowBatch
|
|
279
|
-
* @returns {flowBatch is import("./flowBatch").FacetBatch}
|
|
280
|
-
*/
|
|
281
|
-
export function isFacetBatch(flowBatch) {
|
|
282
|
-
return flowBatch.type == "facet";
|
|
283
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
2
|
-
import FlowNode from "./flowNode";
|
|
3
|
-
import { validateLinks } from "./flowOptimizer";
|
|
4
|
-
|
|
5
|
-
describe("Flow mutation", () => {
|
|
6
|
-
test("Excise a terminal node", () => {
|
|
7
|
-
const a = new FlowNode();
|
|
8
|
-
const b = new FlowNode();
|
|
9
|
-
|
|
10
|
-
a.addChild(b);
|
|
11
|
-
b.excise();
|
|
12
|
-
|
|
13
|
-
expect(a.children[0]).toBeUndefined();
|
|
14
|
-
expect(b.parent).toBeUndefined();
|
|
15
|
-
|
|
16
|
-
expect(validateLinks(a)).toBeTruthy();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("Excise a node in the middle", () => {
|
|
20
|
-
const a = new FlowNode();
|
|
21
|
-
const b = new FlowNode();
|
|
22
|
-
const c = new FlowNode();
|
|
23
|
-
|
|
24
|
-
a.addChild(b);
|
|
25
|
-
b.addChild(c);
|
|
26
|
-
b.excise();
|
|
27
|
-
|
|
28
|
-
expect(a.children[0]).toBe(c);
|
|
29
|
-
expect(c.parent).toBe(a);
|
|
30
|
-
|
|
31
|
-
expect(validateLinks(a)).toBeTruthy();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("Insert as parent", () => {
|
|
35
|
-
const a = new FlowNode();
|
|
36
|
-
const b = new FlowNode();
|
|
37
|
-
const c = new FlowNode();
|
|
38
|
-
const d = new FlowNode();
|
|
39
|
-
|
|
40
|
-
a.addChild(c);
|
|
41
|
-
a.addChild(d);
|
|
42
|
-
c.insertAsParent(b);
|
|
43
|
-
|
|
44
|
-
expect(a.children[0]).toBe(b);
|
|
45
|
-
expect(a.children[1]).toBe(d);
|
|
46
|
-
expect(a.children[0].children[0]).toBe(c);
|
|
47
|
-
|
|
48
|
-
expect(validateLinks(a)).toBeTruthy();
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import Collector from "./collector";
|
|
2
|
-
import { BEHAVIOR_CLONES } from "./flowNode";
|
|
3
|
-
import CloneTransform from "./transforms/clone";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import("./flowNode").default} FlowNode
|
|
7
|
-
* @typedef {import("./sources/dataSource").default} DataSource
|
|
8
|
-
* @typedef {import("./dataFlow").default<any>} DataFlow
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {FlowNode} node
|
|
13
|
-
* @param {FlowNode} [parent]
|
|
14
|
-
*/
|
|
15
|
-
export function validateLinks(node, parent = undefined) {
|
|
16
|
-
if (node.parent !== parent) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
for (const child of node.children) {
|
|
21
|
-
if (!validateLinks(child, node)) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Removes possible redundant CloneTransforms that were added during graph construction.
|
|
31
|
-
*
|
|
32
|
-
* @param {FlowNode} node
|
|
33
|
-
*/
|
|
34
|
-
export function removeRedundantCloneTransforms(node, cloneRequired = false) {
|
|
35
|
-
if (node instanceof Collector) {
|
|
36
|
-
// If an object is modified downstream of Collector, it must be cloned
|
|
37
|
-
cloneRequired = true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (node instanceof CloneTransform) {
|
|
41
|
-
if (cloneRequired) {
|
|
42
|
-
cloneRequired = false;
|
|
43
|
-
} else {
|
|
44
|
-
const child = node.children[0];
|
|
45
|
-
node.excise();
|
|
46
|
-
if (child) {
|
|
47
|
-
removeRedundantCloneTransforms(child, cloneRequired);
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (node.behavior & BEHAVIOR_CLONES) {
|
|
54
|
-
cloneRequired = false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
for (let i = 0, n = node.children.length; i < n; i++) {
|
|
58
|
-
// All but the last branch need defensive copies to prevent side effects
|
|
59
|
-
removeRedundantCloneTransforms(
|
|
60
|
-
node.children[i],
|
|
61
|
-
cloneRequired || i < n - 1
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function removeRedundantCollectors() {
|
|
67
|
-
// TODO: Remove chained collectors, e.g., first collect and sort, then just collect
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function combineAndPullCollectorsUp() {
|
|
71
|
-
// TODO:
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @param {import("./dataFlow").default<any>} dataFlow
|
|
76
|
-
*/
|
|
77
|
-
export function combineIdenticalDataSources(dataFlow) {
|
|
78
|
-
const dataSourceEntries = [...dataFlow._dataSourcesByHost.entries()];
|
|
79
|
-
|
|
80
|
-
/** @type {Map<string, DataSource>} */
|
|
81
|
-
const sourcesByIdentifiers = new Map();
|
|
82
|
-
for (const e of dataSourceEntries) {
|
|
83
|
-
const ds = e[1];
|
|
84
|
-
if (ds.identifier && !sourcesByIdentifiers.has(ds.identifier)) {
|
|
85
|
-
sourcesByIdentifiers.set(ds.identifier, ds);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
dataFlow._dataSourcesByHost.clear();
|
|
90
|
-
|
|
91
|
-
for (let [key, dataSource] of dataSourceEntries) {
|
|
92
|
-
const target = sourcesByIdentifiers.get(dataSource.identifier);
|
|
93
|
-
if (target) {
|
|
94
|
-
target.adoptChildrenOf(dataSource);
|
|
95
|
-
dataSource = target;
|
|
96
|
-
}
|
|
97
|
-
dataFlow.addDataSource(dataSource, key);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
*
|
|
103
|
-
* @param {FlowNode} root
|
|
104
|
-
*/
|
|
105
|
-
export function optimizeFlowGraph(root) {
|
|
106
|
-
removeRedundantCloneTransforms(root);
|
|
107
|
-
if (!validateLinks(root)) {
|
|
108
|
-
throw new Error(
|
|
109
|
-
"Encountered a bug! There's a problem in the data flow structure."
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @param {import("./dataFlow").default<any>} dataFlow
|
|
116
|
-
*/
|
|
117
|
-
export function optimizeDataFlow(dataFlow) {
|
|
118
|
-
for (const dataSource of dataFlow.dataSources) {
|
|
119
|
-
optimizeFlowGraph(dataSource);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
combineIdenticalDataSources(dataFlow);
|
|
123
|
-
}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
2
|
-
import FlowNode, { BEHAVIOR_CLONES } from "./flowNode";
|
|
3
|
-
import { removeRedundantCloneTransforms, validateLinks } from "./flowOptimizer";
|
|
4
|
-
import CloneTransform from "./transforms/clone";
|
|
5
|
-
import Collector from "./collector";
|
|
6
|
-
import DataFlow from "./dataFlow";
|
|
7
|
-
import { combineIdenticalDataSources } from "./flowOptimizer";
|
|
8
|
-
import InlineSource from "./sources/inlineSource";
|
|
9
|
-
import UrlSource from "./sources/urlSource";
|
|
10
|
-
|
|
11
|
-
test("validateLinks() detects broken graph", () => {
|
|
12
|
-
const root = new FlowNode();
|
|
13
|
-
const a = new FlowNode();
|
|
14
|
-
const b = new FlowNode();
|
|
15
|
-
const c = new FlowNode();
|
|
16
|
-
|
|
17
|
-
root.addChild(a);
|
|
18
|
-
root.addChild(b);
|
|
19
|
-
root.addChild(c);
|
|
20
|
-
|
|
21
|
-
expect(validateLinks(root)).toBeTruthy();
|
|
22
|
-
|
|
23
|
-
// Break it!
|
|
24
|
-
b.parent = undefined;
|
|
25
|
-
|
|
26
|
-
expect(validateLinks(root)).toBeFalsy();
|
|
27
|
-
|
|
28
|
-
// Check handling of root
|
|
29
|
-
|
|
30
|
-
const rootWithParent = new FlowNode();
|
|
31
|
-
// Break it!
|
|
32
|
-
rootWithParent.parent = new FlowNode();
|
|
33
|
-
|
|
34
|
-
expect(validateLinks(rootWithParent)).toBeFalsy();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe("removeRedundantCloneTransforms", () => {
|
|
38
|
-
test("Removes redundancy from linear graph #1", () => {
|
|
39
|
-
const a = new FlowNode();
|
|
40
|
-
const b = new CloneTransform();
|
|
41
|
-
const c = new FlowNode();
|
|
42
|
-
const d = new CloneTransform();
|
|
43
|
-
const e = new CloneTransform();
|
|
44
|
-
const f = new FlowNode();
|
|
45
|
-
|
|
46
|
-
a.addChild(b);
|
|
47
|
-
b.addChild(c);
|
|
48
|
-
c.addChild(d);
|
|
49
|
-
d.addChild(e);
|
|
50
|
-
e.addChild(f);
|
|
51
|
-
|
|
52
|
-
removeRedundantCloneTransforms(a);
|
|
53
|
-
|
|
54
|
-
expect(a.children[0]).toBe(c);
|
|
55
|
-
expect(c.children[0]).toBe(f);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("Removes redundancy from linear graph #2", () => {
|
|
59
|
-
const a = new FlowNode();
|
|
60
|
-
const b = new CloneTransform();
|
|
61
|
-
const c = new FlowNode();
|
|
62
|
-
const d = new CloneTransform();
|
|
63
|
-
const e = new CloneTransform();
|
|
64
|
-
const f = new FlowNode();
|
|
65
|
-
|
|
66
|
-
a.addChild(b);
|
|
67
|
-
b.addChild(c);
|
|
68
|
-
c.addChild(d);
|
|
69
|
-
d.addChild(e);
|
|
70
|
-
e.addChild(f);
|
|
71
|
-
|
|
72
|
-
// First CloneTransform should be retained
|
|
73
|
-
removeRedundantCloneTransforms(a, true);
|
|
74
|
-
|
|
75
|
-
expect(a.children[0]).toBe(b);
|
|
76
|
-
expect(b.children[0]).toBe(c);
|
|
77
|
-
expect(c.children[0]).toBe(f);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("Node with cloning behavior satisfies cloning requirement", () => {
|
|
81
|
-
class CloningFlowNode extends FlowNode {
|
|
82
|
-
get behavior() {
|
|
83
|
-
return BEHAVIOR_CLONES;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const a = new FlowNode();
|
|
88
|
-
const b = new CloningFlowNode();
|
|
89
|
-
const c = new FlowNode();
|
|
90
|
-
const d = new CloneTransform();
|
|
91
|
-
const e = new FlowNode();
|
|
92
|
-
|
|
93
|
-
a.addChild(b);
|
|
94
|
-
b.addChild(c);
|
|
95
|
-
c.addChild(d);
|
|
96
|
-
d.addChild(e);
|
|
97
|
-
|
|
98
|
-
removeRedundantCloneTransforms(a, true);
|
|
99
|
-
|
|
100
|
-
expect(a.children[0]).toBe(b);
|
|
101
|
-
expect(b.children[0]).toBe(c);
|
|
102
|
-
expect(c.children[0]).toBe(e);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test("Removes redundancy from a branching graph", () => {
|
|
106
|
-
const root = new FlowNode();
|
|
107
|
-
const branching = new FlowNode();
|
|
108
|
-
const a = new CloneTransform();
|
|
109
|
-
const al = new FlowNode();
|
|
110
|
-
const b = new CloneTransform();
|
|
111
|
-
const bl = new FlowNode();
|
|
112
|
-
const c = new CloneTransform();
|
|
113
|
-
const cl = new FlowNode();
|
|
114
|
-
|
|
115
|
-
root.addChild(branching);
|
|
116
|
-
branching.addChild(a);
|
|
117
|
-
branching.addChild(b);
|
|
118
|
-
branching.addChild(c);
|
|
119
|
-
a.addChild(al);
|
|
120
|
-
b.addChild(bl);
|
|
121
|
-
c.addChild(cl);
|
|
122
|
-
|
|
123
|
-
removeRedundantCloneTransforms(root);
|
|
124
|
-
|
|
125
|
-
// All but the last branch needs cloning
|
|
126
|
-
expect(branching.children[0]).toBe(a);
|
|
127
|
-
expect(branching.children[1]).toBe(b);
|
|
128
|
-
expect(branching.children[2]).toBe(cl);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe("Merge indentical data sources", () => {
|
|
133
|
-
test("Merges correctly", () => {
|
|
134
|
-
/** @type {DataFlow<string>} */
|
|
135
|
-
const dataFlow = new DataFlow();
|
|
136
|
-
|
|
137
|
-
const a = new UrlSource({ url: "http://genomespy.app/" });
|
|
138
|
-
const ac = new Collector();
|
|
139
|
-
a.addChild(ac);
|
|
140
|
-
|
|
141
|
-
const b = new UrlSource({ url: "http://genomespy.app/" });
|
|
142
|
-
const bc = new Collector();
|
|
143
|
-
b.addChild(bc);
|
|
144
|
-
|
|
145
|
-
const c = new UrlSource({ url: "http://helsinki.fi/" });
|
|
146
|
-
const cc = new Collector();
|
|
147
|
-
c.addChild(cc);
|
|
148
|
-
|
|
149
|
-
dataFlow.addDataSource(a, "a");
|
|
150
|
-
dataFlow.addDataSource(b, "b");
|
|
151
|
-
dataFlow.addDataSource(c, "c");
|
|
152
|
-
|
|
153
|
-
dataFlow.addCollector(ac, "a");
|
|
154
|
-
dataFlow.addCollector(bc, "b");
|
|
155
|
-
dataFlow.addCollector(cc, "c");
|
|
156
|
-
|
|
157
|
-
combineIdenticalDataSources(dataFlow);
|
|
158
|
-
|
|
159
|
-
expect(dataFlow.dataSources.length).toEqual(2);
|
|
160
|
-
|
|
161
|
-
expect(dataFlow.findDataSourceByKey("a")).toBe(a);
|
|
162
|
-
expect(dataFlow.findDataSourceByKey("b")).toBe(a); // Merged!
|
|
163
|
-
expect(dataFlow.findDataSourceByKey("c")).toBe(c);
|
|
164
|
-
|
|
165
|
-
expect(new Set(a.children)).toEqual(new Set([ac, bc]));
|
|
166
|
-
expect(c.children[0]).toBe(cc);
|
|
167
|
-
|
|
168
|
-
for (const dataSource of dataFlow.dataSources) {
|
|
169
|
-
// Cheat that we loaded something
|
|
170
|
-
dataSource.complete();
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
expect(ac.completed).toBeTruthy();
|
|
174
|
-
expect(bc.completed).toBeTruthy();
|
|
175
|
-
expect(cc.completed).toBeTruthy();
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test("Does not merge those with undefined identifier", () => {
|
|
179
|
-
/** @type {DataFlow<string>} */
|
|
180
|
-
const dataFlow = new DataFlow();
|
|
181
|
-
|
|
182
|
-
const a = new InlineSource({ values: [1, 2, 3] });
|
|
183
|
-
const b = new InlineSource({ values: [1, 2, 3] });
|
|
184
|
-
|
|
185
|
-
dataFlow.addDataSource(a, "a");
|
|
186
|
-
dataFlow.addDataSource(b, "b");
|
|
187
|
-
|
|
188
|
-
combineIdenticalDataSources(dataFlow);
|
|
189
|
-
|
|
190
|
-
expect(dataFlow.findDataSourceByKey("a")).toBe(a);
|
|
191
|
-
expect(dataFlow.findDataSourceByKey("b")).toBe(b);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import Collector from "./collector";
|
|
2
|
-
import FlowNode from "./flowNode";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {import("./flowNode").default} flowNode
|
|
7
|
-
* @param {any[]} data
|
|
8
|
-
*/
|
|
9
|
-
export function processData(flowNode, data) {
|
|
10
|
-
const collector = new Collector();
|
|
11
|
-
flowNode.addChild(collector);
|
|
12
|
-
|
|
13
|
-
for (const d of data) {
|
|
14
|
-
flowNode.handle(d);
|
|
15
|
-
}
|
|
16
|
-
flowNode.complete();
|
|
17
|
-
|
|
18
|
-
flowNode.removeChild(collector);
|
|
19
|
-
|
|
20
|
-
return [...collector.getData()];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* For testing
|
|
25
|
-
*/
|
|
26
|
-
export class SynchronousSource extends FlowNode {
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
* @param {any[]} data
|
|
30
|
-
*/
|
|
31
|
-
constructor(data) {
|
|
32
|
-
super();
|
|
33
|
-
this.data = data;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
dispatch() {
|
|
37
|
-
for (const d of this.data) {
|
|
38
|
-
this._propagate(d);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
this.complete();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* For testing
|
|
47
|
-
*/
|
|
48
|
-
export class SynchronousSequenceSource extends SynchronousSource {
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
* @param {number} n number of elements
|
|
52
|
-
*/
|
|
53
|
-
constructor(n) {
|
|
54
|
-
n = n || 10;
|
|
55
|
-
|
|
56
|
-
const data = [];
|
|
57
|
-
for (let i = 0; i < n; i++) {
|
|
58
|
-
data.push({ data: i });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
super(data);
|
|
62
|
-
}
|
|
63
|
-
}
|