@genome-spy/core 0.48.2 → 0.49.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 (221) hide show
  1. package/dist/bundle/index.es.js +7226 -6923
  2. package/dist/bundle/index.js +121 -108
  3. package/dist/schema.json +838 -344
  4. package/dist/src/data/collector.test.d.ts +2 -0
  5. package/dist/src/data/collector.test.d.ts.map +1 -0
  6. package/dist/src/data/dataFlow.test.d.ts +2 -0
  7. package/dist/src/data/dataFlow.test.d.ts.map +1 -0
  8. package/dist/src/data/flow.test.d.ts +2 -0
  9. package/dist/src/data/flow.test.d.ts.map +1 -0
  10. package/dist/src/data/flow.test.js +19 -14
  11. package/dist/src/data/flowNode.test.d.ts +2 -0
  12. package/dist/src/data/flowNode.test.d.ts.map +1 -0
  13. package/dist/src/data/flowOptimizer.test.d.ts +2 -0
  14. package/dist/src/data/flowOptimizer.test.d.ts.map +1 -0
  15. package/dist/src/data/flowOptimizer.test.js +9 -10
  16. package/dist/src/data/formats/fasta.test.d.ts +2 -0
  17. package/dist/src/data/formats/fasta.test.d.ts.map +1 -0
  18. package/dist/src/data/sources/inlineSource.test.d.ts +2 -0
  19. package/dist/src/data/sources/inlineSource.test.d.ts.map +1 -0
  20. package/dist/src/data/sources/inlineSource.test.js +23 -16
  21. package/dist/src/data/sources/sequenceSource.test.d.ts +2 -0
  22. package/dist/src/data/sources/sequenceSource.test.d.ts.map +1 -0
  23. package/dist/src/data/sources/sequenceSource.test.js +59 -42
  24. package/dist/src/data/transforms/clone.test.d.ts +2 -0
  25. package/dist/src/data/transforms/clone.test.d.ts.map +1 -0
  26. package/dist/src/data/transforms/coverage.test.d.ts +2 -0
  27. package/dist/src/data/transforms/coverage.test.d.ts.map +1 -0
  28. package/dist/src/data/transforms/coverage.test.js +1 -1
  29. package/dist/src/data/transforms/filter.d.ts +10 -0
  30. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  31. package/dist/src/data/transforms/filter.js +30 -1
  32. package/dist/src/data/transforms/filter.test.d.ts +2 -0
  33. package/dist/src/data/transforms/filter.test.d.ts.map +1 -0
  34. package/dist/src/data/transforms/flatten.test.d.ts +2 -0
  35. package/dist/src/data/transforms/flatten.test.d.ts.map +1 -0
  36. package/dist/src/data/transforms/flatten.test.js +10 -7
  37. package/dist/src/data/transforms/flattenDelimited.test.d.ts +2 -0
  38. package/dist/src/data/transforms/flattenDelimited.test.d.ts.map +1 -0
  39. package/dist/src/data/transforms/flattenDelimited.test.js +16 -13
  40. package/dist/src/data/transforms/flattenSequence.test.d.ts +2 -0
  41. package/dist/src/data/transforms/flattenSequence.test.d.ts.map +1 -0
  42. package/dist/src/data/transforms/flattenSequence.test.js +1 -1
  43. package/dist/src/data/transforms/formula.test.d.ts +2 -0
  44. package/dist/src/data/transforms/formula.test.d.ts.map +1 -0
  45. package/dist/src/data/transforms/formula.test.js +1 -1
  46. package/dist/src/data/transforms/identifier.test.d.ts +2 -0
  47. package/dist/src/data/transforms/identifier.test.d.ts.map +1 -0
  48. package/dist/src/data/transforms/pileup.test.d.ts +2 -0
  49. package/dist/src/data/transforms/pileup.test.d.ts.map +1 -0
  50. package/dist/src/data/transforms/project.test.d.ts +2 -0
  51. package/dist/src/data/transforms/project.test.d.ts.map +1 -0
  52. package/dist/src/data/transforms/project.test.js +1 -1
  53. package/dist/src/data/transforms/regexExtract.test.d.ts +2 -0
  54. package/dist/src/data/transforms/regexExtract.test.d.ts.map +1 -0
  55. package/dist/src/data/transforms/regexExtract.test.js +6 -3
  56. package/dist/src/data/transforms/regexFold.test.d.ts +2 -0
  57. package/dist/src/data/transforms/regexFold.test.d.ts.map +1 -0
  58. package/dist/src/data/transforms/sample.test.d.ts +2 -0
  59. package/dist/src/data/transforms/sample.test.d.ts.map +1 -0
  60. package/dist/src/data/transforms/stack.test.d.ts +2 -0
  61. package/dist/src/data/transforms/stack.test.d.ts.map +1 -0
  62. package/dist/src/data/transforms/stack.test.js +8 -8
  63. package/dist/src/encoder/accessor.d.ts +17 -14
  64. package/dist/src/encoder/accessor.d.ts.map +1 -1
  65. package/dist/src/encoder/accessor.js +127 -56
  66. package/dist/src/encoder/accessor.test.d.ts +2 -0
  67. package/dist/src/encoder/accessor.test.d.ts.map +1 -0
  68. package/dist/src/encoder/accessor.test.js +145 -31
  69. package/dist/src/encoder/encoder.d.ts +26 -13
  70. package/dist/src/encoder/encoder.d.ts.map +1 -1
  71. package/dist/src/encoder/encoder.js +98 -114
  72. package/dist/src/encoder/encoder.test.d.ts +2 -0
  73. package/dist/src/encoder/encoder.test.d.ts.map +1 -0
  74. package/dist/src/encoder/encoder.test.js +85 -82
  75. package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
  76. package/dist/src/fonts/bmFontManager.js +10 -4
  77. package/dist/src/genome/genome.test.d.ts +2 -0
  78. package/dist/src/genome/genome.test.d.ts.map +1 -0
  79. package/dist/src/genome/scaleIndex.test.d.ts +2 -0
  80. package/dist/src/genome/scaleIndex.test.d.ts.map +1 -0
  81. package/dist/src/genome/scaleLocus.test.d.ts +2 -0
  82. package/dist/src/genome/scaleLocus.test.d.ts.map +1 -0
  83. package/dist/src/genomeSpy.d.ts +3 -2
  84. package/dist/src/genomeSpy.d.ts.map +1 -1
  85. package/dist/src/genomeSpy.js +15 -6
  86. package/dist/src/gl/dataToVertices.d.ts +6 -8
  87. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  88. package/dist/src/gl/dataToVertices.js +42 -33
  89. package/dist/src/gl/glslScaleGenerator.d.ts +84 -15
  90. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  91. package/dist/src/gl/glslScaleGenerator.js +260 -73
  92. package/dist/src/marks/link.common.glsl.js +1 -1
  93. package/dist/src/marks/link.d.ts.map +1 -1
  94. package/dist/src/marks/link.js +10 -0
  95. package/dist/src/marks/link.vertex.glsl.js +1 -1
  96. package/dist/src/marks/mark.d.ts +6 -9
  97. package/dist/src/marks/mark.d.ts.map +1 -1
  98. package/dist/src/marks/mark.js +212 -95
  99. package/dist/src/marks/point.d.ts.map +1 -1
  100. package/dist/src/marks/point.js +5 -1
  101. package/dist/src/marks/rect.d.ts.map +1 -1
  102. package/dist/src/marks/rect.js +9 -4
  103. package/dist/src/marks/rule.d.ts.map +1 -1
  104. package/dist/src/marks/rule.js +4 -0
  105. package/dist/src/marks/text.d.ts.map +1 -1
  106. package/dist/src/marks/text.js +5 -1
  107. package/dist/src/scale/scale.test.d.ts +2 -0
  108. package/dist/src/scale/scale.test.d.ts.map +1 -0
  109. package/dist/src/scale/scale.test.js +2 -0
  110. package/dist/src/scale/ticks.test.d.ts +2 -0
  111. package/dist/src/scale/ticks.test.d.ts.map +1 -0
  112. package/dist/src/scale/ticks.test.js +6 -0
  113. package/dist/src/selection/selection.d.ts +39 -0
  114. package/dist/src/selection/selection.d.ts.map +1 -0
  115. package/dist/src/selection/selection.js +78 -0
  116. package/dist/src/spec/channel.d.ts +137 -83
  117. package/dist/src/spec/mark.d.ts +9 -0
  118. package/dist/src/spec/parameter.d.ts +112 -3
  119. package/dist/src/spec/root.d.ts +0 -1
  120. package/dist/src/spec/transform.d.ts +19 -1
  121. package/dist/src/spec/view.d.ts +3 -3
  122. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  123. package/dist/src/types/encoder.d.ts +80 -26
  124. package/dist/src/types/rendering.d.ts +1 -0
  125. package/dist/src/types/selectionTypes.d.ts +44 -0
  126. package/dist/src/types/viewContext.d.ts +1 -4
  127. package/dist/src/utils/addBaseUrl.test.d.ts +2 -0
  128. package/dist/src/utils/addBaseUrl.test.d.ts.map +1 -0
  129. package/dist/src/utils/binnedIndex.test.d.ts +2 -0
  130. package/dist/src/utils/binnedIndex.test.d.ts.map +1 -0
  131. package/dist/src/utils/cloner.test.d.ts +2 -0
  132. package/dist/src/utils/cloner.test.d.ts.map +1 -0
  133. package/dist/src/utils/coalesce.test.d.ts +2 -0
  134. package/dist/src/utils/coalesce.test.d.ts.map +1 -0
  135. package/dist/src/utils/concatIterables.test.d.ts +2 -0
  136. package/dist/src/utils/concatIterables.test.d.ts.map +1 -0
  137. package/dist/src/utils/domainArray.test.d.ts +2 -0
  138. package/dist/src/utils/domainArray.test.d.ts.map +1 -0
  139. package/dist/src/utils/expression.d.ts +2 -2
  140. package/dist/src/utils/expression.d.ts.map +1 -1
  141. package/dist/src/utils/expression.js +11 -2
  142. package/dist/src/utils/indexer.test.d.ts +2 -0
  143. package/dist/src/utils/indexer.test.d.ts.map +1 -0
  144. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  145. package/dist/src/utils/inputBinding.js +4 -0
  146. package/dist/src/utils/iterateNestedMaps.test.d.ts +2 -0
  147. package/dist/src/utils/iterateNestedMaps.test.d.ts.map +1 -0
  148. package/dist/src/utils/kWayMerge.test.d.ts +2 -0
  149. package/dist/src/utils/kWayMerge.test.d.ts.map +1 -0
  150. package/dist/src/utils/mergeObjects.test.d.ts +2 -0
  151. package/dist/src/utils/mergeObjects.test.d.ts.map +1 -0
  152. package/dist/src/utils/numberExtractor.test.d.ts +2 -0
  153. package/dist/src/utils/numberExtractor.test.d.ts.map +1 -0
  154. package/dist/src/utils/propertyCacher.test.d.ts +2 -0
  155. package/dist/src/utils/propertyCacher.test.d.ts.map +1 -0
  156. package/dist/src/utils/propertyCoalescer.test.d.ts +2 -0
  157. package/dist/src/utils/propertyCoalescer.test.d.ts.map +1 -0
  158. package/dist/src/utils/propertyCoalescer.test.js +3 -0
  159. package/dist/src/utils/radixSort.test.d.ts +2 -0
  160. package/dist/src/utils/radixSort.test.d.ts.map +1 -0
  161. package/dist/src/utils/reservationMap.test.d.ts +2 -0
  162. package/dist/src/utils/reservationMap.test.d.ts.map +1 -0
  163. package/dist/src/utils/ringBuffer.test.d.ts +2 -0
  164. package/dist/src/utils/ringBuffer.test.d.ts.map +1 -0
  165. package/dist/src/utils/topK.test.d.ts +2 -0
  166. package/dist/src/utils/topK.test.d.ts.map +1 -0
  167. package/dist/src/utils/trees.test.d.ts +2 -0
  168. package/dist/src/utils/trees.test.d.ts.map +1 -0
  169. package/dist/src/utils/trees.test.js +8 -3
  170. package/dist/src/utils/variableTools.test.d.ts +2 -0
  171. package/dist/src/utils/variableTools.test.d.ts.map +1 -0
  172. package/dist/src/view/axisResolution.d.ts +19 -6
  173. package/dist/src/view/axisResolution.d.ts.map +1 -1
  174. package/dist/src/view/axisResolution.js +16 -7
  175. package/dist/src/view/axisResolution.test.d.ts +2 -0
  176. package/dist/src/view/axisResolution.test.d.ts.map +1 -0
  177. package/dist/src/view/axisResolution.test.js +16 -11
  178. package/dist/src/view/facetView.d.ts +1 -1
  179. package/dist/src/view/facetView.d.ts.map +1 -1
  180. package/dist/src/view/flowBuilder.d.ts +1 -1
  181. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  182. package/dist/src/view/flowBuilder.js +34 -5
  183. package/dist/src/view/flowBuilder.test.d.ts +2 -0
  184. package/dist/src/view/flowBuilder.test.d.ts.map +1 -0
  185. package/dist/src/view/gridView.d.ts +0 -6
  186. package/dist/src/view/gridView.d.ts.map +1 -1
  187. package/dist/src/view/layerView.d.ts +0 -6
  188. package/dist/src/view/layerView.d.ts.map +1 -1
  189. package/dist/src/view/layout/flexLayout.test.d.ts +2 -0
  190. package/dist/src/view/layout/flexLayout.test.d.ts.map +1 -0
  191. package/dist/src/view/layout/grid.test.d.ts +2 -0
  192. package/dist/src/view/layout/grid.test.d.ts.map +1 -0
  193. package/dist/src/view/layout/rectangle.test.d.ts +2 -0
  194. package/dist/src/view/layout/rectangle.test.d.ts.map +1 -0
  195. package/dist/src/view/paramMediator.d.ts +32 -5
  196. package/dist/src/view/paramMediator.d.ts.map +1 -1
  197. package/dist/src/view/paramMediator.js +97 -9
  198. package/dist/src/view/paramMediator.test.d.ts +2 -0
  199. package/dist/src/view/paramMediator.test.d.ts.map +1 -0
  200. package/dist/src/view/paramMediator.test.js +17 -1
  201. package/dist/src/view/scaleResolution.d.ts +17 -9
  202. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  203. package/dist/src/view/scaleResolution.js +51 -34
  204. package/dist/src/view/scaleResolution.test.d.ts +2 -0
  205. package/dist/src/view/scaleResolution.test.d.ts.map +1 -0
  206. package/dist/src/view/scaleResolution.test.js +2 -0
  207. package/dist/src/view/testUtils.d.ts.map +1 -1
  208. package/dist/src/view/testUtils.js +15 -3
  209. package/dist/src/view/unitView.d.ts +5 -15
  210. package/dist/src/view/unitView.d.ts.map +1 -1
  211. package/dist/src/view/unitView.js +81 -101
  212. package/dist/src/view/view.d.ts +1 -1
  213. package/dist/src/view/view.d.ts.map +1 -1
  214. package/dist/src/view/view.test.d.ts +2 -0
  215. package/dist/src/view/view.test.d.ts.map +1 -0
  216. package/dist/src/view/view.test.js +73 -55
  217. package/dist/src/view/viewFactory.test.d.ts +2 -0
  218. package/dist/src/view/viewFactory.test.d.ts.map +1 -0
  219. package/dist/src/view/viewFactory.test.js +2 -2
  220. package/dist/src/view/zoom.js +2 -2
  221. package/package.json +5 -2
