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,35 +1,274 @@
1
- import { isPlainObject } from "../core/immutable.js";
1
+ import { cloneAndFreeze, isPlainObject } from "../core/immutable.js";
2
2
  import { validateBoxTransform } from "./boxPlot.js";
3
- import { validateBinTransform } from "./bin.js";
3
+ import { normalizeBinTransform, validateBinTransform } from "./bin.js";
4
4
  import {
5
+ normalizeBin2DTransform,
5
6
  requestedBin2DTransform,
6
7
  validateBin2DTransform
7
8
  } from "./bin2d.js";
8
- import { validateDensityTransform } from "./density.js";
9
- import { validateECDFTransform } from "./ecdf.js";
10
- import { validateComputedTransform } from "./computed.js";
11
- import { validateFilterTransform } from "./filter.js";
12
- import { validateFoldTransform } from "./fold.js";
9
+ import {
10
+ normalizeDensityTransform,
11
+ validateDensityTransform
12
+ } from "./density.js";
13
+ import {
14
+ normalizeECDFTransform,
15
+ validateECDFTransform
16
+ } from "./ecdf.js";
17
+ import {
18
+ normalizeComputedTransform,
19
+ validateComputedTransform
20
+ } from "./computed.js";
21
+ import {
22
+ normalizeCompleteTransform,
23
+ validateCompleteTransform
24
+ } from "./complete.js";
25
+ import {
26
+ normalizeFilterTransform,
27
+ validateFilterTransform
28
+ } from "./filter.js";
29
+ import { normalizeFoldTransform, validateFoldTransform } from "./fold.js";
13
30
  import {
14
31
  requestedGradientProfileTransform,
15
32
  validateGradientProfileTransform
16
33
  } from "./gradientProfile.js";
17
- import { validateIntervalTransform } from "./interval.js";
34
+ import {
35
+ normalizeIntervalTransform,
36
+ validateIntervalTransform
37
+ } from "./interval.js";
38
+ import {
39
+ normalizeImputeTransform,
40
+ validateImputeTransform
41
+ } from "./impute.js";
18
42
  import {
19
43
  requestedHorizonTransform,
20
44
  validateHorizonTransform
21
45
  } from "./horizon.js";
22
46
  import { validateMarkFilterTransform } from "./markFilter.js";
23
- import { validateRegressionTransform } from "./regression/index.js";
24
- import { validateWindowTransform } from "./window.js";
25
- import { validateTimeUnitTransform } from "./timeUnit.js";
26
- import { validateSummaryTransform } from "./summary.js";
27
- import { validateStackTransform } from "./stack.js";
47
+ import {
48
+ normalizeNormalizeTransform,
49
+ validateNormalizeTransform
50
+ } from "./normalize.js";
51
+ import {
52
+ normalizeRegressionTransform,
53
+ validateRegressionTransform
54
+ } from "./regression/index.js";
55
+ import { normalizeWindowTransform, validateWindowTransform } from "./window.js";
56
+ import {
57
+ normalizeTimeUnitTransform,
58
+ validateTimeUnitTransform
59
+ } from "./timeUnit.js";
60
+ import {
61
+ normalizeSummaryTransform,
62
+ validateSummaryTransform
63
+ } from "./summary.js";
64
+ import { normalizeStackTransform, validateStackTransform } from "./stack.js";
65
+ import { validateStatisticalReferenceTransform } from
66
+ "./statisticalReference.js";
28
67
  import { findTransformTopology } from "./transformTopology.js";
29
68
 
