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
@@ -16,7 +16,7 @@ import {
16
16
  } from "./weightedStatistics.js";
17
17
 
18
18
  const TRANSFORM_KEYS = Object.freeze([
19
- "type", "groupBy", "aggregates", "members", "weight"
19
+ "type", "groupBy", "aggregates", "members", "weight", "missing", "empty"
20
20
  ]);
21
21
  const AGGREGATE_KEYS = Object.freeze(["op", "field", "as"]);
22
22
  const NOMINAL_OPERATIONS = new Set(["distinct", "valid", "missing"]);
@@ -51,7 +51,7 @@ function normalizeAggregate(value) {
51
51
  };
52
52
  }
53
53
 
54
- export function normalizeSummaryTransform({ groupBy, aggregates, members, weight } = {}) {
54
+ export function normalizeSummaryTransform({ groupBy, aggregates, members, weight, missing, empty } = {}) {
55
55
  const transform = {
56
56
  type: "summary",
57
57
  groupBy: normalizeGroupBy(groupBy),
@@ -61,7 +61,9 @@ export function normalizeSummaryTransform({ groupBy, aggregates, members, weight
61
61
  ...(members === undefined ? {} : { members }),
62
62
  ...(weight === undefined
63
63
  ? {}
64
- : { weight: normalizeStatisticalWeight(weight, "Summary weight") })
64
+ : { weight: normalizeStatisticalWeight(weight, "Summary weight") }),
65
+ ...(missing === undefined ? {} : { missing }),
66
+ ...(empty === undefined ? {} : { empty })
65
67
  };
66
68
  validateSummaryTransform(transform);
67
69
  return cloneAndFreeze(transform);
@@ -120,6 +122,12 @@ export function validateSummaryTransform(transform) {
120
122
  if (transform.weight !== undefined) {
121
123
  normalizeStatisticalWeight(transform.weight, "Summary weight");
122
124
  }
125
+ if (transform.missing !== undefined && !["error", "drop"].includes(transform.missing)) {
126
+ throw new Error('Summary missing must be "error" or "drop".');
127
+ }
128
+ if (transform.empty !== undefined && !["null", "identity"].includes(transform.empty)) {
129
+ throw new Error('Summary empty must be "null" or "identity".');
130
+ }
123
131
  return transform;
124
132
  }
125
133
 
@@ -169,12 +177,13 @@ function validateAggregateValues(rows, aggregate) {
169
177
  export function deriveSummaryRows(rows, transform) {
170
178
  validateSummaryTransform(transform);
171
179
  requireSourceFields(rows, transform);
180
+ const explicitWeighted = transform.weight !== undefined && transform.missing !== undefined;
172
181
  let weightEntries;
173
182
  if (transform.weight === undefined) {
174
183
  for (const aggregate of transform.aggregates) {
175
184
  validateAggregateValues(rows, aggregate);
176
185
  }
177
- } else {
186
+ } else if (!explicitWeighted) {
178
187
  weightEntries = readStatisticalWeights(rows, transform.weight, "Summary").entries;
179
188
  validateWeightedNumericFields(
180
189
  weightEntries,
@@ -183,6 +192,37 @@ export function deriveSummaryRows(rows, transform) {
183
192
  ))],
184
193
  "Summary"
185
194
  );
195
+ } else {
196
+ // Explicit missing policy is evaluated per measure. Validate every
197
+ // nonmissing value now, while leaving nullish value/weight pairs for the
198
+ // reason-priority accounting below.
199
+ readStatisticalWeights(
200
+ rows.filter(row => row[transform.weight.field] !== null && row[transform.weight.field] !== undefined),
201
+ transform.weight,
202
+ "Summary"
203
+ );
204
+ for (const aggregate of transform.aggregates) {
205
+ if (aggregate.field === undefined) continue;
206
+ validateAggregateValues(
207
+ rows.filter(row => row[aggregate.field] !== null && row[aggregate.field] !== undefined),
208
+ aggregate
209
+ );
210
+ }
211
+ }
212
+ if (transform.missing === "error") {
213
+ if (transform.weight !== undefined) {
214
+ const weightIndex = rows.findIndex(row =>
215
+ row[transform.weight.field] === null || row[transform.weight.field] === undefined
216
+ );
217
+ if (weightIndex !== -1) {
218
+ throw new TypeError(`Summary weight "${transform.weight.field}" is missing at row ${weightIndex}.`);
219
+ }
220
+ }
221
+ for (const aggregate of transform.aggregates) {
222
+ if (aggregate.field === undefined) continue;
223
+ const index = rows.findIndex(row => row[aggregate.field] === null || row[aggregate.field] === undefined);
224
+ if (index !== -1) throw new TypeError(`Summary field "${aggregate.field}" is missing at row ${index}.`);
225
+ }
186
226
  }
187
227
 
188
228
  const groups = new Map();
@@ -212,34 +252,92 @@ export function deriveSummaryRows(rows, transform) {
212
252
  throw new RangeError(`Summary output cannot exceed ${MAX_OUTPUT_ROWS} groups.`);
213
253
  }
214
254
 
215
- return [...groups.values()].map(group => {
216
- const weightSummary = transform.weight === undefined
255
+ const units = [];
256
+ const values = [...groups.values()].map(group => {
257
+ const sharedWeightSummary = transform.weight === undefined || explicitWeighted
217
258
  ? undefined
218
259
  : summarizeStatisticalWeights(
219
260
  group.entries,
220
261
  transform.weight.kind,
221
262
  "Summary group"
222
263
  );
264
+ const aggregated = Object.fromEntries(transform.aggregates.map(aggregate => {
265
+ let missingValue = 0;
266
+ let missingWeight = 0;
267
+ let zeroWeightRows = 0;
268
+ let measureWeightSummary = sharedWeightSummary;
269
+ if (explicitWeighted) {
270
+ const eligible = group.rows.filter(row => {
271
+ if (aggregate.field !== undefined &&
272
+ (row[aggregate.field] === null || row[aggregate.field] === undefined)) {
273
+ missingValue += 1;
274
+ return false;
275
+ }
276
+ if (row[transform.weight.field] === null || row[transform.weight.field] === undefined) {
277
+ missingWeight += 1;
278
+ return false;
279
+ }
280
+ return true;
281
+ });
282
+ const entries = readStatisticalWeights(eligible, transform.weight, "Summary").entries;
283
+ zeroWeightRows = entries.filter(entry => entry.weight === 0).length;
284
+ measureWeightSummary = summarizeStatisticalWeights(
285
+ entries,
286
+ transform.weight.kind,
287
+ "Summary group"
288
+ );
289
+ }
290
+ let value = measureWeightSummary === undefined
291
+ ? aggregateRows(group.rows, aggregate.field ?? "__row", aggregate.op)
292
+ : calculateWeightedAggregate(
293
+ measureWeightSummary,
294
+ aggregate.field,
295
+ aggregate.op,
296
+ `Summary aggregate "${aggregate.as}"`
297
+ );
298
+ if (value === undefined && transform.empty !== undefined) {
299
+ const op = typeof aggregate.op === "string" ? aggregate.op : aggregate.op.op;
300
+ value = transform.empty === "identity" && op === "sum" ? 0 : null;
301
+ }
302
+ if (transform.missing !== undefined || transform.empty !== undefined) {
303
+ const missing = explicitWeighted
304
+ ? missingValue + missingWeight
305
+ : aggregate.field === undefined ? 0 : group.rows.filter(row => row[aggregate.field] === null || row[aggregate.field] === undefined).length;
306
+ units.push({
307
+ role: aggregate.as,
308
+ group: group.values,
309
+ inputRows: group.rows.length,
310
+ usedRows: group.rows.length - missing,
311
+ excludedRows: missing,
312
+ excludedByReason: missing === 0 ? {} : {
313
+ ...(missingValue === 0 && explicitWeighted ? {} : { "missing-value": explicitWeighted ? missingValue : missing }),
314
+ ...(missingWeight === 0 ? {} : { "missing-weight": missingWeight })
315
+ },
316
+ ...(explicitWeighted ? { zeroWeightRows } : {})
317
+ });
318
+ }
319
+ return [aggregate.as, value];
320
+ }));
223
321
  return {
224
322
  ...group.values,
225
- ...Object.fromEntries(transform.aggregates.map(aggregate => [
226
- aggregate.as,
227
- weightSummary === undefined
228
- ? aggregateRows(group.rows, aggregate.field ?? "__row", aggregate.op)
229
- : calculateWeightedAggregate(
230
- weightSummary,
231
- aggregate.field,
232
- aggregate.op,
233
- `Summary aggregate "${aggregate.as}"`
234
- )
235
- ])),
323
+ ...aggregated,
236
324
  ...(transform.members === undefined
237
325
  ? {}
238
326
  : {
239
- [transform.members]: weightSummary === undefined
327
+ [transform.members]: sharedWeightSummary === undefined
240
328
  ? group.rows
241
- : weightedRows(weightSummary)
329
+ : weightedRows(sharedWeightSummary)
242
330
  })
243
331
  };
244
332
  });
333
+ if (transform.missing === undefined && transform.empty === undefined) return values;
334
+ return {
335
+ values,
336
+ report: cloneAndFreeze({
337
+ version: 1,
338
+ owner: { kind: "data", id: "pending" },
339
+ inputs: [],
340
+ units
341
+ })
342
+ };
245
343
  }
@@ -16,6 +16,7 @@ const TRANSFORM_TOPOLOGY = Object.freeze({
16
16
  markFilter: Object.freeze({ provenanceTransparent: true }),
17
17
  normalize: Object.freeze({ facetTopology: "statistical" }),
18
18
  regression: Object.freeze({ facetTopology: "statistical" }),
19
+ sort: Object.freeze({ facetTopology: "statistical" }),
19
20
  summary: Object.freeze({ facetTopology: "statistical" }),
20
21
  stack: Object.freeze({ facetTopology: "statistical" }),
21
22
  statisticalReference: Object.freeze({ facetTopology: "statistical" }),
@@ -23,6 +23,7 @@ import {
23
23
  validateCompleteTransform
24
24
  } from "./complete.js";
25
25
  import {
26
+ normalizeFilterTransformEdit,
26
27
  normalizeFilterTransform,
27
28
  validateFilterTransform
28
29
  } from "./filter.js";
@@ -62,6 +63,7 @@ import {
62
63
  validateSummaryTransform
63
64
  } from "./summary.js";
64
65
  import { normalizeStackTransform, validateStackTransform } from "./stack.js";
66
+ import { normalizeSortTransform, validateSortTransform } from "./sort.js";
65
67
  import { validateStatisticalReferenceTransform } from
66
68
  "./statisticalReference.js";
67
69
  import { findTransformTopology } from "./transformTopology.js";
@@ -102,15 +104,6 @@ function normalizeSimple(normalize) {
102
104
  return (transform, patch) => normalize(mergedOptions(transform, patch));
103
105
  }
104
106
 
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
107
  function normalizeBinEdit(transform, patch) {
115
108
  const prior = requestedOptions(transform);
116
109
  const base = replaceExclusive(
@@ -202,6 +195,7 @@ function normalizeNormalizeEdit(transform, patch) {
202
195
 
203
196
  function normalizeRegressionEdit(transform, patch) {
204
197
  const base = { ...requestedOptions(transform) };
198
+ if (patch.predict === false) delete base.predict;
205
199
  const method = patch.method ?? base.method;
206
200
  if (method !== base.method) {
207
201
  if (method !== "polynomial") delete base.degree;
@@ -212,7 +206,14 @@ function normalizeRegressionEdit(transform, patch) {
212
206
  ]) delete base[key];
213
207
  }
214
208
  }
215
- return normalizeRegressionTransform({ ...base, ...patch, method });
209
+ if (patch.interval === false) {
210
+ for (const key of ["confidenceMethod", "level", "confidence"]) delete base[key];
211
+ }
212
+ return normalizeRegressionTransform({
213
+ ...base,
214
+ ...Object.fromEntries(Object.entries(patch).filter(([key, value]) => !(key === "predict" && value === false))),
215
+ method
216
+ });
216
217
  }
217
218
 
218
219
  function normalizeTimeUnitEdit(transform, patch) {
@@ -373,7 +374,7 @@ const TRANSFORM_POLICIES = Object.freeze({
373
374
  materializeOp: "materializeFilteredData",
374
375
  replayTransform: requestedTransform,
375
376
  editable: true,
376
- normalizeEdit: normalizeFilterEdit,
377
+ normalizeEdit: normalizeFilterTransformEdit,
377
378
  outputRoles: () => ({})
378
379
  }),
379
380
  fold: Object.freeze({
@@ -442,6 +443,15 @@ const TRANSFORM_POLICIES = Object.freeze({
442
443
  normalizeEdit: normalizeRegressionEdit,
443
444
  outputRoles: () => ({})
444
445
  }),
446
+ sort: Object.freeze({
447
+ ...findTransformTopology("sort"),
448
+ validate: validateSortTransform,
449
+ materializeOp: "materializeSortedData",
450
+ replayTransform: requestedTransform,
451
+ editable: true,
452
+ normalizeEdit: normalizeSimple(normalizeSortTransform),
453
+ outputRoles: () => ({})
454
+ }),
445
455
  summary: Object.freeze({
446
456
  ...findTransformTopology("summary"),
447
457
  validate: validateSummaryTransform,