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.
- package/CHANGELOG.md +146 -0
- package/README.md +41 -12
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-packet.schema.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +39 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +20 -12
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +34 -9
- package/src/actions/boxPlots/materialize.js +12 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +21 -12
- package/src/actions/charts/area.js +6 -2
- package/src/actions/charts/bar.js +3 -2
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +7 -3
- package/src/actions/charts/ecdf.js +6 -3
- package/src/actions/charts/endpoints.js +29 -7
- package/src/actions/charts/heatmap.js +3 -2
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +4 -2
- package/src/actions/charts/interval-regression.js +7 -4
- package/src/actions/charts/line.js +4 -2
- package/src/actions/charts/parallel.js +9 -3
- package/src/actions/charts/pie.js +11 -3
- package/src/actions/charts/polar.js +17 -6
- package/src/actions/charts/radar.js +9 -3
- package/src/actions/charts/radial.js +12 -4
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +8 -4
- package/src/actions/charts/scatter.js +4 -2
- package/src/actions/composition/actions.js +29 -24
- package/src/actions/coordinates/actions.js +2 -2
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +63 -193
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +4 -4
- package/src/actions/data/create.js +7 -14
- package/src/actions/data/density.js +15 -23
- package/src/actions/data/derived.js +57 -31
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +551 -0
- package/src/actions/data/filter.js +28 -22
- package/src/actions/data/fold.js +2 -2
- package/src/actions/data/gradientProfile.js +2 -2
- package/src/actions/data/horizon.js +2 -2
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +62 -47
- package/src/actions/data/interval.js +2 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +21 -27
- package/src/actions/data/revise.js +48 -0
- package/src/actions/data/revisionBindings.js +125 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +6 -3
- package/src/actions/data/window.js +3 -3
- package/src/actions/encodings/angle.js +1 -1
- package/src/actions/encodings/appearance.js +4 -4
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +3 -2
- package/src/actions/encodings/density.js +7 -4
- package/src/actions/encodings/histogram.js +4 -3
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +22 -15
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +14 -6
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/ranged.js +5 -5
- package/src/actions/encodings/remove.js +13 -9
- package/src/actions/encodings/ruleAppearance.js +2 -24
- package/src/actions/encodings/seriesLayout.js +2 -1
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +2 -2
- package/src/actions/encodings/text.js +1 -1
- package/src/actions/errorBands/create.js +34 -20
- package/src/actions/errorBands/edit.js +34 -137
- package/src/actions/errorBars/create.js +43 -20
- package/src/actions/errorBars/edit.js +29 -125
- package/src/actions/facets/actions.js +267 -73
- package/src/actions/facets/derive.js +99 -28
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +15 -8
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +18 -9
- package/src/actions/gradientPlots/materialize.js +5 -3
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/applicability.js +8 -2
- package/src/actions/guides/axes/axes.js +23 -4
- package/src/actions/guides/axes/axis.js +2 -2
- package/src/actions/guides/axes/edit.js +2 -2
- package/src/actions/guides/axes/labels.js +67 -21
- package/src/actions/guides/axes/lines.js +15 -9
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- package/src/actions/guides/axes/parallel.js +5 -5
- package/src/actions/guides/axes/remove.js +4 -4
- package/src/actions/guides/axes/tickGroups.js +6 -5
- package/src/actions/guides/axes/ticks.js +19 -6
- package/src/actions/guides/axes/titles.js +21 -13
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +20 -4
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +138 -52
- package/src/actions/guides/legends/categorical/components.js +55 -45
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +98 -16
- package/src/actions/guides/legends/categorical/options.js +2 -2
- package/src/actions/guides/legends/categorical/recipes.js +111 -20
- package/src/actions/guides/legends/categorical/resolve.js +12 -8
- package/src/actions/guides/legends/categorical/symbols.js +104 -52
- package/src/actions/guides/legends/continuous/common.js +76 -20
- package/src/actions/guides/legends/continuous/gradient.js +95 -158
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +21 -16
- package/src/actions/guides/legends/continuous/opacity.js +37 -83
- package/src/actions/guides/legends/continuous/stroke.js +225 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +159 -60
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +59 -24
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +17 -8
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +100 -108
- package/src/actions/guides/legends/strokeWidth.js +38 -92
- package/src/actions/guides/legends/target.js +112 -1
- package/src/actions/guides/legends/transition.js +165 -16
- package/src/actions/guides/polar/axes/facade.js +8 -8
- package/src/actions/guides/polar/axes/labels.js +29 -10
- package/src/actions/guides/polar/axes/lines.js +19 -19
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +10 -16
- package/src/actions/guides/polar/axes/titles.js +6 -6
- package/src/actions/guides/polar/grids.js +12 -14
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +16 -3
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +80 -22
- package/src/actions/marks/area/actions.js +38 -13
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +12 -3
- package/src/actions/marks/bar/edit.js +21 -4
- package/src/actions/marks/bar/materialize.js +34 -40
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +40 -17
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +9 -3
- package/src/actions/marks/point/edit.js +19 -7
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +48 -22
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +36 -15
- package/src/actions/marks/references.js +602 -33
- package/src/actions/marks/remove.js +67 -41
- package/src/actions/marks/rule/actions.js +51 -14
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +79 -14
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +157 -17
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +72 -0
- package/src/actions/marks/tick/actions.js +25 -8
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +31 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +11 -3
- package/src/actions/primitives/semanticAction.js +90 -14
- package/src/actions/primitives/semanticValidation/dataset.js +2 -4
- package/src/actions/primitives/semanticValidation/guide.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +5 -0
- package/src/actions/primitives/semanticValidation/scale.js +28 -7
- package/src/actions/regression/components.js +36 -25
- package/src/actions/regression/create.js +13 -6
- package/src/actions/regression/edit.js +24 -11
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +173 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +1 -1
- package/src/actions/scales/consumers/families.js +3 -2
- package/src/actions/scales/consumers/index.js +19 -2
- package/src/actions/scales/consumers/seriesLayout.js +28 -14
- package/src/actions/scales/create.js +55 -23
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +67 -12
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +5 -4
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/preview.js +111 -10
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +179 -66
- package/src/actions/selection/index.js +3 -0
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +70 -15
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +313 -121
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +6 -3
- package/src/actions/violinPlots/edit.js +2 -1
- package/src/core/action.js +117 -35
- package/src/core/compositionState.js +6 -1
- package/src/core/diagnostics.js +16 -0
- package/src/core/extensionRegistry.js +27 -0
- package/src/core/font.js +18 -0
- package/src/core/identifiers.js +5 -4
- package/src/core/immutable.js +10 -3
- package/src/core/optionRequirements.js +8 -0
- package/src/core/programState.js +21 -1
- package/src/core/resourceReferences.js +341 -0
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/core/vocabulary.js +16 -3
- package/src/diagnostics.js +1 -0
- package/src/grammar/bars/aggregate.js +4 -1
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bin.js +54 -9
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +265 -64
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +7 -47
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/impute.js +341 -0
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +18 -1
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/pathSeries.js +26 -8
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/parameters.js +23 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +1 -0
- package/src/grammar/scales/colorConsumers.js +20 -1
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +27 -4
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +190 -41
- package/src/grammar/schemas/semanticPath.js +7 -2
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +78 -16
- package/src/grammar/timeUnit.js +216 -5
- package/src/grammar/transformTopology.js +4 -0
- package/src/grammar/transforms.js +394 -28
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +221 -16
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +59 -5
- package/src/layout/labels.js +351 -7
- package/src/layout/legend.js +4 -4
- package/src/layout/legendItems.js +6 -6
- package/src/layout/text.js +10 -9
- package/src/layout/title.js +9 -9
- package/src/materialization/bars/aggregate.js +25 -2
- package/src/materialization/bars/histogram.js +84 -24
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/composition.js +3 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +36 -0
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +9 -3
- package/src/materialization/facetGuides/preparation.js +13 -8
- package/src/materialization/facetHeaders.js +347 -0
- package/src/materialization/facets.js +15 -65
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/guides/resources.js +26 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/index.js +11 -5
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/rect.js +25 -12
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/map.js +5 -3
- package/src/materialization/scales/policies/binnedPosition.js +2 -2
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +4 -1
- package/src/materialization/scales/resolve.js +22 -6
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +30 -3
- package/src/materialization/selection/items/common.js +20 -5
- package/src/materialization/selection/items/rect.js +28 -4
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +265 -14
- package/src/materialization/typography.js +31 -0
- package/src/mcp/cli.js +5 -3
- package/src/persistence/codec.js +65 -0
- package/src/persistence/validation.js +185 -0
- package/src/persistence.js +74 -0
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/index.js +5 -4
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- package/src/renderers/nativeBackend.js +10 -0
- package/src/renderers/options.js +13 -0
- package/src/renderers/pdf.js +25 -54
- package/src/renderers/png.js +22 -17
- package/src/renderers/svg.js +29 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +38 -5
- package/src/selectors/layers.js +10 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +103 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +10 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +90 -0
- package/types/pdf.d.ts +9 -0
- package/types/persistence.d.ts +7 -0
- package/types/png.d.ts +9 -0
- package/types/program.d.ts +944 -118
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import { action, closedAction } from "../../core/action.js";
|
|
2
|
+
import { isPlainObject } from "../../core/immutable.js";
|
|
3
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
4
|
+
import { validateKeys } from "../../core/validation.js";
|
|
5
|
+
import {
|
|
6
|
+
findTransformPolicy,
|
|
7
|
+
normalizeDatasetTransformEdit,
|
|
8
|
+
requestedDatasetTransform
|
|
9
|
+
} from "../../grammar/transforms.js";
|
|
10
|
+
import {
|
|
11
|
+
findDataset,
|
|
12
|
+
hasDataset
|
|
13
|
+
} from "../../selectors/datasets.js";
|
|
14
|
+
import { applyLayerDataRematerialization } from
|
|
15
|
+
"../../materialization/dependencies.js";
|
|
16
|
+
import {
|
|
17
|
+
outputFieldChanges,
|
|
18
|
+
rebindLayerOutputFields,
|
|
19
|
+
rebindMaterializationDataReferences
|
|
20
|
+
} from "./revisionBindings.js";
|
|
21
|
+
|
|
22
|
+
const GENERIC_OPTIONS = Object.freeze([
|
|
23
|
+
"target", "definition", "dependents"
|
|
24
|
+
]);
|
|
25
|
+
const DEPENDENT_POLICIES = new Set(["reject", "recompute"]);
|
|
26
|
+
const CREATOR_BY_TYPE = Object.freeze({
|
|
27
|
+
bin: "createBinData",
|
|
28
|
+
bin2d: "createBin2DData",
|
|
29
|
+
complete: "createCompleteData",
|
|
30
|
+
computed: "createComputedData",
|
|
31
|
+
density: "createDensityData",
|
|
32
|
+
ecdf: "createECDFData",
|
|
33
|
+
filter: "filterData",
|
|
34
|
+
fold: "createFoldData",
|
|
35
|
+
impute: "createImputedData",
|
|
36
|
+
interval: "createIntervalData",
|
|
37
|
+
normalize: "createNormalizedData",
|
|
38
|
+
regression: "createRegressionData",
|
|
39
|
+
stack: "createStackData",
|
|
40
|
+
summary: "createSummaryData",
|
|
41
|
+
timeUnit: "createTimeUnitData",
|
|
42
|
+
window: "createWindowData"
|
|
43
|
+
});
|
|
44
|
+
const REVISION_ROLE = Object.freeze({
|
|
45
|
+
bin: "BinData",
|
|
46
|
+
bin2d: "Bin2DData",
|
|
47
|
+
complete: "CompleteData",
|
|
48
|
+
computed: "ComputedData",
|
|
49
|
+
density: "DensityData",
|
|
50
|
+
ecdf: "ECDFData",
|
|
51
|
+
filter: "FilteredData",
|
|
52
|
+
fold: "FoldData",
|
|
53
|
+
impute: "ImputedData",
|
|
54
|
+
interval: "IntervalData",
|
|
55
|
+
normalize: "NormalizedData",
|
|
56
|
+
regression: "RegressionData",
|
|
57
|
+
stack: "StackData",
|
|
58
|
+
summary: "SummaryData",
|
|
59
|
+
timeUnit: "TimeUnitData",
|
|
60
|
+
window: "WindowData"
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function ownerRecords(program, type) {
|
|
64
|
+
const families = program.materializationConfigs.data ?? {};
|
|
65
|
+
return Object.entries(families).flatMap(([family, owners]) =>
|
|
66
|
+
Object.entries(owners ?? {}).flatMap(([owner, config]) => {
|
|
67
|
+
if (typeof config?.current !== "string") return [];
|
|
68
|
+
const dataset = findDataset(program, config.current);
|
|
69
|
+
const currentType = dataset?.transform?.[0]?.type ?? family;
|
|
70
|
+
if (type !== undefined && currentType !== type) return [];
|
|
71
|
+
return [{ family, owner, current: config.current, dataset }];
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function escapedPattern(value) {
|
|
77
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function staleOwnerRecord(program, requested, type) {
|
|
81
|
+
return ownerRecords(program, type).find(record => {
|
|
82
|
+
const transformType = record.dataset?.transform?.[0]?.type ?? record.family;
|
|
83
|
+
const role = REVISION_ROLE[transformType];
|
|
84
|
+
if (role === undefined || requested === record.current) return false;
|
|
85
|
+
return new RegExp(
|
|
86
|
+
`^${escapedPattern(record.owner)}${role}Revision\\d+$`
|
|
87
|
+
).test(requested);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function topLevelCreatorRecorded(program, dataset) {
|
|
92
|
+
const creator = CREATOR_BY_TYPE[dataset.transform?.[0]?.type];
|
|
93
|
+
return creator !== undefined && program.trace.children.some(node =>
|
|
94
|
+
node.op === creator && node.args?.id === dataset.id
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function resolveDerivedDataOwner(program, target, type) {
|
|
99
|
+
const requested = validateUserId(target, "Derived dataset target");
|
|
100
|
+
const matching = ownerRecords(program, type).filter(record =>
|
|
101
|
+
record.owner === requested || record.current === requested
|
|
102
|
+
);
|
|
103
|
+
if (matching.length > 1) {
|
|
104
|
+
throw new Error(`Derived dataset target "${requested}" is ambiguous.`);
|
|
105
|
+
}
|
|
106
|
+
if (matching.length === 1) {
|
|
107
|
+
const record = matching[0];
|
|
108
|
+
if (record.dataset === undefined) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Derived dataset owner "${record.owner}" has no current dataset.`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return { ...record, lazy: false };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const dataset = findDataset(program, requested);
|
|
117
|
+
if (dataset === undefined) {
|
|
118
|
+
throw new Error(staleOwnerRecord(program, requested, type) !== undefined
|
|
119
|
+
? `Derived dataset revision "${requested}" is stale.`
|
|
120
|
+
: `Unknown derived dataset owner "${requested}".`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
if (staleOwnerRecord(program, requested, type) !== undefined) {
|
|
124
|
+
throw new Error(`Derived dataset revision "${requested}" is stale.`);
|
|
125
|
+
}
|
|
126
|
+
if (dataset.source === undefined || dataset.transform?.length !== 1) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Dataset "${requested}" is a source dataset and cannot be edited.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const currentType = dataset.transform[0].type;
|
|
132
|
+
if (type !== undefined && currentType !== type) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Derived dataset "${requested}" is ${currentType}, not ${type}.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
findTransformPolicy(currentType)?.editable !== true ||
|
|
139
|
+
!topLevelCreatorRecorded(program, dataset)
|
|
140
|
+
) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Derived dataset "${requested}" is chart-owned; use its owning chart editor.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
family: currentType,
|
|
147
|
+
owner: dataset.id,
|
|
148
|
+
current: dataset.id,
|
|
149
|
+
dataset,
|
|
150
|
+
lazy: true
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function normalizeDerivedDependentPolicy(value) {
|
|
155
|
+
const policy = value ?? "reject";
|
|
156
|
+
if (!DEPENDENT_POLICIES.has(policy)) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
'Derived data dependents must be "reject" or "recompute".'
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
return policy;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function downstreamDatasets(program, root) {
|
|
165
|
+
const order = new Map(
|
|
166
|
+
program.semanticSpec.datasets.map((dataset, index) => [dataset.id, index])
|
|
167
|
+
);
|
|
168
|
+
const bySource = new Map();
|
|
169
|
+
for (const dataset of program.semanticSpec.datasets) {
|
|
170
|
+
if (dataset.source === undefined) continue;
|
|
171
|
+
const children = bySource.get(dataset.source) ?? [];
|
|
172
|
+
children.push(dataset);
|
|
173
|
+
bySource.set(dataset.source, children);
|
|
174
|
+
}
|
|
175
|
+
for (const children of bySource.values()) {
|
|
176
|
+
children.sort((left, right) => order.get(left.id) - order.get(right.id));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const result = [];
|
|
180
|
+
const visiting = new Set();
|
|
181
|
+
const visited = new Set();
|
|
182
|
+
function visit(id) {
|
|
183
|
+
if (visiting.has(id)) {
|
|
184
|
+
throw new Error(`Derived dataset dependency graph contains a cycle at "${id}".`);
|
|
185
|
+
}
|
|
186
|
+
if (visited.has(id)) return;
|
|
187
|
+
visiting.add(id);
|
|
188
|
+
for (const child of bySource.get(id) ?? []) {
|
|
189
|
+
if (child.transform?.length !== 1) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Derived dataset "${child.id}" requires one replayable transform.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const policy = findTransformPolicy(child.transform[0].type);
|
|
195
|
+
if (typeof policy?.materializeOp !== "string") {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Derived dataset "${child.id}" has unsupported transform ` +
|
|
198
|
+
`"${child.transform[0].type ?? "unknown"}".`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
// Statistical reference data is an owned cache. Its mark lifecycle
|
|
202
|
+
// reconnects and recomputes it after the visible source mark is rebound.
|
|
203
|
+
if (child.transform[0].type === "statisticalReference") continue;
|
|
204
|
+
result.push(child);
|
|
205
|
+
visit(child.id);
|
|
206
|
+
}
|
|
207
|
+
visiting.delete(id);
|
|
208
|
+
visited.add(id);
|
|
209
|
+
}
|
|
210
|
+
visit(root);
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function ownerForCurrent(program, dataset) {
|
|
215
|
+
const matches = ownerRecords(program).filter(record =>
|
|
216
|
+
record.current === dataset.id
|
|
217
|
+
);
|
|
218
|
+
if (matches.length > 1) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`Derived dataset "${dataset.id}" has ambiguous logical ownership.`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
return matches[0];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function nextRevisionId(program, owner, role, reserved) {
|
|
227
|
+
let revision = 1;
|
|
228
|
+
const prefix = `${owner}${role}Revision`;
|
|
229
|
+
while (
|
|
230
|
+
hasDataset(program, `${prefix}${revision}`) ||
|
|
231
|
+
reserved.has(`${prefix}${revision}`)
|
|
232
|
+
) revision += 1;
|
|
233
|
+
const id = `${prefix}${revision}`;
|
|
234
|
+
reserved.add(id);
|
|
235
|
+
return id;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function buildRevisionPlan(
|
|
239
|
+
program,
|
|
240
|
+
resolved,
|
|
241
|
+
definition,
|
|
242
|
+
dependents,
|
|
243
|
+
rootSource = resolved.dataset.source
|
|
244
|
+
) {
|
|
245
|
+
const downstream = downstreamDatasets(program, resolved.current);
|
|
246
|
+
if (dependents === "reject" && downstream.length > 0) {
|
|
247
|
+
throw new Error(
|
|
248
|
+
`Cannot edit derived dataset "${resolved.owner}" while derived dataset ` +
|
|
249
|
+
`"${downstream[0].id}" depends on it; use dependents: "recompute".`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (downstream.some(dataset => dataset.id === rootSource)) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`Derived dataset "${resolved.owner}" cannot use one of its dependents as source.`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const reserved = new Set(resolved.revision === undefined ? [] : [resolved.revision]);
|
|
258
|
+
const revisions = [];
|
|
259
|
+
const replacements = new Map();
|
|
260
|
+
const add = (dataset, ownerRecord, transform, requestedSource) => {
|
|
261
|
+
const owner = ownerRecord?.owner ?? dataset.id;
|
|
262
|
+
const role = REVISION_ROLE[transform.type] ?? "DerivedData";
|
|
263
|
+
const id = nextRevisionId(program, owner, role, reserved);
|
|
264
|
+
const originalSource = requestedSource ?? dataset.source;
|
|
265
|
+
const source = replacements.get(originalSource) ?? originalSource;
|
|
266
|
+
const revision = {
|
|
267
|
+
old: dataset.id,
|
|
268
|
+
id,
|
|
269
|
+
source,
|
|
270
|
+
transform,
|
|
271
|
+
family: ownerRecord?.family,
|
|
272
|
+
owner: ownerRecord?.owner
|
|
273
|
+
};
|
|
274
|
+
revisions.push(revision);
|
|
275
|
+
replacements.set(dataset.id, id);
|
|
276
|
+
};
|
|
277
|
+
if (resolved.revision === undefined) {
|
|
278
|
+
add(resolved.dataset, resolved, definition, rootSource);
|
|
279
|
+
} else {
|
|
280
|
+
revisions.push({ old: resolved.current, id: resolved.revision });
|
|
281
|
+
replacements.set(resolved.current, resolved.revision);
|
|
282
|
+
}
|
|
283
|
+
if (dependents === "recompute") {
|
|
284
|
+
for (const dataset of downstream) {
|
|
285
|
+
const policy = findTransformPolicy(dataset.transform[0].type);
|
|
286
|
+
const transform = policy.replayTransform?.(dataset.transform[0]) ??
|
|
287
|
+
dataset.transform[0];
|
|
288
|
+
add(dataset, ownerForCurrent(program, dataset), transform);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return { revisions, replacements };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function directLayerConsumers(program, data) {
|
|
295
|
+
return program.semanticSpec.layers
|
|
296
|
+
.filter(layer => layer.data === data)
|
|
297
|
+
.map(layer => layer.id);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function applyRevisionPlan(program, resolved, plan, { retain = new Set() } = {}) {
|
|
301
|
+
const root = plan.revisions[0];
|
|
302
|
+
const changes = resolved === undefined ? new Map() : outputFieldChanges(
|
|
303
|
+
resolved.dataset.transform[0],
|
|
304
|
+
root.transform
|
|
305
|
+
);
|
|
306
|
+
let next = program;
|
|
307
|
+
for (const revision of plan.revisions) {
|
|
308
|
+
if (revision.transform === undefined) continue;
|
|
309
|
+
const policy = findTransformPolicy(revision.transform.type);
|
|
310
|
+
next = next.createDerivedData({
|
|
311
|
+
id: revision.id,
|
|
312
|
+
source: revision.source,
|
|
313
|
+
transform: [revision.transform]
|
|
314
|
+
});
|
|
315
|
+
if (revision.transform.type === "markFilter") {
|
|
316
|
+
next = next.rebindLayerData({
|
|
317
|
+
id: revision.transform.target,
|
|
318
|
+
data: revision.source
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
next = next[policy.materializeOp]({ id: revision.id });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const consumers = plan.revisions.flatMap(revision =>
|
|
325
|
+
directLayerConsumers(program, revision.old).map(id => ({
|
|
326
|
+
id,
|
|
327
|
+
old: revision.old,
|
|
328
|
+
data: revision.id,
|
|
329
|
+
root: revision.old === root.old
|
|
330
|
+
}))
|
|
331
|
+
);
|
|
332
|
+
for (const consumer of consumers) {
|
|
333
|
+
next = next.rebindLayerData({ id: consumer.id, data: consumer.data });
|
|
334
|
+
}
|
|
335
|
+
for (const consumer of consumers) {
|
|
336
|
+
if (consumer.root) {
|
|
337
|
+
next = rebindLayerOutputFields(next, consumer.id, changes);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
next = rebindMaterializationDataReferences(next, plan.replacements);
|
|
342
|
+
for (const revision of plan.revisions) {
|
|
343
|
+
if (revision.owner !== undefined) {
|
|
344
|
+
next = next._withMaterializationConfig(
|
|
345
|
+
["data", revision.family, revision.owner],
|
|
346
|
+
{ current: revision.id }
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
for (const consumer of consumers) {
|
|
351
|
+
next = applyLayerDataRematerialization(next, consumer.id);
|
|
352
|
+
}
|
|
353
|
+
for (const revision of [...plan.revisions].reverse()) {
|
|
354
|
+
if (retain.has(revision.old)) continue;
|
|
355
|
+
next = next.releaseDerivedData({ id: revision.old });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const currentData = plan.replacements.get(program.context.currentData) ??
|
|
359
|
+
program.context.currentData;
|
|
360
|
+
return next._withContext({ ...program.context, currentData });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function buildSourceRevisionPlan(program, source, id) {
|
|
364
|
+
return buildRevisionPlan(program, {
|
|
365
|
+
current: source, dataset: findDataset(program, source), revision: id
|
|
366
|
+
}, undefined, "recompute");
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function sameRequested(left, right) {
|
|
370
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function reviseDerivedData(program, {
|
|
374
|
+
resolved,
|
|
375
|
+
definition,
|
|
376
|
+
dependents = "reject",
|
|
377
|
+
source = resolved.dataset.source
|
|
378
|
+
}) {
|
|
379
|
+
const policy = normalizeDerivedDependentPolicy(dependents);
|
|
380
|
+
const plan = buildRevisionPlan(
|
|
381
|
+
program,
|
|
382
|
+
resolved,
|
|
383
|
+
definition,
|
|
384
|
+
policy,
|
|
385
|
+
source
|
|
386
|
+
);
|
|
387
|
+
applyRevisionPlan(program, resolved, plan);
|
|
388
|
+
return applyRevisionPlan(program, resolved, plan);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export const editDerivedData = /* @__PURE__ */ closedAction(
|
|
392
|
+
{
|
|
393
|
+
op: "editDerivedData",
|
|
394
|
+
description: "Atomically revise one standalone derived-data definition."
|
|
395
|
+
}, GENERIC_OPTIONS,
|
|
396
|
+
function (args = {}) {
|
|
397
|
+
if (!Object.hasOwn(args, "target")) {
|
|
398
|
+
throw new TypeError("editDerivedData requires target.");
|
|
399
|
+
}
|
|
400
|
+
if (!isPlainObject(args.definition)) {
|
|
401
|
+
throw new TypeError("editDerivedData definition must be a plain object.");
|
|
402
|
+
}
|
|
403
|
+
for (const forbidden of ["id", "source", "resolved", "current"]) {
|
|
404
|
+
if (Object.hasOwn(args.definition, forbidden)) {
|
|
405
|
+
throw new Error(`editDerivedData definition cannot include ${forbidden}.`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const dependents = normalizeDerivedDependentPolicy(args.dependents);
|
|
409
|
+
const resolved = resolveDerivedDataOwner(
|
|
410
|
+
this,
|
|
411
|
+
args.target,
|
|
412
|
+
args.definition.type
|
|
413
|
+
);
|
|
414
|
+
const definition = requestedDatasetTransform(args.definition);
|
|
415
|
+
findTransformPolicy(definition.type).validate(definition);
|
|
416
|
+
const previous = requestedDatasetTransform(resolved.dataset.transform[0]);
|
|
417
|
+
if (sameRequested(definition, previous)) return this;
|
|
418
|
+
|
|
419
|
+
return reviseDerivedData(this, { resolved, definition, dependents });
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
function focusedEditor(op, type, properties) {
|
|
424
|
+
const supported = Object.freeze(["target", "dependents", ...properties]);
|
|
425
|
+
return action(
|
|
426
|
+
{ op, description: `Partially revise one standalone ${type} dataset.` },
|
|
427
|
+
function (args = {}) {
|
|
428
|
+
validateKeys(args, supported, op);
|
|
429
|
+
if (!Object.hasOwn(args, "target")) {
|
|
430
|
+
throw new TypeError(`${op} requires target.`);
|
|
431
|
+
}
|
|
432
|
+
const patch = Object.fromEntries(Object.entries(args).filter(
|
|
433
|
+
([key]) => key !== "target" && key !== "dependents"
|
|
434
|
+
));
|
|
435
|
+
if (Object.keys(patch).length === 0) {
|
|
436
|
+
throw new Error(`${op} requires at least one transform option.`);
|
|
437
|
+
}
|
|
438
|
+
const undefinedKey = Object.keys(patch).find(
|
|
439
|
+
key => patch[key] === undefined
|
|
440
|
+
);
|
|
441
|
+
if (undefinedKey !== undefined) {
|
|
442
|
+
throw new TypeError(
|
|
443
|
+
`${op} ${undefinedKey} cannot be undefined; omission preserves it.`
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
const resolved = resolveDerivedDataOwner(this, args.target, type);
|
|
447
|
+
const definition = normalizeDatasetTransformEdit(
|
|
448
|
+
resolved.dataset.transform[0],
|
|
449
|
+
patch,
|
|
450
|
+
resolved.owner
|
|
451
|
+
);
|
|
452
|
+
return this.editDerivedData({
|
|
453
|
+
target: args.target,
|
|
454
|
+
definition,
|
|
455
|
+
...(args.dependents === undefined
|
|
456
|
+
? {}
|
|
457
|
+
: { dependents: args.dependents })
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export const editComputedData = /* @__PURE__ */ focusedEditor(
|
|
464
|
+
"editComputedData", "computed", ["as", "expression"]
|
|
465
|
+
);
|
|
466
|
+
export const editFilteredData = /* @__PURE__ */ focusedEditor(
|
|
467
|
+
"editFilteredData", "filter", ["field", "oneOf", "predicate", "range"]
|
|
468
|
+
);
|
|
469
|
+
export const editFoldData = /* @__PURE__ */ focusedEditor(
|
|
470
|
+
"editFoldData", "fold", ["fields", "as"]
|
|
471
|
+
);
|
|
472
|
+
export const editSummaryData = /* @__PURE__ */ focusedEditor(
|
|
473
|
+
"editSummaryData", "summary", ["groupBy", "aggregates", "members", "weight"]
|
|
474
|
+
);
|
|
475
|
+
export const editBinData = /* @__PURE__ */ focusedEditor(
|
|
476
|
+
"editBinData", "bin", [
|
|
477
|
+
"field", "maxBins", "step", "boundaries", "extent", "nice", "zero",
|
|
478
|
+
"includeEmpty", "members", "as", "weight"
|
|
479
|
+
]
|
|
480
|
+
);
|
|
481
|
+
export const editTimeUnitData = /* @__PURE__ */ focusedEditor(
|
|
482
|
+
"editTimeUnitData", "timeUnit", [
|
|
483
|
+
"field", "unit", "as", "temporalUnit", "timeZone", "weekStartsOn",
|
|
484
|
+
"weekRule"
|
|
485
|
+
]
|
|
486
|
+
);
|
|
487
|
+
export const editWindowData = /* @__PURE__ */ focusedEditor(
|
|
488
|
+
"editWindowData", "window", [
|
|
489
|
+
"partitionBy", "sortBy", "operations", "temporalUnit"
|
|
490
|
+
]
|
|
491
|
+
);
|
|
492
|
+
export const editDensityData = /* @__PURE__ */ focusedEditor(
|
|
493
|
+
"editDensityData", "density", [
|
|
494
|
+
"field", "groupBy", "bandwidth", "extent", "steps", "kernel",
|
|
495
|
+
"normalization", "as", "weight"
|
|
496
|
+
]
|
|
497
|
+
);
|
|
498
|
+
export const editStackData = /* @__PURE__ */ focusedEditor(
|
|
499
|
+
"editStackData", "stack", ["category", "group", "value", "mode", "as"]
|
|
500
|
+
);
|
|
501
|
+
export const editRegressionData = /* @__PURE__ */ focusedEditor(
|
|
502
|
+
"editRegressionData", "regression", [
|
|
503
|
+
"x", "y", "groupBy", "method", "degree", "span", "confidenceMethod",
|
|
504
|
+
"level", "confidence", "interval"
|
|
505
|
+
]
|
|
506
|
+
);
|
|
507
|
+
export const editIntervalData = /* @__PURE__ */ focusedEditor(
|
|
508
|
+
"editIntervalData", "interval", [
|
|
509
|
+
"field", "groupBy", "center", "extent", "method", "level", "as"
|
|
510
|
+
]
|
|
511
|
+
);
|
|
512
|
+
export const editECDFData = /* @__PURE__ */ focusedEditor(
|
|
513
|
+
"editECDFData", "ecdf", [
|
|
514
|
+
"field", "groupBy", "weight", "missing", "as"
|
|
515
|
+
]
|
|
516
|
+
);
|
|
517
|
+
export const editNormalizedData = /* @__PURE__ */ focusedEditor(
|
|
518
|
+
"editNormalizedData", "normalize", [
|
|
519
|
+
"field", "as", "groupBy", "method", "variance", "zeroDenominator",
|
|
520
|
+
"baseline", "sortBy"
|
|
521
|
+
]
|
|
522
|
+
);
|
|
523
|
+
export const editCompleteData = /* @__PURE__ */ focusedEditor(
|
|
524
|
+
"editCompleteData", "complete", [
|
|
525
|
+
"key", "groupBy", "values", "sequence", "fill", "members"
|
|
526
|
+
]
|
|
527
|
+
);
|
|
528
|
+
export const editImputedData = /* @__PURE__ */ focusedEditor(
|
|
529
|
+
"editImputedData", "impute", [
|
|
530
|
+
"fields", "groupBy", "sortBy", "method", "value", "edges", "maxGap"
|
|
531
|
+
]
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
export const EDIT_DERIVED_DATA_ACTIONS = Object.freeze({
|
|
535
|
+
editDerivedData,
|
|
536
|
+
editComputedData,
|
|
537
|
+
editFilteredData,
|
|
538
|
+
editFoldData,
|
|
539
|
+
editSummaryData,
|
|
540
|
+
editBinData,
|
|
541
|
+
editTimeUnitData,
|
|
542
|
+
editWindowData,
|
|
543
|
+
editDensityData,
|
|
544
|
+
editStackData,
|
|
545
|
+
editRegressionData,
|
|
546
|
+
editIntervalData,
|
|
547
|
+
editECDFData,
|
|
548
|
+
editNormalizedData,
|
|
549
|
+
editCompleteData,
|
|
550
|
+
editImputedData
|
|
551
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { withPreviewDatasetValues } from
|
|
5
5
|
"../primitives/semanticAction.js";
|
|
6
6
|
import {
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import {
|
|
23
23
|
hasDataset,
|
|
24
24
|
findDataset,
|
|
25
|
+
resolveDatasetReference,
|
|
25
26
|
requireLayer,
|
|
26
27
|
resolveEligibleLayer
|
|
27
28
|
} from "../../selectors/index.js";
|
|
@@ -49,10 +50,9 @@ function retainedHistogramBoundaries(layer, items) {
|
|
|
49
50
|
return boundaries.length < 2 ? undefined : boundaries;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
export const materializeFilteredData =
|
|
53
|
-
{ op: "materializeFilteredData", description: "Materialize one filtered derived dataset." },
|
|
53
|
+
export const materializeFilteredData = /* @__PURE__ */ closedAction(
|
|
54
|
+
{ op: "materializeFilteredData", description: "Materialize one filtered derived dataset." }, MATERIALIZE_OPTIONS,
|
|
54
55
|
function (args = {}) {
|
|
55
|
-
validateKeys(args, MATERIALIZE_OPTIONS, "materializeFilteredData");
|
|
56
56
|
const { id, source, transform } = requireDerivedDataset(
|
|
57
57
|
this,
|
|
58
58
|
args.id,
|
|
@@ -65,33 +65,42 @@ export const materializeFilteredData = action(
|
|
|
65
65
|
}
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
-
export const filterData =
|
|
69
|
-
{ op: "filterData", description: "Create a named dataset from one field filter." },
|
|
68
|
+
export const filterData = /* @__PURE__ */ closedAction(
|
|
69
|
+
{ op: "filterData", description: "Create a named dataset from one field filter." }, OPTIONS,
|
|
70
70
|
function (args = {}) {
|
|
71
|
-
validateKeys(args, OPTIONS, "filterData");
|
|
72
71
|
const id = validateUserId(args.id, "Filtered dataset id");
|
|
73
|
-
const
|
|
72
|
+
const requestedSource = validateUserId(
|
|
74
73
|
args.source ?? this.context.currentData,
|
|
75
74
|
"Source dataset id"
|
|
76
75
|
);
|
|
76
|
+
const source = resolveDatasetReference(
|
|
77
|
+
this,
|
|
78
|
+
requestedSource,
|
|
79
|
+
"Filter source dataset"
|
|
80
|
+
).id;
|
|
77
81
|
const transform = normalizeFilterTransform(args);
|
|
78
|
-
|
|
82
|
+
const next = this
|
|
79
83
|
.createDerivedData({
|
|
80
84
|
id,
|
|
81
85
|
source,
|
|
82
86
|
transform: [transform]
|
|
83
87
|
})
|
|
84
88
|
.materializeFilteredData({ id });
|
|
89
|
+
return this.actionStack.length === 1
|
|
90
|
+
? next._withMaterializationConfig(
|
|
91
|
+
["data", "filter", id],
|
|
92
|
+
{ current: id }
|
|
93
|
+
)
|
|
94
|
+
: next;
|
|
85
95
|
}
|
|
86
96
|
);
|
|
87
97
|
|
|
88
|
-
export const materializeMarkFilteredData =
|
|
98
|
+
export const materializeMarkFilteredData = /* @__PURE__ */ closedAction(
|
|
89
99
|
{
|
|
90
100
|
op: "materializeMarkFilteredData",
|
|
91
101
|
description: "Materialize member rows retained by one final-item mark selection."
|
|
92
|
-
},
|
|
102
|
+
}, MATERIALIZE_OPTIONS,
|
|
93
103
|
function (args = {}) {
|
|
94
|
-
validateKeys(args, MATERIALIZE_OPTIONS, "materializeMarkFilteredData");
|
|
95
104
|
const { id, dataset, source, transform } = requireDerivedDataset(
|
|
96
105
|
this,
|
|
97
106
|
args.id,
|
|
@@ -158,13 +167,12 @@ export const materializeMarkFilteredData = action(
|
|
|
158
167
|
}
|
|
159
168
|
);
|
|
160
169
|
|
|
161
|
-
export const materializeEmptyMark =
|
|
170
|
+
export const materializeEmptyMark = /* @__PURE__ */ closedAction(
|
|
162
171
|
{
|
|
163
172
|
op: "materializeEmptyMark",
|
|
164
173
|
description: "Clear one active empty-filter mark without changing its domains."
|
|
165
|
-
},
|
|
174
|
+
}, EMPTY_MARK_OPTIONS,
|
|
166
175
|
function (args = {}) {
|
|
167
|
-
validateKeys(args, EMPTY_MARK_OPTIONS, "materializeEmptyMark");
|
|
168
176
|
const id = validateUserId(args.id, "Empty mark id");
|
|
169
177
|
const layer = requireLayer(this, id);
|
|
170
178
|
const owner = this.markConfigs[id]?.markFilter;
|
|
@@ -249,13 +257,12 @@ function sameSelector(left, right) {
|
|
|
249
257
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
250
258
|
}
|
|
251
259
|
|
|
252
|
-
export const removeMarkFilter =
|
|
260
|
+
export const removeMarkFilter = /* @__PURE__ */ closedAction(
|
|
253
261
|
{
|
|
254
262
|
op: "removeMarkFilter",
|
|
255
263
|
description: "Remove one active final-item filter and restore its source."
|
|
256
|
-
},
|
|
264
|
+
}, REMOVE_MARK_FILTER_OPTIONS,
|
|
257
265
|
function (args = {}) {
|
|
258
|
-
validateKeys(args, REMOVE_MARK_FILTER_OPTIONS, "removeMarkFilter");
|
|
259
266
|
const target = args.target === undefined
|
|
260
267
|
? undefined
|
|
261
268
|
: validateUserId(args.target, "Mark filter target id");
|
|
@@ -268,13 +275,12 @@ export const removeMarkFilter = action(
|
|
|
268
275
|
}
|
|
269
276
|
);
|
|
270
277
|
|
|
271
|
-
export const filterMarks =
|
|
278
|
+
export const filterMarks = /* @__PURE__ */ closedAction(
|
|
272
279
|
{
|
|
273
280
|
op: "filterMarks",
|
|
274
281
|
description: "Retain selected final mark items through immutable derived data."
|
|
275
|
-
},
|
|
282
|
+
}, MARK_OPTIONS,
|
|
276
283
|
function (args = {}) {
|
|
277
|
-
validateKeys(args, MARK_OPTIONS, "filterMarks");
|
|
278
284
|
if (args.mode !== undefined && !["replace", "compose"].includes(args.mode)) {
|
|
279
285
|
throw new Error(`Unknown mark filter mode "${args.mode}".`);
|
|
280
286
|
}
|
package/src/actions/data/fold.js
CHANGED
|
@@ -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,
|