@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identifier.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/identifier.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export type PileupParams = import("../../spec/transform.js").PileupParams;
2
+ //# sourceMappingURL=pileup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pileup.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/pileup.test.js"],"names":[],"mappings":"2BAOa,OAAO,yBAAyB,EAAE,YAAY"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=project.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/project.test.js"],"names":[],"mappings":""}
@@ -11,7 +11,7 @@ test("Project", () => {
11
11
  },
12
12
  ];
13
13
 
14
- /** @param {import("./project.js").ProjectParams} params */
14
+ /** @param {import("../../spec/transform.js").ProjectParams} params */
15
15
  const p = (params) => processData(new ProjectTransform(params), data);
16
16
 
17
17
  expect(p({ type: "project", fields: ["bar"] })).toEqual([{ bar: "BAR" }]);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=regexExtract.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regexExtract.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/regexExtract.test.js"],"names":[],"mappings":""}
@@ -4,7 +4,7 @@ import { processData } from "../flowTestUtils.js";
4
4
  import RegexExtractTransform from "./regexExtract.js";
5
5
 
6
6
  /**
7
- * @param {import("./regexExtract.js").RegexExtractParams} params
7
+ * @param {import("../../spec/transform.js").RegexExtractParams} params
8
8
  * @param {any[]} data
9
9
  */
