ggaction 0.0.13 → 0.0.16

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 (359) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +41 -12
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-packet.schema.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +39 -7
  9. package/src/BasicChartProgram.js +3 -1
  10. package/src/ChartProgram.js +2 -0
  11. package/src/accessibility.js +157 -0
  12. package/src/actions/basic.js +2 -2
  13. package/src/actions/boxPlots/components.js +20 -12
  14. package/src/actions/boxPlots/create.js +4 -5
  15. package/src/actions/boxPlots/edit.js +34 -9
  16. package/src/actions/boxPlots/materialize.js +12 -4
  17. package/src/actions/boxPlots/options.js +48 -16
  18. package/src/actions/canvas/actions.js +3 -3
  19. package/src/actions/canvas/fitting.js +1 -1
  20. package/src/actions/categoryOrder/index.js +21 -12
  21. package/src/actions/charts/area.js +6 -2
  22. package/src/actions/charts/bar.js +3 -2
  23. package/src/actions/charts/beeswarm.js +1 -1
  24. package/src/actions/charts/density.js +7 -3
  25. package/src/actions/charts/ecdf.js +6 -3
  26. package/src/actions/charts/endpoints.js +29 -7
  27. package/src/actions/charts/heatmap.js +3 -2
  28. package/src/actions/charts/histogram.js +5 -4
  29. package/src/actions/charts/horizon.js +4 -2
  30. package/src/actions/charts/interval-regression.js +7 -4
  31. package/src/actions/charts/line.js +4 -2
  32. package/src/actions/charts/parallel.js +9 -3
  33. package/src/actions/charts/pie.js +11 -3
  34. package/src/actions/charts/polar.js +17 -6
  35. package/src/actions/charts/radar.js +9 -3
  36. package/src/actions/charts/radial.js +12 -4
  37. package/src/actions/charts/raincloud.js +2 -2
  38. package/src/actions/charts/rug-strip.js +8 -4
  39. package/src/actions/charts/scatter.js +4 -2
  40. package/src/actions/composition/actions.js +29 -24
  41. package/src/actions/coordinates/actions.js +2 -2
  42. package/src/actions/coordinates/edit.js +76 -0
  43. package/src/actions/data/basicBin2d.js +4 -5
  44. package/src/actions/data/bin.js +3 -3
  45. package/src/actions/data/bin2d.js +63 -193
  46. package/src/actions/data/bin2dMaterialize.js +4 -5
  47. package/src/actions/data/box.js +4 -4
  48. package/src/actions/data/complete.js +26 -0
  49. package/src/actions/data/computed.js +4 -4
  50. package/src/actions/data/create.js +7 -14
  51. package/src/actions/data/density.js +15 -23
  52. package/src/actions/data/derived.js +57 -31
  53. package/src/actions/data/ecdf.js +2 -2
  54. package/src/actions/data/edit.js +551 -0
  55. package/src/actions/data/filter.js +28 -22
  56. package/src/actions/data/fold.js +2 -2
  57. package/src/actions/data/gradientProfile.js +2 -2
  58. package/src/actions/data/horizon.js +2 -2
  59. package/src/actions/data/impute.js +26 -0
  60. package/src/actions/data/index.js +62 -47
  61. package/src/actions/data/interval.js +2 -2
  62. package/src/actions/data/intervalEdit.js +26 -18
  63. package/src/actions/data/normalize.js +27 -0
  64. package/src/actions/data/regression.js +21 -27
  65. package/src/actions/data/revise.js +48 -0
  66. package/src/actions/data/revisionBindings.js +125 -0
  67. package/src/actions/data/shared.js +20 -4
  68. package/src/actions/data/stack.js +2 -2
  69. package/src/actions/data/summary.js +3 -3
  70. package/src/actions/data/timeUnit.js +6 -3
  71. package/src/actions/data/window.js +3 -3
  72. package/src/actions/encodings/angle.js +1 -1
  73. package/src/actions/encodings/appearance.js +4 -4
  74. package/src/actions/encodings/barWidth.js +1 -1
  75. package/src/actions/encodings/channels.js +415 -0
  76. package/src/actions/encodings/color/index.js +3 -2
  77. package/src/actions/encodings/density.js +7 -4
  78. package/src/actions/encodings/histogram.js +4 -3
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/index.js +4 -0
  81. package/src/actions/encodings/offset.js +22 -15
  82. package/src/actions/encodings/parallel.js +4 -5
  83. package/src/actions/encodings/pathOrder.js +6 -11
  84. package/src/actions/encodings/position/apply.js +53 -7
  85. package/src/actions/encodings/position/index.js +14 -6
  86. package/src/actions/encodings/position/policies/bar.js +9 -0
  87. package/src/actions/encodings/position/resolve.js +24 -7
  88. package/src/actions/encodings/ranged.js +5 -5
  89. package/src/actions/encodings/remove.js +13 -9
  90. package/src/actions/encodings/ruleAppearance.js +2 -24
  91. package/src/actions/encodings/seriesLayout.js +2 -1
  92. package/src/actions/encodings/shared.js +82 -14
  93. package/src/actions/encodings/stroke.js +226 -0
  94. package/src/actions/encodings/strokeDash.js +2 -2
  95. package/src/actions/encodings/text.js +1 -1
  96. package/src/actions/errorBands/create.js +34 -20
  97. package/src/actions/errorBands/edit.js +34 -137
  98. package/src/actions/errorBars/create.js +43 -20
  99. package/src/actions/errorBars/edit.js +29 -125
  100. package/src/actions/facets/actions.js +267 -73
  101. package/src/actions/facets/derive.js +99 -28
  102. package/src/actions/facets/guides.js +4 -5
  103. package/src/actions/facets/replay.js +4 -5
  104. package/src/actions/gradientPlots/components.js +15 -8
  105. package/src/actions/gradientPlots/create.js +4 -5
  106. package/src/actions/gradientPlots/edit.js +18 -9
  107. package/src/actions/gradientPlots/materialize.js +5 -3
  108. package/src/actions/gradientPlots/options.js +10 -2
  109. package/src/actions/gradientPlots/rebind.js +4 -5
  110. package/src/actions/guides/applicability.js +8 -2
  111. package/src/actions/guides/axes/axes.js +23 -4
  112. package/src/actions/guides/axes/axis.js +2 -2
  113. package/src/actions/guides/axes/edit.js +2 -2
  114. package/src/actions/guides/axes/labels.js +67 -21
  115. package/src/actions/guides/axes/lines.js +15 -9
  116. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  117. package/src/actions/guides/axes/parallel/resolve.js +6 -2
  118. package/src/actions/guides/axes/parallel.js +5 -5
  119. package/src/actions/guides/axes/remove.js +4 -4
  120. package/src/actions/guides/axes/tickGroups.js +6 -5
  121. package/src/actions/guides/axes/ticks.js +19 -6
  122. package/src/actions/guides/axes/titles.js +21 -13
  123. package/src/actions/guides/grids/grid.js +18 -29
  124. package/src/actions/guides/grids/resolve.js +7 -2
  125. package/src/actions/guides/guides.js +20 -4
  126. package/src/actions/guides/legends/blocks.js +426 -0
  127. package/src/actions/guides/legends/categorical/actions.js +138 -52
  128. package/src/actions/guides/legends/categorical/components.js +55 -45
  129. package/src/actions/guides/legends/categorical/index.js +37 -33
  130. package/src/actions/guides/legends/categorical/layout.js +98 -16
  131. package/src/actions/guides/legends/categorical/options.js +2 -2
  132. package/src/actions/guides/legends/categorical/recipes.js +111 -20
  133. package/src/actions/guides/legends/categorical/resolve.js +12 -8
  134. package/src/actions/guides/legends/categorical/symbols.js +104 -52
  135. package/src/actions/guides/legends/continuous/common.js +76 -20
  136. package/src/actions/guides/legends/continuous/gradient.js +95 -158
  137. package/src/actions/guides/legends/continuous/index.js +2 -0
  138. package/src/actions/guides/legends/continuous/interval.js +21 -16
  139. package/src/actions/guides/legends/continuous/opacity.js +37 -83
  140. package/src/actions/guides/legends/continuous/stroke.js +225 -0
  141. package/src/actions/guides/legends/creation.js +14 -1
  142. package/src/actions/guides/legends/edit.js +159 -60
  143. package/src/actions/guides/legends/focused.js +5 -5
  144. package/src/actions/guides/legends/index.js +2 -0
  145. package/src/actions/guides/legends/lane.js +59 -24
  146. package/src/actions/guides/legends/lifecycle.js +19 -8
  147. package/src/actions/guides/legends/remove.js +17 -8
  148. package/src/actions/guides/legends/sampling.js +140 -0
  149. package/src/actions/guides/legends/size.js +100 -108
  150. package/src/actions/guides/legends/strokeWidth.js +38 -92
  151. package/src/actions/guides/legends/target.js +112 -1
  152. package/src/actions/guides/legends/transition.js +165 -16
  153. package/src/actions/guides/polar/axes/facade.js +8 -8
  154. package/src/actions/guides/polar/axes/labels.js +29 -10
  155. package/src/actions/guides/polar/axes/lines.js +19 -19
  156. package/src/actions/guides/polar/axes/shared.js +16 -0
  157. package/src/actions/guides/polar/axes/ticks.js +10 -16
  158. package/src/actions/guides/polar/axes/titles.js +6 -6
  159. package/src/actions/guides/polar/grids.js +12 -14
  160. package/src/actions/guides/polar/resolve.js +12 -8
  161. package/src/actions/index.js +16 -3
  162. package/src/actions/intervals/revision.js +126 -0
  163. package/src/actions/marks/arc/actions.js +80 -22
  164. package/src/actions/marks/area/actions.js +38 -13
  165. package/src/actions/marks/area/materialize.js +17 -1
  166. package/src/actions/marks/bar/create.js +12 -3
  167. package/src/actions/marks/bar/edit.js +21 -4
  168. package/src/actions/marks/bar/materialize.js +34 -40
  169. package/src/actions/marks/index.js +10 -1
  170. package/src/actions/marks/line/actions.js +40 -17
  171. package/src/actions/marks/line/materialize.js +29 -10
  172. package/src/actions/marks/point/create.js +9 -3
  173. package/src/actions/marks/point/edit.js +19 -7
  174. package/src/actions/marks/point/jitter.js +6 -8
  175. package/src/actions/marks/point/materialize.js +48 -22
  176. package/src/actions/marks/point/packing.js +6 -8
  177. package/src/actions/marks/rect/actions.js +36 -15
  178. package/src/actions/marks/references.js +602 -33
  179. package/src/actions/marks/remove.js +67 -41
  180. package/src/actions/marks/rule/actions.js +51 -14
  181. package/src/actions/marks/shared.js +1 -1
  182. package/src/actions/marks/text/actions.js +79 -14
  183. package/src/actions/marks/text/index.js +4 -0
  184. package/src/actions/marks/text/layout.js +157 -17
  185. package/src/actions/marks/text/removal.js +173 -0
  186. package/src/actions/marks/text/selection.js +72 -0
  187. package/src/actions/marks/tick/actions.js +25 -8
  188. package/src/actions/primitives/createGraphics.js +5 -4
  189. package/src/actions/primitives/editGraphics.js +31 -4
  190. package/src/actions/primitives/graphicProperties.js +6 -0
  191. package/src/actions/primitives/semantic.js +11 -3
  192. package/src/actions/primitives/semanticAction.js +90 -14
  193. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  194. package/src/actions/primitives/semanticValidation/guide.js +1 -1
  195. package/src/actions/primitives/semanticValidation/index.js +9 -1
  196. package/src/actions/primitives/semanticValidation/layer.js +5 -0
  197. package/src/actions/primitives/semanticValidation/scale.js +28 -7
  198. package/src/actions/regression/components.js +36 -25
  199. package/src/actions/regression/create.js +13 -6
  200. package/src/actions/regression/edit.js +24 -11
  201. package/src/actions/resources/index.js +7 -0
  202. package/src/actions/resources/remove.js +173 -0
  203. package/src/actions/scales/channels.js +212 -0
  204. package/src/actions/scales/consumers/common.js +1 -1
  205. package/src/actions/scales/consumers/families.js +3 -2
  206. package/src/actions/scales/consumers/index.js +19 -2
  207. package/src/actions/scales/consumers/seriesLayout.js +28 -14
  208. package/src/actions/scales/create.js +55 -23
  209. package/src/actions/scales/definitions.js +94 -40
  210. package/src/actions/scales/edit.js +67 -12
  211. package/src/actions/scales/editPolicy.js +81 -11
  212. package/src/actions/scales/index.js +6 -0
  213. package/src/actions/scales/materialize.js +5 -4
  214. package/src/actions/scales/offset.js +48 -0
  215. package/src/actions/scales/parallel.js +71 -0
  216. package/src/actions/scales/preview.js +111 -10
  217. package/src/actions/scales/quantitativeColor.js +4 -5
  218. package/src/actions/selection/actions.js +179 -66
  219. package/src/actions/selection/index.js +3 -0
  220. package/src/actions/textMetrics/index.js +56 -0
  221. package/src/actions/theme/actions.js +70 -15
  222. package/src/actions/theme/composition.js +238 -0
  223. package/src/actions/theme/index.js +9 -2
  224. package/src/actions/theme/reconcile.js +313 -121
  225. package/src/actions/theme/state.js +160 -0
  226. package/src/actions/titles/actions.js +8 -8
  227. package/src/actions/titles/resolve.js +3 -3
  228. package/src/actions/violinPlots/create.js +6 -3
  229. package/src/actions/violinPlots/edit.js +2 -1
  230. package/src/core/action.js +117 -35
  231. package/src/core/compositionState.js +6 -1
  232. package/src/core/diagnostics.js +16 -0
  233. package/src/core/extensionRegistry.js +27 -0
  234. package/src/core/font.js +18 -0
  235. package/src/core/identifiers.js +5 -4
  236. package/src/core/immutable.js +10 -3
  237. package/src/core/optionRequirements.js +8 -0
  238. package/src/core/programState.js +21 -1
  239. package/src/core/resourceReferences.js +341 -0
  240. package/src/core/textMetricProfile.js +28 -0
  241. package/src/core/textMetrics.js +24 -3
  242. package/src/core/validation.js +22 -10
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/diagnostics.js +1 -0
  245. package/src/grammar/bars/aggregate.js +4 -1
  246. package/src/grammar/bars/geometry.js +44 -0
  247. package/src/grammar/bin.js +54 -9
  248. package/src/grammar/complete.js +279 -0
  249. package/src/grammar/computed.js +265 -64
  250. package/src/grammar/coordinates.js +37 -0
  251. package/src/grammar/density.js +239 -37
  252. package/src/grammar/displayLabels.js +57 -0
  253. package/src/grammar/facets/dependencies.js +133 -1
  254. package/src/grammar/facets/guides.js +3 -0
  255. package/src/grammar/facets/index.js +7 -47
  256. package/src/grammar/facets/scales.js +15 -18
  257. package/src/grammar/impute.js +341 -0
  258. package/src/grammar/markLabelSelection.js +57 -0
  259. package/src/grammar/markLabels.js +18 -1
  260. package/src/grammar/normalize.js +366 -0
  261. package/src/grammar/pathSeries.js +26 -8
  262. package/src/grammar/pointShapes.js +13 -4
  263. package/src/grammar/polar.js +90 -8
  264. package/src/grammar/regression/index.js +1 -0
  265. package/src/grammar/regression/parameters.js +23 -0
  266. package/src/grammar/roundedRect.js +180 -0
  267. package/src/grammar/rules.js +1 -0
  268. package/src/grammar/scales/colorConsumers.js +20 -1
  269. package/src/grammar/scales/continuous.js +2 -2
  270. package/src/grammar/scales/definition.js +27 -4
  271. package/src/grammar/scales/index.js +1 -0
  272. package/src/grammar/scales/ordinal.js +12 -3
  273. package/src/grammar/scales/policies.js +2 -2
  274. package/src/grammar/scales/size.js +456 -0
  275. package/src/grammar/scales/types.js +8 -0
  276. package/src/grammar/schemas/concreteGraphic.js +14 -2
  277. package/src/grammar/schemas/graphic.js +15 -0
  278. package/src/grammar/schemas/graphicBounds.js +190 -41
  279. package/src/grammar/schemas/semanticPath.js +7 -2
  280. package/src/grammar/statisticalReference.js +103 -0
  281. package/src/grammar/strokeStyle.js +77 -0
  282. package/src/grammar/summary.js +78 -16
  283. package/src/grammar/timeUnit.js +216 -5
  284. package/src/grammar/transformTopology.js +4 -0
  285. package/src/grammar/transforms.js +394 -28
  286. package/src/grammar/weightedStatistics.js +374 -0
  287. package/src/grammar/window.js +221 -16
  288. package/src/layout/aspect.js +80 -0
  289. package/src/layout/facets.js +59 -5
  290. package/src/layout/labels.js +351 -7
  291. package/src/layout/legend.js +4 -4
  292. package/src/layout/legendItems.js +6 -6
  293. package/src/layout/text.js +10 -9
  294. package/src/layout/title.js +9 -9
  295. package/src/materialization/bars/aggregate.js +25 -2
  296. package/src/materialization/bars/histogram.js +84 -24
  297. package/src/materialization/bars/ranged.js +19 -3
  298. package/src/materialization/bars/resolve.js +7 -4
  299. package/src/materialization/composition.js +3 -1
  300. package/src/materialization/coordinateBounds.js +204 -0
  301. package/src/materialization/dependencies.js +36 -0
  302. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  303. package/src/materialization/facetGuides/placement.js +9 -3
  304. package/src/materialization/facetGuides/preparation.js +13 -8
  305. package/src/materialization/facetHeaders.js +347 -0
  306. package/src/materialization/facets.js +15 -65
  307. package/src/materialization/guides/layout.js +3 -3
  308. package/src/materialization/guides/resources.js +26 -0
  309. package/src/materialization/legends.js +1 -1
  310. package/src/materialization/marks/index.js +11 -5
  311. package/src/materialization/marks/policies.js +2 -1
  312. package/src/materialization/rect.js +25 -12
  313. package/src/materialization/rectConfig.js +5 -1
  314. package/src/materialization/scaleGuideDependencies.js +10 -0
  315. package/src/materialization/scales/map.js +5 -3
  316. package/src/materialization/scales/policies/binnedPosition.js +2 -2
  317. package/src/materialization/scales/policies/offset.js +50 -8
  318. package/src/materialization/scales/policies/series.js +4 -1
  319. package/src/materialization/scales/resolve.js +22 -6
  320. package/src/materialization/selection/items/arc.js +28 -4
  321. package/src/materialization/selection/items/bar.js +30 -3
  322. package/src/materialization/selection/items/common.js +20 -5
  323. package/src/materialization/selection/items/rect.js +28 -4
  324. package/src/materialization/selection/path.js +1 -1
  325. package/src/materialization/selection/point.js +3 -1
  326. package/src/materialization/text.js +265 -14
  327. package/src/materialization/typography.js +31 -0
  328. package/src/mcp/cli.js +5 -3
  329. package/src/persistence/codec.js +65 -0
  330. package/src/persistence/validation.js +185 -0
  331. package/src/persistence.js +74 -0
  332. package/src/renderers/canvas/circle.js +2 -3
  333. package/src/renderers/canvas/index.js +5 -4
  334. package/src/renderers/canvas/line.js +2 -3
  335. package/src/renderers/canvas/native.js +4 -4
  336. package/src/renderers/canvas/path.js +2 -3
  337. package/src/renderers/canvas/rect.js +2 -3
  338. package/src/renderers/canvas/stroke.js +11 -0
  339. package/src/renderers/nativeBackend.js +10 -0
  340. package/src/renderers/options.js +13 -0
  341. package/src/renderers/pdf.js +25 -54
  342. package/src/renderers/png.js +22 -17
  343. package/src/renderers/svg.js +29 -14
  344. package/src/renderers/text.js +1 -11
  345. package/src/selectors/coordinates.js +3 -1
  346. package/src/selectors/datasets.js +38 -5
  347. package/src/selectors/layers.js +10 -4
  348. package/src/selectors/markOwners.js +46 -0
  349. package/src/selectors/scales.js +6 -4
  350. package/src/theme/defaults.js +103 -1
  351. package/src/version.js +2 -0
  352. package/types/accessibility.d.ts +37 -0
  353. package/types/basic.d.ts +10 -2
  354. package/types/diagnostics.d.ts +15 -0
  355. package/types/index.d.ts +90 -0
  356. package/types/pdf.d.ts +9 -0
  357. package/types/persistence.d.ts +7 -0
  358. package/types/png.d.ts +9 -0
  359. package/types/program.d.ts +944 -118
