@genome-spy/core 0.14.0

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 (226) hide show
  1. package/dist/index.js +224 -0
  2. package/dist/style.css +1 -0
  3. package/package.json +54 -0
  4. package/src/data/collector.js +178 -0
  5. package/src/data/collector.test.js +82 -0
  6. package/src/data/dataFlow.js +109 -0
  7. package/src/data/dataFlow.test.js +3 -0
  8. package/src/data/facetNode.js +17 -0
  9. package/src/data/flow.test.js +71 -0
  10. package/src/data/flowBatch.d.ts +40 -0
  11. package/src/data/flowNode.js +283 -0
  12. package/src/data/flowNode.test.js +49 -0
  13. package/src/data/flowOptimizer.js +117 -0
  14. package/src/data/flowOptimizer.test.js +192 -0
  15. package/src/data/flowTestUtils.js +63 -0
  16. package/src/data/formats/fasta.js +32 -0
  17. package/src/data/formats/fasta.test.js +26 -0
  18. package/src/data/sources/dataSource.js +22 -0
  19. package/src/data/sources/dataSourceFactory.js +24 -0
  20. package/src/data/sources/dataUtils.js +31 -0
  21. package/src/data/sources/dynamicCallbackSource.js +56 -0
  22. package/src/data/sources/dynamicSource.js +36 -0
  23. package/src/data/sources/inlineSource.js +69 -0
  24. package/src/data/sources/inlineSource.test.js +55 -0
  25. package/src/data/sources/namedSource.js +74 -0
  26. package/src/data/sources/sequenceSource.js +46 -0
  27. package/src/data/sources/sequenceSource.test.js +45 -0
  28. package/src/data/sources/urlSource.js +74 -0
  29. package/src/data/transforms/aggregate.js +69 -0
  30. package/src/data/transforms/clone.js +40 -0
  31. package/src/data/transforms/clone.test.js +10 -0
  32. package/src/data/transforms/coverage.js +187 -0
  33. package/src/data/transforms/coverage.test.js +122 -0
  34. package/src/data/transforms/filter.js +37 -0
  35. package/src/data/transforms/filter.test.js +17 -0
  36. package/src/data/transforms/filterScoredLabels.js +134 -0
  37. package/src/data/transforms/flattenCompressedExons.js +57 -0
  38. package/src/data/transforms/flattenDelimited.js +68 -0
  39. package/src/data/transforms/flattenDelimited.test.js +86 -0
  40. package/src/data/transforms/flattenSequence.js +39 -0
  41. package/src/data/transforms/flattenSequence.test.js +33 -0
  42. package/src/data/transforms/formula.js +39 -0
  43. package/src/data/transforms/formula.test.js +18 -0
  44. package/src/data/transforms/identifier.js +108 -0
  45. package/src/data/transforms/identifier.test.js +82 -0
  46. package/src/data/transforms/linearizeGenomicCoordinate.js +101 -0
  47. package/src/data/transforms/measureText.js +44 -0
  48. package/src/data/transforms/pileup.js +128 -0
  49. package/src/data/transforms/pileup.test.js +69 -0
  50. package/src/data/transforms/project.js +41 -0
  51. package/src/data/transforms/project.test.js +31 -0
  52. package/src/data/transforms/regexExtract.js +61 -0
  53. package/src/data/transforms/regexExtract.test.js +66 -0
  54. package/src/data/transforms/regexFold.js +141 -0
  55. package/src/data/transforms/regexFold.test.js +159 -0
  56. package/src/data/transforms/sample.js +101 -0
  57. package/src/data/transforms/sample.test.js +37 -0
  58. package/src/data/transforms/stack.js +137 -0
  59. package/src/data/transforms/stack.test.js +90 -0
  60. package/src/data/transforms/transformFactory.js +60 -0
  61. package/src/encoder/accessor.js +82 -0
  62. package/src/encoder/accessor.test.js +46 -0
  63. package/src/encoder/encoder.js +369 -0
  64. package/src/encoder/encoder.test.js +97 -0
  65. package/src/fonts/Lato-Regular.json +1267 -0
  66. package/src/fonts/Lato-Regular.png +0 -0
  67. package/src/fonts/OFL.txt +93 -0
  68. package/src/fonts/README.md +3 -0
  69. package/src/fonts/bmFont.d.ts +58 -0
  70. package/src/fonts/bmFontManager.js +357 -0
  71. package/src/fonts/bmFontMetrics.js +108 -0
  72. package/src/genome/genome.js +305 -0
  73. package/src/genome/genome.test.js +152 -0
  74. package/src/genome/genomeStore.js +54 -0
  75. package/src/genome/locusFormat.js +31 -0
  76. package/src/genome/scaleIndex.js +199 -0
  77. package/src/genome/scaleIndex.test.js +61 -0
  78. package/src/genome/scaleLocus.js +112 -0
  79. package/src/genome/scaleLocus.test.js +3 -0
  80. package/src/genomeSpy.js +753 -0
  81. package/src/gl/arrayBuilder.js +199 -0
  82. package/src/gl/dataToVertices.js +621 -0
  83. package/src/gl/includes/common.glsl +63 -0
  84. package/src/gl/includes/fp64-arithmetic.glsl +187 -0
  85. package/src/gl/includes/fp64-utils.js +132 -0
  86. package/src/gl/includes/picking.fragment.glsl +3 -0
  87. package/src/gl/includes/picking.vertex.glsl +29 -0
  88. package/src/gl/includes/sampleFacet.glsl +107 -0
  89. package/src/gl/includes/scales.glsl +79 -0
  90. package/src/gl/includes/scales_fp64.glsl +30 -0
  91. package/src/gl/link.fragment.glsl +18 -0
  92. package/src/gl/link.vertex.glsl +111 -0
  93. package/src/gl/point.fragment.glsl +123 -0
  94. package/src/gl/point.vertex.glsl +128 -0
  95. package/src/gl/rect.fragment.glsl +51 -0
  96. package/src/gl/rect.vertex.glsl +114 -0
  97. package/src/gl/rule.fragment.glsl +52 -0
  98. package/src/gl/rule.vertex.glsl +89 -0
  99. package/src/gl/text.fragment.glsl +31 -0
  100. package/src/gl/text.vertex.glsl +246 -0
  101. package/src/gl/webGLHelper.js +490 -0
  102. package/src/img/bowtie.svg +1 -0
  103. package/src/img/genomespy-favicon.svg +34 -0
  104. package/src/index.html +11 -0
  105. package/src/index.js +151 -0
  106. package/src/marks/link.js +189 -0
  107. package/src/marks/mark.js +867 -0
  108. package/src/marks/markUtils.js +109 -0
  109. package/src/marks/pointMark.js +279 -0
  110. package/src/marks/rectMark.js +236 -0
  111. package/src/marks/rule.js +231 -0
  112. package/src/marks/text.js +274 -0
  113. package/src/options.d.ts +9 -0
  114. package/src/scale/colorUtils.js +184 -0
  115. package/src/scale/glslScaleGenerator.js +462 -0
  116. package/src/scale/scale.js +441 -0
  117. package/src/scale/scale.test.js +323 -0
  118. package/src/scale/ticks.js +198 -0
  119. package/src/scale/ticks.test.js +39 -0
  120. package/src/singlePageApp.js +13 -0
  121. package/src/spec/axis.d.ts +296 -0
  122. package/src/spec/channel.d.ts +127 -0
  123. package/src/spec/data.d.ts +185 -0
  124. package/src/spec/font.d.ts +15 -0
  125. package/src/spec/genome.d.ts +35 -0
  126. package/src/spec/mark.d.ts +432 -0
  127. package/src/spec/root.d.ts +22 -0
  128. package/src/spec/scale.d.ts +265 -0
  129. package/src/spec/tooltip.d.ts +9 -0
  130. package/src/spec/transform.d.ts +479 -0
  131. package/src/spec/view.d.ts +215 -0
  132. package/src/styles/genome-spy.scss +153 -0
  133. package/src/tooltip/dataTooltipHandler.js +59 -0
  134. package/src/tooltip/refseqGeneTooltipHandler.js +77 -0
  135. package/src/tooltip/tooltipHandler.ts +12 -0
  136. package/src/types/filetypes.d.ts +4 -0
  137. package/src/types/flatqueue.d.ts +53 -0
  138. package/src/types/glsl.d.ts +4 -0
  139. package/src/types/object.d.ts +21 -0
  140. package/src/types/vega-scale.d.ts +60 -0
  141. package/src/utils/animator.js +83 -0
  142. package/src/utils/arrayUtils.js +55 -0
  143. package/src/utils/binnedRangeIndex.js +83 -0
  144. package/src/utils/clamp.js +8 -0
  145. package/src/utils/cloner.js +32 -0
  146. package/src/utils/cloner.test.js +23 -0
  147. package/src/utils/coalesce.js +11 -0
  148. package/src/utils/coalesce.test.js +15 -0
  149. package/src/utils/concatIterables.js +26 -0
  150. package/src/utils/concatIterables.test.js +7 -0
  151. package/src/utils/debounce.js +37 -0
  152. package/src/utils/domainArray.js +224 -0
  153. package/src/utils/domainArray.test.js +129 -0
  154. package/src/utils/eerp.js +13 -0
  155. package/src/utils/expression.js +32 -0
  156. package/src/utils/field.js +28 -0
  157. package/src/utils/fisheye.js +60 -0
  158. package/src/utils/formatObject.js +31 -0
  159. package/src/utils/html.js +23 -0
  160. package/src/utils/html.test.js +13 -0
  161. package/src/utils/indexer.js +43 -0
  162. package/src/utils/indexer.test.js +46 -0
  163. package/src/utils/inertia.js +124 -0
  164. package/src/utils/interactionEvent.js +33 -0
  165. package/src/utils/iterateNestedMaps.js +21 -0
  166. package/src/utils/iterateNestedMaps.test.js +32 -0
  167. package/src/utils/kWayMerge.js +42 -0
  168. package/src/utils/kWayMerge.test.js +25 -0
  169. package/src/utils/layout/flexLayout.js +336 -0
  170. package/src/utils/layout/flexLayout.test.js +296 -0
  171. package/src/utils/layout/padding.js +107 -0
  172. package/src/utils/layout/point.js +23 -0
  173. package/src/utils/layout/rectangle.js +282 -0
  174. package/src/utils/layout/rectangle.test.js +171 -0
  175. package/src/utils/mergeObjects.js +99 -0
  176. package/src/utils/mergeObjects.test.js +41 -0
  177. package/src/utils/numberExtractor.js +24 -0
  178. package/src/utils/numberExtractor.test.js +5 -0
  179. package/src/utils/point.js +14 -0
  180. package/src/utils/propertyCacher.js +70 -0
  181. package/src/utils/propertyCacher.test.js +84 -0
  182. package/src/utils/propertyCoalescer.js +37 -0
  183. package/src/utils/propertyCoalescer.test.js +21 -0
  184. package/src/utils/reservationMap.js +103 -0
  185. package/src/utils/reservationMap.test.js +19 -0
  186. package/src/utils/scaleNull.js +19 -0
  187. package/src/utils/setOperations.js +75 -0
  188. package/src/utils/smoothstep.js +10 -0
  189. package/src/utils/throttle.js +34 -0
  190. package/src/utils/topK.js +76 -0
  191. package/src/utils/topK.test.js +63 -0
  192. package/src/utils/transition.js +74 -0
  193. package/src/utils/ui/tooltip.js +189 -0
  194. package/src/utils/url.js +22 -0
  195. package/src/utils/variableTools.js +24 -0
  196. package/src/utils/variableTools.test.js +12 -0
  197. package/src/view/axisResolution.js +135 -0
  198. package/src/view/axisResolution.test.js +200 -0
  199. package/src/view/axisView.js +746 -0
  200. package/src/view/channel.js +5 -0
  201. package/src/view/concatView.js +296 -0
  202. package/src/view/containerView.js +141 -0
  203. package/src/view/decoratorView.js +510 -0
  204. package/src/view/facetView.js +488 -0
  205. package/src/view/flowBuilder.js +362 -0
  206. package/src/view/flowBuilder.test.js +124 -0
  207. package/src/view/importView.js +19 -0
  208. package/src/view/layerView.js +60 -0
  209. package/src/view/rendering.d.ts +44 -0
  210. package/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
  211. package/src/view/renderingContext/deferredViewRenderingContext.js +174 -0
  212. package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
  213. package/src/view/renderingContext/simpleViewRenderingContext.js +62 -0
  214. package/src/view/renderingContext/svgViewRenderingContext.js +121 -0
  215. package/src/view/renderingContext/viewRenderingContext.js +41 -0
  216. package/src/view/scaleResolution.js +756 -0
  217. package/src/view/scaleResolution.test.js +571 -0
  218. package/src/view/scaleResolutionApi.d.ts +40 -0
  219. package/src/view/testUtils.js +48 -0
  220. package/src/view/unitView.js +368 -0
  221. package/src/view/view.js +589 -0
  222. package/src/view/view.test.js +213 -0
  223. package/src/view/viewContext.d.ts +57 -0
  224. package/src/view/viewFactory.js +179 -0
  225. package/src/view/viewFactory.test.js +16 -0
  226. package/src/view/viewUtils.js +420 -0