10
10
  function transform(params, data) {
@@ -12,9 +12,12 @@ function transform(params, data) {
12
12
  }
13
13
 
14
14
  describe("RegexExtractTransform", () => {
15
+ /**
16
+ * @typedef {import("../../spec/transform.js").RegexExtractParams} RegexExtractParams
17
+ */
15
18
  const rows = [{ a: "12-34" }, { a: "23-45" }];
16
19
 
17
- /** @type {import("./regexExtract.js").RegexExtractParams} */
20
+ /** @type {RegexExtractParams} */
18
21
  const params = {
19
22
  type: "regexExtract",
20
23
  regex: "^(\\d+)-(\\d+)$",
@@ -30,7 +33,7 @@ describe("RegexExtractTransform", () => {
30
33
  });
31
34
 
32
35
  test("Invalid config", () => {
33
- /** @type {import("./regexExtract.js").RegexExtractParams} */
36
+ /** @type {RegexExtractParams} */
34
37
  const config2 = {
35
38
  type: "regexExtract",
36
39
  regex: "^(\\d+)-(\\d+)$",
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=regexFold.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regexFold.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/regexFold.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sample.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/sample.test.js"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=stack.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.test.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/stack.test.js"],"names":[],"mappings":""}
@@ -8,8 +8,8 @@ const sampleData = [
8
8
  { group: "b", choice: "y", value: 3 },
9
9
  ];
10
10
 
11
- /** @type {import("./stack.js").StackParams} */
12
- const baseConf = {
11
+ /** @type {import("../../spec/transform.js").StackParams} */
12
+ const baseParams = {
13
13
  type: "stack",
14
14
  field: "value",
15
15
  groupby: ["group"],
@@ -23,7 +23,7 @@ const baseConf = {
23
23
 
24
24
  /**
25
25
  *
26
- * @param {import("./stack.js").StackParams} params
26
+ * @param {import("../../spec/transform.js").StackParams} params
27
27
  * @param {any[]} data
28
28
  */
29
29
  function transform(params, data) {
@@ -32,7 +32,7 @@ function transform(params, data) {
32
32
 
33
33
  describe("Stack transform", () => {
34
34
  test("No field", () => {
35
- const conf = Object.assign({}, baseConf, {
35
+ const conf = Object.assign({}, baseParams, {
36
36
  field: undefined,
37
37
  });
38
38
 
@@ -44,7 +44,7 @@ describe("Stack transform", () => {
44
44
  });
45
45
 
46
46
  test("Zero offset", () => {
47
- expect(transform(baseConf, sampleData)).toEqual([
47
+ expect(transform(baseParams, sampleData)).toEqual([
48
48
  { group: "a", choice: "q", value: 1, z0: 0, z1: 1 },
49
49
  { group: "b", choice: "x", value: 1, z0: 0, z1: 1 },
50
50
  { group: "b", choice: "y", value: 3, z0: 1, z1: 4 },
@@ -52,7 +52,7 @@ describe("Stack transform", () => {
52
52
  });
53
53
 
54
54
  test("Normalize offset", () => {
55
- const conf = Object.assign({}, baseConf, {
55
+ const conf = Object.assign({}, baseParams, {
56
56
  offset: "normalize",
57
57
  });
58
58
 
@@ -64,7 +64,7 @@ describe("Stack transform", () => {
64
64
  });
65
65
 
66
66
  test("Center offset", () => {
67
- const conf = Object.assign({}, baseConf, {
67
+ const conf = Object.assign({}, baseParams, {
68
68
  offset: "center",
69
69
  });
70
70
 
@@ -76,7 +76,7 @@ describe("Stack transform", () => {
76
76
  });
77
77
 
78
78
  test("Descending sort", () => {
79
- const conf = Object.assign({}, baseConf, {
79
+ const conf = Object.assign({}, baseParams, {
80
80
  sort: {
81
81
  field: "value",
82
82
  order: "descending",
@@ -1,15 +1,18 @@
1
- export default class AccessorFactory {
2
- /** @type {(function(import("../spec/channel.js").ChannelDef):Accessor)[]} */
3
- accessorCreators: ((arg0: import("../spec/channel.js").ChannelDef) => import("../types/encoder.js").Accessor)[];
4
- /**
5
- *
6
- * @param {function(import("../spec/channel.js").ChannelDef):Accessor} creator
7
- */
8
- register(creator: (arg0: import("../spec/channel.js").ChannelDef) => import("../types/encoder.js").Accessor): void;
9
- /**
10
- *
11
- * @param {import("../spec/channel.js").ChannelDef} encoding
12
- */
13
- createAccessor(encoding: import("../spec/channel.js").ChannelDef): import("../types/encoder.js").Accessor;
14
- }
1
+ /**
2
+ * @param {import("../spec/channel.js").Channel} channel
3
+ * @param {import("../spec/channel.js").ChannelDef | import("../spec/channel.js").Conditional<import("../spec/channel.js").ChannelDef>} channelDef
4
+ * @param {import("../view/paramMediator.js").default} paramMediator
5
+ * @returns {import("../types/encoder.js").Accessor}
6
+ */
7
+ export function createAccessor(channel: import("../spec/channel.js").Channel, channelDef: import("../spec/channel.js").ChannelDef | import("../spec/channel.js").Conditional<import("../spec/channel.js").ChannelDef>, paramMediator: import("../view/paramMediator.js").default): import("../types/encoder.js").Accessor;
8
+ /**
9
+ * Returns an array of acessors and their predicates. A returned array with
10
+ * a single element indicates that no conditions are present.
11
+ * The default accessor is always the last element in the array.
12
+ *
13
+ * @param {import("../spec/channel.js").Channel} channel
14
+ * @param {import("../spec/channel.js").ChannelDef} channelDef
15
+ * @param {import("../view/paramMediator.js").default} paramMediator
16
+ */
17
+ export function createConditionalAccessors(channel: import("../spec/channel.js").Channel, channelDef: import("../spec/channel.js").ChannelDef, paramMediator: import("../view/paramMediator.js").default): import("../types/encoder.js").Accessor<import("../spec/channel.js").Scalar>[];
15
18
  //# sourceMappingURL=accessor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accessor.d.ts","sourceRoot":"","sources":["../../../src/encoder/accessor.js"],"names":[],"mappings":"AAMA;IAKQ,6EAA6E;IAC7E,0BADqB,OAAO,oBAAoB,EAAE,UAAU,+CAClC;IAkC9B;;;OAGG;IACH,yBAFoB,OAAO,oBAAoB,EAAE,UAAU,mDAI1D;IAED;;;OAGG;IACH,yBAFW,OAAO,oBAAoB,EAAE,UAAU,0CASjD;CACJ"}
1
+ {"version":3,"file":"accessor.d.ts","sourceRoot":"","sources":["../../../src/encoder/accessor.js"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,wCALW,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,oBAAoB,EAAE,UAAU,GAAG,OAAO,oBAAoB,EAAE,WAAW,CAAC,OAAO,oBAAoB,EAAE,UAAU,CAAC,iBAC3H,OAAO,0BAA0B,EAAE,OAAO,GACxC,OAAO,qBAAqB,EAAE,QAAQ,CAyFlD;AAED;;;;;;;;GAQG;AACH,oDAJW,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,oBAAoB,EAAE,UAAU,iBACvC,OAAO,0BAA0B,EAAE,OAAO,iFAgCpD"}
@@ -1,78 +1,149 @@
1
- import createFunction from "../utils/expression.js";
2
-
3
- import { accessorFields, constant } from "vega-util";
4
- import { isDatumDef, isExprDef, isFieldDef } from "./encoder.js";
1
+ import {
2
+ isChannelDefWithScale,
3
+ isChannelWithScale,
4
+ isDatumDef,
5
+ isExprDef,
6
+ isFieldDef,
7
+ isFieldOrDatumDefWithCondition,
8
+ isValueDef,
9
+ isValueDefWithCondition,
10
+ } from "./encoder.js";
5
11
  import { field } from "../utils/field.js";
12
+ import { isExprRef, makeConstantExprRef } from "../view/paramMediator.js";
13
+ import { makeSelectionTestExpression } from "../selection/selection.js";
6
14
 
7
- export default class AccessorFactory {
15
+ /**
16
+ * @param {import("../spec/channel.js").Channel} channel
17
+ * @param {import("../spec/channel.js").ChannelDef | import("../spec/channel.js").Conditional<import("../spec/channel.js").ChannelDef>} channelDef
18
+ * @param {import("../view/paramMediator.js").default} paramMediator
19
+ * @returns {import("../types/encoder.js").Accessor}
20
+ */
21
+ export function createAccessor(channel, channelDef, paramMediator) {
8
22
  /**
9
- * @typedef {import("../types/encoder.js").Accessor} Accessor
23
+ * @typedef {import("../data/flowNode.js").Datum} Datum
24
+ * @typedef {import("../spec/channel.js").Scalar} Scalar
10
25
  */
11
- constructor() {
12
- /** @type {(function(import("../spec/channel.js").ChannelDef):Accessor)[]} */
13
- this.accessorCreators = [];
14
-
15
- this.register((channelDef) => {
16
- if (isFieldDef(channelDef)) {
17
- try {
18
- const accessor = /** @type {Accessor} */ (
19
- field(channelDef.field)
20
- );
21
- accessor.constant = false;
22
- accessor.fields = accessorFields(accessor);
23
- return accessor;
24
- } catch (e) {
25
- throw new Error(`Invalid field definition: ${e.message}`);
26
- }
27
- }
28
- });
29
-
30
- this.register((channelDef) =>
31
- isExprDef(channelDef)
32
- ? createExpressionAccessor(channelDef.expr)
33
- : undefined
34
- );
35
26
 
36
- this.register((channelDef) => {
37
- if (isDatumDef(channelDef)) {
38
- const c = /** @type {any} */ (constant(channelDef.datum));
39
- const accessor = /** @type {Accessor} */ (c);
40
- accessor.constant = true; // Can be optimized downstream
41
- accessor.fields = [];
42
- return accessor;
43
- }
44
- });
27
+ if (!channel) {
28
+ // TODO: Don't call with an undefined channel
29
+ return;
45
30
  }
46
31
 
47
32
  /**
48
- *
49
- * @param {function(import("../spec/channel.js").ChannelDef):Accessor} creator
33
+ * @param {(datum?: Datum) => Scalar} fn
34
+ * @returns {import("../types/encoder.js").Accessor<Scalar>}
50
35
  */
51
- register(creator) {
52
- this.accessorCreators.push(creator);
36
+ function asAccessor(fn) {
37
+ const a = /** @type {import("../types/encoder.js").Accessor} */ (fn);
38
+ a.fields ??= [];
39
+ a.constant = a.fields.length === 0;
40
+ a.channelDef = channelDef;
41
+ a.channel = channel;
42
+
43
+ a.scaleChannel =
44
+ ((isChannelDefWithScale(channelDef) &&
45
+ channelDef.resolutionChannel) ??
46
+ (isChannelWithScale(channel) && channel)) ||
47
+ undefined;
48
+
49
+ if ("param" in channelDef) {
50
+ a.predicate = paramMediator.createExpression(
51
+ makeSelectionTestExpression(channelDef)
52
+ );
53
+ a.predicate.param = channelDef.param;
54
+ a.predicate.empty = channelDef.empty ?? true;
55
+ } else {
56
+ a.predicate = makeConstantExprRef(true); // Always true (default accessor)
57
+ a.predicate.empty = false;
58
+ }
59
+
60
+ a.asNumberAccessor = () =>
61
+ /** @type {import("../types/encoder.js").Accessor<number>} */ (a);
62
+
63
+ return a;
53
64
  }
54
65
 
55
66
  /**
56
67
  *
57
- * @param {import("../spec/channel.js").ChannelDef} encoding
68
+ * @param {Scalar | import("../spec/parameter.js").ExprRef} potentialExprRef
58
69
  */
59
- createAccessor(encoding) {
60
- for (const creator of this.accessorCreators) {
61
- const accessor = creator(encoding);
62
- if (accessor) {
63
- return accessor;
70
+ function potentialExprRefToAccessor(potentialExprRef) {
71
+ if (isExprRef(potentialExprRef)) {
72
+ const a = asAccessor(
73
+ paramMediator.createExpression(potentialExprRef.expr)
74
+ );
75
+ if (a.fields.length > 0) {
76
+ throw new Error(
77
+ "Expression in DatumDef/ValueDef cannot access data fields: " +
78
+ potentialExprRef.expr
79
+ );
64
80
  }
81
+ return a;
82
+ } else {
83
+ const v = potentialExprRef;
84
+ return asAccessor(() => v);
65
85
  }
66
86
  }
87
+
88
+ if (isFieldDef(channelDef)) {
89
+ try {
90
+ return asAccessor(field(channelDef.field));
91
+ } catch (e) {
92
+ throw new Error(`Invalid field definition: ${e.message}`);
93
+ }
94
+ } else if (isExprDef(channelDef)) {
95
+ // TODO: If parameters change, the data should be re-evaluated
96
+ return asAccessor(paramMediator.createExpression(channelDef.expr));
97
+ } else if (isDatumDef(channelDef)) {
98
+ return potentialExprRefToAccessor(channelDef.datum);
99
+ } else if (isValueDef(channelDef)) {
100
+ return potentialExprRefToAccessor(channelDef.value);
101
+ } else {
102
+ throw new Error(
103
+ `Invalid channel definition: ${JSON.stringify(
104
+ channelDef
105
+ )}. Cannot create an accessor for channel ${channel}!`
106
+ );
107
+ }
67
108
  }
68
109
 
69
110
  /**
70
- * @param {string} expr
111
+ * Returns an array of acessors and their predicates. A returned array with
112
+ * a single element indicates that no conditions are present.
113
+ * The default accessor is always the last element in the array.
114
+ *
115
+ * @param {import("../spec/channel.js").Channel} channel
116
+ * @param {import("../spec/channel.js").ChannelDef} channelDef
117
+ * @param {import("../view/paramMediator.js").default} paramMediator
71
118
  */
72
- function createExpressionAccessor(expr) {
73
- const fn = createFunction(expr);
74
- const accessor = /** @type {Accessor} */ (/** @type {any} */ (fn));
75
- // Not bulletproof and probably erroneous with global params
76
- accessor.constant = accessor.fields.length == 0;
77
- return accessor;
119
+ export function createConditionalAccessors(channel, channelDef, paramMediator) {
120
+ /** @type {import("../types/encoder.js").Accessor[]} */
121
+ const conditionalAccessors = [];
122
+
123
+ // TODO: Support an array of conditions
124
+ if (
125
+ isFieldOrDatumDefWithCondition(channelDef) ||
126
+ isValueDefWithCondition(channelDef)
127
+ ) {
128
+ const conditions = Array.isArray(channelDef.condition)
129
+ ? channelDef.condition
130
+ : [channelDef.condition];
131
+
132
+ for (const condition of conditions) {
133
+ conditionalAccessors.push(
134
+ createAccessor(channel, condition, paramMediator)
135
+ );
136
+ }
137
+ }
138
+
139
+ conditionalAccessors.push(
140
+ createAccessor(channel, channelDef, paramMediator)
141
+ );
142
+
143
+ if (conditionalAccessors.filter((a) => !a.constant).length > 1) {
144
+ throw new Error(
145
+ "Only one accessor can be non-constant. Channel: " + channel
146
+ );
147
+ }
148
+ return conditionalAccessors;
78
149
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=accessor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessor.test.d.ts","sourceRoot":"","sources":["../../../src/encoder/accessor.test.js"],"names":[],"mappings":""}
@@ -1,7 +1,8 @@
1
- import { expect, test } from "vitest";
2
- import AccessorFactory from "./accessor.js";
3
-
4
- const af = new AccessorFactory();
1
+ import { describe, expect, test } from "vitest";
2
+ import ParamMediator from "../view/paramMediator.js";
3
+ import { createAccessor, createConditionalAccessors } from "./accessor.js";
4
+ import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
5
+ import { createSinglePointSelection } from "../selection/selection.js";
5
6
 
6
7
  const datum = {
7
8
  a: 1,
@@ -9,39 +10,152 @@ const datum = {
9
10
  "x.c": 3,
10
11
  };
11
12
 
12
- test("Creates a field accessor", () => {
13
- const a = af.createAccessor({ field: "a" });
14
- expect(a(datum)).toEqual(1);
15
- expect(a.constant).toBeFalsy();
16
- expect(a.fields).toEqual(["a"]);
17
- });
13
+ describe("Accessors for different encoding types", () => {
14
+ test("Creates a field accessor", () => {
15
+ const a = createAccessor("x", { field: "a" }, new ParamMediator());
16
+ expect(a(datum)).toEqual(1);
17
+ expect(a.constant).toBeFalsy();
18
+ expect(a.fields).toEqual(["a"]);
19
+ });
18
20
 
19
- test("Creates an expression accessor", () => {
20
- const a = af.createAccessor({ expr: `datum.b + datum['x\.c']` });
21
- expect(a(datum)).toEqual(5);
22
- expect(a.constant).toBeFalsy();
23
- expect(a.fields.sort()).toEqual(["b", "x.c"].sort());
24
- });
21
+ test("Creates an expression accessor", () => {
22
+ const a = createAccessor(
23
+ "x",
24
+ { expr: `datum.b + datum['x\.c']` },
25
+ new ParamMediator()
26
+ );
27
+ expect(a(datum)).toEqual(5);
28
+ expect(a.constant).toBeFalsy();
29
+ expect(a.fields.sort()).toEqual(["b", "x.c"].sort());
30
+ });
31
+
32
+ test("Creates a constant accessor", () => {
33
+ const a = createAccessor("x", { datum: 0 }, new ParamMediator());
34
+ expect(a(datum)).toEqual(0);
35
+ expect(a.constant).toBeTruthy();
36
+ expect(a.fields).toEqual([]);
37
+ });
25
38
 
26
- test("Creates a constant accessor", () => {
27
- const a = af.createAccessor({ datum: 0 });
28
- expect(a(datum)).toEqual(0);
29
- expect(a.constant).toBeTruthy();
30
- expect(a.fields).toEqual([]);
39
+ test("Creates a value accessor", () => {
40
+ const a = createAccessor("x", { value: 123 }, new ParamMediator());
41
+ expect(a(datum)).toEqual(123);
42
+ expect(a.constant).toBeTruthy();
43
+ expect(a.fields).toEqual([]);
44
+ });
31
45
  });
32
46
 
33
- test("Returns undefined on incomplete encoding spec", () => {
34
- expect(af.createAccessor({})).toBeUndefined();
47
+ test("Throws on incomplete encoding spec", () => {
48
+ expect(() => createAccessor("x", {}, new ParamMediator())).toThrow();
35
49
  });
36
50
 
37
- test("Registers and creates a custom accessor", () => {
38
- const af = new AccessorFactory();
39
- af.register((encoding) => {
40
- if (encoding.iddqd && encoding.idkfa) {
41
- return (datum) =>
42
- `${datum[encoding.iddqd]}-${datum[encoding.idkfa]}`;
43
- }
51
+ describe("createConditionalAccessors", () => {
52
+ const data = [
53
+ { a: 1, b: 2, [UNIQUE_ID_KEY]: 0 },
54
+ { a: 3, b: 4, [UNIQUE_ID_KEY]: 1 },
55
+ ];
56
+
57
+ const paramMediator = new ParamMediator();
58
+ paramMediator.allocateSetter("p", createSinglePointSelection(data[0]));
59
+
60
+ const a = createConditionalAccessors(
61
+ "x",
62
+ {
63
+ field: "a",
64
+ type: "quantitative",
65
+ condition: { param: "p", value: 123 },
66
+ },
67
+ paramMediator
68
+ );
69
+
70
+ const b = createConditionalAccessors(
71
+ "x",
72
+ {
73
+ field: "a",
74
+ type: "quantitative",
75
+ condition: [
76
+ { param: "p", value: 123 },
77
+ { param: "p", value: 234 },
78
+ ],
79
+ },
80
+ paramMediator
81
+ );
82
+
83
+ const c = createConditionalAccessors(
84
+ "x",
85
+ {
86
+ value: 123,
87
+ condition: {
88
+ param: "p",
89
+ field: "a",
90
+ type: "quantitative",
91
+ },
92
+ },
93
+ paramMediator
94
+ );
95
+
96
+ // TODO: Add more combinations of datum, field, expr, etc
97
+
98
+ test("Creates a correct number of accessors", () => {
99
+ expect(a.length).toBe(2);
100
+ expect(b.length).toBe(3);
101
+ expect(c.length).toBe(2);
102
+ });
103
+
104
+ // Conditional accessor
105
+ test("Conditional accessor accesses the correct field", () => {
106
+ expect(a[0](data[0])).toEqual(123);
107
+ expect(a[0].predicate.param).toEqual("p");
108
+ });
109
+
110
+ test("Conditional predicate is true only for the selected datum", () => {
111
+ expect(a[0].predicate(data[0])).toBeTruthy();
112
+ expect(a[0].predicate(data[1])).toBeFalsy();
44
113
  });
45
114
 
46
- expect(af.createAccessor({ iddqd: "a", idkfa: "b" })(datum)).toEqual("1-2");
115
+ // Default accessor
116
+ test("Default accessor accesses the correct field", () => {
117
+ expect(a[1](data[0])).toEqual(1);
118
+ expect(a[1].predicate.param).toBeFalsy();
119
+ });
120
+
121
+ test("Default predicate is true for all data", () => {
122
+ expect(a[1].predicate(data[0])).toBeTruthy();
123
+ expect(a[1].predicate(data[1])).toBeTruthy();
124
+ });
125
+
126
+ test("Throws if multiple non-constant accessors are used", () => {
127
+ expect(() =>
128
+ createConditionalAccessors(
129
+ "x",
130
+ {
131
+ field: "a",
132
+ type: "quantitative",
133
+ condition: {
134
+ param: "p",
135
+ // @ts-expect-error
136
+ field: "b",
137
+ type: "quantitative",
138
+ },
139
+ },
140
+ paramMediator
141
+ )
142
+ ).toThrow();
143
+
144
+ expect(() =>
145
+ createConditionalAccessors(
146
+ "x",
147
+ {
148
+ field: "a",
149
+ type: "quantitative",
150
+ condition: {
151
+ param: "p",
152
+ // @ts-expect-error
153
+ expr: "datum.b",
154
+ type: "quantitative",
155
+ },
156
+ },
157
+ paramMediator
158
+ )
159
+ ).toThrow();
160
+ });
47
161
  });