vega 0.3.2 → 0.4.0

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.
@@ -6,7 +6,7 @@
6
6
 
7
7
  var name = "vega-lite";
8
8
  var author = "Dominik Moritz, Kanit \"Ham\" Wongsuphasawat, Arvind Satyanarayan, Jeffrey Heer";
9
- var version$1 = "5.19.0";
9
+ var version$1 = "5.21.0";
10
10
  var collaborators = [
11
11
  "Kanit Wongsuphasawat (http://kanitw.yellowpigz.com)",
12
12
  "Dominik Moritz (https://www.domoritz.de)",
@@ -84,50 +84,50 @@
84
84
  url: "https://github.com/vega/vega-lite/issues"
85
85
  };
86
86
  var devDependencies = {
87
- "@babel/core": "^7.24.7",
88
- "@babel/preset-env": "^7.24.7",
87
+ "@babel/core": "^7.24.9",
88
+ "@babel/preset-env": "^7.25.0",
89
89
  "@babel/preset-typescript": "^7.24.7",
90
90
  "@release-it/conventional-changelog": "^8.0.1",
91
91
  "@rollup/plugin-alias": "^5.1.0",
92
92
  "@rollup/plugin-babel": "^6.0.4",
93
- "@rollup/plugin-commonjs": "^25.0.7",
93
+ "@rollup/plugin-commonjs": "^26.0.1",
94
94
  "@rollup/plugin-json": "^6.1.0",
95
95
  "@rollup/plugin-node-resolve": "^15.2.3",
96
96
  "@rollup/plugin-terser": "^0.4.4",
97
97
  "@types/d3": "^7.4.3",
98
98
  "@types/jest": "^29.5.12",
99
99
  "@types/pako": "^2.0.3",
100
- "@typescript-eslint/eslint-plugin": "^7.13.0",
101
- "@typescript-eslint/parser": "^7.13.0",
102
- ajv: "^8.16.0",
103
- "ajv-formats": "^2.1.1",
100
+ "@typescript-eslint/eslint-plugin": "^7.17.0",
101
+ "@typescript-eslint/parser": "^7.17.0",
102
+ ajv: "^8.17.1",
103
+ "ajv-formats": "^3.0.1",
104
104
  cheerio: "^1.0.0-rc.12",
105
- "conventional-changelog-cli": "^4.1.0",
105
+ "conventional-changelog-cli": "^5.0.0",
106
106
  d3: "^7.9.0",
107
107
  "del-cli": "^5.1.0",
108
108
  eslint: "^8.57.0",
109
109
  "eslint-config-prettier": "^9.1.0",
110
110
  "eslint-plugin-jest": "^27.9.0",
111
- "eslint-plugin-prettier": "^5.1.3",
111
+ "eslint-plugin-prettier": "^5.2.1",
112
112
  "fast-json-stable-stringify": "~2.1.0",
113
- "highlight.js": "^11.9.0",
113
+ "highlight.js": "^11.10.0",
114
114
  jest: "^29.7.0",
115
115
  "jest-dev-server": "^10.0.0",
116
116
  mkdirp: "^3.0.1",
117
117
  pako: "^2.1.0",
118
- prettier: "^3.3.2",
118
+ prettier: "^3.3.3",
119
119
  puppeteer: "^15.0.0",
120
- "release-it": "17.2.1",
121
- rollup: "^4.18.0",
120
+ "release-it": "17.6.0",
121
+ rollup: "^4.19.1",
122
122
  "rollup-plugin-bundle-size": "^1.0.3",
123
123
  serve: "^14.2.3",
124
- terser: "^5.31.1",
125
- "ts-jest": "^29.1.4",
126
- "ts-json-schema-generator": "^1.5.0",
127
- typescript: "~5.4.5",
124
+ terser: "^5.31.3",
125
+ "ts-jest": "^29.2.3",
126
+ "ts-json-schema-generator": "^2.3.0",
127
+ typescript: "~5.5.4",
128
128
  "vega-cli": "^5.28.0",
129
129
  "vega-datasets": "^2.8.1",
130
- "vega-embed": "^6.25.0",
130
+ "vega-embed": "^6.26.0",
131
131
  "vega-tooltip": "^0.34.0",
132
132
  "yaml-front-matter": "^4.1.1"
133
133
  };
@@ -135,7 +135,7 @@
135
135
  "json-stringify-pretty-compact": "~3.0.0",
136
136
  tslib: "~2.6.3",
137
137
  "vega-event-selector": "~3.0.1",
138
- "vega-expression": "~5.1.0",
138
+ "vega-expression": "~5.1.1",
139
139
  "vega-util": "~1.17.2",
140
140
  yargs: "~17.7.2"
141
141
  };
@@ -173,13 +173,13 @@
173
173
  };
174
174
 
175
175
  function isLogicalOr(op) {
176
- return !!op.or;
176
+ return hasProperty(op, 'or');
177
177
  }
178
178
  function isLogicalAnd(op) {
179
- return !!op.and;
179
+ return hasProperty(op, 'and');
180
180
  }
181
181
  function isLogicalNot(op) {
182
- return !!op.not;
182
+ return hasProperty(op, 'not');
183
183
  }
184
184
  function forEachLeaf(op, fn) {
185
185
  if (isLogicalNot(op)) {
@@ -417,7 +417,11 @@
417
417
 
418
418
  // This is a stricter version of Object.keys but with better types. See https://github.com/Microsoft/TypeScript/pull/12253#issuecomment-263132208
419
419
  const keys = Object.keys;
420
+
421
+ // Stricter version from https://github.com/microsoft/TypeScript/issues/51572#issuecomment-1319153323
420
422
  const vals = Object.values;
423
+
424
+ // Stricter version from https://github.com/microsoft/TypeScript/issues/51572#issuecomment-1319153323
421
425
  const entries$1 = Object.entries;
422
426
 
423
427
  // Using mapped type to declare a collect of flags for a string literal type S
@@ -540,12 +544,7 @@
540
544
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
541
545
  args[_key2] = arguments[_key2];
542
546
  }
543
- for (const arg of args) {
544
- if (arg !== undefined) {
545
- return arg;
546
- }
547
- }
548
- return undefined;
547
+ return args.find(a => a !== undefined);
549
548
  }
550
549
 
551
550
  // variable used to generate id
@@ -615,13 +614,13 @@
615
614
  }
616
615
  if (a instanceof Map && b instanceof Map) {
617
616
  if (a.size !== b.size) return false;
618
- for (i of a.entries()) if (!b.has(i[0])) return false;
619
- for (i of a.entries()) if (!deepEqual(i[1], b.get(i[0]))) return false;
617
+ for (const e of a.entries()) if (!b.has(e[0])) return false;
618
+ for (const e of a.entries()) if (!deepEqual(e[1], b.get(e[0]))) return false;
620
619
  return true;
621
620
  }
622
621
  if (a instanceof Set && b instanceof Set) {
623
622
  if (a.size !== b.size) return false;
624
- for (i of a.entries()) if (!b.has(i[0])) return false;
623
+ for (const e of a.entries()) if (!b.has(e[0])) return false;
625
624
  return true;
626
625
  }
627
626
  if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
@@ -691,6 +690,17 @@
691
690
  }(data);
692
691
  }
693
692
 