@@ -0,0 +1,5 @@
1
+ export default class Channel {
2
+ constructor() {
3
+ this.type = null; // x, y, etc
4
+ }
5
+ }
@@ -0,0 +1,296 @@
1
+ import { isHConcatSpec, isVConcatSpec } from "./viewFactory";
2
+ import ContainerView from "./containerView";
3
+ import {
4
+ mapToPixelCoords,
5
+ getMinimumSize,
6
+ parseSizeDef,
7
+ FlexDimensions,
8
+ } from "../utils/layout/flexLayout";
9
+ import Rectangle from "../utils/layout/rectangle";
10
+ import Padding from "../utils/layout/padding";
11
+ import { peek } from "../utils/arrayUtils";
12
+
13
+ /**
14
+ * Creates a vertically or horizontally concatenated layout for children.
15
+ *
16
+ * @typedef {import("./view").default} View
17
+ * @typedef { import("../utils/layout/flexLayout").SizeDef} SizeDef
18
+ */
19
+ export default class ConcatView extends ContainerView {
20
+ /**
21
+ *
22
+ * @param {import("./viewUtils").AnyConcatSpec} spec
23
+ * @param {import("./viewUtils").ViewContext} context
24
+ * @param {import("./containerView").default} parent
25
+ * @param {string} name
26
+ */
27
+ constructor(spec, context, parent, name) {
28
+ super(spec, context, parent, name);
29
+
30
+ this.spec = spec;
31
+
32
+ if (!("spacing" in this.spec)) {
33
+ this.spec.spacing = 10; // TODO: Provide a global configuration (theme!)
34
+ }
35
+
36
+ /** @type {import("../spec/view").GeometricDimension } */
37
+ this.mainDimension = isHConcatSpec(spec) ? "width" : "height";
38
+ /** @type {import("../spec/view").GeometricDimension } */
39
+ this.secondaryDimension =
40
+ this.mainDimension == "width" ? "height" : "width";
41
+
42
+ const childSpecs = isHConcatSpec(spec)
43
+ ? spec.hconcat
44
+ : isVConcatSpec(spec)
45
+ ? spec.vconcat
46
+ : spec.concat;
47
+
48
+ /** @type { View[] } */
49
+ this.children = childSpecs.map((childSpec, i) =>
50
+ context.createView(childSpec, this, "concat" + i)
51
+ );
52
+ }
53
+
54
+ /*
55
+ _getEffectiveChildPaddings() {
56
+ return this.children
57
+ .map((view) => view.getEffectivePadding())
58
+ .map((padding) =>
59
+ this.mainDimension == "height"
60
+ ? [padding.left, padding.right]
61
+ : [padding.top, padding.bottom]
62
+ )
63
+ }
64
+ */
65
+
66
+ getEffectivePadding() {
67
+ return this._cache("size/effectivePadding", () => {
68
+ const visibleChildren = this.children.filter((view) =>
69
+ view.isVisible()
70
+ );
71
+
72
+ if (!visibleChildren.length) {
73
+ return this.getPadding();
74
+ }
75
+
76
+ // Max paddings along the secondary dimension
77
+
78
+ const paddings = visibleChildren
79
+ .map((view) => view.getEffectivePadding())
80
+ .map((padding) =>
81
+ this.mainDimension == "height"
82
+ ? [padding.left, padding.right]
83
+ : [padding.top, padding.bottom]
84
+ );
85
+
86
+ const maxPaddings = getMaxEffectivePaddings(paddings);
87
+
88
+ const effectiveChildPadding =
89
+ this.mainDimension == "height"
90
+ ? new Padding(
91
+ visibleChildren[0].getEffectivePadding().top,
92
+ maxPaddings[1],
93
+ peek(visibleChildren).getEffectivePadding().bottom,
94
+ maxPaddings[0]
95
+ )
96
+ : new Padding(
97
+ maxPaddings[0],
98
+ visibleChildren[0].getEffectivePadding().left,
99
+ maxPaddings[1],
100
+ peek(visibleChildren).getEffectivePadding().right
101
+ );
102
+
103
+ return this.getPadding().add(effectiveChildPadding);
104
+ });
105
+ }
106
+
107
+ getSize() {
108
+ return this._cache("size", () => {
109
+ /** @type {SizeDef} */
110
+ let mainSizeDef;
111
+ if (this.spec[this.mainDimension]) {
112
+ mainSizeDef = parseSizeDef(this.spec[this.mainDimension]);
113
+ } else {
114
+ const childMainSizeDefs = this.children
115
+ .filter((view) => view.isVisible())
116
+ .map((view) => view.getSize()[this.mainDimension]);
117
+
118
+ mainSizeDef = {
119
+ // Grows are summed to support sensible nesting of concatViews
120
+ grow: childMainSizeDefs
121
+ .map((sizeDef) => +sizeDef.grow)
122
+ .reduce((a, b) => a + b, 0),
123
+ px: getMinimumSize(childMainSizeDefs, {
124
+ spacing: this.spec.spacing,
125
+ }),
126
+ };
127
+ }
128
+
129
+ const secondarySizeDef = (this.spec[this.secondaryDimension] &&
130
+ parseSizeDef(this.spec[this.secondaryDimension])) || {
131
+ grow: 1,
132
+ };
133
+
134
+ return (
135
+ this.mainDimension == "height"
136
+ ? new FlexDimensions(secondarySizeDef, mainSizeDef)
137
+ : new FlexDimensions(mainSizeDef, secondarySizeDef)
138
+ ).addPadding(this.getPadding());
139
+ });
140
+ }
141
+
142
+ /**
143
+ * @param {import("./renderingContext/viewRenderingContext").default} context
144
+ * @param {import("../utils/layout/rectangle").default} coords
145
+ * @param {import("./view").RenderingOptions} [options]
146
+ */
147
+ render(context, coords, options = {}) {
148
+ if (!this.isVisible()) {
149
+ return;
150
+ }
151
+
152
+ coords = coords.shrink(this.getPadding());
153
+ context.pushView(this, coords);
154
+
155
+ // This method produces piles of garbage when used with sample faceting.
156
+ // TODO: Figure out something. Perhaps the rectangles could be cached because
157
+ // they are identical for each sample facet.
158
+
159
+ const visibleChildren = this.children.filter((view) =>
160
+ view.isVisible()
161
+ );
162
+ const childSizeDefs = visibleChildren.map(
163
+ (view) => view.getSize()[this.mainDimension]
164
+ );
165
+
166
+ const mappedCoords = mapToPixelCoords(
167
+ childSizeDefs,
168
+ coords[this.mainDimension],
169
+ {
170
+ spacing: this.spec.spacing,
171
+ devicePixelRatio: this.context.glHelper.dpr,
172
+ }
173
+ );
174
+
175
+ // Align the views.
176
+ const paddings = visibleChildren
177
+ .map((view) => view.getEffectivePadding())
178
+ .map((padding) =>
179
+ this.mainDimension == "height"
180
+ ? [padding.left, padding.right]
181
+ : [padding.top, padding.bottom]
182
+ );
183
+
184
+ const maxPaddings = getMaxEffectivePaddings(paddings);
185
+
186
+ for (let i = 0; i < visibleChildren.length; i++) {
187
+ const view = visibleChildren[i];
188
+ const flexCoords = mappedCoords[i];
189
+
190
+ const pa = maxPaddings[0] - paddings[i][0];
191
+ const pb = maxPaddings[1] - paddings[i][1];
192
+
193
+ const secondarySize = coords[this.secondaryDimension] - pa - pb;
194
+
195
+ const childCoords =
196
+ this.mainDimension == "height"
197
+ ? new Rectangle(
198
+ () => coords.x + pa,
199
+ () => coords.y + flexCoords.location,
200
+ () => secondarySize,
201
+ () => flexCoords.size
202
+ )
203
+ : new Rectangle(
204
+ () => coords.x + flexCoords.location,
205
+ () => coords.y + pa,
206
+ () => flexCoords.size,
207
+ () => secondarySize
208
+ );
209
+
210
+ view.render(context, childCoords, options);
211
+ }
212
+
213
+ context.popView(this);
214
+ }
215
+
216
+ /**
217
+ * @returns {IterableIterator<View>}
218
+ */
219
+ *[Symbol.iterator]() {
220
+ for (const child of this.children) {
221
+ yield child;
222
+ }
223
+ }
224
+
225
+ /**
226
+ * @param {import("./view").default} child
227
+ * @param {import("./view").default} replacement
228
+ */
229
+ replaceChild(child, replacement) {
230
+ const i = this.children.indexOf(child);
231
+ if (i >= 0) {
232
+ this.children[i] = replacement;
233
+ } else {
234
+ throw new Error("Not my child view!");
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Adds a child using a spec. Does NOT perform any initializations.
240
+ * Returns the newly added view instance.
241
+ *
242
+ * @param {import("./viewUtils").ViewSpec} viewSpec
243
+ */
244
+ addChildBySpec(viewSpec) {
245
+ // TODO: Move to containerView
246
+
247
+ // TODO: More robust solution. Will break in future when views can be removed
248
+ const i = this.children.length;
249
+
250
+ const view = this.context.createView(viewSpec, this, "concat" + i);
251
+ this.children.push(view);
252
+
253
+ return view;
254
+ }
255
+
256
+ /**
257
+ * Adds a child. Does NOT perform any initializations.
258
+ * Returns the newly added view instance.
259
+ *
260
+ * @param {View} view
261
+ */
262
+ addChild(view) {
263
+ // TODO: Move to containerView
264
+
265
+ // TODO: More robust solution. Will break in future when views can be removed
266
+ const i = this.children.length;
267
+
268
+ if (!view.name) {
269
+ view.name = "concat" + i;
270
+ }
271
+ view.parent = this;
272
+ this.children.push(view);
273
+
274
+ return view;
275
+ }
276
+
277
+ /**
278
+ * @param {string} channel
279
+ * @param {import("./containerView").ResolutionTarget} resolutionType
280
+ * @returns {import("../spec/view").ResolutionBehavior}
281
+ */
282
+ getDefaultResolution(channel, resolutionType) {
283
+ // TODO: Default to shared when working with genomic coordinates
284
+ return "independent";
285
+ }
286
+ }
287
+
288
+ /**
289
+ *
290
+ * @param {number[][]} paddings
291
+ */
292
+ function getMaxEffectivePaddings(paddings) {
293
+ return [0, 1].map((i) =>
294
+ paddings.map((p) => p[i]).reduce((a, c) => Math.max(a, c), 0)
295
+ );
296
+ }
@@ -0,0 +1,141 @@
1
+ import View, { VISIT_STOP, VISIT_SKIP } from "./view";
2
+
3
+ /**
4
+ * Compositor view represents a non-leaf node in the view hierarchy.
5
+ * @typedef {import("../spec/view").ResolutionTarget} ResolutionTarget
6
+ */
7
+ export default class ContainerView extends View {
8
+ /**
9
+ *
10
+ * @param {import("./viewUtils").ContainerSpec} spec
11
+ * @param {import("./view").ViewContext} context
12
+ * @param {ContainerView} parent
13
+ * @param {string} name
14
+ */
15
+ constructor(spec, context, parent, name) {
16
+ super(spec, context, parent, name);
17
+
18
+ this.spec = spec;
19
+ }
20
+
21
+ /**
22
+ * @returns {IterableIterator<View>}
23
+ */
24
+ *[Symbol.iterator]() {
25
+ // override
26
+ }
27
+
28
+ /**
29
+ * Replaces a child view with another one. Does not alter the old or new child.
30
+ *
31
+ * @param {import("./view").default} child
32
+ * @param {import("./view").default} replacement
33
+ */
34
+ replaceChild(child, replacement) {
35
+ throw new Error("Not implemented");
36
+ }
37
+
38
+ /**
39
+ * Visits child views in depth-first pre-order. Terminates the search and returns
40
+ * the value if the visitor returns a defined value. The `afterChildren` callback
41
+ * allows for post-order traversal
42
+ *
43
+ * @param {import("./view").Visitor} visitor
44
+ * @returns {import("./view").VisitResult}
45
+ */
46
+ visit(visitor) {
47
+ /** @type {import("./view").VisitResult}*/
48
+ let result;
49
+ try {
50
+ result = visitor(this);
51
+ } catch (e) {
52
+ // Augment the exception with the view
53
+ e.view = this;
54
+ throw e;
55
+ }
56
+
57
+ if (result === VISIT_STOP) {
58
+ return result;
59
+ }
60
+
61
+ if (result !== VISIT_SKIP) {
62
+ if (visitor.beforeChildren) {
63
+ visitor.beforeChildren(this);
64
+ }
65
+
66
+ for (const view of this) {
67
+ const result = view.visit(visitor);
68
+ if (result === VISIT_STOP) {
69
+ return result;
70
+ }
71
+ }
72
+
73
+ if (visitor.afterChildren) {
74
+ visitor.afterChildren(this);
75
+ }
76
+
77
+ if (visitor.postOrder) {
78
+ visitor.postOrder(this);
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @param {string[]} path An array of view names
85
+ * @returns {View}
86
+ */
87
+ findDescendantByPath(path) {
88
+ for (const child of this) {
89
+ if (child.name === path[0]) {
90
+ if (path.length == 1) {
91
+ return child;
92
+ } else if (child instanceof ContainerView) {
93
+ return child.findDescendantByPath(path.slice(1));
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ *
101
+ * @param {string} name
102
+ */
103
+ findChildByName(name) {
104
+ for (const child of this) {
105
+ if (child.name === name) {
106
+ return child;
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * @param {import("../spec/channel").Channel | "default"} channel
113
+ * @param {ResolutionTarget} resolutionType
114
+ * @returns {import("../spec/view").ResolutionBehavior}
115
+ */
116
+ getConfiguredResolution(channel, resolutionType) {
117
+ return this.spec.resolve?.[resolutionType]?.[channel];
118
+ }
119
+
120
+ /**
121
+ * @param {import("../spec/channel").Channel} channel
122
+ * @param {ResolutionTarget} resolutionType
123
+ * @returns {import("../spec/view").ResolutionBehavior}
124
+ */
125
+ getDefaultResolution(channel, resolutionType) {
126
+ return "shared";
127
+ }
128
+
129
+ /**
130
+ * @param {import("../spec/channel").Channel} channel
131
+ * @param {ResolutionTarget} resolutionType
132
+ * @returns {import("../spec/view").ResolutionBehavior}
133
+ */
134
+ getConfiguredOrDefaultResolution(channel, resolutionType) {
135
+ return (
136
+ this.getConfiguredResolution(channel, resolutionType) ??
137
+ this.getConfiguredResolution("default", resolutionType) ??
138
+ this.getDefaultResolution(channel, resolutionType)
139
+ );
140
+ }
141
+ }