ggaction 0.0.1

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 (222) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +108 -0
  4. package/package.json +84 -0
  5. package/src/AGENTS.md +119 -0
  6. package/src/ChartProgram.js +10 -0
  7. package/src/actions/boxPlots/components.js +88 -0
  8. package/src/actions/boxPlots/create.js +84 -0
  9. package/src/actions/boxPlots/index.js +10 -0
  10. package/src/actions/boxPlots/materialize.js +183 -0
  11. package/src/actions/boxPlots/options.js +147 -0
  12. package/src/actions/boxPlots/resolve.js +38 -0
  13. package/src/actions/canvas/actions.js +144 -0
  14. package/src/actions/canvas/index.js +6 -0
  15. package/src/actions/coordinates/actions.js +85 -0
  16. package/src/actions/coordinates/index.js +5 -0
  17. package/src/actions/data/box.js +40 -0
  18. package/src/actions/data/create.js +33 -0
  19. package/src/actions/data/density.js +62 -0
  20. package/src/actions/data/derived.js +52 -0
  21. package/src/actions/data/filter.js +168 -0
  22. package/src/actions/data/index.js +32 -0
  23. package/src/actions/data/interval.js +69 -0
  24. package/src/actions/data/regression.js +71 -0
  25. package/src/actions/data/shared.js +25 -0
  26. package/src/actions/encodings/appearance.js +243 -0
  27. package/src/actions/encodings/barWidth.js +60 -0
  28. package/src/actions/encodings/color.js +329 -0
  29. package/src/actions/encodings/density.js +225 -0
  30. package/src/actions/encodings/histogram.js +50 -0
  31. package/src/actions/encodings/index.js +23 -0
  32. package/src/actions/encodings/offset.js +104 -0
  33. package/src/actions/encodings/position/policies/area.js +24 -0
  34. package/src/actions/encodings/position/policies/bar.js +110 -0
  35. package/src/actions/encodings/position/policies/common.js +17 -0
  36. package/src/actions/encodings/position/policies/index.js +25 -0
  37. package/src/actions/encodings/position/policies/line.js +74 -0
  38. package/src/actions/encodings/position/policies/point.js +19 -0
  39. package/src/actions/encodings/position/policies/rule.js +17 -0
  40. package/src/actions/encodings/position/resolve.js +170 -0
  41. package/src/actions/encodings/position.js +176 -0
  42. package/src/actions/encodings/ranged.js +276 -0
  43. package/src/actions/encodings/ruleAppearance.js +47 -0
  44. package/src/actions/encodings/shared.js +164 -0
  45. package/src/actions/encodings/strokeDash.js +145 -0
  46. package/src/actions/errorBands/components.js +81 -0
  47. package/src/actions/errorBands/create.js +159 -0
  48. package/src/actions/errorBands/index.js +7 -0
  49. package/src/actions/errorBands/resolve.js +28 -0
  50. package/src/actions/errorBars/components.js +62 -0
  51. package/src/actions/errorBars/create.js +144 -0
  52. package/src/actions/errorBars/index.js +7 -0
  53. package/src/actions/errorBars/resolve.js +25 -0
  54. package/src/actions/guides/axes/axes.js +204 -0
  55. package/src/actions/guides/axes/axis.js +131 -0
  56. package/src/actions/guides/axes/index.js +17 -0
  57. package/src/actions/guides/axes/labels.js +231 -0
  58. package/src/actions/guides/axes/lines.js +149 -0
  59. package/src/actions/guides/axes/policy.js +155 -0
  60. package/src/actions/guides/axes/tickGroups.js +149 -0
  61. package/src/actions/guides/axes/ticks.js +179 -0
  62. package/src/actions/guides/axes/titles.js +264 -0
  63. package/src/actions/guides/grids/grid.js +228 -0
  64. package/src/actions/guides/grids/index.js +1 -0
  65. package/src/actions/guides/grids/resolve.js +258 -0
  66. package/src/actions/guides/guides.js +138 -0
  67. package/src/actions/guides/index.js +11 -0
  68. package/src/actions/guides/legends/categorical/actions.js +329 -0
  69. package/src/actions/guides/legends/categorical/components.js +140 -0
  70. package/src/actions/guides/legends/categorical/index.js +49 -0
  71. package/src/actions/guides/legends/categorical/layout.js +445 -0
  72. package/src/actions/guides/legends/categorical/options.js +188 -0
  73. package/src/actions/guides/legends/categorical/recipes.js +120 -0
  74. package/src/actions/guides/legends/categorical/resolve.js +131 -0
  75. package/src/actions/guides/legends/categorical/symbols.js +280 -0
  76. package/src/actions/guides/legends/categorical/validation.js +27 -0
  77. package/src/actions/guides/legends/continuous/common.js +273 -0
  78. package/src/actions/guides/legends/continuous/gradient.js +363 -0
  79. package/src/actions/guides/legends/continuous/index.js +25 -0
  80. package/src/actions/guides/legends/continuous/interval.js +234 -0
  81. package/src/actions/guides/legends/continuous/opacity.js +382 -0
  82. package/src/actions/guides/legends/edit.js +314 -0
  83. package/src/actions/guides/legends/index.js +9 -0
  84. package/src/actions/guides/legends/size.js +220 -0
  85. package/src/actions/guides/tickValues.js +84 -0
  86. package/src/actions/index.js +31 -0
  87. package/src/actions/intervals/resolve.js +352 -0
  88. package/src/actions/marks/area.js +369 -0
  89. package/src/actions/marks/bar/create.js +46 -0
  90. package/src/actions/marks/bar/edit.js +90 -0
  91. package/src/actions/marks/bar/index.js +9 -0
  92. package/src/actions/marks/bar/materialize.js +130 -0
  93. package/src/actions/marks/index.js +13 -0
  94. package/src/actions/marks/line.js +248 -0
  95. package/src/actions/marks/point.js +420 -0
  96. package/src/actions/marks/rule.js +287 -0
  97. package/src/actions/marks/shared.js +112 -0
  98. package/src/actions/primitives/createGraphics.js +163 -0
  99. package/src/actions/primitives/editGraphics.js +208 -0
  100. package/src/actions/primitives/index.js +9 -0
  101. package/src/actions/primitives/semantic.js +168 -0
  102. package/src/actions/primitives/semanticValue.js +182 -0
  103. package/src/actions/regression/components.js +216 -0
  104. package/src/actions/regression/create.js +102 -0
  105. package/src/actions/regression/index.js +23 -0
  106. package/src/actions/regression/resolve.js +57 -0
  107. package/src/actions/scales/consumers.js +283 -0
  108. package/src/actions/scales/create.js +148 -0
  109. package/src/actions/scales/definitions.js +319 -0
  110. package/src/actions/scales/edit.js +290 -0
  111. package/src/actions/scales/index.js +11 -0
  112. package/src/actions/scales/materialize.js +466 -0
  113. package/src/actions/scales/quantitativeColor.js +45 -0
  114. package/src/actions/selection/actions.js +384 -0
  115. package/src/actions/selection/index.js +23 -0
  116. package/src/actions/titles/actions.js +235 -0
  117. package/src/actions/titles/index.js +19 -0
  118. package/src/actions/titles/resolve.js +321 -0
  119. package/src/core/ChartProgram.js +316 -0
  120. package/src/core/action.js +120 -0
  121. package/src/core/identifiers.js +28 -0
  122. package/src/core/immutable.js +94 -0
  123. package/src/core/specs.js +29 -0
  124. package/src/core/textMetrics.js +23 -0
  125. package/src/core/validation.js +54 -0
  126. package/src/core/vocabulary.js +58 -0
  127. package/src/extension.js +2 -0
  128. package/src/grammar/aggregate.js +259 -0
  129. package/src/grammar/areaSeries.js +217 -0
  130. package/src/grammar/bars/aggregate.js +98 -0
  131. package/src/grammar/bars/geometry.js +54 -0
  132. package/src/grammar/bars/policy.js +90 -0
  133. package/src/grammar/boxPlot.js +140 -0
  134. package/src/grammar/coordinates.js +25 -0
  135. package/src/grammar/curveCommands.js +356 -0
  136. package/src/grammar/density.js +296 -0
  137. package/src/grammar/filter.js +169 -0
  138. package/src/grammar/histogram.js +332 -0
  139. package/src/grammar/interval.js +343 -0
  140. package/src/grammar/lineSeries.js +197 -0
  141. package/src/grammar/markFilter.js +46 -0
  142. package/src/grammar/markSelection.js +326 -0
  143. package/src/grammar/palettes.js +208 -0
  144. package/src/grammar/pathCommands.js +86 -0
  145. package/src/grammar/pointShapes.js +164 -0
  146. package/src/grammar/positionCompatibility.js +32 -0
  147. package/src/grammar/regression.js +578 -0
  148. package/src/grammar/ruleAppearance.js +12 -0
  149. package/src/grammar/rules.js +90 -0
  150. package/src/grammar/scales/appearance.js +185 -0
  151. package/src/grammar/scales/color.js +349 -0
  152. package/src/grammar/scales/continuous.js +111 -0
  153. package/src/grammar/scales/definition.js +153 -0
  154. package/src/grammar/scales/discretized.js +159 -0
  155. package/src/grammar/scales/fields.js +133 -0
  156. package/src/grammar/scales/index.js +12 -0
  157. package/src/grammar/scales/mapping.js +27 -0
  158. package/src/grammar/scales/ordinal.js +221 -0
  159. package/src/grammar/scales/policies.js +50 -0
  160. package/src/grammar/scales/temporal.js +53 -0
  161. package/src/grammar/scales/transformed.js +236 -0
  162. package/src/grammar/scales/types.js +102 -0
  163. package/src/grammar/scales/validation.js +66 -0
  164. package/src/grammar/scales.js +1 -0
  165. package/src/grammar/schemas/concreteGraphic.js +73 -0
  166. package/src/grammar/schemas/graphic.js +131 -0
  167. package/src/grammar/schemas/graphicBounds.js +146 -0
  168. package/src/grammar/schemas/graphicTree.js +133 -0
  169. package/src/grammar/schemas/mark.js +4 -0
  170. package/src/grammar/schemas/semanticPath.js +174 -0
  171. package/src/grammar/seriesLayout.js +76 -0
  172. package/src/grammar/ticks.js +149 -0
  173. package/src/grammar/transforms.js +37 -0
  174. package/src/index.js +2 -0
  175. package/src/layout/canvas.js +114 -0
  176. package/src/layout/grid.js +17 -0
  177. package/src/layout/legend.js +51 -0
  178. package/src/layout/text.js +62 -0
  179. package/src/layout/title.js +107 -0
  180. package/src/materialization/bars/aggregate.js +184 -0
  181. package/src/materialization/bars/grouped.js +117 -0
  182. package/src/materialization/bars/histogram.js +163 -0
  183. package/src/materialization/bars/ranged.js +53 -0
  184. package/src/materialization/bars/resolve.js +56 -0
  185. package/src/materialization/dataProvenance.js +15 -0
  186. package/src/materialization/density.js +29 -0
  187. package/src/materialization/dependencies.js +134 -0
  188. package/src/materialization/encodings.js +50 -0
  189. package/src/materialization/graphicHierarchy.js +104 -0
  190. package/src/materialization/legends.js +20 -0
  191. package/src/materialization/marks.js +110 -0
  192. package/src/materialization/planner.js +38 -0
  193. package/src/materialization/selection/filter.js +40 -0
  194. package/src/materialization/selection/items.js +503 -0
  195. package/src/materialization/selection/path.js +37 -0
  196. package/src/materialization/selection/point.js +118 -0
  197. package/src/materialization/selection/policies/area.js +10 -0
  198. package/src/materialization/selection/policies/bar.js +10 -0
  199. package/src/materialization/selection/policies/index.js +40 -0
  200. package/src/materialization/selection/policies/line.js +10 -0
  201. package/src/materialization/selection/policies/point.js +10 -0
  202. package/src/materialization/selection/policies/rule.js +10 -0
  203. package/src/materialization/selection/state.js +67 -0
  204. package/src/materialization/selection/styles.js +183 -0
  205. package/src/renderers/canvas/circle.js +62 -0
  206. package/src/renderers/canvas/index.js +132 -0
  207. package/src/renderers/canvas/line.js +54 -0
  208. package/src/renderers/canvas/path.js +98 -0
  209. package/src/renderers/canvas/rect.js +57 -0
  210. package/src/renderers/canvas/text.js +96 -0
  211. package/src/renderers/canvas/validation.js +23 -0
  212. package/src/renderers/png.js +29 -0
  213. package/src/selectors/coordinates.js +13 -0
  214. package/src/selectors/datasets.js +13 -0
  215. package/src/selectors/index.js +4 -0
  216. package/src/selectors/layers.js +32 -0
  217. package/src/selectors/scales.js +21 -0
  218. package/src/theme/defaults.js +13 -0
  219. package/types/extension.d.ts +14 -0
  220. package/types/index.d.ts +81 -0
  221. package/types/png.d.ts +14 -0
  222. package/types/program.d.ts +1096 -0