@@ -13,9 +13,18 @@ import coalesce from "../utils/coalesce.js";
13
13
  import mergeObjects from "../utils/mergeObjects.js";
14
14
  import { getCachedOrCall } from "../utils/propertyCacher.js";
15
15
 
16
+ /**
17
+ * @template {import("../spec/channel.js").PositionalChannel}[T=PositionalChannel]
18
+ *
19
+ * @typedef {object} AxisResolutionMember
20
+ * @prop {import("./unitView.js").default} view
21
+ * @prop {T} channel
22
+ * @prop {import("../spec/channel.js").ChannelDefWithScale} channelDef
23
+ */
16
24
  export default class AxisResolution {
17
25
  /**
18
- * @typedef { import("./unitView.js").default} UnitView
26
+ * @typedef {import("./unitView.js").default} UnitView
27
+ * @typedef {import("../spec/channel.js").PositionalChannel} PositionalChannel
19
28
  */
20
29
 
21
30
  /**
@@ -23,7 +32,7 @@ export default class AxisResolution {
23
32
  */
24
33
  constructor(channel) {
25
34
  this.channel = channel;
26
- /** @type {import("./scaleResolution.js").ResolutionMember<import("../spec/channel.js").PositionalChannel>[]} The involved views */
35
+ /** @type {AxisResolutionMember[]} The involved views */
27
36
  this.members = [];
28
37
  }
29
38
 
@@ -35,10 +44,10 @@ export default class AxisResolution {
35
44
  * N.B. This is expected to be called in depth-first order, AFTER the
36
45
  * scales have been resolved.
37
46
  *
38
- * @param {UnitView} view
39
- * @param {import("../spec/channel.js").PositionalChannel} channel TODO: Do something for this
47
+ * @param {AxisResolutionMember} newMember
40
48
  */
41
- pushUnitView(view, channel) {
49
+ pushUnitView(newMember) {
50
+ const { view } = newMember;
42
51
  const newScaleResolution = view.getScaleResolution(this.channel);
43
52
 
44
53
  if (!newScaleResolution) {
@@ -52,7 +61,7 @@ export default class AxisResolution {
52
61
  throw new Error("Shared axes must have a shared scale!");
53
62
  }
54
63
 
55
- this.members.push({ view, channel });
64
+ this.members.push(newMember);
56
65
  }
57
66
 
58
67
  getAxisProps() {
@@ -81,7 +90,7 @@ export default class AxisResolution {
81
90
  }
82
91
 
83
92
  getTitle() {
84
- /** @param {import("./scaleResolution.js").ResolutionMember} member} */
93
+ /** @param {AxisResolutionMember} member} */
85
94
  const computeTitle = (member) => {
86
95
  const channelDef = getChannelDefWithScale(
87
96
  member.view,
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=axisResolution.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axisResolution.test.d.ts","sourceRoot":"","sources":["../../../src/view/axisResolution.test.js"],"names":[],"mappings":""}
@@ -35,19 +35,17 @@ const spec = {
35
35
  };
36
36
 
37
37
  describe("Axes resolve properly", () => {
38
- const sharedSpec = {
39
- ...spec,
40
- resolve: { scale: { y: "shared" }, axis: { y: "shared" } },
41
- };
42
-
43
38
  test("Independent axes are independent", async () => {
44
- const independentSpec = {
45
- ...spec,
46
- resolve: { scale: { y: "shared" }, axis: { y: "independent" } },
47
- };
39
+ const view = await createAndInitialize(
40
+ {
41
+ ...spec,
42
+ resolve: { scale: { y: "shared" }, axis: { y: "independent" } },
43
+ },
44
+ View
45
+ );
48
46
 
49
- const view = await createAndInitialize(independentSpec, View);
50
47
  const [r0, r1] = [0, 1].map((i) =>
48
+ // @ts-ignore
51
49
  view.children[i].getAxisResolution("y")
52
50
  );
53
51
 
@@ -57,7 +55,14 @@ describe("Axes resolve properly", () => {
57
55
  });
58
56
 
59
57
  test("Shared axes have joined titles", async () => {
60
- const view = await createAndInitialize(sharedSpec, View);
58
+ const view = await createAndInitialize(
59
+ {
60
+ ...spec,
61
+ resolve: { scale: { y: "shared" }, axis: { y: "shared" } },
62
+ },
63
+ View
64
+ );
65
+ // @ts-ignore
61
66
  expect(view.children[0].getAxisResolution("y").getTitle()).toEqual(
62
67
  "a, b"
63
68
  );
@@ -45,7 +45,7 @@ export default class FacetView extends ContainerView {
45
45
  *
46
46
  * @param {"row" | "column"} channel
47
47
  */
48
- getAccessor(channel: "row" | "column"): import("../types/encoder.js").Accessor;
48
+ getAccessor(channel: "row" | "column"): any;
49
49
  updateFacets(): void;
50
50
  updateLabels(): void;
51
51
  getFacetGroups(): any[];
@@ -1 +1 @@
1
- {"version":3,"file":"facetView.d.ts","sourceRoot":"","sources":["../../../src/view/facetView.js"],"names":[],"mappings":"AAmDA;;;;;;;;;;;;;;GAcG;AACH;IACI;;;;;;;OAOG;IACH;;;;;;OAMG;IACH,6CAHW,aAAa,QACb,MAAM,EA8BhB;IAzBG,UAAgB;IAEhB,WAEC;IAED;;;;OAIG;IACH,aAFU,OAAO,YAAY,EAAE,QAAQ,CAAC,CAYvC;IAED,oDAAoD;IACpD,kBADY,OAAO,YAAY,EAAE,cAAc,CAAC,CACa;IA2BjE,sBAIC;IAED;;;OAGG;IACH,qBAFW,KAAK,GAAG,QAAQ,0CAwB1B;IAED,qBAyCC;IAED,qBASC;IA6BD,wBAgBC;IAOD;;;;OAIG;IACH,gBAJW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,uBA4LjD;IA3KO,wBAA0B;CA4KrC;2BA/bY,QAAQ,GAAG,KAAK;;;;;;aA4CnB,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE;;;0BA1Df,oBAAoB;qBACzB,eAAe"}
1
+ {"version":3,"file":"facetView.d.ts","sourceRoot":"","sources":["../../../src/view/facetView.js"],"names":[],"mappings":"AAmDA;;;;;;;;;;;;;;GAcG;AACH;IACI;;;;;;;OAOG;IACH;;;;;;OAMG;IACH,6CAHW,aAAa,QACb,MAAM,EA8BhB;IAzBG,UAAgB;IAEhB,WAEC;IAED;;;;OAIG;IACH,aAFU,OAAO,YAAY,EAAE,QAAQ,CAAC,CAYvC;IAED,oDAAoD;IACpD,kBADY,OAAO,YAAY,EAAE,cAAc,CAAC,CACa;IA2BjE,sBAIC;IAED;;;OAGG;IACH,qBAFW,KAAK,GAAG,QAAQ,OAwB1B;IAED,qBAyCC;IAED,qBASC;IA6BD,wBAgBC;IAOD;;;;OAIG;IACH,gBAJW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,uBA4LjD;IA3KO,wBAA0B;CA4KrC;2BA/bY,QAAQ,GAAG,KAAK;;;;;;aA4CnB,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE;;;0BA1Df,oBAAoB;qBACzB,eAAe"}
@@ -13,7 +13,7 @@ export function buildDataFlow(root: import("./view.js").default, existingFlow?:
13
13
  */
14
14
  export function linearizeLocusAccess(view: import("./view.js").default): {
15
15
  transforms: import("../data/flowNode.js").default[];
16
- rewrittenEncoding: import("../spec/channel.js").Encoding<string>;
16
+ rewrittenEncoding: import("../spec/channel.js").Encoding;
17
17
  /**
18
18
  * Should be called after the whole flow has been created in order to
19
19
  * not disrupt inheritance of encodings
@@ -1 +1 @@
1
- {"version":3,"file":"flowBuilder.d.ts","sourceRoot":"","sources":["../../../src/view/flowBuilder.js"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,8JAkKC;AAED;;;;;;GAMG;AACH;;;IAgGc;;;OAGG;;EAYhB;AAgCD;;;;;;GAMG;AACH;;;0BAqB0B,QAAQ,SAAS,OAAO,qBAAqB,EAAE,KAAK,CAAC,CAAC;EAkB/E;qBA/XoB,qBAAqB;sBANpB,sBAAsB"}
1
+ {"version":3,"file":"flowBuilder.d.ts","sourceRoot":"","sources":["../../../src/view/flowBuilder.js"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,8JA+LC;AAED;;;;;;GAMG;AACH;;;IAgGc;;;OAGG;;EAYhB;AAgCD;;;;;;GAMG;AACH;;;0BAqB0B,QAAQ,SAAS,OAAO,qBAAqB,EAAE,KAAK,CAAC,CAAC;EAkB/E;qBA5ZoB,qBAAqB;sBANpB,sBAAsB"}
@@ -35,6 +35,8 @@ export function buildDataFlow(root, existingFlow) {
35
35
 
36
36
  /** @type {FlowNode[]} "Current nodes" on the path from view root to the current view */
37
37
  const nodeStack = [];
38
+ /** @type {{view: View, nodeStackDepth: number}[]} */
39
+ const viewStack = [];
38
40
 
39
41
  /** @type {FlowNode} */
40
42
  let currentNode;
@@ -59,6 +61,7 @@ export function buildDataFlow(root, existingFlow) {
59
61
  }
60
62
  currentNode.addChild(node);
61
63
  currentNode = node;
64
+ nodeStack.push(node);
62
65
  return node;
63
66
  }
64
67
 
@@ -108,10 +111,16 @@ export function buildDataFlow(root, existingFlow) {
108
111
  }
109
112
  }
110
113
 
114
+ function isInBranchWithIdentifier() {
115
+ return (
116
+ nodeStack.findLastIndex(
117
+ (node) => node instanceof IdentifierTransform
118
+ ) > nodeStack.findLastIndex((node) => node instanceof DataSource)
119
+ );
120
+ }
121
+
111
122
  /** @param {View} view */
112
123
  const processView = (view) => {
113
- nodeStack.push(currentNode);
114
-
115
124
  if (view.spec.data) {
116
125
  const dataSource = isNamedData(view.spec.data)
117
126
  ? new NamedSource(
@@ -122,6 +131,7 @@ export function buildDataFlow(root, existingFlow) {
122
131
  : createDataSource(view.spec.data, view);
123
132
 
124
133
  currentNode = dataSource;
134
+ nodeStack.push(dataSource);
125
135
  dataFlow.addDataSource(dataSource, view);
126
136
  }
127
137
 
@@ -148,13 +158,24 @@ export function buildDataFlow(root, existingFlow) {
148
158
  }
149
159
  }
150
160
 
151
- if (view.mark.isPickingParticipant()) {
161
+ if (
162
+ view.mark.isPickingParticipant() &&
163
+ !isInBranchWithIdentifier()
164
+ ) {
165
+ // TODO: If two branches receive the same data, they should have
166
+ // a shared identifier transform. However, unique ids cannot be
167
+ // assigned right after the data source, because some transforms,
168
+ // (e.g, RegexFold) may generate new tuples.
169
+ //
152
170
  appendTransform(new CloneTransform());
153
171
  appendTransform(
154
172
  new IdentifierTransform({ type: "identifier" })
155
173
  );
156
174
  }
157
175
 
176
+ // TODO: Handle cases where the spec contains terminal collector nodes
177
+ // (with custom sort configuration, for example). Now a new collector
178
+ // is always appended to the end of the current branch.
158
179
  const collector = new Collector({
159
180
  type: "collect",
160
181
  groupby: view.getFacetFields(),
@@ -178,10 +199,18 @@ export function buildDataFlow(root, existingFlow) {
178
199
 
179
200
  for (const dataTree of dataTrees) {
180
201
  visitTree(dataTree, {
181
- preOrder: (node) => processView(node.ref),
202
+ preOrder: (node) => {
203
+ viewStack.push({
204
+ view: node.ref,
205
+ nodeStackDepth: nodeStack.length,
206
+ });
207
+ processView(node.ref);
208
+ },
182
209
  // eslint-disable-next-line no-loop-func
183
210
  postOrder: () => {
184
- currentNode = nodeStack.pop();
211
+ const { nodeStackDepth } = viewStack.pop();
212
+ nodeStack.length = nodeStackDepth;
213
+ currentNode = nodeStack.at(-1);
185
214
  },
186
215
  });
187
216
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=flowBuilder.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowBuilder.test.d.ts","sourceRoot":"","sources":["../../../src/view/flowBuilder.test.js"],"names":[],"mappings":""}
@@ -66,12 +66,6 @@ export default class GridView extends ContainerView {
66
66
  * @protected
67
67
  */
68
68
  protected createAxes(): Promise<void[]>;
69
- /**
70
- * @param {import("./renderingContext/viewRenderingContext.js").default} context
71
- * @param {import("./layout/rectangle.js").default} coords
72
- * @param {import("../types/rendering.js").RenderingOptions} [options]
73
- */
74
- render(context: import("./renderingContext/viewRenderingContext.js").default, coords: import("./layout/rectangle.js").default, options?: import("../types/rendering.js").RenderingOptions): void;
75
69
  #private;
76
70
  }
77
71
  export class GridChild {
@@ -1 +1 @@
1
- {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAswBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA53BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAoGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAlrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAqrC5C;IAeI;;;OAGG;IACH,uBAHW,SAAS,8CA6FnB;IAhGD,uBAAmB;IAsCf;;;MAAoB;IAIpB;;;;MAQC;IAgDL,2BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;;CACJ;oBAx2CmB,qBAAqB"}
1
+ {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAswBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA53BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;;CA+jBJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAlrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAqrC5C;IAeI;;;OAGG;IACH,uBAHW,SAAS,8CA6FnB;IAhGD,uBAAmB;IAsCf;;;MAAoB;IAIpB;;;;MAQC;IAgDL,2BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;;CACJ;oBAx2CmB,qBAAqB"}
@@ -11,12 +11,6 @@ export default class LayerView extends ContainerView {
11
11
  constructor(spec: import("../spec/view.js").LayerSpec, context: import("../types/viewContext.js").default, layoutParent: ContainerView, dataParent: import("./view.js").default, name: string, options?: import("./view.js").ViewOptions);
12
12
  spec: import("../spec/view.js").LayerSpec;
13
13
  get children(): (import("./unitView.js").default | LayerView)[];
14
- /**
15
- * @param {import("./renderingContext/viewRenderingContext.js").default} context
16
- * @param {import("./layout/rectangle.js").default} coords
17
- * @param {import("../types/rendering.js").RenderingOptions} [options]
18
- */
19
- render(context: import("./renderingContext/viewRenderingContext.js").default, coords: import("./layout/rectangle.js").default, options?: import("../types/rendering.js").RenderingOptions): void;
20
14
  #private;
21
15
  }
22
16
  import ContainerView from "./containerView.js";
@@ -1 +1 @@
1
- {"version":3,"file":"layerView.d.ts","sourceRoot":"","sources":["../../../src/view/layerView.js"],"names":[],"mappings":"AAIA;IAQI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,SAAS,WACnC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,cACb,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAQzC;IAHG,0CAAgB;IAoCpB,gEAEC;IAWD;;;;OAIG;IACH,gBAJW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QAgB1D;;CAeJ;0BA1GyB,oBAAoB"}
1
+ {"version":3,"file":"layerView.d.ts","sourceRoot":"","sources":["../../../src/view/layerView.js"],"names":[],"mappings":"AAIA;IAQI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,SAAS,WACnC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,cACb,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAQzC;IAHG,0CAAgB;IAoCpB,gEAEC;;CA6CJ;0BA1GyB,oBAAoB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=flexLayout.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flexLayout.test.d.ts","sourceRoot":"","sources":["../../../../src/view/layout/flexLayout.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=grid.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.test.d.ts","sourceRoot":"","sources":["../../../../src/view/layout/grid.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rectangle.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rectangle.test.d.ts","sourceRoot":"","sources":["../../../../src/view/layout/rectangle.test.js"],"names":[],"mappings":""}
@@ -11,7 +11,17 @@ export function isExprRef(x: any): x is import("../spec/parameter.js").ExprRef;
11
11
  * @template T
12
12
  * @returns {T}
13
13
  */
14
- export function withoutExprRef<T>(x: T | import("../spec/parameter.js").ExprRef): T;
14
+ export function withoutExprRef<T>(x: import("../spec/parameter.js").ExprRef | T): T;
15
+ /**
16
+ * @param {Parameter} param
17
+ * @returns {param is import("../spec/parameter.js").VariableParameter}
18
+ */
19
+ export function isVariableParameter(param: import("../spec/parameter.js").Parameter): param is import("../spec/parameter.js").VariableParameter;
20
+ /**
21
+ * @param {Parameter} param
22
+ * @returns {param is import("../spec/parameter.js").SelectionParameter}
23
+ */
24
+ export function isSelectionParameter(param: import("../spec/parameter.js").Parameter): param is import("../spec/parameter.js").SelectionParameter<import("../spec/parameter.js").SelectionType>;
15
25
  /**
16
26
  * Takes a record of properties that may have ExprRefs as values. Converts the
17
27
  * ExprRefs to getters and setups a listener that is called when any of the
@@ -24,6 +34,23 @@ export function withoutExprRef<T>(x: T | import("../spec/parameter.js").ExprRef)
24
34
  * @template {Record<string, any | import("../spec/parameter.js").ExprRef>} T
25
35
  */
26
36
  export function activateExprRefProps<T extends Record<string, any>>(paramMediator: ParamMediator, props: T, listener?: (props: (keyof T)[]) => void): T;
37
+ /**
38
+ * Validates a parameter name. If the name is invalid, throws an error.
39
+ * Otherwise, returns the name.
40
+ *
41
+ * @param {string} name
42
+ * @returns {string} the name
43
+ */
44
+ export function validateParameterName(name: string): string;
45
+ /**
46
+ * Creates a function that always returns the same value.
47
+ * Provides functionality for creating a constant expression reference.
48
+ * They just do nothing.
49
+ *
50
+ * @param {any} value
51
+ * @returns {ExprRefFunction}
52
+ */
53
+ export function makeConstantExprRef(value: any): ExprRefFunction;
27
54
  /**
28
55
  * A class that manages parameters and expressions.
29
56
  * Supports nesting and scoped parameters.
@@ -44,10 +71,10 @@ export default class ParamMediator {
44
71
  */
45
72
  protected paramListeners: Map<string, Set<() => void>>;
46
73
  /**
47
- * @param {VariableParameter} param
74
+ * @param {Parameter} param
48
75
  * @returns {ParameterSetter}
49
76
  */
50
- registerParam(param: import("../spec/parameter.js").VariableParameter): (value: any) => void;
77
+ registerParam(param: import("../spec/parameter.js").Parameter): (value: any) => void;
51
78
  /**
52
79
  *
53
80
  * @param {string} paramName
@@ -75,7 +102,7 @@ export default class ParamMediator {
75
102
  /**
76
103
  * Returns configs for all parameters that have been registered using `registerParam`.
77
104
  */
78
- get paramConfigs(): ReadonlyMap<string, import("../spec/parameter.js").VariableParameter>;
105
+ get paramConfigs(): ReadonlyMap<string, import("../spec/parameter.js").Parameter>;
79
106
  /**
80
107
  *
81
108
  * @param {string} paramName
@@ -101,7 +128,7 @@ export default class ParamMediator {
101
128
  * A class that manages parameters and expressions.
102
129
  * Supports nesting and scoped parameters.
103
130
  */
104
- export type ExprRefFunction = ((datum?: object) => any) & import("../utils/expression.js").ExpressionProps & {
131
+ export type ExprRefFunction = ((datum?: import("../data/flowNode.js").Datum) => any) & import("../utils/expression.js").ExpressionProps & {
105
132
  addListener: (listener: () => void) => void;
106
133
  invalidate: () => void;
107
134
  identifier: () => string;
@@ -1 +1 @@
1
- {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AAuQA;;;GAGG;AACH,6BAHW,GAAG,+CAKb;AAED;;;;;;;GAOG;AACH,oFASC;AAED;;;;;;;;;;GAUG;AACH,mFANW,aAAa,+CAEW,IAAI,KAwCtC;AA9UD;;;;;GAKG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,IAAI,MAAM,EAAE,IAAI,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,gFAzCqB,GAAG,KAAK,IAAI,CAkEhC;IAED;;;;;;;OAOG;IACH,6BANW,MAAM,6BAEN,OAAO,iBACS,IAAI,CA8B9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WA/Fc,GAAG,KAAK,IAAI,CAuG1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,0FAIC;IAED;;;;;OAKG;IACH,0CAJW,MAAM,GACJ,aAAa,CASzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBA4EhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;;CACJ;;;;;;4BA9P4F,MAAM,IAAI,KAAK,IAAI;gBAAc,MAAM,IAAI;gBAAc,MAAM,MAAM"}
1
+ {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AA2SA;;;GAGG;AACH,6BAHW,GAAG,+CAKb;AAED;;;;;;;GAOG;AACH,oFASC;AAED;;;GAGG;AACH,gJAEC;AAED;;;GAGG;AACH,gMAEC;AAED;;;;;;;;;;GAUG;AACH,mFANW,aAAa,+CAEW,IAAI,KAwCtC;AAED;;;;;;GAMG;AACH,4CAHW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;GAOG;AACH,2CAHW,GAAG,GACD,eAAe,CAW3B;AAraD;;;;;GAKG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,IAAI,MAAM,EAAE,IAAI,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,wEAzCqB,GAAG,KAAK,IAAI,CAmGhC;IAED;;;;;;;OAOG;IACH,6BANW,MAAM,6BAEN,OAAO,iBACS,IAAI,CAgC9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WAlIc,GAAG,KAAK,IAAI,CA0I1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,kFAIC;IAED;;;;;OAKG;IACH,0CAJW,MAAM,GACJ,aAAa,CASzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBA4EhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;;CACJ;;;;;;4BAjS4F,MAAM,IAAI,KAAK,IAAI;gBAAc,MAAM,IAAI;gBAAc,MAAM,MAAM"}
@@ -1,5 +1,6 @@
1
1
  import { isString } from "vega-util";
2
2
  import createFunction from "../utils/expression.js";
3
+ import { createSinglePointSelection } from "../selection/selection.js";
3
4
 
4
5
  /**
5
6
  * A class that manages parameters and expressions.
@@ -9,7 +10,7 @@ import createFunction from "../utils/expression.js";
9
10
  */
10
11
  export default class ParamMediator {
11
12
  /**
12
- * @typedef {import("../spec/parameter.js").VariableParameter} VariableParameter
13
+ * @typedef {import("../spec/parameter.js").Parameter} Parameter
13
14
  * @typedef {(value: any) => void} ParameterSetter
14
15
  */
15
16
 
@@ -28,7 +29,7 @@ export default class ParamMediator {
28
29
  /** @type {Map<string, ExprRefFunction>} */
29
30
  #expressions = new Map();
30
31
 
31
- /** @type {Map<string, VariableParameter>} */
32
+ /** @type {Map<string, Parameter>} */
32
33
  #paramConfigs = new Map();
33
34
 
34
35
  /** @type {() => ParamMediator} */
@@ -48,32 +49,65 @@ export default class ParamMediator {
48
49
  }
49
50
 
50
51
  /**
51
- * @param {VariableParameter} param
52
+ * @param {Parameter} param
52
53
  * @returns {ParameterSetter}
53
54
  */
54
55
  registerParam(param) {
56
+ const name = param.name;
57
+
55
58
  if ("value" in param && "expr" in param) {
56
59
  throw new Error(
57
- "Parameter must not have both value and expr: " + param.name
60
+ `The parameter "${name}" must not have both value and expr properties!`
58
61
  );
59
62
  }
60
63
 
61
64
  /** @type {ParameterSetter} */
62
65
  let setter;
63
66
 
64
- if ("value" in param) {
65
- setter = this.allocateSetter(param.name, param.value);
67
+ if (param.push == "outer") {
68
+ const outerMediator = this.findMediatorForParam(name);
69
+ if (!outerMediator) {
70
+ throw new Error(
71
+ `Parameter "${name}" not found in outer scope!`
72
+ );
73
+ }
74
+
75
+ const outerProps = outerMediator.paramConfigs.get(name);
76
+ if ("expr" in outerProps || "select" in outerProps) {
77
+ throw new Error(
78
+ `The outer parameter "${name}" must not have expr or select properties!`
79
+ );
80
+ }
81
+ setter = outerMediator.getSetter(name);
82
+ // The following will become a bit fragile if the view hierarchy is going to
83
+ // support mutation (i.e. adding/removing children) in future.
84
+ this.#allocatedSetters.set(name, setter);
85
+ } else if ("value" in param) {
86
+ setter = this.allocateSetter(name, param.value);
66
87
  } else if ("expr" in param) {
67
88
  const expr = this.createExpression(param.expr);
68
89
  // TODO: getSetter(param) should return a setter that throws if
69
90
  // modifying the value is attempted.
70
- const realSetter = this.allocateSetter(param.name, expr(null));
91
+ const realSetter = this.allocateSetter(name, expr(null));
71
92
  expr.addListener(() => realSetter(expr(null)));
72
93
  // NOP
73
94
  setter = (_) => undefined;
95
+ } else {
96
+ setter = this.allocateSetter(name, null);
74
97
  }
75
98
 
76
- this.#paramConfigs.set(param.name, param);
99
+ if ("select" in param) {
100
+ const type = isString(param.select)
101
+ ? param.select
102
+ : param.select.type;
103
+
104
+ // Set initial value so that production rules in shaders can be generated, etc.
105
+ if (type == "point") {
106
+ setter(createSinglePointSelection(null));
107
+ }
108
+ }
109
+
110
+ this.#paramConfigs.set(name, param);
77
111
 
78
112
  return setter;
79
113
  }
@@ -87,6 +121,8 @@ export default class ParamMediator {
87
121
  * @template T
88
122
  */
89
123
  allocateSetter(paramName, initialValue, passive = false) {
124
+ validateParameterName(paramName);
125
+
90
126
  if (this.#allocatedSetters.has(paramName)) {
91
127
  throw new Error(
92
128
  "Setter already allocated for parameter: " + paramName
@@ -148,7 +184,7 @@ export default class ParamMediator {
148
184
  * Returns configs for all parameters that have been registered using `registerParam`.
149
185
  */
150
186
  get paramConfigs() {
151
- return /** @type {ReadonlyMap<string, VariableParameter>} */ (
187
+ return /** @type {ReadonlyMap<string, Parameter>} */ (
152
188
  this.#paramConfigs
153
189
  );
154
190
  }
@@ -288,6 +324,22 @@ export function withoutExprRef(x) {
288
324
  return /** @type {T} */ (x);
289
325
  }
290
326
 
327
+ /**
328
+ * @param {Parameter} param
329
+ * @returns {param is import("../spec/parameter.js").VariableParameter}
330
+ */
331
+ export function isVariableParameter(param) {
332
+ return ("expr" in param || "bind" in param) && !("select" in param);
333
+ }
334
+
335
+ /**
336
+ * @param {Parameter} param
337
+ * @returns {param is import("../spec/parameter.js").SelectionParameter}
338
+ */
339
+ export function isSelectionParameter(param) {
340
+ return !("expr" in param || "bind" in param) && "select" in param;
341
+ }
342
+
291
343
  /**
292
344
  * Takes a record of properties that may have ExprRefs as values. Converts the
293
345
  * ExprRefs to getters and setups a listener that is called when any of the
@@ -336,3 +388,39 @@ export function activateExprRefProps(paramMediator, props, listener) {
336
388
 
337
389
  return /** @type {T} */ (activatedProps);
338
390
  }
391
+
392
+ /**
393
+ * Validates a parameter name. If the name is invalid, throws an error.
394
+ * Otherwise, returns the name.
395
+ *
396
+ * @param {string} name
397
+ * @returns {string} the name
398
+ */
399
+ export function validateParameterName(name) {
400
+ if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) {
401
+ throw new Error(
402
+ `Invalid parameter name: ${name}. Must be a valid JavaScript identifier.`
403
+ );
404
+ }
405
+
406
+ return name;
407
+ }
408
+
409
+ /**
410
+ * Creates a function that always returns the same value.
411
+ * Provides functionality for creating a constant expression reference.
412
+ * They just do nothing.
413
+ *
414
+ * @param {any} value
415
+ * @returns {ExprRefFunction}
416
+ */
417
+ export function makeConstantExprRef(value) {
418
+ return Object.assign(() => value, {
419
+ addListener: () => undefined,
420
+ invalidate: () => undefined,
421
+ identifier: () => "constant",
422
+ fields: [],
423
+ globals: [],
424
+ code: JSON.stringify(value),
425
+ });
426
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=paramMediator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paramMediator.test.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.test.js"],"names":[],"mappings":""}
@@ -173,6 +173,22 @@ describe("Nested ParamMediators", () => {
173
173
  childSetter(20);
174
174
  expect(result).toBe(30);
175
175
  });
176
+
177
+ test("Pushing to outer parameter", () => {
178
+ const parent = new ParamMediator();
179
+ const child = new ParamMediator(() => parent);
180
+
181
+ parent.registerParam({ name: "foo", value: 1 });
182
+ const childSetter = child.registerParam({ name: "foo", push: "outer" });
183
+
184
+ expect(parent.findValue("foo")).toBe(1);
185
+ expect(child.findValue("foo")).toBe(1);
186
+
187
+ childSetter(2);
188
+
189
+ expect(parent.findValue("foo")).toBe(2);
190
+ expect(child.findValue("foo")).toBe(2);
191
+ });
176
192
  });
177
193
 
178
194
  test("activateExprRefProps", async () => {
@@ -181,7 +197,7 @@ test("activateExprRefProps", async () => {
181
197
  const fooSetter = pm.registerParam({ name: "foo", value: 7 });
182
198
  const barSetter = pm.registerParam({ name: "bar", value: 11 });
183
199
 
184
- /** @type {Record<string, any | import("../spec/parameter.js").ExprRef} */
200
+ /** @type {Record<string, any | import("../spec/parameter.js").ExprRef>} */
185
201
  const props = {
186
202
  a: 42,
187
203
  b: { expr: "foo" },