@genome-spy/core 0.30.0 → 0.30.3

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.
Files changed (234) hide show
  1. package/dist/index.es.js +16379 -0
  2. package/dist/index.js +43 -43
  3. package/package.json +10 -7
  4. package/src/data/collector.js +0 -183
  5. package/src/data/collector.test.js +0 -84
  6. package/src/data/dataFlow.js +0 -148
  7. package/src/data/dataFlow.test.js +0 -5
  8. package/src/data/facetNode.js +0 -17
  9. package/src/data/flow.test.js +0 -72
  10. package/src/data/flowBatch.d.ts +0 -40
  11. package/src/data/flowNode.js +0 -283
  12. package/src/data/flowNode.test.js +0 -50
  13. package/src/data/flowOptimizer.js +0 -123
  14. package/src/data/flowOptimizer.test.js +0 -193
  15. package/src/data/flowTestUtils.js +0 -63
  16. package/src/data/formats/fasta.js +0 -32
  17. package/src/data/formats/fasta.test.js +0 -27
  18. package/src/data/sources/dataSource.js +0 -22
  19. package/src/data/sources/dataSourceFactory.js +0 -24
  20. package/src/data/sources/dataUtils.js +0 -78
  21. package/src/data/sources/dynamicCallbackSource.js +0 -57
  22. package/src/data/sources/dynamicSource.js +0 -37
  23. package/src/data/sources/inlineSource.js +0 -67
  24. package/src/data/sources/inlineSource.test.js +0 -56
  25. package/src/data/sources/namedSource.js +0 -79
  26. package/src/data/sources/sequenceSource.js +0 -46
  27. package/src/data/sources/sequenceSource.test.js +0 -46
  28. package/src/data/sources/urlSource.js +0 -74
  29. package/src/data/transforms/aggregate.js +0 -70
  30. package/src/data/transforms/clone.js +0 -40
  31. package/src/data/transforms/clone.test.js +0 -11
  32. package/src/data/transforms/coverage.js +0 -187
  33. package/src/data/transforms/coverage.test.js +0 -123
  34. package/src/data/transforms/filter.js +0 -37
  35. package/src/data/transforms/filter.test.js +0 -18
  36. package/src/data/transforms/filterScoredLabels.js +0 -134
  37. package/src/data/transforms/flattenCompressedExons.js +0 -57
  38. package/src/data/transforms/flattenDelimited.js +0 -74
  39. package/src/data/transforms/flattenDelimited.test.js +0 -87
  40. package/src/data/transforms/flattenSequence.js +0 -39
  41. package/src/data/transforms/flattenSequence.test.js +0 -34
  42. package/src/data/transforms/formula.js +0 -39
  43. package/src/data/transforms/formula.test.js +0 -19
  44. package/src/data/transforms/identifier.js +0 -108
  45. package/src/data/transforms/identifier.test.js +0 -83
  46. package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
  47. package/src/data/transforms/measureText.js +0 -44
  48. package/src/data/transforms/pileup.js +0 -128
  49. package/src/data/transforms/pileup.test.js +0 -70
  50. package/src/data/transforms/project.js +0 -41
  51. package/src/data/transforms/project.test.js +0 -32
  52. package/src/data/transforms/regexExtract.js +0 -61
  53. package/src/data/transforms/regexExtract.test.js +0 -67
  54. package/src/data/transforms/regexFold.js +0 -141
  55. package/src/data/transforms/regexFold.test.js +0 -160
  56. package/src/data/transforms/sample.js +0 -101
  57. package/src/data/transforms/sample.test.js +0 -38
  58. package/src/data/transforms/stack.js +0 -137
  59. package/src/data/transforms/stack.test.js +0 -91
  60. package/src/data/transforms/transformFactory.js +0 -60
  61. package/src/embedApi.d.ts +0 -67
  62. package/src/encoder/accessor.js +0 -82
  63. package/src/encoder/accessor.test.js +0 -47
  64. package/src/encoder/encoder.js +0 -394
  65. package/src/encoder/encoder.test.js +0 -98
  66. package/src/fonts/Lato-Regular.json +0 -1267
  67. package/src/fonts/Lato-Regular.png +0 -0
  68. package/src/fonts/OFL.txt +0 -93
  69. package/src/fonts/README.md +0 -3
  70. package/src/fonts/bmFont.d.ts +0 -58
  71. package/src/fonts/bmFontManager.js +0 -357
  72. package/src/fonts/bmFontMetrics.js +0 -108
  73. package/src/genome/genome.js +0 -317
  74. package/src/genome/genome.test.js +0 -188
  75. package/src/genome/genomeStore.js +0 -54
  76. package/src/genome/locusFormat.js +0 -31
  77. package/src/genome/scaleIndex.d.ts +0 -38
  78. package/src/genome/scaleIndex.js +0 -166
  79. package/src/genome/scaleIndex.test.js +0 -78
  80. package/src/genome/scaleLocus.d.ts +0 -11
  81. package/src/genome/scaleLocus.js +0 -108
  82. package/src/genome/scaleLocus.test.js +0 -4
  83. package/src/genomeSpy.js +0 -785
  84. package/src/gl/arrayBuilder.js +0 -199
  85. package/src/gl/dataToVertices.js +0 -636
  86. package/src/gl/includes/common.glsl +0 -63
  87. package/src/gl/includes/picking.fragment.glsl +0 -1
  88. package/src/gl/includes/picking.vertex.glsl +0 -27
  89. package/src/gl/includes/sampleFacet.glsl +0 -107
  90. package/src/gl/includes/scales.glsl +0 -112
  91. package/src/gl/link.fragment.glsl +0 -18
  92. package/src/gl/link.vertex.glsl +0 -111
  93. package/src/gl/point.fragment.glsl +0 -123
  94. package/src/gl/point.vertex.glsl +0 -129
  95. package/src/gl/rect.fragment.glsl +0 -51
  96. package/src/gl/rect.vertex.glsl +0 -114
  97. package/src/gl/rule.fragment.glsl +0 -52
  98. package/src/gl/rule.vertex.glsl +0 -89
  99. package/src/gl/text.fragment.glsl +0 -31
  100. package/src/gl/text.vertex.glsl +0 -246
  101. package/src/gl/webGLHelper.js +0 -504
  102. package/src/img/bowtie.svg +0 -1
  103. package/src/img/genomespy-favicon.svg +0 -34
  104. package/src/index.html +0 -11
  105. package/src/index.js +0 -128
  106. package/src/marks/link.js +0 -175
  107. package/src/marks/mark.js +0 -975
  108. package/src/marks/markUtils.js +0 -125
  109. package/src/marks/pointMark.js +0 -251
  110. package/src/marks/rectMark.js +0 -241
  111. package/src/marks/rule.js +0 -250
  112. package/src/marks/text.js +0 -278
  113. package/src/node_modules/.vitest/results.json +0 -1
  114. package/src/scale/colorUtils.js +0 -184
  115. package/src/scale/glslScaleGenerator.js +0 -502
  116. package/src/scale/scale.js +0 -451
  117. package/src/scale/scale.test.js +0 -324
  118. package/src/scale/ticks.js +0 -203
  119. package/src/scale/ticks.test.js +0 -40
  120. package/src/singlePageApp.js +0 -13
  121. package/src/spec/axis.d.ts +0 -296
  122. package/src/spec/channel.d.ts +0 -430
  123. package/src/spec/data.d.ts +0 -196
  124. package/src/spec/font.d.ts +0 -15
  125. package/src/spec/genome.d.ts +0 -35
  126. package/src/spec/mark.d.ts +0 -429
  127. package/src/spec/root.d.ts +0 -17
  128. package/src/spec/sampleView.d.ts +0 -180
  129. package/src/spec/scale.d.ts +0 -273
  130. package/src/spec/title.d.ts +0 -102
  131. package/src/spec/tooltip.d.ts +0 -9
  132. package/src/spec/transform.d.ts +0 -479
  133. package/src/spec/view.d.ts +0 -201
  134. package/src/styles/genome-spy.scss +0 -153
  135. package/src/tooltip/dataTooltipHandler.js +0 -64
  136. package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
  137. package/src/tooltip/tooltipHandler.ts +0 -12
  138. package/src/types/filetypes.d.ts +0 -14
  139. package/src/types/flatqueue.d.ts +0 -53
  140. package/src/types/glsl.d.ts +0 -4
  141. package/src/types/internmap.d.ts +0 -22
  142. package/src/types/object.d.ts +0 -21
  143. package/src/types/vega-loader.d.ts +0 -1
  144. package/src/types/vega-scale.d.ts +0 -60
  145. package/src/utils/addBaseUrl.js +0 -19
  146. package/src/utils/addBaseUrl.test.js +0 -22
  147. package/src/utils/animator.js +0 -83
  148. package/src/utils/arrayUtils.js +0 -61
  149. package/src/utils/binnedIndex.js +0 -167
  150. package/src/utils/binnedIndex.test.js +0 -155
  151. package/src/utils/clamp.js +0 -8
  152. package/src/utils/cloner.js +0 -34
  153. package/src/utils/cloner.test.js +0 -24
  154. package/src/utils/coalesce.js +0 -11
  155. package/src/utils/coalesce.test.js +0 -16
  156. package/src/utils/concatIterables.js +0 -26
  157. package/src/utils/concatIterables.test.js +0 -8
  158. package/src/utils/debounce.js +0 -37
  159. package/src/utils/domainArray.js +0 -216
  160. package/src/utils/domainArray.test.js +0 -130
  161. package/src/utils/eerp.js +0 -13
  162. package/src/utils/expression.js +0 -32
  163. package/src/utils/field.js +0 -28
  164. package/src/utils/formatObject.js +0 -31
  165. package/src/utils/indexer.js +0 -43
  166. package/src/utils/indexer.test.js +0 -47
  167. package/src/utils/inertia.js +0 -124
  168. package/src/utils/interactionEvent.js +0 -33
  169. package/src/utils/iterateNestedMaps.js +0 -21
  170. package/src/utils/iterateNestedMaps.test.js +0 -33
  171. package/src/utils/kWayMerge.js +0 -42
  172. package/src/utils/kWayMerge.test.js +0 -26
  173. package/src/utils/layout/flexLayout.js +0 -368
  174. package/src/utils/layout/flexLayout.test.js +0 -311
  175. package/src/utils/layout/grid.js +0 -95
  176. package/src/utils/layout/grid.test.js +0 -71
  177. package/src/utils/layout/padding.js +0 -120
  178. package/src/utils/layout/point.js +0 -23
  179. package/src/utils/layout/rectangle.js +0 -288
  180. package/src/utils/layout/rectangle.test.js +0 -172
  181. package/src/utils/mergeObjects.js +0 -99
  182. package/src/utils/mergeObjects.test.js +0 -42
  183. package/src/utils/numberExtractor.js +0 -24
  184. package/src/utils/numberExtractor.test.js +0 -6
  185. package/src/utils/point.js +0 -14
  186. package/src/utils/propertyCacher.js +0 -70
  187. package/src/utils/propertyCacher.test.js +0 -85
  188. package/src/utils/propertyCoalescer.js +0 -42
  189. package/src/utils/propertyCoalescer.test.js +0 -22
  190. package/src/utils/reservationMap.js +0 -103
  191. package/src/utils/reservationMap.test.js +0 -20
  192. package/src/utils/scaleNull.js +0 -19
  193. package/src/utils/setOperations.js +0 -75
  194. package/src/utils/smoothstep.js +0 -10
  195. package/src/utils/throttle.js +0 -34
  196. package/src/utils/topK.js +0 -76
  197. package/src/utils/topK.test.js +0 -64
  198. package/src/utils/transition.js +0 -74
  199. package/src/utils/ui/tooltip.js +0 -189
  200. package/src/utils/url.js +0 -22
  201. package/src/utils/variableTools.js +0 -24
  202. package/src/utils/variableTools.test.js +0 -13
  203. package/src/view/axisResolution.js +0 -140
  204. package/src/view/axisResolution.test.js +0 -201
  205. package/src/view/axisView.js +0 -747
  206. package/src/view/concatView.js +0 -45
  207. package/src/view/containerView.js +0 -159
  208. package/src/view/facetView.js +0 -491
  209. package/src/view/flowBuilder.js +0 -367
  210. package/src/view/flowBuilder.test.js +0 -125
  211. package/src/view/gridView.js +0 -786
  212. package/src/view/implicitRootView.js +0 -14
  213. package/src/view/importView.js +0 -19
  214. package/src/view/layerView.js +0 -74
  215. package/src/view/rendering.d.ts +0 -44
  216. package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
  217. package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
  218. package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
  219. package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
  220. package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
  221. package/src/view/renderingContext/viewRenderingContext.js +0 -41
  222. package/src/view/scaleResolution.js +0 -797
  223. package/src/view/scaleResolution.test.js +0 -572
  224. package/src/view/scaleResolutionApi.d.ts +0 -40
  225. package/src/view/testUtils.js +0 -51
  226. package/src/view/title.js +0 -165
  227. package/src/view/unitView.js +0 -382
  228. package/src/view/view.js +0 -612
  229. package/src/view/view.test.js +0 -214
  230. package/src/view/viewContext.d.ts +0 -62
  231. package/src/view/viewFactory.js +0 -181
  232. package/src/view/viewFactory.test.js +0 -17
  233. package/src/view/viewUtils.js +0 -327
  234. package/src/view/zoom.js +0 -89
@@ -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
- }