ggaction 0.0.15 → 0.0.17

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 (270) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +23 -2
  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 +40 -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/boxPlots/components.js +6 -8
  13. package/src/actions/boxPlots/create.js +4 -5
  14. package/src/actions/boxPlots/edit.js +3 -4
  15. package/src/actions/boxPlots/materialize.js +1 -1
  16. package/src/actions/canvas/actions.js +3 -3
  17. package/src/actions/canvas/fitting.js +1 -1
  18. package/src/actions/categoryOrder/index.js +6 -8
  19. package/src/actions/charts/area.js +1 -1
  20. package/src/actions/charts/bar.js +1 -1
  21. package/src/actions/charts/beeswarm.js +1 -1
  22. package/src/actions/charts/density.js +1 -1
  23. package/src/actions/charts/ecdf.js +2 -2
  24. package/src/actions/charts/endpoints.js +4 -4
  25. package/src/actions/charts/heatmap.js +1 -1
  26. package/src/actions/charts/histogram.js +1 -1
  27. package/src/actions/charts/horizon.js +1 -1
  28. package/src/actions/charts/interval-regression.js +2 -2
  29. package/src/actions/charts/line.js +1 -1
  30. package/src/actions/charts/parallel.js +1 -1
  31. package/src/actions/charts/pie.js +1 -1
  32. package/src/actions/charts/polar.js +2 -2
  33. package/src/actions/charts/radar.js +1 -1
  34. package/src/actions/charts/radial.js +2 -2
  35. package/src/actions/charts/raincloud.js +2 -2
  36. package/src/actions/charts/rug-strip.js +2 -2
  37. package/src/actions/charts/scatter.js +1 -1
  38. package/src/actions/composition/actions.js +20 -24
  39. package/src/actions/coordinates/actions.js +1 -1
  40. package/src/actions/coordinates/edit.js +1 -1
  41. package/src/actions/data/basicBin2d.js +4 -5
  42. package/src/actions/data/bin.js +3 -3
  43. package/src/actions/data/bin2d.js +6 -8
  44. package/src/actions/data/bin2dMaterialize.js +4 -5
  45. package/src/actions/data/box.js +4 -4
  46. package/src/actions/data/complete.js +2 -2
  47. package/src/actions/data/computed.js +2 -2
  48. package/src/actions/data/create.js +23 -17
  49. package/src/actions/data/density.js +4 -4
  50. package/src/actions/data/derived.js +25 -15
  51. package/src/actions/data/ecdf.js +2 -2
  52. package/src/actions/data/edit.js +54 -29
  53. package/src/actions/data/filter.js +29 -24
  54. package/src/actions/data/fold.js +2 -2
  55. package/src/actions/data/gradientProfile.js +2 -2
  56. package/src/actions/data/horizon.js +2 -2
  57. package/src/actions/data/impute.js +2 -2
  58. package/src/actions/data/index.js +58 -54
  59. package/src/actions/data/interval.js +4 -2
  60. package/src/actions/data/intervalEdit.js +26 -18
  61. package/src/actions/data/normalize.js +2 -2
  62. package/src/actions/data/regression.js +9 -7
  63. package/src/actions/data/revise.js +80 -0
  64. package/src/actions/data/revisionBindings.js +13 -33
  65. package/src/actions/data/shared.js +30 -2
  66. package/src/actions/data/sort.js +21 -0
  67. package/src/actions/data/stack.js +2 -2
  68. package/src/actions/data/summary.js +3 -3
  69. package/src/actions/data/timeUnit.js +2 -2
  70. package/src/actions/data/window.js +2 -2
  71. package/src/actions/encodings/angle.js +5 -2
  72. package/src/actions/encodings/appearance.js +10 -6
  73. package/src/actions/encodings/barWidth.js +1 -1
  74. package/src/actions/encodings/channels.js +2 -2
  75. package/src/actions/encodings/color/continuous.js +4 -1
  76. package/src/actions/encodings/color/index.js +5 -2
  77. package/src/actions/encodings/density.js +2 -2
  78. package/src/actions/encodings/histogram.js +1 -1
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/offset.js +6 -3
  81. package/src/actions/encodings/parallel.js +4 -5
  82. package/src/actions/encodings/pathOrder.js +6 -11
  83. package/src/actions/encodings/position/index.js +4 -4
  84. package/src/actions/encodings/position/resolve.js +6 -1
  85. package/src/actions/encodings/ranged.js +11 -6
  86. package/src/actions/encodings/remove.js +4 -5
  87. package/src/actions/encodings/ruleAppearance.js +5 -2
  88. package/src/actions/encodings/seriesLayout.js +1 -1
  89. package/src/actions/encodings/stroke.js +5 -2
  90. package/src/actions/encodings/strokeDash.js +8 -3
  91. package/src/actions/encodings/text.js +7 -2
  92. package/src/actions/errorBands/create.js +11 -17
  93. package/src/actions/errorBands/edit.js +13 -131
  94. package/src/actions/errorBars/create.js +8 -13
  95. package/src/actions/errorBars/edit.js +10 -121
  96. package/src/actions/facets/actions.js +30 -16
  97. package/src/actions/facets/derive.js +8 -2
  98. package/src/actions/facets/guides.js +4 -5
  99. package/src/actions/facets/replay.js +4 -5
  100. package/src/actions/gradientPlots/components.js +5 -6
  101. package/src/actions/gradientPlots/create.js +4 -5
  102. package/src/actions/gradientPlots/edit.js +4 -5
  103. package/src/actions/gradientPlots/materialize.js +2 -2
  104. package/src/actions/gradientPlots/rebind.js +4 -5
  105. package/src/actions/guides/axes/axes.js +23 -4
  106. package/src/actions/guides/axes/axis.js +2 -2
  107. package/src/actions/guides/axes/edit.js +2 -2
  108. package/src/actions/guides/axes/labels.js +9 -9
  109. package/src/actions/guides/axes/lines.js +9 -7
  110. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  111. package/src/actions/guides/axes/parallel.js +5 -5
  112. package/src/actions/guides/axes/remove.js +4 -4
  113. package/src/actions/guides/axes/tickGroups.js +4 -4
  114. package/src/actions/guides/axes/ticks.js +13 -4
  115. package/src/actions/guides/axes/titles.js +10 -10
  116. package/src/actions/guides/grids/grid.js +18 -29
  117. package/src/actions/guides/guides.js +1 -1
  118. package/src/actions/guides/legends/blocks.js +1 -1
  119. package/src/actions/guides/legends/categorical/actions.js +4 -4
  120. package/src/actions/guides/legends/categorical/components.js +38 -33
  121. package/src/actions/guides/legends/categorical/layout.js +1 -1
  122. package/src/actions/guides/legends/categorical/symbols.js +27 -30
  123. package/src/actions/guides/legends/continuous/common.js +46 -8
  124. package/src/actions/guides/legends/continuous/gradient.js +89 -155
  125. package/src/actions/guides/legends/continuous/interval.js +13 -13
  126. package/src/actions/guides/legends/continuous/opacity.js +30 -79
  127. package/src/actions/guides/legends/continuous/stroke.js +22 -322
  128. package/src/actions/guides/legends/edit.js +1 -1
  129. package/src/actions/guides/legends/focused.js +5 -5
  130. package/src/actions/guides/legends/lane.js +6 -6
  131. package/src/actions/guides/legends/remove.js +4 -5
  132. package/src/actions/guides/legends/size.js +21 -82
  133. package/src/actions/guides/legends/strokeWidth.js +17 -77
  134. package/src/actions/guides/polar/axes/facade.js +4 -4
  135. package/src/actions/guides/polar/axes/labels.js +5 -5
  136. package/src/actions/guides/polar/axes/lines.js +9 -15
  137. package/src/actions/guides/polar/axes/ticks.js +9 -15
  138. package/src/actions/guides/polar/axes/titles.js +5 -5
  139. package/src/actions/guides/polar/grids.js +11 -13
  140. package/src/actions/index.js +2 -0
  141. package/src/actions/intervals/revision.js +126 -0
  142. package/src/actions/marks/arc/actions.js +3 -3
  143. package/src/actions/marks/area/actions.js +4 -4
  144. package/src/actions/marks/bar/create.js +9 -2
  145. package/src/actions/marks/bar/edit.js +13 -6
  146. package/src/actions/marks/bar/materialize.js +12 -38
  147. package/src/actions/marks/line/actions.js +3 -3
  148. package/src/actions/marks/point/create.js +9 -2
  149. package/src/actions/marks/point/edit.js +13 -6
  150. package/src/actions/marks/point/jitter.js +6 -8
  151. package/src/actions/marks/point/materialize.js +20 -26
  152. package/src/actions/marks/point/packing.js +6 -8
  153. package/src/actions/marks/rect/actions.js +26 -11
  154. package/src/actions/marks/references.js +8 -10
  155. package/src/actions/marks/remove.js +5 -49
  156. package/src/actions/marks/rule/actions.js +28 -12
  157. package/src/actions/marks/text/actions.js +30 -11
  158. package/src/actions/marks/text/layout.js +12 -20
  159. package/src/actions/marks/text/removal.js +1 -1
  160. package/src/actions/marks/text/selection.js +4 -5
  161. package/src/actions/marks/tick/actions.js +26 -11
  162. package/src/actions/primitives/createGraphics.js +5 -4
  163. package/src/actions/primitives/editGraphics.js +5 -4
  164. package/src/actions/primitives/graphicProperties.js +6 -0
  165. package/src/actions/primitives/semantic.js +10 -3
  166. package/src/actions/primitives/semanticAction.js +44 -7
  167. package/src/actions/primitives/semanticValidation/dataset.js +14 -4
  168. package/src/actions/primitives/semanticValidation/layer.js +22 -2
  169. package/src/actions/primitives/semanticValidation/scale.js +6 -0
  170. package/src/actions/regression/components.js +10 -14
  171. package/src/actions/regression/create.js +28 -8
  172. package/src/actions/regression/edit.js +50 -16
  173. package/src/actions/regression/follow.js +22 -0
  174. package/src/actions/resources/remove.js +12 -11
  175. package/src/actions/scales/channels.js +11 -11
  176. package/src/actions/scales/consumers/common.js +2 -1
  177. package/src/actions/scales/create.js +3 -2
  178. package/src/actions/scales/definitions.js +1 -1
  179. package/src/actions/scales/edit.js +2 -2
  180. package/src/actions/scales/materialize.js +1 -1
  181. package/src/actions/scales/offset.js +2 -2
  182. package/src/actions/scales/parallel.js +2 -2
  183. package/src/actions/scales/patch.js +1 -1
  184. package/src/actions/scales/preview.js +28 -1
  185. package/src/actions/scales/quantitativeColor.js +4 -5
  186. package/src/actions/selection/actions.js +25 -36
  187. package/src/actions/textMetrics/index.js +56 -0
  188. package/src/actions/theme/actions.js +2 -2
  189. package/src/actions/theme/reconcile.js +67 -121
  190. package/src/actions/titles/actions.js +8 -8
  191. package/src/actions/titles/resolve.js +3 -3
  192. package/src/actions/violinPlots/create.js +1 -1
  193. package/src/actions/violinPlots/edit.js +1 -1
  194. package/src/core/action.js +109 -36
  195. package/src/core/diagnostics.js +16 -0
  196. package/src/core/extensionRegistry.js +27 -0
  197. package/src/core/font.js +18 -0
  198. package/src/core/identifiers.js +5 -4
  199. package/src/core/immutable.js +10 -3
  200. package/src/core/optionRequirements.js +8 -0
  201. package/src/core/programState.js +6 -2
  202. package/src/core/resourceReferences.js +15 -6
  203. package/src/core/textMetricProfile.js +28 -0
  204. package/src/core/textMetrics.js +24 -3
  205. package/src/core/validation.js +22 -10
  206. package/src/diagnostics.js +1 -0
  207. package/src/grammar/bin.js +39 -10
  208. package/src/grammar/datasetSchema.js +386 -0
  209. package/src/grammar/density.js +53 -5
  210. package/src/grammar/filter.js +133 -39
  211. package/src/grammar/impute.js +3 -2
  212. package/src/grammar/interval.js +32 -1
  213. package/src/grammar/itemMissing.js +59 -0
  214. package/src/grammar/regression/derive.js +57 -16
  215. package/src/grammar/regression/index.js +1 -0
  216. package/src/grammar/regression/models.js +51 -22
  217. package/src/grammar/regression/parameters.js +56 -4
  218. package/src/grammar/scales/definition.js +7 -0
  219. package/src/grammar/scales/types.js +8 -0
  220. package/src/grammar/schemas/graphicBounds.js +11 -11
  221. package/src/grammar/schemas/semanticPath.js +3 -2
  222. package/src/grammar/sort.js +88 -0
  223. package/src/grammar/summary.js +117 -19
  224. package/src/grammar/transformTopology.js +1 -0
  225. package/src/grammar/transforms.js +21 -11
  226. package/src/inspection.js +495 -0
  227. package/src/inspectionDescriptors.js +3 -0
  228. package/src/layout/labels.js +11 -10
  229. package/src/layout/legend.js +4 -4
  230. package/src/layout/legendItems.js +6 -6
  231. package/src/layout/text.js +10 -9
  232. package/src/layout/title.js +9 -9
  233. package/src/materialization/bars/resolve.js +4 -2
  234. package/src/materialization/facetGuides/placement.js +1 -1
  235. package/src/materialization/facetGuides/preparation.js +1 -1
  236. package/src/materialization/facetHeaders.js +11 -10
  237. package/src/materialization/guides/layout.js +3 -3
  238. package/src/materialization/revisionIdentity.js +19 -0
  239. package/src/materialization/scaleGuideDependencies.js +10 -0
  240. package/src/materialization/scales/resolve.js +67 -4
  241. package/src/materialization/selection/items/common.js +1 -1
  242. package/src/materialization/text.js +6 -4
  243. package/src/materialization/typography.js +31 -0
  244. package/src/mcp/cli.js +5 -3
  245. package/src/persistence/codec.js +65 -0
  246. package/src/persistence/validation.js +185 -0
  247. package/src/persistence.js +147 -0
  248. package/src/renderers/canvas/index.js +5 -4
  249. package/src/renderers/nativeBackend.js +10 -0
  250. package/src/renderers/options.js +13 -0
  251. package/src/renderers/pdf.js +25 -54
  252. package/src/renderers/png.js +22 -17
  253. package/src/renderers/svg.js +10 -14
  254. package/src/renderers/text.js +1 -11
  255. package/src/selectors/coordinates.js +3 -1
  256. package/src/selectors/datasets.js +8 -6
  257. package/src/selectors/layers.js +6 -4
  258. package/src/selectors/markOwners.js +46 -0
  259. package/src/selectors/scales.js +6 -4
  260. package/src/theme/defaults.js +2 -1
  261. package/src/version.js +2 -0
  262. package/types/accessibility.d.ts +37 -0
  263. package/types/basic.d.ts +4 -2
  264. package/types/diagnostics.d.ts +15 -0
  265. package/types/index.d.ts +5 -0
  266. package/types/inspection.d.ts +17 -0
  267. package/types/pdf.d.ts +9 -0
  268. package/types/persistence.d.ts +7 -0
  269. package/types/png.d.ts +9 -0
  270. package/types/program.d.ts +181 -28