@@ -0,0 +1,352 @@
1
+ import { isPlainObject } from "../../core/immutable.js";
2
+ import {
3
+ resolveOptionalUserId,
4
+ validateUserId
5
+ } from "../../core/identifiers.js";
6
+ import { readQuantitativeField } from "../../grammar/scales.js";
7
+ import { findDataset } from "../../selectors/datasets.js";
8
+ import { hasLayer, resolveEligibleLayer } from "../../selectors/layers.js";
9
+ import { findSemanticScale } from "../../selectors/scales.js";
10
+
11
+ const CHANNEL_OPTIONS = Object.freeze([
12
+ "field", "fieldType", "scale", "center", "extent", "level", "lower", "upper"
13
+ ]);
14
+ const INTERVAL_PARAMETER_KEYS = Object.freeze([
15
+ "center", "extent", "level", "lower", "upper"
16
+ ]);
17
+ const FIELD_TYPES = Object.freeze([
18
+ "quantitative", "temporal", "ordinal", "nominal"
19
+ ]);
20
+
21
+ function requireObject(value, label) {
22
+ if (!isPlainObject(value)) {
23
+ throw new TypeError(`${label} must be a plain object.`);
24
+ }
25
+ const unknown = Object.keys(value).find(key => !CHANNEL_OPTIONS.includes(key));
26
+ if (unknown !== undefined) {
27
+ throw new Error(`Unknown ${label} option "${unknown}".`);
28
+ }
29
+ return value;
30
+ }
31
+
32
+ function requireField(value, label) {
33
+ if (typeof value !== "string" || value.length === 0) {
34
+ throw new TypeError(`${label} must be a non-empty string.`);
35
+ }
36
+ return value;
37
+ }
38
+
39
+ function hasCompleteFieldPositions(layer) {
40
+ const x = layer.encoding?.x;
41
+ const y = layer.encoding?.y;
42
+ return (
43
+ typeof layer.data === "string" &&
44
+ typeof layer.coordinate === "string" &&
45
+ typeof x?.field === "string" &&
46
+ typeof y?.field === "string" &&
47
+ typeof x.scale === "string" &&
48
+ typeof y.scale === "string" &&
49
+ FIELD_TYPES.includes(x.fieldType) &&
50
+ FIELD_TYPES.includes(y.fieldType)
51
+ );
52
+ }
53
+
54
+ function resolveSourceLayer(program, args, operation) {
55
+ if (args.target === undefined && args.x !== undefined && args.y !== undefined) {
56
+ return undefined;
57
+ }
58
+ const target = args.target === undefined
59
+ ? undefined
60
+ : validateUserId(args.target, `${operation} source layer id`);
61
+ return resolveEligibleLayer(program, {
62
+ target,
63
+ predicate: hasCompleteFieldPositions,
64
+ label: operation
65
+ });
66
+ }
67
+
68
+ function resolveDataset(program, args, sourceLayer, operation, resourceLabel) {
69
+ const requested = args.data ?? sourceLayer?.data ?? program.context.currentData;
70
+ let dataset;
71
+ if (requested !== undefined) {
72
+ const id = validateUserId(requested, `${resourceLabel} dataset id`);
73
+ dataset = findDataset(program, id);
74
+ if (dataset === undefined) {
75
+ throw new Error(`Unknown ${resourceLabel} dataset "${id}".`);
76
+ }
77
+ } else if (program.semanticSpec.datasets.length === 1) {
78
+ dataset = program.semanticSpec.datasets[0];
79
+ }
80
+ if (dataset === undefined) {
81
+ throw new Error(`${operation} requires data or one uniquely inferable dataset.`);
82
+ }
83
+ if (sourceLayer !== undefined && dataset.id !== sourceLayer.data) {
84
+ throw new Error(
85
+ `${operation} data must match source layer "${sourceLayer.id}" data "${sourceLayer.data}".`
86
+ );
87
+ }
88
+ return dataset;
89
+ }
90
+
91
+ function scaleOptions(program, value, inferredId, defaults = {}) {
92
+ if (value !== undefined && !isPlainObject(value)) {
93
+ throw new TypeError("Interval scale must be a plain object.");
94
+ }
95
+ const id = value?.id ?? inferredId;
96
+ const usesExisting = id !== undefined && findSemanticScale(program, id) !== undefined;
97
+ return {
98
+ ...(usesExisting ? {} : defaults),
99
+ ...(value ?? {}),
100
+ ...(value?.id === undefined && inferredId !== undefined
101
+ ? { id: inferredId }
102
+ : {})
103
+ };
104
+ }
105
+
106
+ function hasAny(value, keys) {
107
+ return keys.some(key => Object.hasOwn(value ?? {}, key));
108
+ }
109
+
110
+ function resolveIntervalChannel(channels, sourceLayer, {
111
+ operation,
112
+ positionTypes,
113
+ defaultIntervalChannel,
114
+ ambiguousMessage
115
+ }) {
116
+ const explicitBounds = ["x", "y"].filter(channel =>
117
+ hasAny(channels[channel], ["lower", "upper"])
118
+ );
119
+ if (explicitBounds.length > 1) {
120
+ throw new Error(`${operation} requires exactly one interval channel.`);
121
+ }
122
+ if (explicitBounds.length === 1) return explicitBounds[0];
123
+
124
+ const statisticalHints = ["x", "y"].filter(channel =>
125
+ hasAny(channels[channel], ["center", "extent", "level"])
126
+ );
127
+ if (statisticalHints.length > 1) {
128
+ throw new Error(`${operation} requires exactly one interval channel.`);
129
+ }
130
+ if (statisticalHints.length === 1) return statisticalHints[0];
131
+
132
+ const effectiveTypes = Object.fromEntries(["x", "y"].map(channel => [
133
+ channel,
134
+ channels[channel]?.fieldType ?? sourceLayer?.encoding?.[channel]?.fieldType
135
+ ]));
136
+ const quantitative = ["x", "y"].filter(channel =>
137
+ effectiveTypes[channel] === "quantitative"
138
+ );
139
+ const positional = ["x", "y"].filter(channel =>
140
+ positionTypes.includes(effectiveTypes[channel])
141
+ );
142
+ if (quantitative.length === 1) {
143
+ const positionChannel = quantitative[0] === "x" ? "y" : "x";
144
+ if (positionTypes.includes(effectiveTypes[positionChannel])) {
145
+ return quantitative[0];
146
+ }
147
+ }
148
+ if (positional.length === 1) {
149
+ return positional[0] === "x" ? "y" : "x";
150
+ }
151
+ if (sourceLayer !== undefined) {
152
+ throw new Error(ambiguousMessage);
153
+ }
154
+ return defaultIntervalChannel;
155
+ }
156
+
157
+ function resolvePosition(program, channel, explicit, inferred, {
158
+ operation,
159
+ positionTypes,
160
+ defaultPositionType,
161
+ scaleDefaults
162
+ }) {
163
+ if (hasAny(explicit, INTERVAL_PARAMETER_KEYS)) {
164
+ throw new Error(`${operation} ${channel} position does not accept interval options.`);
165
+ }
166
+ const fieldType = explicit?.fieldType ?? inferred?.fieldType ?? defaultPositionType;
167
+ if (!positionTypes.includes(fieldType)) {
168
+ throw new Error(
169
+ `${operation} ${channel} position requires ${positionTypes.join(", ")} field type.`
170
+ );
171
+ }
172
+ return {
173
+ channel,
174
+ field: requireField(
175
+ explicit?.field ?? inferred?.field,
176
+ `${operation} ${channel} field`
177
+ ),
178
+ fieldType,
179
+ scale: scaleOptions(
180
+ program,
181
+ explicit?.scale,
182
+ inferred?.scale,
183
+ inferred === undefined ? scaleDefaults(fieldType) : {}
184
+ )
185
+ };
186
+ }
187
+
188
+ function resolveInterval(program, channel, explicit, inferred, dataset, {
189
+ operation,
190
+ intervalScaleDefaults
191
+ }) {
192
+ if (explicit?.fieldType !== undefined) {
193
+ throw new Error(`${operation} ${channel} interval does not accept fieldType.`);
194
+ }
195
+ if (inferred !== undefined && inferred.fieldType !== "quantitative") {
196
+ throw new Error(`${operation} ${channel} interval requires a quantitative field.`);
197
+ }
198
+ const hasLower = Object.hasOwn(explicit ?? {}, "lower");
199
+ const hasUpper = Object.hasOwn(explicit ?? {}, "upper");
200
+ const explicitMode = hasLower || hasUpper;
201
+ const scale = scaleOptions(
202
+ program,
203
+ explicit?.scale,
204
+ inferred?.scale,
205
+ inferred === undefined ? intervalScaleDefaults : {}
206
+ );
207
+ if (explicitMode) {
208
+ if (!hasLower || !hasUpper || !Object.hasOwn(explicit, "center")) {
209
+ throw new Error(
210
+ `Explicit ${operation} ${channel} interval requires center, lower, and upper fields.`
211
+ );
212
+ }
213
+ if (
214
+ explicit.field !== undefined ||
215
+ explicit.extent !== undefined ||
216
+ explicit.level !== undefined
217
+ ) {
218
+ throw new Error(
219
+ `Explicit ${operation} ${channel} interval cannot combine field, extent, or level.`
220
+ );
221
+ }
222
+ const fields = {
223
+ center: requireField(explicit.center, `${operation} ${channel} center`),
224
+ lower: requireField(explicit.lower, `${operation} ${channel} lower`),
225
+ upper: requireField(explicit.upper, `${operation} ${channel} upper`)
226
+ };
227
+ if (new Set(Object.values(fields)).size !== 3) {
228
+ throw new Error("Explicit interval center, lower, and upper fields must be distinct.");
229
+ }
230
+ for (const field of Object.values(fields)) {
231
+ readQuantitativeField(dataset.values, field);
232
+ }
233
+ return { channel, mode: "explicit", fields, scale, title: fields.center };
234
+ }
235
+ return {
236
+ channel,
237
+ mode: "statistical",
238
+ field: requireField(
239
+ explicit?.field ?? inferred?.field,
240
+ `${operation} ${channel} field`
241
+ ),
242
+ center: explicit?.center,
243
+ extent: explicit?.extent,
244
+ level: explicit?.level,
245
+ scale
246
+ };
247
+ }
248
+
249
+ function resolveGrouping(args, sourceLayer, independentField, mode, {
250
+ operation,
251
+ allowExplicitGrouping
252
+ }) {
253
+ if (mode === "explicit" && !allowExplicitGrouping && args.groupBy !== undefined) {
254
+ throw new Error(`Explicit ${operation} intervals do not accept groupBy.`);
255
+ }
256
+ const inferred = sourceLayer?.encoding?.group?.field;
257
+ const groupField = args.groupBy ?? inferred;
258
+ const normalizedGroup = groupField === undefined
259
+ ? undefined
260
+ : requireField(groupField, `${operation} groupBy`);
261
+ return {
262
+ groupField: normalizedGroup,
263
+ transformGroupBy: mode === "statistical"
264
+ ? normalizedGroup === undefined || normalizedGroup === independentField
265
+ ? [independentField]
266
+ : [independentField, normalizedGroup]
267
+ : undefined
268
+ };
269
+ }
270
+
271
+ function resolveOwner(program, requested, {
272
+ defaultId,
273
+ ownerLabel,
274
+ operation
275
+ }) {
276
+ const defaultOccupied = hasLayer(program, defaultId) ||
277
+ program.graphicSpec.objects[defaultId] !== undefined ||
278
+ findDataset(program, `${defaultId}IntervalData`) !== undefined;
279
+ return resolveOptionalUserId(requested, {
280
+ defaultId,
281
+ label: ownerLabel,
282
+ operation,
283
+ ambiguous: defaultOccupied
284
+ });
285
+ }
286
+
287
+ export function resolveIntervalComposite(program, args, policy) {
288
+ const channels = {
289
+ x: args.x === undefined
290
+ ? undefined
291
+ : requireObject(args.x, `${policy.operation} x`),
292
+ y: args.y === undefined
293
+ ? undefined
294
+ : requireObject(args.y, `${policy.operation} y`)
295
+ };
296
+ const sourceLayer = resolveSourceLayer(program, args, policy.operation);
297
+ const dataset = resolveDataset(
298
+ program,
299
+ args,
300
+ sourceLayer,
301
+ policy.operation,
302
+ policy.resourceLabel
303
+ );
304
+ const intervalChannel = resolveIntervalChannel(channels, sourceLayer, policy);
305
+ const positionChannel = intervalChannel === "x" ? "y" : "x";
306
+ const position = resolvePosition(
307
+ program,
308
+ positionChannel,
309
+ channels[positionChannel],
310
+ sourceLayer?.encoding?.[positionChannel],
311
+ policy
312
+ );
313
+ const interval = resolveInterval(
314
+ program,
315
+ intervalChannel,
316
+ channels[intervalChannel],
317
+ sourceLayer?.encoding?.[intervalChannel],
318
+ dataset,
319
+ policy
320
+ );
321
+ const id = resolveOwner(program, args.id, policy);
322
+ const generatedFields = {
323
+ center: `__${id}_center`,
324
+ lower: `__${id}_lower`,
325
+ upper: `__${id}_upper`
326
+ };
327
+ const fields = interval.mode === "explicit" ? interval.fields : generatedFields;
328
+ const grouping = resolveGrouping(
329
+ args,
330
+ sourceLayer,
331
+ position.field,
332
+ interval.mode,
333
+ policy
334
+ );
335
+
336
+ return {
337
+ id,
338
+ sourceLayer,
339
+ source: dataset.id,
340
+ dataId: interval.mode === "statistical" ? `${id}IntervalData` : dataset.id,
341
+ coordinate: validateUserId(
342
+ args.coordinate ?? sourceLayer?.coordinate ?? "main",
343
+ `${policy.resourceLabel} coordinate id`
344
+ ),
345
+ orientation: intervalChannel === "y" ? "vertical" : "horizontal",
346
+ position,
347
+ interval,
348
+ fields,
349
+ groupField: grouping.groupField,
350
+ groupBy: grouping.transformGroupBy
351
+ };
352
+ }