@@ -1,4 +1,5 @@
1
- import { action } from "../../core/action.js";
1
+ import { action, closedAction } from "../../core/action.js";
2
+ import { registerFacetDataRevision, reviseUnitData } from "../data/revise.js";
2
3
  import { freezeOwned, isPlainObject } from "../../core/immutable.js";
3
4
  import { validateUserId } from "../../core/identifiers.js";
4
5
  import {
@@ -11,6 +12,8 @@ import {
11
12
  resolveFacetDefinition,
12
13
  resolveFacetGridDefinition
13
14
  } from "../../grammar/facets/index.js";
15
+ import { collectFacetScaleBindings, resolveFacetFamily } from
16
+ "../../grammar/facets/dependencies.js";
14
17
  import {
15
18
  FACET_SCALE_CHANNELS,
16
19
  normalizeFacetScalePolicies
@@ -18,14 +21,21 @@ import {
18
21
  import { resolveFacetLayout } from "../../layout/facets.js";
19
22
  import { compositionChildDescriptor } from
20
23
  "../../materialization/composition.js";
21
- import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from "../../theme/defaults.js";
22
24
  import { deriveFacetChildren } from "./derive.js";
23
25
  import { resolveFacetChildrenScales } from "./derive.js";
24
26
  import { replayDerivedData } from "./replay.js";
25
27
  import { composeFacetGuides } from "./guides.js";
26
28
  import { applyCompositionState } from "../composition/actions.js";
29
+ import { replayCompositionThemeState } from "../theme/composition.js";
27
30
  import { findDataset } from "../../selectors/datasets.js";
28
31
  import { findLayer } from "../../selectors/layers.js";
32
+ import { findSemanticScale } from "../../selectors/scales.js";
33
+ import { normalizeDisplayLabelMap } from "../../grammar/displayLabels.js";
34
+ import {
35
+ createDefaultFacetHeaders,
36
+ normalizeFacetHeadersConfig,
37
+ resolveFacetHeaderConfig
38
+ } from "../../materialization/facetHeaders.js";
29
39
 
30
40
  const FACET_OPTIONS = Object.freeze([
31
41
  "id", "field", "data", "values", "columns", "gap", "align", "padding", "scales",
@@ -42,15 +52,12 @@ const REPEAT_OPTIONS = Object.freeze([
42
52
  const SOURCE_EDIT_OPTIONS = Object.freeze(["program"]);
43
53
  const GUIDE_OPTIONS = Object.freeze(["axes", "legend"]);
44
54
  const HEADER_OPTIONS = Object.freeze([
45
- "fontSize", "fontFamily", "fontWeight", "color", "offset"
55
+ "fontSize", "fontFamily", "fontWeight", "color", "offset", "role",
56
+ "labelMap", "side", "align"
57
+ ]);
58
+ const HEADER_STYLE_OPTIONS = Object.freeze([
59
+ "fontSize", "fontFamily", "fontWeight", "color", "offset", "align"
46
60
  ]);
47
- const DEFAULT_HEADERS = Object.freeze({
48
- fontSize: 12,
49
- fontFamily: DEFAULT_FONT_FAMILY,
50
- fontWeight: 600,
51
- color: DEFAULT_COLORS.strongText,
52
- offset: 10
53
- });
54
61
 
55
62
  function normalizeGuides(guides) {
56
63
  if (guides === undefined) return { axes: "each", legend: false };
@@ -74,11 +81,14 @@ function requireFacetProgram(program, operation) {
74
81
  }
75
82
 
76
83
  function usedFacetScalePolicies(program, policies) {
77
- return Object.fromEntries(FACET_SCALE_CHANNELS.flatMap(channel =>
78
- program.semanticSpec.layers.some(
79
- layer => layer.encoding?.[channel]?.scale !== undefined
80
- ) ? [[channel, policies[channel]]] : []
81
- ));
84
+ const used = new Set(
85
+ collectFacetScaleBindings(program.semanticSpec).map(binding => binding.policyKey)
86
+ );
87
+ return Object.fromEntries(
88
+ FACET_SCALE_CHANNELS.flatMap(channel =>
89
+ used.has(channel) ? [[channel, policies[channel]]] : []
90
+ )
91
+ );
82
92
  }
83
93
 
84
94
  function facetUnitTemplate(program) {
@@ -96,6 +106,9 @@ function facetUnitTemplate(program) {
96
106
  resolvedScales: program.resolvedScales,
97
107
  materializationConfigs: freezeOwned({
98
108
  ...unitConfigs,
109
+ ...(seed.materializationConfigs.theme === undefined
110
+ ? {}
111
+ : { theme: seed.materializationConfigs.theme }),
99
112
  ...(seed.materializationConfigs.guides === undefined
100
113
  ? {}
101
114
  : { guides: seed.materializationConfigs.guides }),
@@ -145,11 +158,7 @@ function rederiveFacet(program, { scales, guides }) {
145
158
  columns: current.facet.grid.columns,
146
159
  combinations: current.facet.grid.combinations
147
160
  });
148
- const request = Object.fromEntries(FACET_SCALE_CHANNELS.flatMap(channel =>
149
- program.semanticSpec.layers.some(
150
- layer => layer.encoding?.[channel]?.scale !== undefined
151
- ) ? [[channel, scales[channel]]] : []
152
- ));
161
+ const request = usedFacetScalePolicies(program, scales);
153
162
  const normalized = normalizeFacetScalePolicies(program.semanticSpec, request);
154
163
  const template = facetUnitTemplate(program);
155
164
  const derived = deriveFacetChildren(template, definition, {
@@ -175,15 +184,17 @@ function rederiveFacet(program, { scales, guides }) {
175
184
  }, compositionSpec.children);
176
185
  }
177
186
 
178
- export const facet = action(
187
+ export const facet = /* @__PURE__ */ closedAction(
179
188
  {
180
189
  op: "facet",
181
190
  description: "Repeat one direct-source chart by field value."
182
- },
191
+ }, FACET_OPTIONS,
183
192
  function (args = {}) {
184
- validateOptionObject(args, FACET_OPTIONS, "facet");
185
193
  const guides = normalizeGuides(args.guides);
186
194
  const definition = resolveFacetDefinition(this.semanticSpec, args);
195
+ if (definition.family !== "cartesian" && guides.axes === "outer") {
196
+ throw new Error("Polar and Parallel facets do not support outer axes.");
197
+ }
187
198
  const scalePolicies = normalizeFacetScalePolicies(
188
199
  this.semanticSpec,
189
200
  args.scales ?? {}
@@ -222,7 +233,7 @@ export const facet = action(
222
233
  };
223
234
  return applyCompositionState(
224
235
  this._withMaterializationConfig(["facets", definition.id], {
225
- headers: DEFAULT_HEADERS
236
+ headers: createDefaultFacetHeaders()
226
237
  }),
227
238
  {
228
239
  children: derived.children,
@@ -238,8 +249,20 @@ function resolveRepeatDefinition(program, args) {
238
249
  throw new TypeError("repeatCharts options must be a plain object.");
239
250
  }
240
251
  const id = validateUserId(args.id ?? "repeat", "Repeat id");
241
- if (!["x", "y"].includes(args.channel)) {
242
- throw new Error('repeatCharts channel must be "x" or "y".');
252
+ const parallelChannel = isPlainObject(args.channel);
253
+ if (parallelChannel) {
254
+ const keys = Object.keys(args.channel);
255
+ if (keys.length !== 1 || keys[0] !== "parallelDimension" ||
256
+ typeof args.channel.parallelDimension !== "string" ||
257
+ args.channel.parallelDimension.length === 0) {
258
+ throw new Error(
259
+ "repeatCharts Parallel channel must contain exactly one non-empty parallelDimension."
260
+ );
261
+ }
262
+ } else if (!["x", "y", "theta", "r"].includes(args.channel)) {
263
+ throw new Error(
264
+ 'repeatCharts channel must be "x", "y", "theta", "r", or one parallelDimension.'
265
+ );
243
266
  }
244
267
  if (!Array.isArray(args.fields) || args.fields.length === 0 ||
245
268
  args.fields.some(field => typeof field !== "string" || field.length === 0)) {
@@ -248,29 +271,53 @@ function resolveRepeatDefinition(program, args) {
248
271
  if (new Set(args.fields).size !== args.fields.length) {
249
272
  throw new Error("repeatCharts fields must be unique.");
250
273
  }
251
- const eligible = program.semanticSpec.layers.filter(layer =>
252
- layer.encoding?.x?.scale !== undefined &&
253
- layer.encoding?.y?.scale !== undefined &&
254
- layer.encoding?.[args.channel]?.field !== undefined &&
255
- ["point", "line", "area", "bar", "rule", "tick", "rect"].includes(layer.mark?.type)
256
- );
274
+ const family = resolveFacetFamily(program.semanticSpec).family;
275
+ const semanticChannel = args.channel === "r" ? "radius" : args.channel;
276
+ const eligible = program.semanticSpec.layers.filter(layer => {
277
+ if (parallelChannel) {
278
+ const matches = (layer.encoding?.parallel?.dimensions ?? []).filter(
279
+ dimension => dimension.field === args.channel.parallelDimension
280
+ );
281
+ return family === "parallel" && layer.mark?.type === "line" && matches.length === 1;
282
+ }
283
+ if (["x", "y"].includes(args.channel)) {
284
+ return family === "cartesian" &&
285
+ layer.encoding?.x?.scale !== undefined &&
286
+ layer.encoding?.y?.scale !== undefined &&
287
+ layer.encoding?.[args.channel]?.field !== undefined &&
288
+ ["point", "line", "area", "bar", "rule", "tick", "rect"].includes(layer.mark?.type);
289
+ }
290
+ const role = program.markConfigs[layer.id]?.compositionRole;
291
+ if (family !== "polar" || ["pie", "radar"].includes(role)) return false;
292
+ return ["point", "line", "arc"].includes(layer.mark?.type) &&
293
+ layer.encoding?.[semanticChannel]?.field !== undefined;
294
+ });
257
295
  let target;
258
296
  if (args.target !== undefined) {
259
297
  target = validateUserId(args.target, "Repeat target");
260
298
  if (!eligible.some(layer => layer.id === target)) {
261
- throw new Error(`repeatCharts target "${target}" is not an eligible Cartesian mark.`);
299
+ throw new Error(
300
+ `repeatCharts target "${target}" is not eligible for the requested field role.`
301
+ );
262
302
  }
263
303
  } else if (eligible.length === 1) {
264
304
  target = eligible[0].id;
265
305
  } else {
266
306
  throw new Error(
267
307
  eligible.length === 0
268
- ? "repeatCharts requires one complete Cartesian mark."
308
+ ? "repeatCharts requires one eligible complete mark for the requested field role."
269
309
  : "repeatCharts target is ambiguous; provide target."
270
310
  );
271
311
  }
272
- if (program.semanticSpec.layers.length !== 1) {
273
- throw new Error("repeatCharts currently supports one direct Cartesian mark only.");
312
+ const unrelatedLayers = program.semanticSpec.layers.filter(layer => {
313
+ if (layer.id === target) return false;
314
+ const attachedLabel = layer.mark?.type === "text" && layer.source === target;
315
+ const statisticalReference = program.markConfigs[layer.id]
316
+ ?.statisticalReference?.source === target;
317
+ return !attachedLabel && !statisticalReference;
318
+ });
319
+ if (unrelatedLayers.length > 0) {
320
+ throw new Error("repeatCharts currently supports one direct mark only.");
274
321
  }
275
322
  const config = program.markConfigs[target] ?? {};
276
323
  const composite = [
@@ -285,14 +332,23 @@ function resolveRepeatDefinition(program, args) {
285
332
  if (dataset?.transform?.length > 0) {
286
333
  throw new Error("repeatCharts does not rewrite a derived dataset dependency.");
287
334
  }
288
- const encoding = layer.encoding[args.channel];
335
+ const encoding = parallelChannel
336
+ ? layer.encoding.parallel
337
+ : layer.encoding[semanticChannel];
338
+ const dimensionIndex = parallelChannel
339
+ ? encoding.dimensions.findIndex(
340
+ dimension => dimension.field === args.channel.parallelDimension
341
+ )
342
+ : undefined;
289
343
  return {
290
344
  id,
291
345
  target,
292
- channel: args.channel,
346
+ channel: parallelChannel ? { ...args.channel } : args.channel,
347
+ policyKey: parallelChannel ? "parallelDimensions" : args.channel,
293
348
  fields: [...args.fields],
294
349
  data: layer.data,
295
350
  encoding,
351
+ ...(dimensionIndex === undefined ? {} : { dimensionIndex }),
296
352
  cells: args.fields.map((field, index) => ({
297
353
  id: `${id}-field-${index + 1}`,
298
354
  field,
@@ -316,15 +372,52 @@ function repeatEncodingArgs(definition, field) {
316
372
  };
317
373
  }
318
374
 
375
+ function parallelRepeatDimensions(program, definition, field) {
376
+ return definition.encoding.dimensions.map((dimension, index) => {
377
+ const semanticScale = findSemanticScale(program, dimension.scale);
378
+ if (semanticScale === undefined) {
379
+ throw new Error(`repeatCharts Parallel dimension scale "${dimension.scale}" is missing.`);
380
+ }
381
+ const { id: _id, ...scale } = semanticScale;
382
+ void _id;
383
+ const replacement = index === definition.dimensionIndex;
384
+ return {
385
+ field: replacement ? field : dimension.field,
386
+ fieldType: dimension.fieldType,
387
+ title: replacement && dimension.title === dimension.field
388
+ ? field
389
+ : dimension.title,
390
+ scale
391
+ };
392
+ });
393
+ }
394
+
395
+ function deriveRepeatedProgram(template, definition, field) {
396
+ if (isPlainObject(definition.channel)) {
397
+ return template.encodeParallelCoordinates({
398
+ target: definition.target,
399
+ coordinate: findLayer(template, definition.target).coordinate,
400
+ dimensions: parallelRepeatDimensions(template, definition, field),
401
+ ...(definition.encoding.key === undefined ? {} : { key: definition.encoding.key }),
402
+ missing: definition.encoding.missing
403
+ });
404
+ }
405
+ const operation = {
406
+ x: "encodeX",
407
+ y: "encodeY",
408
+ theta: "encodeTheta",
409
+ r: "encodeR"
410
+ }[definition.channel];
411
+ return template[operation](repeatEncodingArgs(definition, field));
412
+ }
413
+
319
414
  function deriveRepeatChildren(base, definition, scales, closeInheritedAction) {
320
415
  const template = base.semanticSpec.title.text === undefined
321
416
  ? base
322
417
  : base.removeTitle();
323
418
  const independentlyResolved = Object.fromEntries(definition.cells.map(cell => [
324
419
  cell.id,
325
- template[definition.channel === "x" ? "encodeX" : "encodeY"](
326
- repeatEncodingArgs(definition, cell.field)
327
- )
420
+ deriveRepeatedProgram(template, definition, cell.field)
328
421
  ]));
329
422
  return resolveFacetChildrenScales(
330
423
  template,
@@ -335,13 +428,12 @@ function deriveRepeatChildren(base, definition, scales, closeInheritedAction) {
335
428
  );
336
429
  }
337
430
 
338
- export const repeatCharts = action(
431
+ export const repeatCharts = /* @__PURE__ */ closedAction(
339
432
  {
340
433
  op: "repeatCharts",
341
- description: "Repeat one direct Cartesian chart across an ordered field list."
342
- },
434
+ description: "Repeat one direct chart across an ordered field-role list."
435
+ }, REPEAT_OPTIONS,
343
436
  function (args = {}) {
344
- validateOptionObject(args, REPEAT_OPTIONS, "repeatCharts");
345
437
  const guides = normalizeGuides(args.guides);
346
438
  if (guides.axes === "outer") {
347
439
  throw new Error("repeatCharts does not promote axes across different repeated fields.");
@@ -349,7 +441,7 @@ export const repeatCharts = action(
349
441
  const definition = resolveRepeatDefinition(this, args);
350
442
  const requestedScales = {
351
443
  ...(args.scales ?? {}),
352
- [definition.channel]: args.scales?.[definition.channel] ?? "independent"
444
+ [definition.policyKey]: args.scales?.[definition.policyKey] ?? "independent"
353
445
  };
354
446
  const scalePolicies = normalizeFacetScalePolicies(
355
447
  this.semanticSpec,
@@ -394,7 +486,7 @@ export const repeatCharts = action(
394
486
  };
395
487
  return applyCompositionState(
396
488
  this._withMaterializationConfig(["facets", definition.id], {
397
- headers: DEFAULT_HEADERS
489
+ headers: createDefaultFacetHeaders()
398
490
  }),
399
491
  { children: derived.children, compositionSpec },
400
492
  compositionSpec.children
@@ -402,15 +494,17 @@ export const repeatCharts = action(
402
494
  }
403
495
  );
404
496
 
405
- export const facetGrid = action(
497
+ export const facetGrid = /* @__PURE__ */ closedAction(
406
498
  {
407
499
  op: "facetGrid",
408
500
  description: "Repeat one direct-source Cartesian chart across a row and column field grid."
409
- },
501
+ }, FACET_GRID_OPTIONS,
410
502
  function (args = {}) {
411
- validateOptionObject(args, FACET_GRID_OPTIONS, "facetGrid");
412
503
  const guides = normalizeGuides(args.guides);
413
504
  const definition = resolveFacetGridDefinition(this.semanticSpec, args);
505
+ if (definition.family !== "cartesian" && guides.axes === "outer") {
506
+ throw new Error("Polar and Parallel facets do not support outer axes.");
507
+ }
414
508
  const scalePolicies = normalizeFacetScalePolicies(
415
509
  this.semanticSpec,
416
510
  args.scales ?? {}
@@ -461,7 +555,7 @@ export const facetGrid = action(
461
555
  };
462
556
  return applyCompositionState(
463
557
  this._withMaterializationConfig(["facets", definition.id], {
464
- headers: DEFAULT_HEADERS
558
+ headers: createDefaultFacetHeaders()
465
559
  }),
466
560
  { children: derived.children, compositionSpec },
467
561
  compositionSpec.children
@@ -469,7 +563,7 @@ export const facetGrid = action(
469
563
  }
470
564
  );
471
565
 
472
- export const editFacetHeaders = action(
566
+ export const editFacetHeaders = /* @__PURE__ */ action(
473
567
  {
474
568
  op: "editFacetHeaders",
475
569
  description: "Edit parent-owned facet header appearance.",
@@ -486,18 +580,73 @@ export const editFacetHeaders = action(
486
580
  allowEmpty: false,
487
581
  emptyMessage: "editFacetHeaders requires at least one change."
488
582
  });
489
- const headers = { ...config.headers, ...args };
490
- validatePositiveFinite(headers.fontSize, "Facet header fontSize");
491
- validateNonEmptyString(headers.fontFamily, "Facet header fontFamily");
492
- validateNonEmptyString(headers.color, "Facet header color");
493
- validateNonNegativeFinite(headers.offset, "Facet header offset");
494
- if (!(
495
- (typeof headers.fontWeight === "string" && headers.fontWeight.length > 0) ||
496
- Number.isFinite(headers.fontWeight)
497
- )) {
498
- throw new TypeError(
499
- "Facet header fontWeight must be a non-empty string or number."
500
- );
583
+ const role = args.role ?? "all";
584
+ if (!["all", "row", "column"].includes(role)) {
585
+ throw new Error(`Unknown facet header role "${role}".`);
586
+ }
587
+ if (role === "all" && Object.hasOwn(args, "side")) {
588
+ throw new Error("editFacetHeaders side requires an explicit row or column role.");
589
+ }
590
+ if (role === "row" && this.compositionSpec.facet.grid === undefined) {
591
+ throw new Error("editFacetHeaders row role requires a row-column facet grid.");
592
+ }
593
+ if (Object.hasOwn(args, "side")) {
594
+ const sides = role === "row" ? ["left", "right"] : ["top", "bottom"];
595
+ if (!sides.includes(args.side)) {
596
+ throw new Error(`editFacetHeaders ${role} side must be ${sides.join(" or ")}.`);
597
+ }
598
+ }
599
+ if (Object.hasOwn(args, "align") &&
600
+ !["start", "center", "end"].includes(args.align)) {
601
+ throw new Error("editFacetHeaders align must be start, center, or end.");
602
+ }
603
+ if (role === "all" && Object.keys(args).every(key => key === "role")) {
604
+ throw new Error("editFacetHeaders requires at least one change.");
605
+ }
606
+ const current = normalizeFacetHeadersConfig(config.headers);
607
+ const owner = role === "all" ? "common" : role;
608
+ const patch = { ...current[owner] };
609
+ for (const key of HEADER_STYLE_OPTIONS) {
610
+ if (Object.hasOwn(args, key)) patch[key] = args[key];
611
+ }
612
+ if (Object.hasOwn(args, "side")) patch.side = args.side;
613
+ if (Object.hasOwn(args, "labelMap")) {
614
+ if (args.labelMap === "auto") delete patch.labelMap;
615
+ else {
616
+ patch.labelMap = normalizeDisplayLabelMap(
617
+ args.labelMap,
618
+ `editFacetHeaders ${role} labelMap`
619
+ );
620
+ }
621
+ }
622
+ const headers = {
623
+ ...current,
624
+ ...(role === "all" ? {} : { mode: "roles" }),
625
+ [owner]: patch
626
+ };
627
+ for (const headerRole of ["all", "row", "column"]) {
628
+ const resolved = resolveFacetHeaderConfig(headers, headerRole);
629
+ validatePositiveFinite(resolved.fontSize, `Facet ${headerRole} header fontSize`);
630
+ validateNonEmptyString(resolved.fontFamily, `Facet ${headerRole} header fontFamily`);
631
+ validateNonEmptyString(resolved.color, `Facet ${headerRole} header color`);
632
+ validateNonNegativeFinite(resolved.offset, `Facet ${headerRole} header offset`);
633
+ if (!(
634
+ (typeof resolved.fontWeight === "string" && resolved.fontWeight.length > 0) ||
635
+ Number.isFinite(resolved.fontWeight)
636
+ )) {
637
+ throw new TypeError(
638
+ `Facet ${headerRole} header fontWeight must be a non-empty string or number.`
639
+ );
640
+ }
641
+ if (!["start", "center", "end"].includes(resolved.align)) {
642
+ throw new Error(`Facet ${headerRole} header align must be start, center, or end.`);
643
+ }
644
+ if (resolved.labelMap !== undefined) {
645
+ normalizeDisplayLabelMap(
646
+ resolved.labelMap,
647
+ `Facet ${headerRole} header labelMap`
648
+ );
649
+ }
501
650
  }
502
651
  return this
503
652
  ._withMaterializationConfig(["facets", id], { ...config, headers })
@@ -505,7 +654,7 @@ export const editFacetHeaders = action(
505
654
  }
506
655
  );
507
656
 
508
- export const editFacetScales = action(
657
+ export const editFacetScales = /* @__PURE__ */ action(
509
658
  {
510
659
  op: "editFacetScales",
511
660
  description: "Edit facet scale-resolution policies and rederive every cell.",
@@ -518,8 +667,8 @@ export const editFacetScales = action(
518
667
  emptyMessage: "editFacetScales requires at least one channel policy change."
519
668
  });
520
669
  for (const channel of Object.keys(args)) {
521
- if (!this.semanticSpec.layers.some(
522
- layer => layer.encoding?.[channel]?.scale !== undefined
670
+ if (!collectFacetScaleBindings(this.semanticSpec).some(
671
+ binding => binding.policyKey === channel
523
672
  )) {
524
673
  throw new Error(
525
674
  `Facet scale channel "${channel}" is not used by an affected layer.`
@@ -540,7 +689,7 @@ export const editFacetScales = action(
540
689
  }
541
690
  );
542
691
 
543
- export const editFacetGuides = action(
692
+ export const editFacetGuides = /* @__PURE__ */ action(
544
693
  {
545
694
  op: "editFacetGuides",
546
695
  description: "Edit facet guide ownership and rederive every cell.",
@@ -554,6 +703,10 @@ export const editFacetGuides = action(
554
703
  });
555
704
  const current = this.compositionSpec.facet;
556
705
  const guides = normalizeGuides({ ...current.guides, ...args });
706
+ const family = resolveFacetFamily(this.semanticSpec).family;
707
+ if (family !== "cartesian" && guides.axes === "outer") {
708
+ throw new Error("Polar and Parallel facets do not support outer axes.");
709
+ }
557
710
  if (current.repeat !== undefined && guides.axes === "outer") {
558
711
  throw new Error("repeatCharts does not promote axes across different repeated fields.");
559
712
  }
@@ -574,11 +727,33 @@ function adoptUnitState(program, actionOwner) {
574
727
  if (program.actionStack.length !== 0) {
575
728
  throw new Error("editFacetSource program has an unfinished action stack.");
576
729
  }
730
+ const seedId = actionOwner.compositionSpec.children.find(id =>
731
+ actionOwner.children[id]?.semanticSpec.layers.length > 0
732
+ ) ?? actionOwner.compositionSpec.children[0];
733
+ const retained = actionOwner.children[seedId]?.materializationConfigs ?? {};
734
+ const {
735
+ canvas: _retainedCanvas,
736
+ theme: _retainedTheme,
737
+ facets: _retainedFacets,
738
+ ...retainedRecipe
739
+ } = retained;
740
+ void _retainedCanvas;
741
+ void _retainedTheme;
742
+ void _retainedFacets;
577
743
  return new actionOwner.constructor({
578
744
  semanticSpec: program.semanticSpec,
579
745
  graphicSpec: program.graphicSpec,
580
746
  resolvedScales: program.resolvedScales,
581
- materializationConfigs: program.materializationConfigs,
747
+ materializationConfigs: freezeOwned({
748
+ ...program.materializationConfigs,
749
+ ...retainedRecipe,
750
+ ...(program.materializationConfigs.canvas === undefined
751
+ ? {}
752
+ : { canvas: program.materializationConfigs.canvas }),
753
+ ...(program.materializationConfigs.theme === undefined
754
+ ? {}
755
+ : { theme: program.materializationConfigs.theme })
756
+ }),
582
757
  children: {},
583
758
  context: program.context,
584
759
  trace: actionOwner.trace,
@@ -587,14 +762,13 @@ function adoptUnitState(program, actionOwner) {
587
762
  });
588
763
  }
589
764
 
590
- export const editFacetSource = action(
765
+ export const editFacetSource = /* @__PURE__ */ closedAction(
591
766
  {
592
767
  op: "editFacetSource",
593
768
  description: "Reapply one facet, grid, or repeat recipe to a revised complete unit program.",
594
769
  scope: "composition"
595
- },
770
+ }, SOURCE_EDIT_OPTIONS,
596
771
  function (args = {}) {
597
- validateOptionObject(args, SOURCE_EDIT_OPTIONS, "editFacetSource");
598
772
  requireFacetProgram(this, "editFacetSource");
599
773
  const current = this.compositionSpec;
600
774
  const facetConfig = this.materializationConfigs.facets?.[current.id];
@@ -653,11 +827,31 @@ export const editFacetSource = action(
653
827
  ...this.semanticSpec.title
654
828
  });
655
829
  }
656
- return revised;
830
+ return replayCompositionThemeState(
831
+ revised,
832
+ this.materializationConfigs.theme
833
+ );
657
834
  }
658
835
  );
659
836
 
660
837
  export function registerFacetActions(ProgramClass) {
838
+ registerFacetDataRevision((program, args) => {
839
+ const { program: unit, plan } = reviseUnitData(facetUnitTemplate(program), args);
840
+ const current = program.compositionSpec;
841
+ // Adopt an already-materialized unit revision into the retained parent.
842
+ const revised = new program.constructor({
843
+ ...unit,
844
+ graphicSpec: program.graphicSpec,
845
+ children: program.children,
846
+ materializationConfigs: { ...unit.materializationConfigs,
847
+ facets: program.materializationConfigs.facets,
848
+ ...(program.titleConfig === undefined ? {} : { title: program.titleConfig }) },
849
+ actionSequence: unit._actionSequence,
850
+ compositionSpec: { ...current, facet: { ...current.facet,
851
+ data: plan.replacements.get(current.facet.data) ?? current.facet.data } }
852
+ });
853
+ return rederiveFacet(revised, current.facet);
854
+ });
661
855
  ProgramClass.prototype.replayDerivedData = replayDerivedData;
662
856
  ProgramClass.prototype.composeFacetGuides = composeFacetGuides;
663
857
  ProgramClass.prototype.facet = facet;