@@ -8,14 +8,14 @@ const OPTIONS = Object.freeze([
8
8
  "id", "source", "key", "groupBy", "values", "sequence", "fill", "members"
9
9
  ]);
10
10
 
11
- export const materializeCompleteData = derivedMaterializer(
11
+ export const materializeCompleteData = /* @__PURE__ */ derivedMaterializer(
12
12
  "materializeCompleteData",
13
13
  "Materialize one immutable completed-key dataset.",
14
14
  "complete",
15
15
  deriveCompleteRows
16
16
  );
17
17
 
18
- export const createCompleteData = derivedCreator(
18
+ export const createCompleteData = /* @__PURE__ */ derivedCreator(
19
19
  "createCompleteData",
20
20
  "Complete one key domain independently within observed groups.",
21
21
  OPTIONS,
@@ -6,14 +6,14 @@ import { derivedCreator, derivedMaterializer } from "./shared.js";
6
6
 
7
7
  const OPTIONS = Object.freeze(["id", "source", "as", "expression"]);
8
8
 
9
- export const materializeComputedData = derivedMaterializer(
9
+ export const materializeComputedData = /* @__PURE__ */ derivedMaterializer(
10
10
  "materializeComputedData",
11
11
  "Materialize one immutable row-level typed expression dataset.",
12
12
  "computed",
13
13
  deriveComputedRows
14
14
  );
15
15
 
16
- export const createComputedData = derivedCreator(
16
+ export const createComputedData = /* @__PURE__ */ derivedCreator(
17
17
  "createComputedData",
18
18
  "Create a typed computed field from a closed expression.",
19
19
  OPTIONS,
@@ -1,33 +1,39 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { resolveOptionalUserId } from "../../core/identifiers.js";
3
- import { isPlainObject } from "../../core/immutable.js";
4
- import { validateKeys } from "../../core/validation.js";
3
+ import { validateDataRows } from "../../core/validation.js";
5
4
  import { hasDataset, hasDatasetOwner } from "../../selectors/index.js";
5
+ import {
6
+ inferDatasetSchema,
7
+ normalizeSourceSchema,
8
+ validateRowsAgainstSchema
9
+ } from "../../grammar/datasetSchema.js";
6
10
 
7
- const OPTIONS = Object.freeze(["id", "values"]);
11
+ const OPTIONS = Object.freeze(["id", "values", "schema"]);
8
12
 
9
- export const createData = action(
10
- { op: "createData", description: "Create an immutable named dataset." },
13
+ export const createData = /* @__PURE__ */ closedAction(
14
+ { op: "createData", description: "Create an immutable named dataset." }, OPTIONS,
11
15
  function (args = {}) {
12
- validateKeys(args, OPTIONS, "createData");
13
16
  const id = resolveOptionalUserId(args.id, {
14
17
  defaultId: "data",
15
18
  label: "Dataset id",
16
19
  operation: "createData",
17
20
  ambiguous: this.semanticSpec.datasets.length > 0
18
21
  });
19
- if (!Array.isArray(args.values)) {
20
- throw new TypeError("createData requires values to be an array.");
21
- }
22
- if (!args.values.every(isPlainObject)) {
23
- throw new TypeError("createData requires every row to be a plain object.");
24
- }
22
+ validateDataRows(args.values, "createData");
23
+ const schema = args.schema === undefined
24
+ ? inferDatasetSchema(args.values)
25
+ : normalizeSourceSchema(args.schema);
26
+ validateRowsAgainstSchema(args.values, schema, "createData");
25
27
  if (hasDataset(this, id) || hasDatasetOwner(this, id)) {
26
28
  throw new Error(`Dataset "${id}" already exists.`);
27
29
  }
28
- return this.editSemantic({
29
- property: `dataset[${id}].values`,
30
- value: args.values
31
- });
30
+ // Keep the historical one-primitive trace for inferred sources. The
31
+ // semantic primitive owns deterministic inference so a dataset never
32
+ // exists between actions without its schema.
33
+ return args.schema === undefined
34
+ ? this.editSemantic({ property: `dataset[${id}].values`, value: args.values })
35
+ : this
36
+ .editSemantic({ property: `dataset[${id}].schema`, value: schema })
37
+ .editSemantic({ property: `dataset[${id}].values`, value: args.values });
32
38
  }
33
39
  );
@@ -6,7 +6,7 @@ import { derivedCreator, derivedMaterializer } from "./shared.js";
6
6
 
7
7
  const OPTIONS = Object.freeze([
8
8
  "id", "source", "field", "groupBy", "bandwidth", "extent", "steps",
9
- "kernel", "normalization", "as", "weight"
9
+ "kernel", "normalization", "as", "weight", "missing"
10
10
  ]);
11
11
  const CATEGORICAL_OPTIONS = Object.freeze([...OPTIONS, "placement"]);
12
12
 
@@ -25,7 +25,7 @@ function requestedTransform(args, op, categorical = false) {
25
25
  });
26
26
  }
27
27
 
28
- export const materializeDensityData = derivedMaterializer(
28
+ export const materializeDensityData = /* @__PURE__ */ derivedMaterializer(
29
29
  "materializeDensityData",
30
30
  "Materialize one grouped kernel-density dataset.",
31
31
  "density",
@@ -44,7 +44,7 @@ export const materializeDensityData = derivedMaterializer(
44
44
  }]
45
45
  );
46
46
 
47
- export const createDensityData = derivedCreator(
47
+ export const createDensityData = /* @__PURE__ */ derivedCreator(
48
48
  "createDensityData",
49
49
  "Create grouped kernel-density values.",
50
50
  OPTIONS,
@@ -54,7 +54,7 @@ export const createDensityData = derivedCreator(
54
54
  "materializeDensityData"
55
55
  );
56
56
 
57
- export const createCategoricalDensityData = derivedCreator(
57
+ export const createCategoricalDensityData = /* @__PURE__ */ derivedCreator(
58
58
  "createCategoricalDensityData",
59
59
  "Create category-placed kernel-density values.",
60
60
  CATEGORICAL_OPTIONS,
@@ -1,6 +1,6 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import { validateKeys } from "../../core/validation.js";
3
+
4
4
  import {
5
5
  findDataset,
6
6
  hasDataset,
@@ -11,6 +11,10 @@ import { requireLayer } from "../../selectors/layers.js";
11
11
  import { applyLayerDataRematerialization } from
12
12
  "../../materialization/dependencies.js";
13
13
  import { collectResourceReferences } from "../../core/resourceReferences.js";
14
+ import {
15
+ assertFieldsAvailable,
16
+ transformInputFields
17
+ } from "../../grammar/datasetSchema.js";
14
18
 
15
19
  const OPTIONS = Object.freeze(["id", "source", "transform"]);
16
20
  const RELEASE_OPTIONS = Object.freeze(["id"]);
@@ -27,10 +31,9 @@ const OWNED_MARK_ROLES = Object.freeze([
27
31
  "statisticalReference"
28
32
  ]);
29
33
 
30
- export const createDerivedData = action(
31
- { op: "createDerivedData", description: "Create an immutable derived dataset definition." },
34
+ export const createDerivedData = /* @__PURE__ */ closedAction(
35
+ { op: "createDerivedData", description: "Create an immutable derived dataset definition." }, OPTIONS,
32
36
  function (args = {}) {
33
- validateKeys(args, OPTIONS, "createDerivedData");
34
37
  const id = validateUserId(args.id, "Derived dataset id");
35
38
  const requestedSource = validateUserId(args.source, "Source dataset id");
36
39
  const source = resolveDatasetReference(
@@ -44,19 +47,25 @@ export const createDerivedData = action(
44
47
  if (!hasDataset(this, source)) {
45
48
  throw new Error(`Unknown source dataset "${source}".`);
46
49
  }
47
- return this
50
+ const created = this
48
51
  .editSemantic({ property: `dataset[${id}].source`, value: source })
49
52
  .editSemantic({ property: `dataset[${id}].transform`, value: args.transform });
53
+ const input = resolveDatasetReference(created, source, "Source dataset");
54
+ const transform = args.transform[0];
55
+ assertFieldsAvailable(input.schema, transformInputFields(transform), {
56
+ data: input.id,
57
+ operation: "createDerivedData"
58
+ });
59
+ return created;
50
60
  }
51
61
  );
52
62
 
53
- export const releaseDerivedData = action(
63
+ export const releaseDerivedData = /* @__PURE__ */ closedAction(
54
64
  {
55
65
  op: "releaseDerivedData",
56
66
  description: "Release one unreferenced derived dataset."
57
- },
67
+ }, RELEASE_OPTIONS,
58
68
  function (args = {}) {
59
- validateKeys(args, RELEASE_OPTIONS, "releaseDerivedData");
60
69
  const validatedId = validateUserId(args.id, "Derived dataset id");
61
70
  const dataset = findDataset(this, validatedId);
62
71
  if (dataset === undefined || dataset.source === undefined) {
@@ -77,6 +86,9 @@ export const releaseDerivedData = action(
77
86
  property: `dataset[${validatedId}]`,
78
87
  remove: true
79
88
  });
89
+ next = next._withoutMaterializationConfig([
90
+ "calculations", "datasets", validatedId
91
+ ]);
80
92
  for (const owner of selfOwners) {
81
93
  const [, family, ownerId] = owner.path;
82
94
  next = next._withoutMaterializationConfig(["data", family, ownerId]);
@@ -85,13 +97,12 @@ export const releaseDerivedData = action(
85
97
  }
86
98
  );
87
99
 
88
- export const rebindLayerData = action(
100
+ export const rebindLayerData = /* @__PURE__ */ closedAction(
89
101
  {
90
102
  op: "rebindLayerData",
91
103
  description: "Rebind one semantic layer to an existing dataset."
92
- },
104
+ }, REBIND_OPTIONS,
93
105
  function (args = {}) {
94
- validateKeys(args, REBIND_OPTIONS, "rebindLayerData");
95
106
  const id = validateUserId(args.id, "Layer id");
96
107
  const requestedData = validateUserId(args.data, "Layer dataset id");
97
108
  const data = resolveDatasetReference(
@@ -134,13 +145,12 @@ function applyMarkDataBinding(program, target, data) {
134
145
  return applyLayerDataRematerialization(rebound, target);
135
146
  }
136
147
 
137
- export const bindMarkData = action(
148
+ export const bindMarkData = /* @__PURE__ */ closedAction(
138
149
  {
139
150
  op: "bindMarkData",
140
151
  description: "Atomically bind one independent mark to materialized data."
141
- },
152
+ }, BIND_OPTIONS,
142
153
  function (args = {}) {
143
- validateKeys(args, BIND_OPTIONS, "bindMarkData");
144
154
  const target = validateUserId(args.target, "Mark target id");
145
155
  const requestedData = validateUserId(args.data, "Mark dataset id");
146
156
  const data = resolveDatasetReference(
@@ -9,7 +9,7 @@ const OPTIONS = Object.freeze([
9
9
  "id", "source", "field", "groupBy", "weight", "missing", "as"
10
10
  ]);
11
11
 
12
- export const materializeECDFData = derivedMaterializer(
12
+ export const materializeECDFData = /* @__PURE__ */ derivedMaterializer(
13
13
  "materializeECDFData",
14
14
  "Materialize one empirical cumulative distribution dataset.",
15
15
  "ecdf",
@@ -17,7 +17,7 @@ export const materializeECDFData = derivedMaterializer(
17
17
  resolveECDFTransform
18
18
  );
19
19
 
20
- export const createECDFData = derivedCreator(
20
+ export const createECDFData = /* @__PURE__ */ derivedCreator(
21
21
  "createECDFData",
22
22
  "Create immutable empirical cumulative distribution values.",
23
23
  OPTIONS,
@@ -1,4 +1,4 @@
1
- import { action } from "../../core/action.js";
1
+ import { action, closedAction } from "../../core/action.js";
2
2
  import { isPlainObject } from "../../core/immutable.js";
3
3
  import { validateUserId } from "../../core/identifiers.js";
4
4
  import { validateKeys } from "../../core/validation.js";
@@ -13,6 +13,8 @@ import {
13
13
  } from "../../selectors/datasets.js";
14
14
  import { applyLayerDataRematerialization } from
15
15
  "../../materialization/dependencies.js";
16
+ import { withLogicalDataReplacements } from
17
+ "../../materialization/revisionIdentity.js";
16
18
  import {
17
19
  outputFieldChanges,
18
20
  rebindLayerOutputFields,
@@ -36,6 +38,7 @@ const CREATOR_BY_TYPE = Object.freeze({
36
38
  interval: "createIntervalData",
37
39
  normalize: "createNormalizedData",
38
40
  regression: "createRegressionData",
41
+ sort: "createSortedData",
39
42
  stack: "createStackData",
40
43
  summary: "createSummaryData",
41
44
  timeUnit: "createTimeUnitData",
@@ -54,6 +57,7 @@ const REVISION_ROLE = Object.freeze({
54
57
  interval: "IntervalData",
55
58
  normalize: "NormalizedData",
56
59
  regression: "RegressionData",
60
+ sort: "SortedData",
57
61
  stack: "StackData",
58
62
  summary: "SummaryData",
59
63
  timeUnit: "TimeUnitData",
@@ -254,7 +258,7 @@ function buildRevisionPlan(
254
258
  `Derived dataset "${resolved.owner}" cannot use one of its dependents as source.`
255
259
  );
256
260
  }
257
- const reserved = new Set();
261
+ const reserved = new Set(resolved.revision === undefined ? [] : [resolved.revision]);
258
262
  const revisions = [];
259
263
  const replacements = new Map();
260
264
  const add = (dataset, ownerRecord, transform, requestedSource) => {
@@ -274,7 +278,12 @@ function buildRevisionPlan(
274
278
  revisions.push(revision);
275
279
  replacements.set(dataset.id, id);
276
280
  };
277
- add(resolved.dataset, resolved, definition, rootSource);
281
+ if (resolved.revision === undefined) {
282
+ add(resolved.dataset, resolved, definition, rootSource);
283
+ } else {
284
+ revisions.push({ old: resolved.current, id: resolved.revision });
285
+ replacements.set(resolved.current, resolved.revision);
286
+ }
278
287
  if (dependents === "recompute") {
279
288
  for (const dataset of downstream) {
280
289
  const policy = findTransformPolicy(dataset.transform[0].type);
@@ -292,14 +301,20 @@ function directLayerConsumers(program, data) {
292
301
  .map(layer => layer.id);
293
302
  }
294
303
 
295
- function applyRevisionPlan(program, resolved, plan) {
304
+ export function applyRevisionPlan(program, resolved, plan, { retain = new Set() } = {}) {
305
+ return withLogicalDataReplacements(plan.replacements, () =>
306
+ applyRevisionPlanWithIdentity(program, resolved, plan, { retain }));
307
+ }
308
+
309
+ function applyRevisionPlanWithIdentity(program, resolved, plan, { retain }) {
296
310
  const root = plan.revisions[0];
297
- const changes = outputFieldChanges(
311
+ const changes = resolved === undefined ? new Map() : outputFieldChanges(
298
312
  resolved.dataset.transform[0],
299
313
  root.transform
300
314
  );
301
315
  let next = program;
302
316
  for (const revision of plan.revisions) {
317
+ if (revision.transform === undefined) continue;
303
318
  const policy = findTransformPolicy(revision.transform.type);
304
319
  next = next.createDerivedData({
305
320
  id: revision.id,
@@ -345,6 +360,7 @@ function applyRevisionPlan(program, resolved, plan) {
345
360
  next = applyLayerDataRematerialization(next, consumer.id);
346
361
  }
347
362
  for (const revision of [...plan.revisions].reverse()) {
363
+ if (retain.has(revision.old)) continue;
348
364
  next = next.releaseDerivedData({ id: revision.old });
349
365
  }
350
366
 
@@ -353,6 +369,12 @@ function applyRevisionPlan(program, resolved, plan) {
353
369
  return next._withContext({ ...program.context, currentData });
354
370
  }
355
371
 
372
+ export function buildSourceRevisionPlan(program, source, id) {
373
+ return buildRevisionPlan(program, {
374
+ current: source, dataset: findDataset(program, source), revision: id
375
+ }, undefined, "recompute");
376
+ }
377
+
356
378
  function sameRequested(left, right) {
357
379
  return JSON.stringify(left) === JSON.stringify(right);
358
380
  }
@@ -375,13 +397,12 @@ export function reviseDerivedData(program, {
375
397
  return applyRevisionPlan(program, resolved, plan);
376
398
  }
377
399
 
378
- export const editDerivedData = action(
400
+ export const editDerivedData = /* @__PURE__ */ closedAction(
379
401
  {
380
402
  op: "editDerivedData",
381
403
  description: "Atomically revise one standalone derived-data definition."
382
- },
404
+ }, GENERIC_OPTIONS,
383
405
  function (args = {}) {
384
- validateKeys(args, GENERIC_OPTIONS, "editDerivedData");
385
406
  if (!Object.hasOwn(args, "target")) {
386
407
  throw new TypeError("editDerivedData requires target.");
387
408
  }
@@ -448,72 +469,75 @@ function focusedEditor(op, type, properties) {
448
469
  );
449
470
  }
450
471
 
451
- export const editComputedData = focusedEditor(
472
+ export const editComputedData = /* @__PURE__ */ focusedEditor(
452
473
  "editComputedData", "computed", ["as", "expression"]
453
474
  );
454
- export const editFilteredData = focusedEditor(
455
- "editFilteredData", "filter", ["field", "oneOf", "predicate", "range"]
475
+ export const editFilteredData = /* @__PURE__ */ focusedEditor(
476
+ "editFilteredData", "filter", ["field", "oneOf", "noneOf", "predicate", "range", "nulls"]
456
477
  );
457
- export const editFoldData = focusedEditor(
478
+ export const editFoldData = /* @__PURE__ */ focusedEditor(
458
479
  "editFoldData", "fold", ["fields", "as"]
459
480
  );
460
- export const editSummaryData = focusedEditor(
461
- "editSummaryData", "summary", ["groupBy", "aggregates", "members", "weight"]
481
+ export const editSummaryData = /* @__PURE__ */ focusedEditor(
482
+ "editSummaryData", "summary", ["groupBy", "aggregates", "members", "weight", "missing", "empty"]
462
483
  );
463
- export const editBinData = focusedEditor(
484
+ export const editBinData = /* @__PURE__ */ focusedEditor(
464
485
  "editBinData", "bin", [
465
486
  "field", "maxBins", "step", "boundaries", "extent", "nice", "zero",
466
- "includeEmpty", "members", "as", "weight"
487
+ "includeEmpty", "members", "as", "weight", "missing"
467
488
  ]
468
489
  );
469
- export const editTimeUnitData = focusedEditor(
490
+ export const editTimeUnitData = /* @__PURE__ */ focusedEditor(
470
491
  "editTimeUnitData", "timeUnit", [
471
492
  "field", "unit", "as", "temporalUnit", "timeZone", "weekStartsOn",
472
493
  "weekRule"
473
494
  ]
474
495
  );
475
- export const editWindowData = focusedEditor(
496
+ export const editWindowData = /* @__PURE__ */ focusedEditor(
476
497
  "editWindowData", "window", [
477
498
  "partitionBy", "sortBy", "operations", "temporalUnit"
478
499
  ]
479
500
  );
480
- export const editDensityData = focusedEditor(
501
+ export const editDensityData = /* @__PURE__ */ focusedEditor(
481
502
  "editDensityData", "density", [
482
503
  "field", "groupBy", "bandwidth", "extent", "steps", "kernel",
483
- "normalization", "as", "weight"
504
+ "normalization", "as", "weight", "missing"
484
505
  ]
485
506
  );
486
- export const editStackData = focusedEditor(
507
+ export const editStackData = /* @__PURE__ */ focusedEditor(
487
508
  "editStackData", "stack", ["category", "group", "value", "mode", "as"]
488
509
  );
489
- export const editRegressionData = focusedEditor(
510
+ export const editRegressionData = /* @__PURE__ */ focusedEditor(
490
511
  "editRegressionData", "regression", [
491
512
  "x", "y", "groupBy", "method", "degree", "span", "confidenceMethod",
492
- "level", "confidence", "interval"
513
+ "level", "confidence", "interval", "predict"
493
514
  ]
494
515
  );
495
- export const editIntervalData = focusedEditor(
516
+ export const editSortedData = /* @__PURE__ */ focusedEditor(
517
+ "editSortedData", "sort", ["sortBy"]
518
+ );
519
+ export const editIntervalData = /* @__PURE__ */ focusedEditor(
496
520
  "editIntervalData", "interval", [
497
- "field", "groupBy", "center", "extent", "method", "level", "as"
521
+ "field", "groupBy", "center", "extent", "method", "level", "missing", "as"
498
522
  ]
499
523
  );
500
- export const editECDFData = focusedEditor(
524
+ export const editECDFData = /* @__PURE__ */ focusedEditor(
501
525
  "editECDFData", "ecdf", [
502
526
  "field", "groupBy", "weight", "missing", "as"
503
527
  ]
504
528
  );
505
- export const editNormalizedData = focusedEditor(
529
+ export const editNormalizedData = /* @__PURE__ */ focusedEditor(
506
530
  "editNormalizedData", "normalize", [
507
531
  "field", "as", "groupBy", "method", "variance", "zeroDenominator",
508
532
  "baseline", "sortBy"
509
533
  ]
510
534
  );
511
- export const editCompleteData = focusedEditor(
535
+ export const editCompleteData = /* @__PURE__ */ focusedEditor(
512
536
  "editCompleteData", "complete", [
513
537
  "key", "groupBy", "values", "sequence", "fill", "members"
514
538
  ]
515
539
  );
516
- export const editImputedData = focusedEditor(
540
+ export const editImputedData = /* @__PURE__ */ focusedEditor(
517
541
  "editImputedData", "impute", [
518
542
  "fields", "groupBy", "sortBy", "method", "value", "edges", "maxGap"
519
543
  ]
@@ -531,6 +555,7 @@ export const EDIT_DERIVED_DATA_ACTIONS = Object.freeze({
531
555
  editDensityData,
532
556
  editStackData,
533
557
  editRegressionData,
558
+ editSortedData,
534
559
  editIntervalData,
535
560
  editECDFData,
536
561
  editNormalizedData,
@@ -1,6 +1,6 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import { validateKeys } from "../../core/validation.js";
3
+
4
4
  import { withPreviewDatasetValues } from
5
5
  "../primitives/semanticAction.js";
6
6
  import {
@@ -27,9 +27,14 @@ import {
27
27
  resolveEligibleLayer
28
28
  } from "../../selectors/index.js";
29
29
  import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
30
+ import {
31
+ assertFieldsAvailable,
32
+ deriveTransformSchema,
33
+ transformInputFields
34
+ } from "../../grammar/datasetSchema.js";
30
35
 
31
36
  const OPTIONS = Object.freeze([
32
- "id", "source", "field", "oneOf", "predicate", "range"
37
+ "id", "source", "field", "oneOf", "noneOf", "predicate", "range", "nulls"
33
38
  ]);
34
39
  const MARK_SELECTOR_KEYS = Object.freeze([
35
40
  "grain", "field", "channel", "property", "op", "value", "values",
@@ -50,26 +55,30 @@ function retainedHistogramBoundaries(layer, items) {
50
55
  return boundaries.length < 2 ? undefined : boundaries;
51
56
  }
52
57
 
53
- export const materializeFilteredData = action(
54
- { op: "materializeFilteredData", description: "Materialize one filtered derived dataset." },
58
+ export const materializeFilteredData = /* @__PURE__ */ closedAction(
59
+ { op: "materializeFilteredData", description: "Materialize one filtered derived dataset." }, MATERIALIZE_OPTIONS,
55
60
  function (args = {}) {
56
- validateKeys(args, MATERIALIZE_OPTIONS, "materializeFilteredData");
57
61
  const { id, source, transform } = requireDerivedDataset(
58
62
  this,
59
63
  args.id,
60
64
  "filter"
61
65
  );
62
- return this.editSemantic({
63
- property: `dataset[${id}].values`,
64
- value: deriveFilteredRows(source.values, transform)
66
+ assertFieldsAvailable(source.schema, transformInputFields(transform), {
67
+ data: source.id,
68
+ operation: "materializeFilteredData"
69
+ });
70
+ const values = deriveFilteredRows(source.values, transform);
71
+ const schema = deriveTransformSchema(source.schema, transform, values, {
72
+ sourceId: source.id,
73
+ ownerId: id
65
74
  });
75
+ return this.editSemantic({ property: `dataset[${id}].values`, value: values });
66
76
  }
67
77
  );
68
78
 
69
- export const filterData = action(
70
- { op: "filterData", description: "Create a named dataset from one field filter." },
79
+ export const filterData = /* @__PURE__ */ closedAction(
80
+ { op: "filterData", description: "Create a named dataset from one field filter." }, OPTIONS,
71
81
  function (args = {}) {
72
- validateKeys(args, OPTIONS, "filterData");
73
82
  const id = validateUserId(args.id, "Filtered dataset id");
74
83
  const requestedSource = validateUserId(
75
84
  args.source ?? this.context.currentData,
@@ -97,13 +106,12 @@ export const filterData = action(
97
106
  }
98
107
  );
99
108
 
100
- export const materializeMarkFilteredData = action(
109
+ export const materializeMarkFilteredData = /* @__PURE__ */ closedAction(
101
110
  {
102
111
  op: "materializeMarkFilteredData",
103
112
  description: "Materialize member rows retained by one final-item mark selection."
104
- },
113
+ }, MATERIALIZE_OPTIONS,
105
114
  function (args = {}) {
106
- validateKeys(args, MATERIALIZE_OPTIONS, "materializeMarkFilteredData");
107
115
  const { id, dataset, source, transform } = requireDerivedDataset(
108
116
  this,
109
117
  args.id,
@@ -170,13 +178,12 @@ export const materializeMarkFilteredData = action(
170
178
  }
171
179
  );
172
180
 
173
- export const materializeEmptyMark = action(
181
+ export const materializeEmptyMark = /* @__PURE__ */ closedAction(
174
182
  {
175
183
  op: "materializeEmptyMark",
176
184
  description: "Clear one active empty-filter mark without changing its domains."
177
- },
185
+ }, EMPTY_MARK_OPTIONS,
178
186
  function (args = {}) {
179
- validateKeys(args, EMPTY_MARK_OPTIONS, "materializeEmptyMark");
180
187
  const id = validateUserId(args.id, "Empty mark id");
181
188
  const layer = requireLayer(this, id);
182
189
  const owner = this.markConfigs[id]?.markFilter;
@@ -261,13 +268,12 @@ function sameSelector(left, right) {
261
268
  return JSON.stringify(left) === JSON.stringify(right);
262
269
  }
263
270
 
264
- export const removeMarkFilter = action(
271
+ export const removeMarkFilter = /* @__PURE__ */ closedAction(
265
272
  {
266
273
  op: "removeMarkFilter",
267
274
  description: "Remove one active final-item filter and restore its source."
268
- },
275
+ }, REMOVE_MARK_FILTER_OPTIONS,
269
276
  function (args = {}) {
270
- validateKeys(args, REMOVE_MARK_FILTER_OPTIONS, "removeMarkFilter");
271
277
  const target = args.target === undefined
272
278
  ? undefined
273
279
  : validateUserId(args.target, "Mark filter target id");
@@ -280,13 +286,12 @@ export const removeMarkFilter = action(
280
286
  }
281
287
  );
282
288
 
283
- export const filterMarks = action(
289
+ export const filterMarks = /* @__PURE__ */ closedAction(
284
290
  {
285
291
  op: "filterMarks",
286
292
  description: "Retain selected final mark items through immutable derived data."
287
- },
293
+ }, MARK_OPTIONS,
288
294
  function (args = {}) {
289
- validateKeys(args, MARK_OPTIONS, "filterMarks");
290
295
  if (args.mode !== undefined && !["replace", "compose"].includes(args.mode)) {
291
296
  throw new Error(`Unknown mark filter mode "${args.mode}".`);
292
297
  }
@@ -6,14 +6,14 @@ import { derivedCreator, derivedMaterializer } from "./shared.js";
6
6
 
7
7
  const OPTIONS = Object.freeze(["id", "source", "fields", "as"]);
8
8
 
9
- export const materializeFoldData = derivedMaterializer(
9
+ export const materializeFoldData = /* @__PURE__ */ derivedMaterializer(
10
10
  "materializeFoldData",
11
11
  "Materialize one immutable wide-to-long dataset.",
12
12
  "fold",
13
13
  deriveFoldRows
14
14
  );
15
15
 
16
- export const createFoldData = derivedCreator(
16
+ export const createFoldData = /* @__PURE__ */ derivedCreator(
17
17
  "createFoldData",
18
18
  "Create reusable key/value rows from selected wide fields.",
19
19
  OPTIONS,
@@ -9,7 +9,7 @@ const OPTIONS = Object.freeze([
9
9
  "kernel", "normalization", "center", "as"
10
10
  ]);
11
11
 
12
- export const materializeGradientProfileData = derivedMaterializer(
12
+ export const materializeGradientProfileData = /* @__PURE__ */ derivedMaterializer(
13
13
  "materializeGradientProfileData",
14
14
  "Materialize one categorical density-profile dataset.",
15
15
  "gradientProfile",
@@ -24,7 +24,7 @@ export const materializeGradientProfileData = derivedMaterializer(
24
24
  }]
25
25
  );
26
26
 
27
- export const createGradientProfileData = derivedCreator(
27
+ export const createGradientProfileData = /* @__PURE__ */ derivedCreator(
28
28
  "createGradientProfileData",
29
29
  "Create one immutable categorical density-profile dataset.",
30
30
  OPTIONS,
@@ -26,7 +26,7 @@ function requestedTransform(args) {
26
26
  });
27
27
  }
28
28
 
29
- export const materializeHorizonData = derivedMaterializer(
29
+ export const materializeHorizonData = /* @__PURE__ */ derivedMaterializer(
30
30
  "materializeHorizonData",
31
31
  "Materialize one immutable Horizon band dataset.",
32
32
  "horizon",
@@ -34,7 +34,7 @@ export const materializeHorizonData = derivedMaterializer(
34
34
  result => [{ ...result.transform, resolved: result.resolved }]
35
35
  );
36
36
 
37
- export const createHorizonData = derivedCreator(
37
+ export const createHorizonData = /* @__PURE__ */ derivedCreator(
38
38
  "createHorizonData",
39
39
  "Create one immutable Horizon band dataset.",
40
40
  OPTIONS,