693
+ /**
694
+ * Check if the input object has the property and it's not undefined.
695
+ *
696
+ * @param object the object
697
+ * @param property the property to search
698
+ * @returns if the object has the property and it's not undefined.
699
+ */
700
+ function hasProperty(obj, key) {
701
+ return vega.isObject(obj) && vega.hasOwnProperty(obj, key) && obj[key] !== undefined;
702
+ }
703
+
694
704
  /*
695
705
  * Constants and utilities for encoding channels (Visual variables)
696
706
  * such as 'x', 'y', 'color'.
@@ -758,7 +768,7 @@
758
768
  radius2: 1
759
769
  };
760
770
  function isPolarPositionChannel(c) {
761
- return c in POLAR_POSITION_CHANNEL_INDEX;
771
+ return vega.hasOwnProperty(POLAR_POSITION_CHANNEL_INDEX, c);
762
772
  }
763
773
  const GEO_POSIITON_CHANNEL_INDEX = {
764
774
  longitude: 1,
@@ -779,7 +789,7 @@
779
789
  }
780
790
  }
781
791
  function isGeoPositionChannel(c) {
782
- return c in GEO_POSIITON_CHANNEL_INDEX;
792
+ return vega.hasOwnProperty(GEO_POSIITON_CHANNEL_INDEX, c);
783
793
  }
784
794
  const GEOPOSITION_CHANNELS = keys(GEO_POSIITON_CHANNEL_INDEX);
785
795
  const UNIT_CHANNEL_INDEX = {
@@ -838,10 +848,10 @@
838
848
  ...SINGLE_DEF_UNIT_CHANNEL_INDEX
839
849
  } = SINGLE_DEF_CHANNEL_INDEX;
840
850
  function isSingleDefUnitChannel(str) {
841
- return !!SINGLE_DEF_UNIT_CHANNEL_INDEX[str];
851
+ return vega.hasOwnProperty(SINGLE_DEF_UNIT_CHANNEL_INDEX, str);
842
852
  }
843
853
  function isChannel(str) {
844
- return !!CHANNEL_INDEX[str];
854
+ return vega.hasOwnProperty(CHANNEL_INDEX, str);
845
855
  }
846
856
  const SECONDARY_RANGE_CHANNEL = [X2, Y2, LATITUDE2, LONGITUDE2, THETA2, RADIUS2];
847
857
  function isSecondaryRangeChannel(c) {
@@ -993,7 +1003,7 @@
993
1003
  };
994
1004
  const POSITION_SCALE_CHANNELS = keys(POSITION_SCALE_CHANNEL_INDEX);
995
1005
  function isXorY(channel) {
996
- return channel in POSITION_SCALE_CHANNEL_INDEX;
1006
+ return vega.hasOwnProperty(POSITION_SCALE_CHANNEL_INDEX, channel);
997
1007
  }
998
1008
  const POLAR_POSITION_SCALE_CHANNEL_INDEX = {
999
1009
  theta: 1,
@@ -1008,7 +1018,7 @@
1008
1018
  yOffset: 1
1009
1019
  };
1010
1020
  function isXorYOffset(channel) {
1011
- return channel in OFFSET_SCALE_CHANNEL_INDEX;
1021
+ return vega.hasOwnProperty(OFFSET_SCALE_CHANNEL_INDEX, channel);
1012
1022
  }
1013
1023
 
1014
1024
  // NON_POSITION_SCALE_CHANNEL = SCALE_CHANNELS without position / offset
@@ -1029,7 +1039,7 @@
1029
1039
  } = NONPOSITION_CHANNEL_INDEX;
1030
1040
  const NONPOSITION_SCALE_CHANNELS = keys(NONPOSITION_SCALE_CHANNEL_INDEX);
1031
1041
  function isNonPositionScaleChannel(channel) {
1032
- return !!NONPOSITION_CHANNEL_INDEX[channel];
1042
+ return vega.hasOwnProperty(NONPOSITION_CHANNEL_INDEX, channel);
1033
1043
  }
1034
1044
 
1035
1045
  /**
@@ -1064,7 +1074,7 @@
1064
1074
  /** List of channels with scales */
1065
1075
  const SCALE_CHANNELS = keys(SCALE_CHANNEL_INDEX);
1066
1076
  function isScaleChannel(channel) {
1067
- return !!SCALE_CHANNEL_INDEX[channel];
1077
+ return vega.hasOwnProperty(SCALE_CHANNEL_INDEX, channel);
1068
1078
  }
1069
1079
  /**
1070
1080
  * Return whether a channel supports a particular mark type.
@@ -1296,13 +1306,13 @@
1296
1306
  max: 1
1297
1307
  };
1298
1308
  function isArgminDef(a) {
1299
- return !!a && !!a['argmin'];
1309
+ return hasProperty(a, 'argmin');
1300
1310
  }
1301
1311
  function isArgmaxDef(a) {
1302
- return !!a && !!a['argmax'];
1312
+ return hasProperty(a, 'argmax');
1303
1313
  }
1304
1314
  function isAggregateOp(a) {
1305
- return vega.isString(a) && !!AGGREGATE_OP_INDEX[a];
1315
+ return vega.isString(a) && vega.hasOwnProperty(AGGREGATE_OP_INDEX, a);
1306
1316
  }
1307
1317
  const COUNTING_OPS = new Set(['count', 'valid', 'missing', 'distinct']);
1308
1318
  function isCountingAggregateOp(aggregate) {
@@ -1351,7 +1361,7 @@
1351
1361
  return vega.isObject(bin);
1352
1362
  }
1353
1363
  function isParameterExtent(extent) {
1354
- return extent?.['param'];
1364
+ return hasProperty(extent, 'param');
1355
1365
  }
1356
1366
  function autoMaxBins(channel) {
1357
1367
  switch (channel) {
@@ -1379,7 +1389,7 @@
1379
1389
  }
1380
1390
 
1381
1391
  function isExprRef(o) {
1382
- return !!o?.expr;
1392
+ return hasProperty(o, 'expr');
1383
1393
  }
1384
1394
  function replaceExprRef(index) {
1385
1395
  let {
@@ -1489,7 +1499,7 @@
1489
1499
  // Remove ValueRefs from mapped types
1490
1500
 
1491
1501
  function isSignalRef(o) {
1492
- return !!o?.signal;
1502
+ return hasProperty(o, 'signal');
1493
1503
  }
1494
1504
 
1495
1505
  // TODO: add type of value (Make it VgValueRef<V extends ValueOrGradient> {value?:V ...})
@@ -1497,7 +1507,7 @@
1497
1507
  // TODO: add vg prefix
1498
1508
 
1499
1509
  function isVgRangeStep(range) {
1500
- return !!range['step'];
1510
+ return hasProperty(range, 'step');
1501
1511
  }
1502
1512
 
1503
1513
  // Domains that are not a union of domains
@@ -1508,19 +1518,19 @@
1508
1518
 
1509
1519
  function isDataRefUnionedDomain(domain) {
1510
1520
  if (!vega.isArray(domain)) {
1511
- return 'fields' in domain && !('data' in domain);
1521
+ return hasProperty(domain, 'fields') && !hasProperty(domain, 'data');
1512
1522
  }
1513
1523
  return false;
1514
1524
  }
1515
1525
  function isFieldRefUnionDomain(domain) {
1516
1526
  if (!vega.isArray(domain)) {
1517
- return 'fields' in domain && 'data' in domain;
1527
+ return hasProperty(domain, 'fields') && hasProperty(domain, 'data');
1518
1528
  }
1519
1529
  return false;
1520
1530
  }
1521
1531
  function isDataRefDomain(domain) {
1522
1532
  if (!vega.isArray(domain)) {
1523
- return 'field' in domain && 'data' in domain;
1533
+ return hasProperty(domain, 'field') && hasProperty(domain, 'data');
1524
1534
  }
1525
1535
  return false;
1526
1536
  }
@@ -1709,7 +1719,7 @@
1709
1719
  vgChannel,
1710
1720
  ignoreVgConfig
1711
1721
  } = opt;
1712
- if (vgChannel && mark[vgChannel] !== undefined) {
1722
+ if (vgChannel && hasProperty(mark, vgChannel)) {
1713
1723
  return mark[vgChannel];
1714
1724
  } else if (mark[channel] !== undefined) {
1715
1725
  return mark[channel];
@@ -1727,9 +1737,10 @@
1727
1737
  let {
1728
1738
  vgChannel
1729
1739
  } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1740
+ const cfg = getMarkStyleConfig(channel, mark, config.style);
1730
1741
  return getFirstDefined(
1731
1742
  // style config has highest precedence
1732
- vgChannel ? getMarkStyleConfig(channel, mark, config.style) : undefined, getMarkStyleConfig(channel, mark, config.style),
1743
+ vgChannel ? cfg : undefined, cfg,
1733
1744
  // then mark-specific config
1734
1745
  vgChannel ? config[mark.type][vgChannel] : undefined, config[mark.type][channel],
1735
1746
  // Need to cast because MarkDef doesn't perfectly match with AnyMarkConfig, but if the type isn't available, we'll get nothing here, which is fine
@@ -1747,7 +1758,7 @@
1747
1758
  let value;
1748
1759
  for (const style of styles) {
1749
1760
  const styleConfig = styleConfigIndex[style];
1750
- if (styleConfig && styleConfig[p] !== undefined) {
1761
+ if (hasProperty(styleConfig, p)) {
1751
1762
  value = styleConfig[p];
1752
1763
  }
1753
1764
  }
@@ -2133,7 +2144,7 @@
2133
2144
  function isDateTime(o) {
2134
2145
  if (o && vega.isObject(o)) {
2135
2146
  for (const part of TIMEUNIT_PARTS) {
2136
- if (part in o) {
2147
+ if (hasProperty(o, part)) {
2137
2148
  return true;
2138
2149
  }
2139
2150
  }
@@ -2317,7 +2328,7 @@
2317
2328
  };
2318
2329
  const TIMEUNIT_PARTS = keys(LOCAL_SINGLE_TIMEUNIT_INDEX);
2319
2330
  function isLocalSingleTimeUnit(timeUnit) {
2320
- return !!LOCAL_SINGLE_TIMEUNIT_INDEX[timeUnit];
2331
+ return vega.hasOwnProperty(LOCAL_SINGLE_TIMEUNIT_INDEX, timeUnit);
2321
2332
  }
2322
2333
  function isBinnedTimeUnit(timeUnit) {
2323
2334
  if (vega.isObject(timeUnit)) {
@@ -2512,7 +2523,7 @@
2512
2523
  milliseconds: 1
2513
2524
  };
2514
2525
  function isDatePart(timeUnit) {
2515
- return !!DATE_PARTS[timeUnit];
2526
+ return vega.hasOwnProperty(DATE_PARTS, timeUnit);
2516
2527
  }
2517
2528
  function getDateTimePartAndStep(timeUnit) {
2518
2529
  let step = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
@@ -2543,7 +2554,7 @@
2543
2554
  }
2544
2555
 
2545
2556
  function isSelectionPredicate(predicate) {
2546
- return predicate?.['param'];
2557
+ return hasProperty(predicate, 'param');
2547
2558
  }
2548
2559
  function isFieldEqualPredicate(predicate) {
2549
2560
  return !!predicate?.field && predicate.equal !== undefined;
@@ -2630,7 +2641,7 @@
2630
2641
  } else if (isFieldRangePredicate(predicate)) {
2631
2642
  const {
2632
2643
  range
2633
- } = predicate;
2644
+ } = replaceExprRef(predicate);
2634
2645
  const lower = isSignalRef(range) ? {
2635
2646
  signal: `${range.signal}[0]`
2636
2647
  } : range[0];
@@ -2834,6 +2845,7 @@
2834
2845
  pointPadding: 0.5,
2835
2846
  barBandPaddingInner: 0.1,
2836
2847
  rectBandPaddingInner: 0,
2848
+ tickBandPaddingInner: 0.25,
2837
2849
  bandWithNestedOffsetPaddingInner: 0.2,
2838
2850
  bandWithNestedOffsetPaddingOuter: 0.2,
2839
2851
  minBandSize: 2,
@@ -2852,13 +2864,13 @@
2852
2864
  zero: true
2853
2865
  };
2854
2866
  function isExtendedScheme(scheme) {
2855
- return !vega.isString(scheme) && !!scheme['name'];
2867
+ return !vega.isString(scheme) && hasProperty(scheme, 'name');
2856
2868
  }
2857
2869
  function isParameterDomain(domain) {
2858
- return domain?.['param'];
2870
+ return hasProperty(domain, 'param');
2859
2871
  }
2860
2872
  function isDomainUnionWith(domain) {
2861
- return domain?.['unionWith'];
2873
+ return hasProperty(domain, 'unionWith');
2862
2874
  }
2863
2875
  function isFieldRange(range) {
2864
2876
  return vega.isObject(range) && 'field' in range;
@@ -3093,11 +3105,11 @@
3093
3105
  return ['line', 'area', 'trail'].includes(m);
3094
3106
  }
3095
3107
  function isRectBasedMark(m) {
3096
- return ['rect', 'bar', 'image', 'arc' /* arc is rect/interval in polar coordinate */].includes(m);
3108
+ return ['rect', 'bar', 'image', 'arc', 'tick' /* arc is rect/interval in polar coordinate */].includes(m);
3097
3109
  }
