ggaction 0.0.12 → 0.0.15
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 +127 -0
- package/README.md +20 -11
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/action-cards.schema.json +1 -1
- package/knowledge/extension-authoring.md +2 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +10 -3
- package/src/actions/basic.js +4 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +13 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -1
- package/src/actions/canvas/fitting.js +211 -0
- package/src/actions/canvas/index.js +2 -0
- package/src/actions/categoryOrder/index.js +18 -6
- package/src/actions/charts/area.js +51 -0
- package/src/actions/charts/bar.js +13 -6
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +48 -0
- package/src/actions/charts/ecdf.js +186 -0
- package/src/actions/charts/endpoints.js +473 -0
- package/src/actions/charts/heatmap.js +4 -3
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +73 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +172 -0
- package/src/actions/charts/line.js +8 -6
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +52 -0
- package/src/actions/charts/polar.js +134 -0
- package/src/actions/charts/radar.js +305 -0
- package/src/actions/charts/radial.js +50 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +283 -0
- package/src/actions/charts/scatter.js +11 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +129 -3
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +111 -15
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +226 -30
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +38 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +19 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/appearance.js +32 -13
- package/src/actions/encodings/barWidth.js +8 -0
- package/src/actions/encodings/basic.js +2 -0
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +30 -23
- package/src/actions/encodings/color/layout.js +3 -97
- package/src/actions/encodings/color/policy.js +5 -8
- package/src/actions/encodings/density/resolve.js +37 -5
- package/src/actions/encodings/density.js +124 -34
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +6 -0
- package/src/actions/encodings/offset.js +30 -29
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +63 -11
- package/src/actions/encodings/position/index.js +52 -6
- package/src/actions/encodings/position/policies/arc.js +14 -0
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +57 -13
- package/src/actions/encodings/position/resolve.js +88 -26
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +44 -34
- package/src/actions/encodings/ruleAppearance.js +24 -32
- package/src/actions/encodings/seriesLayout.js +105 -0
- package/src/actions/encodings/shared.js +107 -37
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +9 -6
- package/src/actions/encodings/temporal.js +7 -0
- package/src/actions/encodings/text.js +30 -15
- package/src/actions/errorBands/create.js +41 -8
- package/src/actions/errorBands/edit.js +360 -25
- package/src/actions/errorBars/create.js +56 -17
- package/src/actions/errorBars/edit.js +372 -21
- package/src/actions/facets/actions.js +619 -41
- package/src/actions/facets/derive.js +139 -25
- package/src/actions/gradientPlots/components.js +43 -13
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +8 -8
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +28 -19
- package/src/actions/guides/axes/axes.js +4 -3
- package/src/actions/guides/axes/axis.js +18 -18
- package/src/actions/guides/axes/components.js +43 -0
- package/src/actions/guides/axes/edit.js +16 -51
- package/src/actions/guides/axes/labels.js +184 -28
- package/src/actions/guides/axes/lines.js +13 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
- package/src/actions/guides/axes/parallel/policy.js +137 -0
- package/src/actions/guides/axes/parallel/resolve.js +50 -25
- package/src/actions/guides/axes/parallel.js +93 -217
- package/src/actions/guides/axes/policy.js +21 -67
- package/src/actions/guides/axes/tickGroups.js +15 -8
- package/src/actions/guides/axes/ticks.js +11 -6
- package/src/actions/guides/axes/titles.js +32 -11
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facade.js +106 -0
- package/src/actions/guides/facadeAxes.js +200 -0
- package/src/actions/guides/facadeLegend.js +63 -0
- package/src/actions/guides/grids/grid.js +37 -33
- package/src/actions/guides/grids/resolve.js +17 -4
- package/src/actions/guides/guides.js +54 -31
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +309 -279
- package/src/actions/guides/legends/categorical/components.js +21 -17
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +123 -354
- package/src/actions/guides/legends/categorical/options.js +32 -16
- package/src/actions/guides/legends/categorical/recipes.js +114 -9
- package/src/actions/guides/legends/categorical/resolve.js +30 -15
- package/src/actions/guides/legends/categorical/symbols.js +87 -33
- package/src/actions/guides/legends/continuous/common.js +99 -26
- package/src/actions/guides/legends/continuous/gradient.js +120 -89
- package/src/actions/guides/legends/continuous/index.js +8 -2
- package/src/actions/guides/legends/continuous/interval.js +79 -95
- package/src/actions/guides/legends/continuous/opacity.js +113 -89
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +40 -0
- package/src/actions/guides/legends/edit.js +321 -90
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +149 -102
- package/src/actions/guides/legends/lifecycle.js +143 -0
- package/src/actions/guides/legends/remove.js +43 -78
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +213 -116
- package/src/actions/guides/legends/strokeWidth.js +121 -73
- package/src/actions/guides/legends/target.js +123 -0
- package/src/actions/guides/legends/transition.js +192 -0
- package/src/actions/guides/polar/axes/facade.js +81 -66
- package/src/actions/guides/polar/axes/labels.js +28 -8
- package/src/actions/guides/polar/axes/lines.js +12 -5
- package/src/actions/guides/polar/axes/shared.js +22 -0
- package/src/actions/guides/polar/axes/ticks.js +6 -5
- package/src/actions/guides/polar/axes/titles.js +6 -5
- package/src/actions/guides/polar/grids.js +8 -8
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +15 -2
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +78 -20
- package/src/actions/marks/area/actions.js +51 -12
- package/src/actions/marks/area/materialize.js +22 -3
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +33 -9
- package/src/actions/marks/index.js +14 -0
- package/src/actions/marks/line/actions.js +71 -113
- package/src/actions/marks/line/materialize.js +57 -56
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +29 -21
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/point/jitter.js +3 -0
- package/src/actions/marks/point/materialize.js +154 -16
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +658 -0
- package/src/actions/marks/remove.js +87 -4
- package/src/actions/marks/rule/actions.js +77 -9
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +13 -13
- package/src/actions/marks/text/actions.js +296 -13
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +156 -8
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +3 -2
- package/src/actions/primitives/semanticAction.js +120 -10
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +23 -1
- package/src/actions/primitives/semanticValidation/scale.js +38 -8
- package/src/actions/regression/components.js +26 -11
- package/src/actions/regression/create.js +11 -3
- package/src/actions/regression/edit.js +40 -13
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +21 -54
- package/src/actions/scales/consumers/families.js +28 -14
- package/src/actions/scales/consumers/index.js +42 -4
- package/src/actions/scales/consumers/seriesLayout.js +57 -12
- package/src/actions/scales/create.js +58 -26
- package/src/actions/scales/definitions.js +109 -39
- package/src/actions/scales/edit.js +101 -34
- package/src/actions/scales/editPolicy.js +95 -35
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +14 -49
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +140 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +98 -0
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +16 -0
- package/src/actions/theme/reconcile.js +1130 -0
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +90 -43
- package/src/actions/violinPlots/edit.js +192 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +32 -2
- package/src/core/compositionState.js +141 -8
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +58 -1
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +37 -13
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +226 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +351 -0
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +123 -52
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/impute.js +340 -0
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +110 -0
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +109 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/positionDatum.js +12 -0
- package/src/grammar/rects.js +9 -1
- package/src/grammar/regression/derive.js +4 -0
- package/src/grammar/regression/index.js +8 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +63 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +8 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +57 -0
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +42 -5
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- package/src/grammar/schemas/semanticPath.js +23 -4
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +245 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +234 -13
- package/src/grammar/transformTopology.js +10 -0
- package/src/grammar/transforms.js +418 -16
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +232 -21
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +100 -12
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/labels.js +343 -0
- package/src/layout/legend.js +2 -10
- package/src/layout/legendItems.js +102 -0
- package/src/layout/legendLane.js +100 -11
- package/src/materialization/bars/aggregate.js +56 -147
- package/src/materialization/bars/histogram.js +104 -20
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/composition.js +3 -1
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +93 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +23 -66
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +28 -2
- package/src/materialization/legends.js +11 -2
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +68 -27
- package/src/materialization/marks/policies.js +4 -1
- package/src/materialization/rect.js +55 -42
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +6 -3
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +5 -1
- package/src/materialization/scales/resolve.js +65 -17
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +42 -71
- package/src/materialization/selection/items/common.js +27 -6
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +35 -8
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +324 -14
- package/src/mcp/adapter.js +2 -2
- package/src/renderers/canvas/circle.js +2 -3
- 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/svg.js +19 -0
- package/src/selectors/datasets.js +44 -0
- package/src/selectors/layers.js +7 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +140 -0
- package/types/basic.d.ts +17 -2
- package/types/index.d.ts +211 -0
- package/types/program.d.ts +2182 -204
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import { findDataset } from "../../selectors/datasets.js";
|
|
5
|
+
import { findLayer } from "../../selectors/layers.js";
|
|
6
|
+
import { rebindDistributionGuides } from "../distributions/revision.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveViolinDensity,
|
|
9
|
+
resolveViolinRoles,
|
|
10
|
+
resolveViolinSplit
|
|
11
|
+
} from "./create.js";
|
|
12
|
+
|
|
13
|
+
const OPERATION = "editViolinPlot";
|
|
14
|
+
const OPTIONS = Object.freeze([
|
|
15
|
+
"target", "data", "x", "y", "split", "density"
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
function resolveOwner(program, requested) {
|
|
19
|
+
const eligible = program.semanticSpec.layers.filter(
|
|
20
|
+
layer => program.markConfigs[layer.id]?.violinPlot?.materialized === true
|
|
21
|
+
);
|
|
22
|
+
if (requested !== undefined) {
|
|
23
|
+
const id = validateUserId(requested, "Violin-plot owner id");
|
|
24
|
+
const layer = findLayer(program, id);
|
|
25
|
+
if (layer === undefined || !eligible.includes(layer)) {
|
|
26
|
+
throw new Error(`Unknown violin-plot owner "${id}".`);
|
|
27
|
+
}
|
|
28
|
+
return layer;
|
|
29
|
+
}
|
|
30
|
+
const current = findLayer(program, program.context.currentMark);
|
|
31
|
+
if (current !== undefined && eligible.includes(current)) return current;
|
|
32
|
+
if (eligible.length === 1) return eligible[0];
|
|
33
|
+
if (eligible.length === 0) throw new Error(`${OPERATION} requires a violin plot.`);
|
|
34
|
+
throw new Error(`${OPERATION} target is ambiguous; provide target.`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function currentPosition(owner, current, channel) {
|
|
38
|
+
const categorical = current.orientation === "vertical"
|
|
39
|
+
? channel === "x"
|
|
40
|
+
: channel === "y";
|
|
41
|
+
return {
|
|
42
|
+
field: categorical ? current.category : current.value,
|
|
43
|
+
fieldType: categorical ? current.categoryType : "quantitative",
|
|
44
|
+
scale: { id: owner.encoding[channel].scale }
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function requestedScale(args, channel, expectedId) {
|
|
49
|
+
if (!Object.hasOwn(args, channel) || typeof args[channel] !== "object") {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const scale = args[channel].scale;
|
|
53
|
+
if (scale === undefined) return undefined;
|
|
54
|
+
if (scale.id !== undefined && scale.id !== expectedId) {
|
|
55
|
+
throw new Error(`${OPERATION} ${channel} scale cannot change its id.`);
|
|
56
|
+
}
|
|
57
|
+
const { id: _id, ...definition } = scale;
|
|
58
|
+
void _id;
|
|
59
|
+
return definition;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function assertSplitSelectionCompatibility(program, owner, changesSplit) {
|
|
63
|
+
if (!changesSplit) return;
|
|
64
|
+
const referenced = Object.entries(
|
|
65
|
+
program.materializationConfigs.selections ?? {}
|
|
66
|
+
).find(([, selection]) =>
|
|
67
|
+
selection.target === owner.id && selection.selector?.channel === "color"
|
|
68
|
+
);
|
|
69
|
+
if (referenced !== undefined) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`${OPERATION} cannot change split while selection "${referenced[0]}" ` +
|
|
72
|
+
"references color."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const editViolinPlot = action(
|
|
78
|
+
{
|
|
79
|
+
op: OPERATION,
|
|
80
|
+
description: "Revise one violin plot's data and statistical roles."
|
|
81
|
+
},
|
|
82
|
+
function (args = {}) {
|
|
83
|
+
validateKeys(args, OPTIONS, OPERATION);
|
|
84
|
+
if (!OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
|
|
85
|
+
throw new Error(`${OPERATION} requires at least one violin-plot option.`);
|
|
86
|
+
}
|
|
87
|
+
const owner = resolveOwner(this, args.target);
|
|
88
|
+
const current = this.markConfigs[owner.id].violinPlot;
|
|
89
|
+
const source = Object.hasOwn(args, "data")
|
|
90
|
+
? validateUserId(args.data, "Violin-plot data id")
|
|
91
|
+
: current.source;
|
|
92
|
+
const dataset = findDataset(this, source);
|
|
93
|
+
if (dataset === undefined) {
|
|
94
|
+
throw new Error(`Unknown violin-plot data "${source}".`);
|
|
95
|
+
}
|
|
96
|
+
const roles = resolveViolinRoles(
|
|
97
|
+
dataset,
|
|
98
|
+
Object.hasOwn(args, "x") ? args.x : currentPosition(owner, current, "x"),
|
|
99
|
+
Object.hasOwn(args, "y") ? args.y : currentPosition(owner, current, "y"),
|
|
100
|
+
OPERATION
|
|
101
|
+
);
|
|
102
|
+
const split = Object.hasOwn(args, "split")
|
|
103
|
+
? resolveViolinSplit(args.split, roles.category, OPERATION, {
|
|
104
|
+
removable: true
|
|
105
|
+
})
|
|
106
|
+
: current.split;
|
|
107
|
+
if (split?.field === roles.category.field) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`${OPERATION} split field must differ from its category field.`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
const density = resolveViolinDensity(args.density, current.density, OPERATION);
|
|
113
|
+
const changesSplit = split?.field !== current.split?.field;
|
|
114
|
+
assertSplitSelectionCompatibility(this, owner, changesSplit);
|
|
115
|
+
if (current.colorRole === "split" && split === undefined) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`${OPERATION} cannot remove split while color encodes the split field.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const categoryChannel = roles.orientation === "vertical" ? "x" : "y";
|
|
122
|
+
const valueChannel = roles.orientation === "vertical" ? "y" : "x";
|
|
123
|
+
const categoryScale = requestedScale(
|
|
124
|
+
args, categoryChannel, owner.encoding[categoryChannel].scale
|
|
125
|
+
);
|
|
126
|
+
const valueScale = requestedScale(
|
|
127
|
+
args, valueChannel, owner.encoding[valueChannel].scale
|
|
128
|
+
);
|
|
129
|
+
const { width, side, ...densityOptions } = density;
|
|
130
|
+
let next = this;
|
|
131
|
+
if (current.colorRole === "split" && changesSplit) {
|
|
132
|
+
next = next.editSemantic({
|
|
133
|
+
property: `layer[${owner.id}].encoding.color.field`,
|
|
134
|
+
value: split.field
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
next = next.editDensity({
|
|
138
|
+
target: owner.id,
|
|
139
|
+
source,
|
|
140
|
+
field: roles.value.field,
|
|
141
|
+
groupBy: roles.category.field,
|
|
142
|
+
densityChannel: roles.densityChannel,
|
|
143
|
+
...densityOptions,
|
|
144
|
+
...(valueScale === undefined ? {} : { valueScale }),
|
|
145
|
+
placement: {
|
|
146
|
+
type: "category",
|
|
147
|
+
...(side === undefined ? {} : { side }),
|
|
148
|
+
width,
|
|
149
|
+
...(split === undefined ? {} : { split }),
|
|
150
|
+
...(categoryScale === undefined ? {} : { scale: categoryScale })
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
next = rebindDistributionGuides(next, {
|
|
154
|
+
oldXScale: owner.encoding.x.scale,
|
|
155
|
+
oldYScale: owner.encoding.y.scale,
|
|
156
|
+
newXScale: owner.encoding.x.scale,
|
|
157
|
+
newYScale: owner.encoding.y.scale,
|
|
158
|
+
oldXTitle: current.orientation === "vertical" ? current.category : current.value,
|
|
159
|
+
oldYTitle: current.orientation === "vertical" ? current.value : current.category,
|
|
160
|
+
newXTitle: roles.x.field,
|
|
161
|
+
newYTitle: roles.y.field,
|
|
162
|
+
oldMeasureChannel: current.orientation === "vertical" ? "y" : "x",
|
|
163
|
+
newMeasureChannel: valueChannel
|
|
164
|
+
});
|
|
165
|
+
const revisedLayer = findLayer(next, owner.id);
|
|
166
|
+
const transform = findDataset(next, revisedLayer.data).transform[0];
|
|
167
|
+
next = next._withMarkConfig(owner.id, {
|
|
168
|
+
...next.markConfigs[owner.id],
|
|
169
|
+
violinPlot: {
|
|
170
|
+
...current,
|
|
171
|
+
materialized: true,
|
|
172
|
+
source,
|
|
173
|
+
orientation: roles.orientation,
|
|
174
|
+
category: roles.category.field,
|
|
175
|
+
categoryType: roles.category.fieldType,
|
|
176
|
+
value: roles.value.field,
|
|
177
|
+
split: transform.placement.split,
|
|
178
|
+
density: {
|
|
179
|
+
bandwidth: transform.bandwidth,
|
|
180
|
+
extent: transform.extent,
|
|
181
|
+
steps: transform.steps,
|
|
182
|
+
kernel: transform.kernel,
|
|
183
|
+
normalization: transform.normalization,
|
|
184
|
+
...(transform.weight === undefined ? {} : { weight: transform.weight }),
|
|
185
|
+
width: transform.placement.width,
|
|
186
|
+
side: transform.placement.side
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return next._withContext({ currentMark: owner.id, currentData: source });
|
|
191
|
+
}
|
|
192
|
+
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createViolinPlot } from "./create.js";
|
|
2
|
+
import { editViolinPlot } from "./edit.js";
|
|
2
3
|
|
|
3
4
|
export function registerViolinPlotActions(ProgramClass) {
|
|
4
5
|
ProgramClass.prototype.createViolinPlot = createViolinPlot;
|
|
6
|
+
ProgramClass.prototype.editViolinPlot = editViolinPlot;
|
|
5
7
|
}
|
package/src/core/ChartProgram.js
CHANGED
|
@@ -173,6 +173,13 @@ export class ChartProgram {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
_withoutResolvedScale(id) {
|
|
177
|
+
if (!Object.hasOwn(this.resolvedScales, id)) return this;
|
|
178
|
+
const { [id]: unused, ...remaining } = this.resolvedScales;
|
|
179
|
+
void unused;
|
|
180
|
+
return this._clone({ resolvedScales: freezeOwned(remaining) });
|
|
181
|
+
}
|
|
182
|
+
|
|
176
183
|
_withMarkConfig(id, config) {
|
|
177
184
|
if (typeof id !== "string" || id.length === 0) {
|
|
178
185
|
throw new TypeError("Mark config id must be a non-empty string.");
|
package/src/core/action.js
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
import { cloneAndFreeze, freezeOwned, isPlainObject } from "./immutable.js";
|
|
2
2
|
|
|
3
3
|
const metadataByWrappedAction = new WeakMap();
|
|
4
|
+
const implementationByWrappedAction = new WeakMap();
|
|
5
|
+
let actionCompletionHook;
|
|
6
|
+
|
|
7
|
+
export function setActionCompletionHook(hook) {
|
|
8
|
+
if (hook !== undefined && typeof hook !== "function") {
|
|
9
|
+
throw new TypeError("Action completion hook must be a function.");
|
|
10
|
+
}
|
|
11
|
+
actionCompletionHook = hook;
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
export function getWrappedActionMetadata(value) {
|
|
6
15
|
return metadataByWrappedAction.get(value);
|
|
7
16
|
}
|
|
8
17
|
|
|
18
|
+
export function invokeWrappedActionImplementation(value, program, args = {}) {
|
|
19
|
+
const implementation = implementationByWrappedAction.get(value);
|
|
20
|
+
if (implementation === undefined) {
|
|
21
|
+
throw new TypeError("Expected an action created by action().");
|
|
22
|
+
}
|
|
23
|
+
return implementation.call(program, args);
|
|
24
|
+
}
|
|
25
|
+
|
|
9
26
|
function summarizeObject(value, ancestors = new WeakSet()) {
|
|
10
27
|
if (ancestors.has(value)) {
|
|
11
28
|
throw new TypeError("Action arguments must not contain circular references.");
|
|
@@ -127,19 +144,32 @@ export function action(metadata, implementation) {
|
|
|
127
144
|
if (scope === "unit") this._assertUnitProgram(ownedMetadata.op);
|
|
128
145
|
if (scope === "composition") this._assertCompositionProgram(ownedMetadata.op);
|
|
129
146
|
|
|
147
|
+
const summarizedArgs = summarizeArgs(args);
|
|
130
148
|
const entered = this._enterAction({
|
|
131
149
|
...ownedMetadata,
|
|
132
|
-
args:
|
|
150
|
+
args: summarizedArgs
|
|
133
151
|
});
|
|
134
|
-
|
|
152
|
+
let result = implementation.call(entered, args);
|
|
135
153
|
|
|
136
154
|
if (!(result instanceof this.constructor)) {
|
|
137
155
|
throw new TypeError(`${ownedMetadata.op} must return a ChartProgram.`);
|
|
138
156
|
}
|
|
139
157
|
|
|
158
|
+
if (this.actionStack.length === 0 && actionCompletionHook !== undefined) {
|
|
159
|
+
result = actionCompletionHook(result, {
|
|
160
|
+
source: this,
|
|
161
|
+
metadata: ownedMetadata,
|
|
162
|
+
args: summarizedArgs
|
|
163
|
+
});
|
|
164
|
+
if (!(result instanceof this.constructor)) {
|
|
165
|
+
throw new TypeError("Action completion hook must return a ChartProgram.");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
140
169
|
return result._exitAction();
|
|
141
170
|
};
|
|
142
171
|
|
|
143
172
|
metadataByWrappedAction.set(wrappedAction, ownedMetadata);
|
|
173
|
+
implementationByWrappedAction.set(wrappedAction, implementation);
|
|
144
174
|
return wrappedAction;
|
|
145
175
|
}
|
|
@@ -11,24 +11,23 @@ function validateFacetSpec(compositionSpec) {
|
|
|
11
11
|
}
|
|
12
12
|
if (
|
|
13
13
|
!Number.isInteger(compositionSpec.columns) ||
|
|
14
|
-
compositionSpec.columns <= 0
|
|
15
|
-
compositionSpec.columns > compositionSpec.children.length
|
|
14
|
+
compositionSpec.columns <= 0
|
|
16
15
|
) {
|
|
17
16
|
throw new RangeError(
|
|
18
|
-
"Facet compositionSpec.columns must be a positive integer
|
|
17
|
+
"Facet compositionSpec.columns must be a positive integer."
|
|
19
18
|
);
|
|
20
19
|
}
|
|
21
20
|
if (!isPlainObject(compositionSpec.facet)) {
|
|
22
21
|
throw new TypeError("Facet compositionSpec.facet must be a plain object.");
|
|
23
22
|
}
|
|
24
|
-
const facetKeys = ["data", "field", "values", "scales", "guides"];
|
|
23
|
+
const facetKeys = ["data", "field", "values", "grid", "repeat", "scales", "guides"];
|
|
25
24
|
const unknownFacet = Object.keys(compositionSpec.facet).find(
|
|
26
25
|
key => !facetKeys.includes(key)
|
|
27
26
|
);
|
|
28
27
|
if (unknownFacet !== undefined) {
|
|
29
28
|
throw new Error(`Unknown compositionSpec.facet property "${unknownFacet}".`);
|
|
30
29
|
}
|
|
31
|
-
for (const property of ["data"
|
|
30
|
+
for (const property of ["data"]) {
|
|
32
31
|
if (
|
|
33
32
|
typeof compositionSpec.facet[property] !== "string" ||
|
|
34
33
|
compositionSpec.facet[property].length === 0
|
|
@@ -36,6 +35,134 @@ function validateFacetSpec(compositionSpec) {
|
|
|
36
35
|
throw new TypeError(`compositionSpec.facet.${property} must be a non-empty string.`);
|
|
37
36
|
}
|
|
38
37
|
}
|
|
38
|
+
const grid = compositionSpec.facet.grid;
|
|
39
|
+
const repeat = compositionSpec.facet.repeat;
|
|
40
|
+
if (grid !== undefined && repeat !== undefined) {
|
|
41
|
+
throw new Error("Facet compositionSpec cannot combine grid and repeat recipes.");
|
|
42
|
+
}
|
|
43
|
+
if (grid === undefined && repeat === undefined) {
|
|
44
|
+
if (compositionSpec.columns > compositionSpec.children.length) {
|
|
45
|
+
throw new RangeError(
|
|
46
|
+
"Facet compositionSpec.columns must be no larger than its children."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (
|
|
50
|
+
typeof compositionSpec.facet.field !== "string" ||
|
|
51
|
+
compositionSpec.facet.field.length === 0
|
|
52
|
+
) {
|
|
53
|
+
throw new TypeError("compositionSpec.facet.field must be a non-empty string.");
|
|
54
|
+
}
|
|
55
|
+
} else if (grid !== undefined) {
|
|
56
|
+
if (compositionSpec.columns !== grid.columns?.values?.length) {
|
|
57
|
+
throw new RangeError(
|
|
58
|
+
"Grid facet compositionSpec.columns must match its column domain."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (compositionSpec.facet.field !== undefined) {
|
|
62
|
+
throw new Error("Grid facet compositionSpec does not use facet.field.");
|
|
63
|
+
}
|
|
64
|
+
if (!isPlainObject(grid)) {
|
|
65
|
+
throw new TypeError("compositionSpec.facet.grid must be a plain object.");
|
|
66
|
+
}
|
|
67
|
+
const gridKeys = ["rows", "columns", "combinations", "cells"];
|
|
68
|
+
const unknownGrid = Object.keys(grid).find(key => !gridKeys.includes(key));
|
|
69
|
+
if (unknownGrid !== undefined) {
|
|
70
|
+
throw new Error(`Unknown compositionSpec.facet.grid property "${unknownGrid}".`);
|
|
71
|
+
}
|
|
72
|
+
for (const role of ["rows", "columns"]) {
|
|
73
|
+
const value = grid[role];
|
|
74
|
+
if (!isPlainObject(value) || Object.keys(value).some(
|
|
75
|
+
key => !["field", "values"].includes(key)
|
|
76
|
+
)) {
|
|
77
|
+
throw new TypeError(
|
|
78
|
+
`compositionSpec.facet.grid.${role} requires field and values.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (typeof value.field !== "string" || value.field.length === 0) {
|
|
82
|
+
throw new TypeError(
|
|
83
|
+
`compositionSpec.facet.grid.${role}.field must be a non-empty string.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (
|
|
87
|
+
!Array.isArray(value.values) || value.values.length === 0 ||
|
|
88
|
+
value.values.some(item => !(
|
|
89
|
+
typeof item === "string" || typeof item === "boolean" ||
|
|
90
|
+
(typeof item === "number" && Number.isFinite(item))
|
|
91
|
+
)) || new Set(value.values).size !== value.values.length
|
|
92
|
+
) {
|
|
93
|
+
throw new TypeError(
|
|
94
|
+
`compositionSpec.facet.grid.${role}.values must contain unique scalars.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (grid.rows.field === grid.columns.field) {
|
|
99
|
+
throw new Error("compositionSpec.facet.grid fields must be different.");
|
|
100
|
+
}
|
|
101
|
+
if (!["observed", "full"].includes(grid.combinations)) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
'compositionSpec.facet.grid.combinations must be "observed" or "full".'
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (!Array.isArray(grid.cells) || grid.cells.length !== compositionSpec.children.length) {
|
|
107
|
+
throw new TypeError(
|
|
108
|
+
"compositionSpec.facet.grid.cells must contain one descriptor per child."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const cellKeys = ["id", "row", "column", "rowValue", "columnValue", "empty"];
|
|
112
|
+
const coordinates = new Set();
|
|
113
|
+
for (const cell of grid.cells) {
|
|
114
|
+
if (!isPlainObject(cell) || Object.keys(cell).some(key => !cellKeys.includes(key))) {
|
|
115
|
+
throw new TypeError("compositionSpec.facet.grid cells must be canonical objects.");
|
|
116
|
+
}
|
|
117
|
+
if (!compositionSpec.children.includes(cell.id)) {
|
|
118
|
+
throw new Error(`Unknown grid facet child "${cell.id}".`);
|
|
119
|
+
}
|
|
120
|
+
if (!Number.isInteger(cell.row) || cell.row < 0 || cell.row >= grid.rows.values.length ||
|
|
121
|
+
!Number.isInteger(cell.column) || cell.column < 0 || cell.column >= grid.columns.values.length) {
|
|
122
|
+
throw new RangeError("Grid facet cell coordinates must be inside their domains.");
|
|
123
|
+
}
|
|
124
|
+
if (cell.rowValue !== grid.rows.values[cell.row] ||
|
|
125
|
+
cell.columnValue !== grid.columns.values[cell.column]) {
|
|
126
|
+
throw new Error("Grid facet cell values must match their row and column coordinates.");
|
|
127
|
+
}
|
|
128
|
+
if (typeof cell.empty !== "boolean") {
|
|
129
|
+
throw new TypeError("Grid facet cell empty must be a boolean.");
|
|
130
|
+
}
|
|
131
|
+
const key = `${cell.row}:${cell.column}`;
|
|
132
|
+
if (coordinates.has(key)) {
|
|
133
|
+
throw new Error("Grid facet cells must occupy unique coordinates.");
|
|
134
|
+
}
|
|
135
|
+
coordinates.add(key);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
if (compositionSpec.facet.field !== undefined) {
|
|
139
|
+
throw new Error("Repeat compositionSpec does not use facet.field.");
|
|
140
|
+
}
|
|
141
|
+
if (compositionSpec.columns > compositionSpec.children.length) {
|
|
142
|
+
throw new RangeError(
|
|
143
|
+
"Repeat compositionSpec.columns must be no larger than its children."
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (!isPlainObject(repeat) || Object.keys(repeat).some(
|
|
147
|
+
key => !["target", "channel", "fields"].includes(key)
|
|
148
|
+
)) {
|
|
149
|
+
throw new TypeError(
|
|
150
|
+
"compositionSpec.facet.repeat requires target, channel, and fields."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const repeatChannel = ["x", "y", "theta", "r"].includes(repeat.channel) ||
|
|
154
|
+
(isPlainObject(repeat.channel) &&
|
|
155
|
+
Object.keys(repeat.channel).length === 1 &&
|
|
156
|
+
typeof repeat.channel.parallelDimension === "string" &&
|
|
157
|
+
repeat.channel.parallelDimension.length > 0);
|
|
158
|
+
if (typeof repeat.target !== "string" || repeat.target.length === 0 ||
|
|
159
|
+
!repeatChannel ||
|
|
160
|
+
!Array.isArray(repeat.fields) || repeat.fields.length === 0 ||
|
|
161
|
+
repeat.fields.some(field => typeof field !== "string" || field.length === 0) ||
|
|
162
|
+
new Set(repeat.fields).size !== repeat.fields.length) {
|
|
163
|
+
throw new TypeError("compositionSpec.facet.repeat is not canonical.");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
39
166
|
const values = compositionSpec.facet.values;
|
|
40
167
|
if (
|
|
41
168
|
!Array.isArray(values) ||
|
|
@@ -45,12 +172,18 @@ function validateFacetSpec(compositionSpec) {
|
|
|
45
172
|
typeof value === "boolean" ||
|
|
46
173
|
(typeof value === "number" && Number.isFinite(value))
|
|
47
174
|
)) ||
|
|
48
|
-
new Set(values).size !== values.length
|
|
175
|
+
(grid === undefined && new Set(values).size !== values.length)
|
|
49
176
|
) {
|
|
50
177
|
throw new TypeError(
|
|
51
178
|
"compositionSpec.facet.values must contain one unique scalar per child."
|
|
52
179
|
);
|
|
53
180
|
}
|
|
181
|
+
if (repeat !== undefined && (
|
|
182
|
+
values.length !== repeat.fields.length ||
|
|
183
|
+
values.some((value, index) => value !== repeat.fields[index])
|
|
184
|
+
)) {
|
|
185
|
+
throw new Error("compositionSpec.facet.values must match repeat fields.");
|
|
186
|
+
}
|
|
54
187
|
const scales = compositionSpec.facet.scales;
|
|
55
188
|
if (
|
|
56
189
|
!isPlainObject(scales) ||
|
|
@@ -80,13 +213,13 @@ function validateFacetSpec(compositionSpec) {
|
|
|
80
213
|
function validateCompositionChildren(compositionSpec, childIds, facet) {
|
|
81
214
|
if (
|
|
82
215
|
!Array.isArray(compositionSpec.children) ||
|
|
83
|
-
compositionSpec.children.length <
|
|
216
|
+
compositionSpec.children.length < 1 ||
|
|
84
217
|
!compositionSpec.children.every(id => typeof id === "string" && id.length > 0)
|
|
85
218
|
) {
|
|
86
219
|
throw new TypeError(
|
|
87
220
|
facet
|
|
88
221
|
? "Facet compositionSpec.children requires at least one child ID."
|
|
89
|
-
: "compositionSpec.children requires at least
|
|
222
|
+
: "compositionSpec.children requires at least one child ID."
|
|
90
223
|
);
|
|
91
224
|
}
|
|
92
225
|
if (new Set(compositionSpec.children).size !== compositionSpec.children.length) {
|
package/src/core/programState.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isOwned,
|
|
5
5
|
isPlainObject
|
|
6
6
|
} from "./immutable.js";
|
|
7
|
+
import { removeMaterializationConfig } from "./materializationState.js";
|
|
7
8
|
|
|
8
9
|
export function ownProgramState(value) {
|
|
9
10
|
return isOwned(value) ? value : cloneAndFreeze(value);
|
|
@@ -26,3 +27,22 @@ export function ownChildPrograms(children, ProgramClass) {
|
|
|
26
27
|
}
|
|
27
28
|
return freezeOwned(owned);
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
// Semantic entries, resolved scale caches, and physical current-resource IDs
|
|
32
|
+
// are removed by editSemantic. A logical data owner also retains its own ID
|
|
33
|
+
// and replay configuration; release those non-semantic references after the
|
|
34
|
+
// domain's dependency validation and before the primitive deletion.
|
|
35
|
+
export function releaseNamedResourceOwnership(program, { kind, id, dataOwner }) {
|
|
36
|
+
if (kind !== "data") return program;
|
|
37
|
+
const materializationConfigs = dataOwner === undefined
|
|
38
|
+
? program.materializationConfigs
|
|
39
|
+
: removeMaterializationConfig(
|
|
40
|
+
program.materializationConfigs,
|
|
41
|
+
["data", dataOwner.family, dataOwner.owner]
|
|
42
|
+
).value;
|
|
43
|
+
const context = program.context.currentData === id
|
|
44
|
+
? freezeOwned({ ...program.context, currentData: undefined })
|
|
45
|
+
: program.context;
|
|
46
|
+
if (context === program.context && materializationConfigs === program.materializationConfigs) return program;
|
|
47
|
+
return program._clone({ context, materializationConfigs });
|
|
48
|
+
}
|