30
- function requestedDensityTransform(transform) {
69
+ function requestedTransform(transform) {
31
70
  const { resolved: _resolved, ...requested } = transform;
32
- return requested;
71
+ return cloneAndFreeze(requested);
72
+ }
73
+
74
+ const requestedDensityTransform = requestedTransform;
75
+
76
+ function requestedOptions(transform) {
77
+ const { type: _type, resolved: _resolved, ...options } = transform;
78
+ return options;
79
+ }
80
+
81
+ function mergedOptions(transform, patch) {
82
+ const options = { ...requestedOptions(transform) };
83
+ if (patch.weight === false) delete options.weight;
84
+ return {
85
+ ...options,
86
+ ...Object.fromEntries(
87
+ Object.entries(patch).filter(
88
+ ([key, value]) => !(key === "weight" && value === false)
89
+ )
90
+ )
91
+ };
92
+ }
93
+
94
+ function replaceExclusive(options, patch, keys) {
95
+ if (!keys.some(key => Object.hasOwn(patch, key))) return options;
96
+ const next = { ...options };
97
+ for (const key of keys) delete next[key];
98
+ return next;
99
+ }
100
+
101
+ function normalizeSimple(normalize) {
102
+ return (transform, patch) => normalize(mergedOptions(transform, patch));
103
+ }
104
+
105
+ function normalizeFilterEdit(transform, patch) {
106
+ const base = replaceExclusive(
107
+ requestedOptions(transform),
108
+ patch,
109
+ ["oneOf", "predicate", "range"]
110
+ );
111
+ return normalizeFilterTransform({ ...base, ...patch });
112
+ }
113
+
114
+ function normalizeBinEdit(transform, patch) {
115
+ const prior = requestedOptions(transform);
116
+ const base = replaceExclusive(
117
+ { ...prior, ...prior.bin },
118
+ patch,
119
+ ["maxBins", "step", "boundaries"]
120
+ );
121
+ delete base.bin;
122
+ if (patch.weight === false) delete base.weight;
123
+ return normalizeBinTransform({
124
+ ...base,
125
+ ...Object.fromEntries(
126
+ Object.entries(patch).filter(
127
+ ([key, value]) => !(key === "weight" && value === false)
128
+ )
129
+ )
130
+ });
131
+ }
132
+
133
+ function normalizeBin2DEdit(transform, patch, owner) {
134
+ const base = requestedOptions(transform);
135
+ const members = patch.members ?? base.members;
136
+ let as = patch.as ?? base.as;
137
+ if (!Object.hasOwn(patch, "as")) {
138
+ as = { ...as };
139
+ if (members && as.members === undefined) {
140
+ as.members = `__${owner}_members`;
141
+ } else if (!members) {
142
+ delete as.members;
143
+ }
144
+ }
145
+ return normalizeBin2DTransform({
146
+ id: owner,
147
+ ...base,
148
+ ...patch,
149
+ members,
150
+ as
151
+ });
152
+ }
153
+
154
+ function normalizeCompleteEdit(transform, patch) {
155
+ const base = replaceExclusive(
156
+ requestedOptions(transform),
157
+ patch,
158
+ ["values", "sequence"]
159
+ );
160
+ return normalizeCompleteTransform({ ...base, ...patch });
161
+ }
162
+
163
+ function normalizeImputeEdit(transform, patch) {
164
+ const base = { ...requestedOptions(transform) };
165
+ if (Object.hasOwn(patch, "method") && patch.method !== base.method) {
166
+ delete base.value;
167
+ if (patch.method === "constant") base.sortBy = [];
168
+ }
169
+ return normalizeImputeTransform({ ...base, ...patch });
170
+ }
171
+
172
+ function normalizeIntervalEdit(transform, patch) {
173
+ const base = { ...requestedOptions(transform) };
174
+ const extent = patch.extent ?? base.extent;
175
+ if (extent !== "ci") {
176
+ delete base.method;
177
+ delete base.level;
178
+ }
179
+ return normalizeIntervalTransform({ ...base, ...patch, extent });
180
+ }
181
+
182
+ function normalizeNormalizeEdit(transform, patch) {
183
+ const base = { ...requestedOptions(transform) };
184
+ const method = patch.method ?? base.method;
185
+ if (method !== base.method) {
186
+ if (method !== "zscore") delete base.variance;
187
+ if (method === "change") delete base.zeroDenominator;
188
+ if (!["index", "change", "percentChange"].includes(method)) {
189
+ delete base.baseline;
190
+ delete base.sortBy;
191
+ }
192
+ if (
193
+ !["index", "change", "percentChange"].includes(base.method) &&
194
+ ["index", "change", "percentChange"].includes(method)
195
+ ) {
196
+ delete base.baseline;
197
+ delete base.sortBy;
198
+ }
199
+ }
200
+ return normalizeNormalizeTransform({ ...base, ...patch, method });
201
+ }
202
+
203
+ function normalizeRegressionEdit(transform, patch) {
204
+ const base = { ...requestedOptions(transform) };
205
+ const method = patch.method ?? base.method;
206
+ if (method !== base.method) {
207
+ if (method !== "polynomial") delete base.degree;
208
+ if (method !== "loess") delete base.span;
209
+ if (method === "loess" || base.method === "loess") {
210
+ for (const key of [
211
+ "confidenceMethod", "level", "confidence", "interval"
212
+ ]) delete base[key];
213
+ }
214
+ }
215
+ return normalizeRegressionTransform({ ...base, ...patch, method });
216
+ }
217
+
218
+ function normalizeTimeUnitEdit(transform, patch) {
219
+ const base = { ...requestedOptions(transform) };
220
+ const unit = patch.unit ?? base.unit;
221
+ if (unit !== "week" && unit !== base.unit) {
222
+ delete base.weekStartsOn;
223
+ delete base.weekRule;
224
+ }
225
+ return normalizeTimeUnitTransform({ ...base, ...patch, unit });
226
+ }
227
+
228
+ function fixedRoles(as, roles) {
229
+ return Object.fromEntries(roles.flatMap(role =>
230
+ typeof as?.[role] === "string" ? [[role, as[role]]] : []
231
+ ));
232
+ }
233
+
234
+ function uniqueRoles(values, key, field = "as") {
235
+ const counts = new Map();
236
+ for (const value of values) {
237
+ const role = key(value);
238
+ counts.set(role, (counts.get(role) ?? 0) + 1);
239
+ }
240
+ return Object.fromEntries(values.flatMap(value => {
241
+ const role = key(value);
242
+ return counts.get(role) === 1 && typeof value[field] === "string"
243
+ ? [[role, value[field]]]
244
+ : [];
245
+ }));
246
+ }
247
+
248
+ function summaryOutputRoles(transform) {
249
+ return {
250
+ ...uniqueRoles(
251
+ transform.aggregates,
252
+ aggregate => `aggregate:${JSON.stringify(aggregate.op)}:${aggregate.field ?? ""}`
253
+ ),
254
+ ...(typeof transform.members === "string"
255
+ ? { members: transform.members }
256
+ : {})
257
+ };
258
+ }
259
+
260
+ function windowOutputRoles(transform) {
261
+ return uniqueRoles(
262
+ transform.operations,
263
+ operation => [
264
+ "operation",
265
+ operation.op,
266
+ operation.field ?? "",
267
+ operation.offset ?? "",
268
+ JSON.stringify(operation.frame ?? null)
269
+ ].join(":"),
270
+ "as"
271
+ );
33
272
  }
34
273
 
35
274
  function facetHorizonTransform(transform, { scales = {} } = {}) {
@@ -53,18 +292,46 @@ const TRANSFORM_POLICIES = Object.freeze({
53
292
  bin: Object.freeze({
54
293
  ...findTransformTopology("bin"),
55
294
  validate: validateBinTransform,
56
- materializeOp: "materializeBinData"
295
+ materializeOp: "materializeBinData",
296
+ replayTransform: requestedTransform,
297
+ editable: true,
298
+ normalizeEdit: normalizeBinEdit,
299
+ outputRoles: transform => fixedRoles(
300
+ transform.as,
301
+ ["lower", "upper", "count", "members"]
302
+ )
57
303
  }),
58
304
  bin2d: Object.freeze({
59
305
  ...findTransformTopology("bin2d"),
60
306
  validate: validateBin2DTransform,
61
307
  materializeOp: "materializeBin2DData",
62
- replayTransform: requestedBin2DTransform
308
+ replayTransform: requestedBin2DTransform,
309
+ editable: true,
310
+ normalizeEdit: normalizeBin2DEdit,
311
+ outputRoles: transform => fixedRoles(
312
+ transform.as,
313
+ ["x0", "x1", "y0", "y1", "count", "members"]
314
+ )
63
315
  }),
64
316
  computed: Object.freeze({
65
317
  ...findTransformTopology("computed"),
66
318
  validate: validateComputedTransform,
67
- materializeOp: "materializeComputedData"
319
+ materializeOp: "materializeComputedData",
320
+ replayTransform: requestedTransform,
321
+ editable: true,
322
+ normalizeEdit: normalizeSimple(normalizeComputedTransform),
323
+ outputRoles: transform => ({ value: transform.as })
324
+ }),
325
+ complete: Object.freeze({
326
+ ...findTransformTopology("complete"),
327
+ validate: validateCompleteTransform,
328
+ materializeOp: "materializeCompleteData",
329
+ replayTransform: requestedTransform,
330
+ editable: true,
331
+ normalizeEdit: normalizeCompleteEdit,
332
+ outputRoles: transform => typeof transform.members === "string"
333
+ ? { members: transform.members }
334
+ : {}
68
335
  }),
69
336
  boxOutlier: Object.freeze({
70
337
  ...findTransformTopology("boxOutlier"),
@@ -80,22 +347,43 @@ const TRANSFORM_POLICIES = Object.freeze({
80
347
  ...findTransformTopology("density"),
81
348
  validate: validateDensityTransform,
82
349
  materializeOp: "materializeDensityData",
83
- replayTransform: requestedDensityTransform
350
+ replayTransform: requestedDensityTransform,
351
+ editable: true,
352
+ normalizeEdit: normalizeSimple(normalizeDensityTransform),
353
+ outputRoles: transform => ({
354
+ value: transform.as[0],
355
+ density: transform.as[1]
356
+ })
84
357
  }),
85
358
  ecdf: Object.freeze({
86
359
  ...findTransformTopology("ecdf"),
87
360
  validate: validateECDFTransform,
88
- materializeOp: "materializeECDFData"
361
+ materializeOp: "materializeECDFData",
362
+ replayTransform: requestedTransform,
363
+ editable: true,
364
+ normalizeEdit: normalizeSimple(normalizeECDFTransform),
365
+ outputRoles: transform => fixedRoles(
366
+ transform.as,
367
+ ["value", "cumulative", "probability"]
368
+ )
89
369
  }),
90
370
  filter: Object.freeze({
91
371
  ...findTransformTopology("filter"),
92
372
  validate: validateFilterTransform,
93
- materializeOp: "materializeFilteredData"
373
+ materializeOp: "materializeFilteredData",
374
+ replayTransform: requestedTransform,
375
+ editable: true,
376
+ normalizeEdit: normalizeFilterEdit,
377
+ outputRoles: () => ({})
94
378
  }),
95
379
  fold: Object.freeze({
96
380
  ...findTransformTopology("fold"),
97
381
  validate: validateFoldTransform,
98
- materializeOp: "materializeFoldData"
382
+ materializeOp: "materializeFoldData",
383
+ replayTransform: requestedTransform,
384
+ editable: true,
385
+ normalizeEdit: normalizeSimple(normalizeFoldTransform),
386
+ outputRoles: transform => fixedRoles(transform.as, ["key", "value"])
99
387
  }),
100
388
  gradientProfile: Object.freeze({
101
389
  ...findTransformTopology("gradientProfile"),
@@ -113,37 +401,91 @@ const TRANSFORM_POLICIES = Object.freeze({
113
401
  interval: Object.freeze({
114
402
  ...findTransformTopology("interval"),
115
403
  validate: validateIntervalTransform,
116
- materializeOp: "materializeIntervalData"
404
+ materializeOp: "materializeIntervalData",
405
+ replayTransform: requestedTransform,
406
+ editable: true,
407
+ normalizeEdit: normalizeIntervalEdit,
408
+ outputRoles: transform => fixedRoles(
409
+ transform.as,
410
+ ["center", "lower", "upper"]
411
+ )
412
+ }),
413
+ impute: Object.freeze({
414
+ ...findTransformTopology("impute"),
415
+ validate: validateImputeTransform,
416
+ materializeOp: "materializeImputedData",
417
+ replayTransform: requestedTransform,
418
+ editable: true,
419
+ normalizeEdit: normalizeImputeEdit,
420
+ outputRoles: () => ({})
117
421
  }),
118
422
  markFilter: Object.freeze({
119
423
  ...findTransformTopology("markFilter"),
120
424
  validate: validateMarkFilterTransform,
121
425
  materializeOp: "materializeMarkFilteredData"
122
426
  }),
427
+ normalize: Object.freeze({
428
+ ...findTransformTopology("normalize"),
429
+ validate: validateNormalizeTransform,
430
+ materializeOp: "materializeNormalizedData",
431
+ replayTransform: requestedTransform,
432
+ editable: true,
433
+ normalizeEdit: normalizeNormalizeEdit,
434
+ outputRoles: transform => ({ value: transform.as })
435
+ }),
123
436
  regression: Object.freeze({
124
437
  ...findTransformTopology("regression"),
125
438
  validate: validateRegressionTransform,
126
- materializeOp: "materializeRegressionData"
439
+ materializeOp: "materializeRegressionData",
440
+ replayTransform: requestedTransform,
441
+ editable: true,
442
+ normalizeEdit: normalizeRegressionEdit,
443
+ outputRoles: () => ({})
127
444
  }),
128
445
  summary: Object.freeze({
129
446
  ...findTransformTopology("summary"),
130
447
  validate: validateSummaryTransform,
131
- materializeOp: "materializeSummaryData"
448
+ materializeOp: "materializeSummaryData",
449
+ replayTransform: requestedTransform,
450
+ editable: true,
451
+ normalizeEdit: normalizeSimple(normalizeSummaryTransform),
452
+ outputRoles: summaryOutputRoles
132
453
  }),
133
454
  stack: Object.freeze({
134
455
  ...findTransformTopology("stack"),
135
456
  validate: validateStackTransform,
136
- materializeOp: "materializeStackData"
457
+ materializeOp: "materializeStackData",
458
+ replayTransform: requestedTransform,
459
+ editable: true,
460
+ normalizeEdit: normalizeSimple(normalizeStackTransform),
461
+ outputRoles: transform => fixedRoles(
462
+ transform.as,
463
+ ["start", "end", "value", "share"]
464
+ )
465
+ }),
466
+ statisticalReference: Object.freeze({
467
+ ...findTransformTopology("statisticalReference"),
468
+ validate: validateStatisticalReferenceTransform,
469
+ materializeOp: "materializeStatisticalReferenceData",
470
+ replayTransform: requestedTransform
137
471
  }),
138
472
  timeUnit: Object.freeze({
139
473
  ...findTransformTopology("timeUnit"),
140
474
  validate: validateTimeUnitTransform,
141
- materializeOp: "materializeTimeUnitData"
475
+ materializeOp: "materializeTimeUnitData",
476
+ replayTransform: requestedTransform,
477
+ editable: true,
478
+ normalizeEdit: normalizeTimeUnitEdit,
479
+ outputRoles: transform => ({ value: transform.as })
142
480
  }),
143
481
  window: Object.freeze({
144
482
  ...findTransformTopology("window"),
145
483
  validate: validateWindowTransform,
146
- materializeOp: "materializeWindowData"
484
+ materializeOp: "materializeWindowData",
485
+ replayTransform: requestedTransform,
486
+ editable: true,
487
+ normalizeEdit: normalizeSimple(normalizeWindowTransform),
488
+ outputRoles: windowOutputRoles
147
489
  })
148
490
  });
149
491
 
@@ -155,6 +497,30 @@ export function findTransformValidator(type) {
155
497
  return findTransformPolicy(type)?.validate;
156
498
  }
157
499
 
500
+ export function requestedDatasetTransform(transform) {
501
+ if (!isPlainObject(transform)) {
502
+ throw new TypeError("Requested dataset transform must be a plain object.");
503
+ }
504
+ const policy = findTransformPolicy(transform.type);
505
+ if (policy?.editable !== true) {
506
+ throw new Error(`Dataset transform "${transform.type ?? "unknown"}" is not editable.`);
507
+ }
508
+ return policy.replayTransform?.(transform) ?? requestedTransform(transform);
509
+ }
510
+
511
+ export function normalizeDatasetTransformEdit(transform, patch, owner) {
512
+ const policy = findTransformPolicy(transform?.type);
513
+ if (policy?.editable !== true || typeof policy.normalizeEdit !== "function") {
514
+ throw new Error(`Dataset transform "${transform?.type ?? "unknown"}" is not editable.`);
515
+ }
516
+ return policy.normalizeEdit(transform, patch, owner);
517
+ }
518
+
519
+ export function datasetTransformOutputRoles(transform) {
520
+ const policy = findTransformPolicy(transform?.type);
521
+ return policy?.outputRoles?.(transform) ?? {};
522
+ }
523
+
158
524
  export function validateDatasetTransforms(value) {
159
525
  if (!Array.isArray(value) || value.length !== 1 || !isPlainObject(value[0])) {
160
526
  throw new TypeError(