3098
3110
  const PRIMITIVE_MARKS = new Set(keys(Mark));
3099
3111
  function isMarkDef(mark) {
3100
- return mark['type'];
3112
+ return hasProperty(mark, 'type');
3101
3113
  }
3102
3114
  const STROKE_CONFIG = ['stroke', 'strokeWidth', 'strokeDash', 'strokeDashOffset', 'strokeOpacity', 'strokeJoin', 'strokeMiterLimit'];
3103
3115
  const FILL_CONFIG = ['fill', 'fillOpacity'];
@@ -3113,12 +3125,13 @@
3113
3125
  timeUnitBandPosition: 1
3114
3126
  };
3115
3127
  const VL_ONLY_MARK_CONFIG_PROPERTIES = keys(VL_ONLY_MARK_CONFIG_INDEX);
3128
+ const VL_ONLY_RECT_CONFIG = ['binSpacing', 'continuousBandSize', 'discreteBandSize', 'minBandSize'];
3116
3129
  const VL_ONLY_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX = {
3117
3130
  area: ['line', 'point'],
3118
- bar: ['binSpacing', 'continuousBandSize', 'discreteBandSize', 'minBandSize'],
3119
- rect: ['binSpacing', 'continuousBandSize', 'discreteBandSize', 'minBandSize'],
3131
+ bar: VL_ONLY_RECT_CONFIG,
3132
+ rect: VL_ONLY_RECT_CONFIG,
3120
3133
  line: ['point'],
3121
- tick: ['bandSize', 'thickness']
3134
+ tick: ['bandSize', 'thickness', ...VL_ONLY_RECT_CONFIG]
3122
3135
  };
3123
3136
  const defaultMarkConfig = {
3124
3137
  color: '#4c78a8',
@@ -3147,7 +3160,7 @@
3147
3160
  };
3148
3161
  const MARK_CONFIGS = keys(MARK_CONFIG_INDEX);
3149
3162
  function isRelativeBandSize(o) {
3150
- return o && o['band'] != undefined;
3163
+ return hasProperty(o, 'band');
3151
3164
  }
3152
3165
  const BAR_CORNER_RADIUS_INDEX = {
3153
3166
  horizontal: ['cornerRadiusTopRight', 'cornerRadiusBottomRight'],
@@ -3157,19 +3170,18 @@
3157
3170
  // Point/Line OverlayMixins are only for area, line, and trail but we don't want to declare multiple types of MarkDef
3158
3171
 
3159
3172
  const DEFAULT_RECT_BAND_SIZE = 5;
3160
- const defaultBarConfig = {
3161
- binSpacing: 1,
3162
- continuousBandSize: DEFAULT_RECT_BAND_SIZE,
3163
- minBandSize: 0.25,
3164
- timeUnitBandPosition: 0.5
3165
- };
3166
3173
  const defaultRectConfig = {
3167
3174
  binSpacing: 0,
3168
3175
  continuousBandSize: DEFAULT_RECT_BAND_SIZE,
3169
3176
  minBandSize: 0.25,
3170
3177
  timeUnitBandPosition: 0.5
3171
3178
  };
3179
+ const defaultBarConfig = {
3180
+ ...defaultRectConfig,
3181
+ binSpacing: 1
3182
+ };
3172
3183
  const defaultTickConfig = {
3184
+ ...defaultRectConfig,
3173
3185
  thickness: 1
3174
3186
  };
3175
3187
  function getMarkType(m) {
@@ -3848,20 +3860,20 @@
3848
3860
  text: 1
3849
3861
  };
3850
3862
  function isSortByChannel(c) {
3851
- return c in SORT_BY_CHANNEL_INDEX;
3863
+ return vega.hasOwnProperty(SORT_BY_CHANNEL_INDEX, c);
3852
3864
  }
3853
3865
  function isSortByEncoding(sort) {
3854
- return !!sort?.['encoding'];
3866
+ return hasProperty(sort, 'encoding');
3855
3867
  }
3856
3868
  function isSortField(sort) {
3857
- return sort && (sort['op'] === 'count' || !!sort['field']);
3869
+ return sort && (sort.op === 'count' || hasProperty(sort, 'field'));
3858
3870
  }
3859
3871
  function isSortArray(sort) {
3860
3872
  return sort && vega.isArray(sort);
3861
3873
  }
3862
3874
 
3863
3875
  function isFacetMapping(f) {
3864
- return 'row' in f || 'column' in f;
3876
+ return hasProperty(f, 'row') || hasProperty(f, 'column');
3865
3877
  }
3866
3878
 
3867
3879
  /**
@@ -3869,7 +3881,7 @@
3869
3881
  */
3870
3882
 
3871
3883
  function isFacetFieldDef(channelDef) {
3872
- return !!channelDef && 'header' in channelDef;
3884
+ return hasProperty(channelDef, 'header');
3873
3885
  }
3874
3886
 
3875
3887
  /**
@@ -3881,7 +3893,7 @@
3881
3893
  */
3882
3894
 
3883
3895
  function isFacetSpec(spec) {
3884
- return 'facet' in spec;
3896
+ return hasProperty(spec, 'facet');
3885
3897
  }
3886
3898
 
3887
3899
  /**
@@ -3901,7 +3913,7 @@
3901
3913
  */
3902
3914
 
3903
3915
  function isConditionalParameter(c) {
3904
- return c['param'];
3916
+ return hasProperty(c, 'param');
3905
3917
  }
3906
3918
 
3907
3919
  /**
@@ -3926,7 +3938,7 @@
3926
3938
  */
3927
3939
 
3928
3940
  function isRepeatRef(field) {
3929
- return field && !vega.isString(field) && 'repeat' in field;
3941
+ return !vega.isString(field) && hasProperty(field, 'repeat');
3930
3942
  }
3931
3943
 
3932
3944
  /** @@hidden */
@@ -3957,7 +3969,7 @@
3957
3969
  */
3958
3970
 
3959
3971
  function isSortableFieldDef(fieldDef) {
3960
- return 'sort' in fieldDef;
3972
+ return hasProperty(fieldDef, 'sort');
3961
3973
  }
3962
3974
 
3963
3975
  /**
@@ -4063,10 +4075,10 @@
4063
4075
  // Order Path have no scale
4064
4076
 
4065
4077
  function isOrderOnlyDef(orderDef) {
4066
- return orderDef && !!orderDef.sort && !orderDef['field'];
4078
+ return hasProperty(orderDef, 'sort') && !hasProperty(orderDef, 'field');
4067
4079
  }
4068
4080
  function isConditionalDef(channelDef) {
4069
- return channelDef && 'condition' in channelDef;
4081
+ return hasProperty(channelDef, 'condition');
4070
4082
  }
4071
4083
 
4072
4084
  /**
@@ -4085,14 +4097,13 @@
4085
4097
  return !!condition && (vega.isArray(condition) || isValueDef(condition));
4086
4098
  }
4087
4099
  function isFieldDef(channelDef) {
4088
- // TODO: we can't use field in channelDef here as it's somehow failing runtime test
4089
- return channelDef && (!!channelDef['field'] || channelDef['aggregate'] === 'count');
4100
+ return hasProperty(channelDef, 'field') || channelDef?.aggregate === 'count';
4090
4101
  }
4091
4102
  function channelDefType(channelDef) {
4092
4103
  return channelDef?.['type'];
4093
4104
  }
4094
4105
  function isDatumDef(channelDef) {
4095
- return channelDef && 'datum' in channelDef;
4106
+ return hasProperty(channelDef, 'datum');
4096
4107
  }
4097
4108
  function isContinuousFieldOrDatumDef(cd) {
4098
4109
  // TODO: make datum support DateTime object
@@ -4109,29 +4120,29 @@
4109
4120
  return isFieldDef(channelDef) || isDatumDef(channelDef);
4110
4121
  }
4111
4122
  function isTypedFieldDef(channelDef) {
4112
- return channelDef && ('field' in channelDef || channelDef['aggregate'] === 'count') && 'type' in channelDef;
4123
+ return channelDef && (hasProperty(channelDef, 'field') || channelDef['aggregate'] === 'count') && hasProperty(channelDef, 'type');
4113
4124
  }
4114
4125
  function isValueDef(channelDef) {
4115
- return channelDef && 'value' in channelDef && 'value' in channelDef;
4126
+ return hasProperty(channelDef, 'value');
4116
4127
  }
4117
4128
  function isScaleFieldDef(channelDef) {
4118
- return channelDef && ('scale' in channelDef || 'sort' in channelDef);
4129
+ return hasProperty(channelDef, 'scale') || hasProperty(channelDef, 'sort');
4119
4130
  }
4120
4131
  function isPositionFieldOrDatumDef(channelDef) {
4121
- return channelDef && ('axis' in channelDef || 'stack' in channelDef || 'impute' in channelDef);
4132
+ return hasProperty(channelDef, 'axis') || hasProperty(channelDef, 'stack') || hasProperty(channelDef, 'impute');
4122
4133
  }
4123
4134
  function isMarkPropFieldOrDatumDef(channelDef) {
4124
- return channelDef && 'legend' in channelDef;
4135
+ return hasProperty(channelDef, 'legend');
4125
4136
  }
4126
4137
  function isStringFieldOrDatumDef(channelDef) {
4127
- return channelDef && ('format' in channelDef || 'formatType' in channelDef);
4138
+ return hasProperty(channelDef, 'format') || hasProperty(channelDef, 'formatType');
4128
4139
  }
4129
4140
  function toStringFieldDef(fieldDef) {
4130
4141
  // omit properties that don't exist in string field defs
4131
4142
  return omit(fieldDef, ['legend', 'axis', 'header', 'scale']);
4132
4143
  }
4133
4144
  function isOpFieldDef(fieldDef) {
4134
- return 'op' in fieldDef;
4145
+ return hasProperty(fieldDef, 'op');
4135
4146
  }
4136
4147
 
4137
4148
  /**
@@ -4256,11 +4267,7 @@
4256
4267
  }
4257
4268
  const timeUnitParams = timeUnit && !isBinnedTimeUnit(timeUnit) ? normalizeTimeUnit(timeUnit) : undefined;
4258
4269
  const fn = aggregate || timeUnitParams?.unit || timeUnitParams?.maxbins && 'timeunit' || isBinning(bin) && 'bin';
4259
- if (fn) {
4260
- return `${fn.toUpperCase()}(${field})`;
4261
- } else {
4262
- return field;
4263
- }
4270
+ return fn ? `${fn.toUpperCase()}(${field})` : field;
4264
4271
  }
4265
4272
  const defaultTitleFormatter = (fieldDef, config) => {
4266
4273
  switch (config.fieldTitle) {
@@ -4543,7 +4550,7 @@
4543
4550
  }
4544
4551
  };
4545
4552
  }
4546
- const sub = sort.substr(1);
4553
+ const sub = sort.substring(1);
4547
4554
  if (sort.charAt(0) === '-' && isSortByChannel(sub)) {
4548
4555
  return {
4549
4556
  ...fieldDef,
@@ -5043,7 +5050,7 @@
5043
5050
  encoding: 1
5044
5051
  };
5045
5052
  function isAxisProperty(prop) {
5046
- return !!AXIS_PROPERTIES_INDEX[prop];
5053
+ return vega.hasOwnProperty(AXIS_PROPERTIES_INDEX, prop);
5047
5054
  }
5048
5055
  const AXIS_CONFIGS_INDEX = {
5049
5056
  axis: 1,
@@ -5088,7 +5095,7 @@
5088
5095
  */
5089
5096
 
5090
5097
  function isUnitSpec(spec) {
5091
- return 'mark' in spec;
5098
+ return hasProperty(spec, 'mark');
5092
5099
  }
5093
5100
 
5094
5101
  // TODO: replace string with Mark
@@ -5576,7 +5583,7 @@
5576
5583
  filteredEncoding.tooltip = customTooltipWithAggregatedField;
5577
5584
  }
5578
5585
  } else {
5579
- if (tooltip['aggregate']) {
5586
+ if (tooltip.aggregate) {
5580
5587
  filteredEncoding.tooltip = tooltip;
5581
5588
  } else {
5582
5589
  customTooltipWithoutAggregatedField = tooltip;
@@ -6165,7 +6172,7 @@
6165
6172
  outerSpec,
6166
6173
  tooltipEncoding
6167
6174
  } = errorBarParams(spec, ERRORBAR, config);
6168
- delete encodingWithoutContinuousAxis['size'];
6175
+ delete encodingWithoutContinuousAxis.size;
6169
6176
  const makeErrorBarPart = makeCompositeAggregatePartFactory(markDef, continuousAxis, continuousAxisChannelDef, encodingWithoutContinuousAxis, config.errorbar);
6170
6177
  const thickness = markDef.thickness;
6171
6178
  const size = markDef.size;
@@ -6848,13 +6855,13 @@
6848
6855
  return isVConcatSpec(spec) || isHConcatSpec(spec) || isConcatSpec(spec);
6849
6856
  }
6850
6857
  function isConcatSpec(spec) {
6851
- return 'concat' in spec;
6858
+ return hasProperty(spec, 'concat');
6852
6859
  }
6853
6860
  function isVConcatSpec(spec) {
6854
- return 'vconcat' in spec;
6861
+ return hasProperty(spec, 'vconcat');
6855
6862
  }
6856
6863
  function isHConcatSpec(spec) {
6857
- return 'hconcat' in spec;
6864
+ return hasProperty(spec, 'hconcat');
6858
6865
  }
6859
6866
 
6860
6867
  /**
@@ -6873,7 +6880,7 @@
6873
6880
  }
6874
6881
  }
6875
6882
  function isStep(size) {
6876
- return vega.isObject(size) && size['step'] !== undefined;
6883
+ return hasProperty(size, 'step');
6877
6884
  }
6878
6885
 
6879
6886
  // TODO(https://github.com/vega/vega-lite/issues/2503): Make this generic so we can support some form of top-down sizing.
@@ -6882,7 +6889,7 @@
6882
6889
  */
6883
6890
 
6884
6891
  function isFrameMixins(o) {
6885
- return o['view'] || o['width'] || o['height'];
6892
+ return hasProperty(o, 'view') || hasProperty(o, 'width') || hasProperty(o, 'height');
6886
6893
  }
6887
6894
 
6888
6895
  /**
@@ -7369,7 +7376,9 @@
7369
7376
 
7370
7377
  // Remove empty config objects.
7371
7378
  for (const prop in config) {
7379
+ // @ts-ignore
7372
7380
  if (vega.isObject(config[prop]) && isEmpty(config[prop])) {
7381
+ // @ts-ignore
7373
7382
  delete config[prop];
7374
7383
  }
7375
7384
  }
@@ -7446,7 +7455,7 @@
7446
7455
  */
7447
7456
 
7448
7457
  function isLayerSpec(spec) {
7449
- return 'layer' in spec;
7458
+ return hasProperty(spec, 'layer');
7450
7459
  }
7451
7460
 
7452
7461
  /**
@@ -7454,10 +7463,10 @@
7454
7463
  */
7455
7464
 
7456
7465
  function isRepeatSpec(spec) {
7457
- return 'repeat' in spec;
7466
+ return hasProperty(spec, 'repeat');
7458
7467
  }
7459
7468
  function isLayerRepeatSpec(spec) {
7460
- return !vega.isArray(spec.repeat) && spec.repeat['layer'];
7469
+ return !vega.isArray(spec.repeat) && hasProperty(spec.repeat, 'layer');
7461
7470
  }
7462
7471
 
7463
7472
  class SpecMapper {
@@ -7535,7 +7544,7 @@
7535
7544
  normalize: 1
7536
7545
  };
7537
7546
  function isStackOffset(s) {
7538
- return s in STACK_OFFSET_INDEX;
7547
+ return vega.hasOwnProperty(STACK_OFFSET_INDEX, s);
7539
7548
  }
7540
7549
  const STACKABLE_MARKS = new Set([ARC, BAR, AREA, RULE, POINT, CIRCLE, SQUARE, LINE, TEXT, TICK]);
7541
7550
  const STACK_BY_DEFAULT_MARKS = new Set([BAR, AREA, ARC]);
@@ -8188,7 +8197,7 @@
8188
8197
  function replaceRepeaterInMapping(mapping, repeater) {
8189
8198
  const out = {};
8190
8199
  for (const channel in mapping) {
8191
- if (vega.hasOwnProperty(mapping, channel)) {
8200
+ if (hasProperty(mapping, channel)) {
8192
8201
  const channelDef = mapping[channel];
8193
8202
  if (vega.isArray(channelDef)) {
8194
8203
  // array cannot have condition
@@ -8244,7 +8253,7 @@
8244
8253
  }
8245
8254
 
8246
8255
  class CoreNormalizer extends SpecMapper {
8247
- nonFacetUnitNormalizers = [boxPlotNormalizer, errorBarNormalizer, errorBandNormalizer, new PathOverlayNormalizer(), new RuleForRangedLineNormalizer()];
8256
+ nonFacetUnitNormalizers = (() => [boxPlotNormalizer, errorBarNormalizer, errorBandNormalizer, new PathOverlayNormalizer(), new RuleForRangedLineNormalizer()])();
8248
8257
  map(spec, params) {
8249
8258
  // Special handling for a faceted unit spec as it can return a facet spec, not just a layer or unit spec like a normal unit spec.
8250
8259
  if (isUnitSpec(spec)) {
@@ -8645,70 +8654,70 @@
8645
8654
  }
8646
8655
 
8647
8656
  function isFilter(t) {
8648
- return 'filter' in t;
8657
+ return hasProperty(t, 'filter');
8649
8658
  }
8650
8659
  function isImputeSequence(t) {
8651
- return t?.['stop'] !== undefined;
8660
+ return hasProperty(t, 'stop');
8652
8661
  }
8653
8662
  function isLookup(t) {
8654
- return 'lookup' in t;
8663
+ return hasProperty(t, 'lookup');
8655
8664
  }
8656
8665
  function isLookupData(from) {
8657
- return 'data' in from;
8666
+ return hasProperty(from, 'data');
8658
8667
  }
8659
8668
  function isLookupSelection(from) {
8660
- return 'param' in from;
8669
+ return hasProperty(from, 'param');
8661
8670
  }
8662
8671
  function isPivot(t) {
8663
- return 'pivot' in t;
8672
+ return hasProperty(t, 'pivot');
8664
8673
  }
8665
8674
  function isDensity(t) {
8666
- return 'density' in t;
8675
+ return hasProperty(t, 'density');
8667
8676
  }
8668
8677
  function isQuantile(t) {
8669
- return 'quantile' in t;
8678
+ return hasProperty(t, 'quantile');
8670
8679
  }
8671
8680
  function isRegression(t) {
8672
- return 'regression' in t;
8681
+ return hasProperty(t, 'regression');
8673
8682
  }
8674
8683
  function isLoess(t) {
8675
- return 'loess' in t;
8684
+ return hasProperty(t, 'loess');
8676
8685
  }
8677
8686
  function isSample(t) {
8678
- return 'sample' in t;
8687
+ return hasProperty(t, 'sample');
8679
8688
  }
8680
8689
  function isWindow(t) {
8681
- return 'window' in t;
8690
+ return hasProperty(t, 'window');
8682
8691
  }
8683
8692
  function isJoinAggregate(t) {
8684
- return 'joinaggregate' in t;
8693
+ return hasProperty(t, 'joinaggregate');
8685
8694
  }
8686
8695
  function isFlatten(t) {
8687
- return 'flatten' in t;
8696
+ return hasProperty(t, 'flatten');
8688
8697
  }
8689
8698
  function isCalculate(t) {
8690
- return 'calculate' in t;
8699
+ return hasProperty(t, 'calculate');
8691
8700
  }
8692
8701
  function isBin(t) {
8693
- return 'bin' in t;
8702
+ return hasProperty(t, 'bin');
8694
8703
  }
8695
8704
  function isImpute(t) {
8696
- return 'impute' in t;
8705
+ return hasProperty(t, 'impute');
8697
8706
  }
8698
8707
  function isTimeUnit(t) {
8699
- return 'timeUnit' in t;
8708
+ return hasProperty(t, 'timeUnit');
8700
8709
  }
8701
8710
  function isAggregate(t) {
8702
- return 'aggregate' in t;
8711
+ return hasProperty(t, 'aggregate');
8703
8712
  }
8704
8713
  function isStack(t) {
8705
- return 'stack' in t;
8714
+ return hasProperty(t, 'stack');
8706
8715
  }
8707
8716
  function isFold(t) {
8708
- return 'fold' in t;
8717
+ return hasProperty(t, 'fold');
8709
8718
  }
8710
8719
  function isExtent(t) {
8711
- return 'extent' in t && !('density' in t) && !('regression' in t);
8720
+ return hasProperty(t, 'extent') && !hasProperty(t, 'density') && !hasProperty(t, 'regression');
8712
8721
  }
8713
8722
  function normalizeTransform(transform) {
8714
8723
  return transform.map(t => {
@@ -9065,7 +9074,7 @@
9065
9074
  */
9066
9075
 
9067
9076
  function isFitType(autoSizeType) {
9068
- return autoSizeType === 'fit' || autoSizeType === 'fit-x' || autoSizeType === 'fit-y';
9077
+ return ['fit', 'fit-x', 'fit-y'].includes(autoSizeType);
9069
9078
  }
9070
9079
  function getFitType(sizeType) {
9071
9080
  return sizeType ? `fit-${getPositionScaleChannel(sizeType)}` : 'fit';
@@ -9249,28 +9258,29 @@
9249
9258
  * Constants and utilities for data.
9250
9259
  */
9251
9260
 
9261
+
9252
9262
  // eslint-disable-next-line @typescript-eslint/ban-types
9253
9263
 
9254
9264
  function isUrlData(data) {
9255
- return 'url' in data;
9265
+ return hasProperty(data, 'url');
9256
9266
  }
9257
9267
  function isInlineData(data) {
9258
- return 'values' in data;
9268
+ return hasProperty(data, 'values');
9259
9269
  }
9260
9270
  function isNamedData(data) {
9261
- return 'name' in data && !isUrlData(data) && !isInlineData(data) && !isGenerator(data);
9271
+ return hasProperty(data, 'name') && !isUrlData(data) && !isInlineData(data) && !isGenerator(data);
9262
9272
  }
9263
9273
  function isGenerator(data) {
9264
9274
  return data && (isSequenceGenerator(data) || isSphereGenerator(data) || isGraticuleGenerator(data));
9265
9275
  }
9266
9276
  function isSequenceGenerator(data) {
9267
- return 'sequence' in data;
9277
+ return hasProperty(data, 'sequence');
9268
9278
  }
9269
9279
  function isSphereGenerator(data) {
9270
- return 'sphere' in data;
9280
+ return hasProperty(data, 'sphere');
9271
9281
  }
9272
9282
  function isGraticuleGenerator(data) {
9273
- return 'graticule' in data;
9283
+ return hasProperty(data, 'graticule');
9274
9284
  }
9275
9285
  let DataSourceType = /*#__PURE__*/function (DataSourceType) {
9276
9286
  DataSourceType[DataSourceType["Raw"] = 0] = "Raw";
@@ -10119,9 +10129,9 @@
10119
10129
  // state is captured by the top-level signals that we insert and "push
10120
10130
  // outer" to from within the units. We need to reassemble this state into
10121
10131
  // the top-level named signal, except no single selCmpt has a global view.
10122
- const namedSg = signals.filter(s => s.name === selCmpt.name)[0];
10132
+ const namedSg = signals.find(s => s.name === selCmpt.name);
10123
10133
  let update = namedSg.update;
10124
- if (update.indexOf(VL_SELECTION_RESOLVE) >= 0) {
10134
+ if (update.includes(VL_SELECTION_RESOLVE)) {
10125
10135
  namedSg.update = `{${bound.map(proj => `${vega.stringValue(replacePathInField(proj.field))}: ${proj.signals.data}`).join(', ')}}`;
10126
10136
  } else {
10127
10137
  for (const proj of bound) {
@@ -10190,7 +10200,7 @@
10190
10200
  continue;
10191
10201
  }
10192
10202
  const filters = vega.array(evt.between[0].filter ??= []);
10193
- if (filters.indexOf(filterExpr) < 0) {
10203
+ if (!filters.includes(filterExpr)) {
10194
10204
  filters.push(filterExpr);
10195
10205
  }
10196
10206
  }
@@ -10723,7 +10733,7 @@
10723
10733
  ...config,
10724
10734
  ...config.tooltipFormat
10725
10735
  };
10726
- const toSkip = {};
10736
+ const toSkip = new Set();
10727
10737
  const expr = reactiveGeom ? 'datum.datum' : 'datum';
10728
10738
  const tuples = [];
10729
10739
  function add(fDef, channel) {
@@ -10750,7 +10760,7 @@
10750
10760
  formatType
10751
10761
  } = getFormatMixins(fieldDef);
10752
10762
  value = binFormatExpression(startField, endField, format, formatType, formatConfig);
10753
- toSkip[channel2] = true;
10763
+ toSkip.add(channel2);
10754
10764
  }
10755
10765
  }
10756
10766
  if ((isXorY(channel) || channel === THETA || channel === RADIUS) && stack && stack.fieldChannel === channel && stack.offset === 'normalize') {
@@ -10787,7 +10797,7 @@
10787
10797
  key,
10788
10798
  value
10789
10799
  } of tuples) {
10790
- if (!toSkip[channel] && !out[key]) {
10800
+ if (!toSkip.has(channel) && !out[key]) {
10791
10801
  out[key] = value;
10792
10802
  }
10793
10803
  }
@@ -10846,7 +10856,7 @@
10846
10856
  }
10847
10857
  };
10848
10858
  }
10849
- return mark in VG_MARK_INDEX ? {} : {
10859
+ return vega.hasOwnProperty(VG_MARK_INDEX, mark) ? {} : {
10850
10860
  ariaRoleDescription: {
10851
10861
  value: mark
10852
10862
  }
@@ -10912,17 +10922,19 @@
10912
10922
  defaultRef,
10913
10923
  defaultValue
10914
10924
  } = opt;
10925
+ const channelDef = encoding[channel];
10915
10926
  if (defaultRef === undefined) {
10916
10927
  // prettier-ignore
10917
10928
  defaultValue ??= getMarkPropOrConfig(channel, markDef, config, {
10918
10929
  vgChannel,
10919
- ignoreVgConfig: true
10930
+ // If there is no conditonal def, we ignore vgConfig so the output spec is concise.
10931
+ // However, if there is a conditional def, we must include vgConfig so the default is respected.
10932
+ ignoreVgConfig: !isConditionalDef(channelDef)
10920
10933
  });
10921
10934
  if (defaultValue !== undefined) {
10922
10935
  defaultRef = signalOrValueRef(defaultValue);
10923
10936
  }
10924
10937
  }
10925
- const channelDef = encoding[channel];
10926
10938
  const commonProps = {
10927
10939
  markDef,
10928
10940
  config,
@@ -11047,6 +11059,7 @@
11047
11059
  const channel = `${baseChannel}Offset`; // Need to cast as the type can't be inferred automatically
11048
11060
 
11049
11061
  const defaultValue = markDef[channel];
11062
+ // FIXME: remove as any
11050
11063
  const channelDef = encoding[channel];
11051
11064
  if ((channel === 'xOffset' || channel === 'yOffset') && channelDef) {
11052
11065
  const ref = midPoint({
@@ -11314,6 +11327,8 @@
11314
11327
  } else {
11315
11328
  alignExcludingSignal = align;
11316
11329
  }
11330
+
11331
+ // FIXME: remove as any
11317
11332
  if (channel === 'x') {
11318
11333
  return ALIGNED_X_CHANNEL[alignExcludingSignal || (defaultAlign === 'top' ? 'left' : 'center')];
11319
11334
  } else {
@@ -11527,7 +11542,7 @@
11527
11542
  vgChannel: sizeChannel
11528
11543
  });
11529
11544
  const offsetScaleChannel = getOffsetChannel(channel);
11530
- const isBarBand = mark === 'bar' && (channel === 'x' ? orient === 'vertical' : orient === 'horizontal');
11545
+ const isBarOrTickBand = mark === 'bar' && (channel === 'x' ? orient === 'vertical' : orient === 'horizontal') || mark === 'tick' && (channel === 'y' ? orient === 'vertical' : orient === 'horizontal');
11531
11546
 
11532
11547
  // x, x2, and width -- we must specify two of these in all conditions
11533
11548
  if (isFieldDef(channelDef) && (isBinning(channelDef.bin) || isBinned(channelDef.bin) || channelDef.timeUnit && !channelDef2) && !(hasSizeDef && !isRelativeBandSize(hasSizeDef)) && !encoding[offsetScaleChannel] && !hasDiscreteDomain(scaleType)) {
@@ -11537,7 +11552,7 @@
11537
11552
  channel,
11538
11553
  model
11539
11554
  });
11540
- } else if ((isFieldOrDatumDef(channelDef) && hasDiscreteDomain(scaleType) || isBarBand) && !channelDef2) {
11555
+ } else if ((isFieldOrDatumDef(channelDef) && hasDiscreteDomain(scaleType) || isBarOrTickBand) && !channelDef2) {
11541
11556
  return positionAndSize(channelDef, channel, model);
11542
11557
  } else {
11543
11558
  return rangePosition(channel, model, {
@@ -11594,9 +11609,10 @@
11594
11609
  const {
11595
11610
  bandPaddingInner,
11596
11611
  barBandPaddingInner,
11597
- rectBandPaddingInner
11612
+ rectBandPaddingInner,
11613
+ tickBandPaddingInner
11598
11614
  } = config.scale;
11599
- const padding = getFirstDefined(bandPaddingInner, mark === 'bar' ? barBandPaddingInner : rectBandPaddingInner); // this part is like paddingInner in scale.ts
11615
+ const padding = getFirstDefined(bandPaddingInner, mark === 'tick' ? tickBandPaddingInner : mark === 'bar' ? barBandPaddingInner : rectBandPaddingInner); // this part is like paddingInner in scale.ts
11600
11616
  if (isSignalRef(padding)) {
11601
11617
  return {
11602
11618
  signal: `(1 - (${padding.signal})) * ${sizeChannel}`
@@ -11631,9 +11647,11 @@
11631
11647
  const offsetScaleChannel = getOffsetChannel(channel);
11632
11648
  const offsetScaleName = model.scaleName(offsetScaleChannel);
11633
11649
  const offsetScale = model.getScaleComponent(getOffsetScaleChannel(channel));
11634
-
11650
+ const useVlSizeChannel =
11651
+ // Always uses size channel for ticks, because tick only calls rectPosition() for the size channel
11652
+ markDef.type === 'tick' ||
11635
11653
  // use "size" channel for bars, if there is orient and the channel matches the right orientation
11636
- const useVlSizeChannel = orient === 'horizontal' && channel === 'y' || orient === 'vertical' && channel === 'x';
11654
+ orient === 'horizontal' && channel === 'y' || orient === 'vertical' && channel === 'x';
11637
11655
 
11638
11656
  // Use size encoding / mark property / config if it exists
11639
11657
  let sizeMixins;
@@ -11916,7 +11934,7 @@
11916
11934
  }
11917
11935
  function markDefProperties(mark, ignore) {
11918
11936
  return VG_MARK_CONFIGS.reduce((m, prop) => {
11919
- if (!ALWAYS_IGNORE.has(prop) && mark[prop] !== undefined && ignore[prop] !== 'ignore') {
11937
+ if (!ALWAYS_IGNORE.has(prop) && hasProperty(mark, prop) && ignore[prop] !== 'ignore') {
11920
11938
  m[prop] = signalOrValueRef(mark[prop]);
11921
11939
  }
11922
11940
  return m;
@@ -12046,7 +12064,7 @@
12046
12064
  const name = mark.name ?? '';
12047
12065
  if (name === model.component.mark[0].name) {
12048
12066
  index = i;
12049
- } else if (name.indexOf(VORONOI) >= 0) {
12067
+ } else if (name.includes(VORONOI)) {
12050
12068
  exists = true;
12051
12069
  }
12052
12070
  });
@@ -12092,7 +12110,7 @@
12092
12110
  signals: (model, selCmpt, signals) => {
12093
12111
  const name = selCmpt.name;
12094
12112
  const proj = selCmpt.project;
12095
- const signal = signals.filter(s => s.name === name + TUPLE)[0];
12113
+ const signal = signals.find(s => s.name === name + TUPLE);
12096
12114
  const fields = name + TUPLE_FIELDS;
12097
12115
  const values = proj.items.map(p => varName(`${name}_${p.field}`));
12098
12116
  const valid = values.map(v => `${v} !== null`).join(' && ');
@@ -12347,7 +12365,7 @@
12347
12365
  const delta = name + DELTA$1;
12348
12366
  const channel = proj.channel;
12349
12367
  const boundScales = scaleBindings.defined(selCmpt);
12350
- const signal = signals.filter(s => s.name === proj.signals[boundScales ? 'data' : 'visual'])[0];
12368
+ const signal = signals.find(s => s.name === proj.signals[boundScales ? 'data' : 'visual']);
12351
12369
  const sizeSg = model.getSizeSignalRef(size).signal;
12352
12370
  const scaleCmpt = model.getScaleComponent(channel);
12353
12371
  const scaleType = scaleCmpt && scaleCmpt.get('type');
@@ -12413,7 +12431,7 @@
12413
12431
  const name = selCmpt.name;
12414
12432
  const channel = proj.channel;
12415
12433
  const boundScales = scaleBindings.defined(selCmpt);
12416
- const signal = signals.filter(s => s.name === proj.signals[boundScales ? 'data' : 'visual'])[0];
12434
+ const signal = signals.find(s => s.name === proj.signals[boundScales ? 'data' : 'visual']);
12417
12435
  const sizeSg = model.getSizeSignalRef(size).signal;
12418
12436
  const scaleCmpt = model.getScaleComponent(channel);
12419
12437
  const scaleType = scaleCmpt && scaleCmpt.get('type');
@@ -12567,9 +12585,9 @@
12567
12585
  continue;
12568
12586
  }
12569
12587
  if (key === 'mark') {
12570
- defaults[key] = {
12571
- ...cfg[key],
12572
- ...defaults[key]
12588
+ defaults.mark = {
12589
+ ...cfg.mark,
12590
+ ...defaults.mark
12573
12591
  };
12574
12592
  }
12575
12593
  if (defaults[key] === undefined || defaults[key] === true) {
@@ -12622,8 +12640,8 @@
12622
12640
  }
12623
12641
  function parseSelectionExtent(model, name, extent) {
12624
12642
  const vname = varName(name);
12625
- const encoding = extent['encoding'];
12626
- let field = extent['field'];
12643
+ const encoding = extent.encoding;
12644
+ let field = extent.field;
12627
12645
  let selCmpt;
12628
12646
  try {
12629
12647
  selCmpt = model.getSelectionComponent(vname, name);
@@ -12705,7 +12723,8 @@
12705
12723
  if (disable) {
12706
12724
  return undefined;
12707
12725
  }
12708
- for (const prop in axis) {
12726
+ for (const p in axis) {
12727
+ const prop = p;
12709
12728
  const propType = AXIS_PROPERTY_TYPE[prop];
12710
12729
  const propValue = axis[prop];
12711
12730
  if (propType && propType !== kind && propType !== 'both') {
@@ -12760,6 +12779,7 @@
12760
12779
  vgProp,
12761
12780
  part
12762
12781
  } = propIndex;
12782
+ // FIXME: remove as any
12763
12783
  setAxisEncode(axis, part, vgProp, propValue);
12764
12784
  delete axis[prop];
12765
12785
  } // else do nothing since the property already supports signal
@@ -13845,37 +13865,33 @@
13845
13865
  // for fill legend, we don't want any fill in symbol
13846
13866
  if (channel === 'fill' || filled && channel === COLOR) {
13847
13867
  delete out.fill;
13848
- } else {
13849
- if (out.fill['field']) {
13850
- // For others, set fill to some opaque value (or nothing if a color is already set)
13851
- if (symbolFillColor) {
13852
- delete out.fill;
13853
- } else {
13854
- out.fill = signalOrValueRef(config.legend.symbolBaseFillColor ?? 'black');
13855
- out.fillOpacity = signalOrValueRef(opacity ?? 1);
13856
- }
13857
- } else if (vega.isArray(out.fill)) {
13858
- const fill = getFirstConditionValue(encoding.fill ?? encoding.color) ?? markDef.fill ?? (filled && markDef.color);
13859
- if (fill) {
13860
- out.fill = signalOrValueRef(fill);
13861
- }
13868
+ } else if (hasProperty(out.fill, 'field')) {
13869
+ // For others, set fill to some opaque value (or nothing if a color is already set)
13870
+ if (symbolFillColor) {
13871
+ delete out.fill;
13872
+ } else {
13873
+ out.fill = signalOrValueRef(config.legend.symbolBaseFillColor ?? 'black');
13874
+ out.fillOpacity = signalOrValueRef(opacity ?? 1);
13875
+ }
13876
+ } else if (vega.isArray(out.fill)) {
13877
+ const fill = getFirstConditionValue(encoding.fill ?? encoding.color) ?? markDef.fill ?? (filled && markDef.color);
13878
+ if (fill) {
13879
+ out.fill = signalOrValueRef(fill);
13862
13880
  }
13863
13881
  }
13864
13882
  }
13865
13883
  if (out.stroke) {
13866
13884
  if (channel === 'stroke' || !filled && channel === COLOR) {
13867
13885
  delete out.stroke;
13868
- } else {
13869
- if (out.stroke['field'] || symbolStrokeColor) {
13870
- // For others, remove stroke field
13871
- delete out.stroke;
13872
- } else if (vega.isArray(out.stroke)) {
13873
- const stroke = getFirstDefined(getFirstConditionValue(encoding.stroke || encoding.color), markDef.stroke, filled ? markDef.color : undefined);
13874
- if (stroke) {
13875
- out.stroke = {
13876
- value: stroke
13877
- };
13878
- }
13886
+ } else if (hasProperty(out.stroke, 'field') || symbolStrokeColor) {
13887
+ // For others, remove stroke field
13888
+ delete out.stroke;
13889
+ } else if (vega.isArray(out.stroke)) {
13890
+ const stroke = getFirstDefined(getFirstConditionValue(encoding.stroke || encoding.color), markDef.stroke, filled ? markDef.color : undefined);
13891
+ if (stroke) {
13892
+ out.stroke = {
13893
+ value: stroke
13894
+ };
13879
13895
  }
13880
13896
  }
13881
13897
  }
@@ -14372,6 +14388,7 @@
14372
14388
  legendType
14373
14389
  };
14374
14390
  for (const part of ['labels', 'legend', 'title', 'symbols', 'gradient', 'entries']) {
14391
+ // FIXME: remove as any (figure out what legendEncoding.entries is)
14375
14392
  const legendEncodingPart = guideEncodeEntry(legendEncoding[part] ?? {}, model);
14376
14393
  const value = part in legendEncodeRules ? legendEncodeRules[part](legendEncodingPart, legendEncodeParams) // apply rule
14377
14394
  : legendEncodingPart; // no rule -- just default values
@@ -15141,9 +15158,10 @@
15141
15158
  })]);
15142
15159
  } else {
15143
15160
  meas[field] ??= {};
15144
- meas[field][op] = new Set([as ? as : vgField(s, {
15161
+ meas[field][op] ??= new Set();
15162
+ meas[field][op].add(as ? as : vgField(s, {
15145
15163
  forAs: true
15146
- })]);
15164
+ }));
15147
15165
  }
15148
15166
  }
15149
15167
  }
@@ -15513,9 +15531,10 @@
15513
15531
  } else if (isFieldGTEPredicate(filter)) {
15514
15532
  val = signalRefOrValue(filter.gte);
15515
15533
  } else if (isFieldRangePredicate(filter)) {
15534
+ // FIXME: remove as any
15516
15535
  val = filter.range[0];
15517
15536
  } else if (isFieldOneOfPredicate(filter)) {
15518
- val = (filter.oneOf ?? filter['in'])[0];
15537
+ val = (filter.oneOf ?? filter.in)[0];
15519
15538
  } // else -- for filter expression, we can't infer anything
15520
15539
 
15521
15540
  if (val) {
@@ -17256,8 +17275,8 @@
17256
17275
  const scale = model.component.scales[channel];
17257
17276
  const spec = model.specifiedScales[channel].domain;
17258
17277
  const bin = model.fieldDef(channel)?.bin;
17259
- const domain = isParameterDomain(spec) && spec;
17260
- const extent = isBinParams(bin) && isParameterExtent(bin.extent) && bin.extent;
17278
+ const domain = isParameterDomain(spec) ? spec : undefined;
17279
+ const extent = isBinParams(bin) && isParameterExtent(bin.extent) ? bin.extent : undefined;
17261
17280
  if (domain || extent) {
17262
17281
  // As scale parsing occurs before selection parsing, we cannot set
17263
17282
  // domainRaw directly. So instead, we store the selectionExtent on
@@ -17448,7 +17467,7 @@
17448
17467
 
17449
17468
  // only keep sort properties that work with unioned domains
17450
17469
  const unionDomainSorts = unique(sorts.map(s => {
17451
- if (isBoolean(s) || !('op' in s) || vega.isString(s.op) && s.op in MULTIDOMAIN_SORT_OP_INDEX) {
17470
+ if (isBoolean(s) || !('op' in s) || vega.isString(s.op) && vega.hasOwnProperty(MULTIDOMAIN_SORT_OP_INDEX, s.op)) {
17452
17471
  return s;
17453
17472
  }
17454
17473
  warn(domainSortDropped(s));
@@ -18187,7 +18206,7 @@
18187
18206
  }
18188
18207
  if (supportedByScaleType && channelIncompatability === undefined) {
18189
18208
  if (specifiedValue !== undefined) {
18190
- const timeUnit = fieldOrDatumDef['timeUnit'];
18209
+ const timeUnit = fieldOrDatumDef.timeUnit;
18191
18210
  const type = fieldOrDatumDef.type;
18192
18211
  switch (property) {
18193
18212
  // domainMax/Min to signal if the value is a datetime object
@@ -18208,7 +18227,7 @@
18208
18227
  localScaleCmpt.copyKeyFromObject(property, specifiedScale);
18209
18228
  }
18210
18229
  } else {
18211
- const value = property in scaleRules ? scaleRules[property]({
18230
+ const value = hasProperty(scaleRules, property) ? scaleRules[property]({
18212
18231
  model,
18213
18232
  channel,
18214
18233
  fieldOrDatumDef,
@@ -18416,12 +18435,13 @@
18416
18435
  bandPaddingInner,
18417
18436
  barBandPaddingInner,
18418
18437
  rectBandPaddingInner,
18438
+ tickBandPaddingInner,
18419
18439
  bandWithNestedOffsetPaddingInner
18420
18440
  } = scaleConfig;
18421
18441
  if (hasNestedOffsetScale) {
18422
18442
  return bandWithNestedOffsetPaddingInner;
18423
18443
  }
18424
- return getFirstDefined(bandPaddingInner, mark === 'bar' ? barBandPaddingInner : rectBandPaddingInner);
18444
+ return getFirstDefined(bandPaddingInner, mark === 'bar' ? barBandPaddingInner : mark === 'tick' ? tickBandPaddingInner : rectBandPaddingInner);
18425
18445
  } else if (isXorYOffset(channel)) {
18426
18446
  if (scaleType === ScaleType.BAND) {
18427
18447
  return scaleConfig.offsetBandPaddingInner;
@@ -18580,8 +18600,8 @@
18580
18600
  return 'ordinal';
18581
18601
  }
18582
18602
  if (isXorY(channel) || isXorYOffset(channel)) {
18583
- if (contains(['rect', 'bar', 'image', 'rule'], mark.type)) {
18584
- // The rect/bar mark should fit into a band.
18603
+ if (contains(['rect', 'bar', 'image', 'rule', 'tick'], mark.type)) {
18604
+ // The rect/bar/tick mark should fit into a band.
18585
18605
  // For rule, using band scale to make rule align with axis ticks better https://github.com/vega/vega-lite/issues/3429
18586
18606
  return 'band';
18587
18607
  }
@@ -18672,7 +18692,7 @@
18672
18692
  if (fieldOrDatumDef && mark === GEOSHAPE && channel === SHAPE && fieldOrDatumDef.type === GEOJSON) {
18673
18693
  continue;
18674
18694
  }
18675
- let specifiedScale = fieldOrDatumDef && fieldOrDatumDef['scale'];
18695
+ let specifiedScale = fieldOrDatumDef && fieldOrDatumDef.scale;
18676
18696
  if (fieldOrDatumDef && specifiedScale !== null && specifiedScale !== false) {
18677
18697
  specifiedScale ??= {};
18678
18698
  const hasNestedOffsetScale = channelHasNestedOffsetScale(encoding, channel);
@@ -20352,7 +20372,7 @@
20352
20372
  return facetFieldDef;
20353
20373
  }
20354
20374
  channelHasField(channel) {
20355
- return !!this.facet[channel];
20375
+ return hasProperty(this.facet, channel);
20356
20376
  }
20357
20377
  fieldDef(channel) {
20358
20378
  return this.facet[channel];
@@ -20750,7 +20770,7 @@
20750
20770
  if (data.name && other.hasName() && data.name !== other.dataName) {
20751
20771
  continue;
20752
20772
  }
20753
- const formatMesh = data['format']?.mesh;
20773
+ const formatMesh = data.format?.mesh;
20754
20774
  const otherFeature = otherData.format?.feature;
20755
20775
 
20756
20776
  // feature and mesh are mutually exclusive
@@ -20759,7 +20779,7 @@
20759
20779
  }
20760
20780
 
20761
20781
  // we have to extract the same feature or mesh
20762
- const formatFeature = data['format']?.feature;
20782
+ const formatFeature = data.format?.feature;
20763
20783
  if ((formatFeature || otherFeature) && formatFeature !== otherFeature) {
20764
20784
  continue;
20765
20785
  }
@@ -21968,7 +21988,8 @@
21968
21988
  markDef
21969
21989
  } = model;
21970
21990
  const orient = markDef.orient;
21971
- const vgSizeChannel = orient === 'horizontal' ? 'width' : 'height';
21991
+ const vgSizeAxisChannel = orient === 'horizontal' ? 'x' : 'y';
21992
+ const vgThicknessAxisChannel = orient === 'horizontal' ? 'y' : 'x';
21972
21993
  const vgThicknessChannel = orient === 'horizontal' ? 'height' : 'width';
21973
21994
  return {
21974
21995
  ...baseEncodeEntry(model, {
@@ -21979,47 +22000,15 @@
21979
22000
  size: 'ignore',
21980
22001
  theta: 'ignore'
21981
22002
  }),
21982
- ...pointPosition('x', model, {
22003
+ ...rectPosition(model, vgSizeAxisChannel),
22004
+ ...pointPosition(vgThicknessAxisChannel, model, {
21983
22005
  defaultPos: 'mid',
21984
- vgChannel: 'xc'
21985
- }),
21986
- ...pointPosition('y', model, {
21987
- defaultPos: 'mid',
21988
- vgChannel: 'yc'
21989
- }),
21990
- // size / thickness => width / height
21991
- ...nonPosition('size', model, {
21992
- defaultValue: defaultSize(model),
21993
- vgChannel: vgSizeChannel
22006
+ vgChannel: vgThicknessAxisChannel === 'y' ? 'yc' : 'xc'
21994
22007
  }),
21995
22008
  [vgThicknessChannel]: signalOrValueRef(getMarkPropOrConfig('thickness', markDef, config))
21996
22009
  };
21997
22010
  }
21998
22011
  };
21999
- function defaultSize(model) {
22000
- const {
22001
- config,
22002
- markDef
22003
- } = model;
22004
- const {
22005
- orient
22006
- } = markDef;
22007
- const vgSizeChannel = orient === 'horizontal' ? 'width' : 'height';
22008
- const scale = model.getScaleComponent(orient === 'horizontal' ? 'x' : 'y');
22009
- const markPropOrConfig = getMarkPropOrConfig('size', markDef, config, {
22010
- vgChannel: vgSizeChannel
22011
- }) ?? config.tick.bandSize;
22012
- if (markPropOrConfig !== undefined) {
22013
- return markPropOrConfig;
22014
- } else {
22015
- const scaleRange = scale ? scale.get('range') : undefined;
22016
- if (scaleRange && isVgRangeStep(scaleRange) && vega.isNumber(scaleRange.step)) {
22017
- return scaleRange.step * 3 / 4;
22018
- }
22019
- const defaultViewStep = getViewConfigDiscreteStep(config.view, vgSizeChannel);
22020
- return defaultViewStep * 3 / 4;
22021
- }
22022
- }
22023
22012
 
22024
22013
  const markCompiler = {
22025
22014
  arc,
@@ -22966,6 +22955,7 @@
22966
22955
  exports.flatAccessWithDatum = flatAccessWithDatum;
22967
22956
  exports.getFirstDefined = getFirstDefined;
22968
22957
  exports.hasIntersection = hasIntersection;
22958
+ exports.hasProperty = hasProperty;
22969
22959
  exports.hash = hash;
22970
22960
  exports.internalField = internalField;
22971
22961
  exports.isBoolean = isBoolean;