@mapbox/mapbox-gl-style-spec 14.28.0 → 14.29.0-rc.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 (63) hide show
  1. package/composite.ts +5 -5
  2. package/diff.ts +38 -40
  3. package/dist/index.cjs +339 -238
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +75 -13
  6. package/dist/index.es.js +339 -238
  7. package/dist/index.es.js.map +1 -1
  8. package/expression/compound_expression.ts +6 -6
  9. package/expression/definitions/assertion.ts +9 -12
  10. package/expression/definitions/at.ts +1 -1
  11. package/expression/definitions/at_interpolated.ts +1 -1
  12. package/expression/definitions/case.ts +1 -2
  13. package/expression/definitions/coalesce.ts +1 -1
  14. package/expression/definitions/coercion.ts +10 -12
  15. package/expression/definitions/collator.ts +8 -8
  16. package/expression/definitions/comparison.ts +0 -1
  17. package/expression/definitions/distance.ts +135 -73
  18. package/expression/definitions/format.ts +10 -13
  19. package/expression/definitions/image.ts +8 -8
  20. package/expression/definitions/index.ts +92 -90
  21. package/expression/definitions/interpolate.ts +18 -19
  22. package/expression/definitions/let.ts +1 -2
  23. package/expression/definitions/literal.ts +1 -1
  24. package/expression/definitions/match.ts +7 -8
  25. package/expression/definitions/number_format.ts +7 -8
  26. package/expression/definitions/step.ts +11 -11
  27. package/expression/definitions/within.ts +23 -24
  28. package/expression/evaluation_context.ts +4 -4
  29. package/expression/expression.ts +1 -1
  30. package/expression/index.ts +43 -21
  31. package/expression/parsing_context.ts +2 -2
  32. package/expression/stops.ts +2 -2
  33. package/expression/values.ts +2 -2
  34. package/feature_filter/index.ts +3 -3
  35. package/function/convert.ts +8 -8
  36. package/function/index.ts +4 -2
  37. package/group_by_layout.ts +6 -4
  38. package/package.json +1 -1
  39. package/read_style.ts +2 -2
  40. package/reference/v8.json +63 -5
  41. package/types/config_options.ts +1 -1
  42. package/types.ts +10 -5
  43. package/util/properties.ts +1 -1
  44. package/validate/validate.ts +15 -5
  45. package/validate/validate_appearance.ts +7 -7
  46. package/validate/validate_array.ts +7 -7
  47. package/validate/validate_enum.ts +2 -3
  48. package/validate/validate_fog.ts +2 -2
  49. package/validate/validate_function.ts +14 -13
  50. package/validate/validate_layer.ts +10 -9
  51. package/validate/validate_light.ts +2 -2
  52. package/validate/validate_lights.ts +3 -3
  53. package/validate/validate_number.ts +10 -7
  54. package/validate/validate_object.ts +11 -10
  55. package/validate/validate_option.ts +24 -9
  56. package/validate/validate_property.ts +4 -4
  57. package/validate/validate_rain.ts +1 -1
  58. package/validate/validate_snow.ts +1 -1
  59. package/validate/validate_style.ts +2 -1
  60. package/validate/validate_terrain.ts +2 -2
  61. package/validate_mapbox_api_supported.ts +5 -6
  62. package/validate_style.min.ts +2 -1
  63. package/visit.ts +11 -10
package/dist/index.cjs CHANGED
@@ -375,6 +375,16 @@
375
375
  },
376
376
  color: {
377
377
  doc: "The result will be coerced to a color."
378
+ },
379
+ object: {
380
+ doc: "The result will be coerced to an object.",
381
+ "sdk-support": {
382
+ "basic functionality": {
383
+ js: "3.29.0",
384
+ android: "11.29.0",
385
+ ios: "11.29.0"
386
+ }
387
+ }
378
388
  }
379
389
  }
380
390
  },
@@ -3006,6 +3016,7 @@
3006
3016
  experimental: true,
3007
3017
  "sdk-support": {
3008
3018
  "basic functionality": {
3019
+ js: "3.7.0",
3009
3020
  android: "11.9.0",
3010
3021
  ios: "11.9.0"
3011
3022
  }
@@ -5479,13 +5490,18 @@
5479
5490
  }
5480
5491
  },
5481
5492
  distance: {
5482
- doc: "Returns the shortest distance in meters between the evaluated feature and the input geometry. The input value can be a valid GeoJSON of type `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`, `Feature`, or `FeatureCollection`. Distance values returned may vary in precision due to loss in precision from encoding geometries, particularly below zoom level 13.",
5493
+ doc: "Returns the shortest distance in meters between the evaluated feature and the input geometry. The input value can be a valid GeoJSON of type `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`, `Feature`, or `FeatureCollection`, or expression that returns a valid GeoJSON. Distance values returned may vary in precision due to loss in precision from encoding geometries, particularly below zoom level 13.",
5483
5494
  group: "Math",
5484
5495
  "sdk-support": {
5485
5496
  "basic functionality": {
5486
5497
  js: "3.0.0",
5487
5498
  android: "9.2.0",
5488
5499
  ios: "5.9.0"
5500
+ },
5501
+ "expressions support": {
5502
+ js: "3.29.0",
5503
+ android: "11.29.0",
5504
+ ios: "11.29.0"
5489
5505
  }
5490
5506
  }
5491
5507
  },
@@ -9455,7 +9471,6 @@
9455
9471
  "default": 0,
9456
9472
  minimum: 0,
9457
9473
  transition: true,
9458
- experimental: true,
9459
9474
  appearance: true,
9460
9475
  "sdk-support": {
9461
9476
  "basic functionality": {
@@ -9509,7 +9524,7 @@
9509
9524
  },
9510
9525
  "raster-color": {
9511
9526
  type: "color",
9512
- doc: "Defines a color map by which to colorize a raster layer, parameterized by the `[\"raster-value\"]` expression and evaluated at 256 uniformly spaced steps over the range specified by `raster-color-range`.",
9527
+ doc: "Defines the color ramp used to colorize a raster layer, parameterized by the `[\"raster-value\"]` expression and evaluated over the range specified by `raster-color-range`. Raster values are spaced evenly across the range by default.",
9513
9528
  "use-theme": true,
9514
9529
  transition: false,
9515
9530
  "sdk-support": {
@@ -9550,7 +9565,7 @@
9550
9565
  "zoom"
9551
9566
  ]
9552
9567
  },
9553
- doc: "When `raster-color` is active, specifies the combination of source RGB channels used to compute the raster value. Computed using the equation `mix.r * src.r + mix.g * src.g + mix.b * src.b + mix.a`. The first three components specify the mix of source red, green, and blue channels, respectively. The fourth component serves as a constant offset and is *not* multipled by source alpha. Source alpha is instead carried through and applied as opacity to the colorized result. Default value corresponds to RGB luminosity.",
9568
+ doc: "When `raster-color` is active, specifies how the raster value is computed from a non-`rasterarray` source's channels, using the equation `mix.r * src.r + mix.g * src.g + mix.b * src.b + mix.a`. The first three components weight the source's red, green, and blue channels; the fourth is a constant offset and is not multiplied by source alpha. Source alpha is carried through and applied as opacity to the colorized result. The default corresponds to RGB luminosity. `rasterarray` sources ignore this property, as their raster value is decoded directly from the source data.",
9554
9569
  example: [
9555
9570
  0.2126,
9556
9571
  0.7152,
@@ -9580,7 +9595,7 @@
9580
9595
  "zoom"
9581
9596
  ]
9582
9597
  },
9583
- doc: "When `raster-color` is active, specifies the range over which `raster-color` is tabulated. Units correspond to the computed raster value via `raster-color-mix`. For `rasterarray` sources, if `raster-color-range` is unspecified, the source's stated data range is used.",
9598
+ doc: "When `raster-color` is active, specifies the range of raster values mapped onto the color ramp, from the start of the ramp (low bound) to its end (high bound). For `rasterarray` sources the raster value is the decoded source data in the source's own units, and the source's stated data range is used when this property is unspecified. For other raster sources the raster value is computed from the source's channels via `raster-color-mix`. Defaults to `[0, 1]` when no range is otherwise available.",
9584
9599
  example: [
9585
9600
  0.5,
9586
9601
  10
@@ -9593,6 +9608,37 @@
9593
9608
  }
9594
9609
  }
9595
9610
  },
9611
+ "raster-color-scale": {
9612
+ type: "enum",
9613
+ doc: "When `raster-color` is active, specifies how raster values are distributed across the color ramp over the range specified by `raster-color-range`.",
9614
+ values: {
9615
+ linear: {
9616
+ doc: "Raster values are spaced evenly across the color ramp."
9617
+ },
9618
+ log: {
9619
+ doc: "Raster values are spaced logarithmically, giving more of the color ramp to smaller values. Useful for data concentrated near the low end of a wide range."
9620
+ }
9621
+ },
9622
+ "default": "linear",
9623
+ requires: [
9624
+ "raster-color",
9625
+ {
9626
+ source: "raster-array"
9627
+ }
9628
+ ],
9629
+ expression: {
9630
+ interpolated: false,
9631
+ parameters: [
9632
+ ]
9633
+ },
9634
+ "property-type": "data-constant",
9635
+ experimental: true,
9636
+ "sdk-support": {
9637
+ "basic functionality": {
9638
+ js: "3.29.0"
9639
+ }
9640
+ }
9641
+ },
9596
9642
  "raster-hue-rotate": {
9597
9643
  type: "number",
9598
9644
  "default": 0,
@@ -9846,6 +9892,21 @@
9846
9892
  interpolated: false
9847
9893
  },
9848
9894
  "property-type": "data-constant"
9895
+ },
9896
+ "raster-allow-draping": {
9897
+ type: "boolean",
9898
+ "default": true,
9899
+ experimental: true,
9900
+ doc: "Whether the raster layer is allowed to drape over terrain and globe. When disabled, the layer is rendered after all draped layers, which can change its position in the layer order. Disabling draping has a performance cost, since the terrain/globe geometry must be rendered again for each such layer.",
9901
+ transition: false,
9902
+ "property-type": "data-constant",
9903
+ "sdk-support": {
9904
+ "basic functionality": {
9905
+ js: "3.28.0",
9906
+ android: "11.28.0",
9907
+ ios: "11.28.0"
9908
+ }
9909
+ }
9849
9910
  }
9850
9911
  };
9851
9912
  var paint_hillshade = {
@@ -14881,6 +14942,189 @@
14881
14942
 
14882
14943
  var EXTENT = 8192;
14883
14944
 
14945
+ const FQIDSeparator = "";
14946
+ function makeConfigFQID(id, ownScope, contextScope) {
14947
+ return [id, ownScope, contextScope].filter(Boolean).join(FQIDSeparator);
14948
+ }
14949
+ function coerceValue(type, value) {
14950
+ switch (type) {
14951
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
14952
+ case "string":
14953
+ return toString(value);
14954
+ case "number":
14955
+ return +value;
14956
+ case "boolean":
14957
+ return !!value;
14958
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
14959
+ case "color":
14960
+ return Color.parse(value);
14961
+ case "formatted": {
14962
+ return Formatted.fromString(toString(value));
14963
+ }
14964
+ case "resolvedImage": {
14965
+ return ResolvedImage.build(toString(value));
14966
+ }
14967
+ }
14968
+ return value;
14969
+ }
14970
+ function clampToAllowedNumber(value, min, max, step) {
14971
+ if (step !== void 0) {
14972
+ value = step * Math.round(value / step);
14973
+ }
14974
+ if (min !== void 0 && value < min) {
14975
+ value = min;
14976
+ }
14977
+ if (max !== void 0 && value > max) {
14978
+ value = max;
14979
+ }
14980
+ return value;
14981
+ }
14982
+ class Config {
14983
+ constructor(type, key, scope, featureConstant = false) {
14984
+ this.type = type;
14985
+ this.key = key;
14986
+ this.scope = scope;
14987
+ this.featureConstant = featureConstant;
14988
+ }
14989
+ static parse(args, context) {
14990
+ let type = context.expectedType;
14991
+ type ?? (type = ValueType);
14992
+ if (args.length < 2 || args.length > 3) {
14993
+ return context.error(`Invalid number of arguments for 'config' expression.`);
14994
+ }
14995
+ const configKey = context.parse(args[1], 1);
14996
+ if (!(configKey instanceof Literal)) {
14997
+ return context.error(`Key name of 'config' expression must be a string literal.`);
14998
+ }
14999
+ let featureConstant = true;
15000
+ let configScopeValue;
15001
+ const configKeyValue = toString(configKey.value);
15002
+ if (args.length >= 3) {
15003
+ const configScope = context.parse(args[2], 2);
15004
+ if (!(configScope instanceof Literal)) {
15005
+ return context.error(`Scope of 'config' expression must be a string literal.`);
15006
+ }
15007
+ configScopeValue = toString(configScope.value);
15008
+ }
15009
+ if (context.options) {
15010
+ const fqid = makeConfigFQID(configKeyValue, configScopeValue, context._scope);
15011
+ const config = context.options.get(fqid);
15012
+ if (config) {
15013
+ featureConstant = isFeatureConstant(config.value || config.default);
15014
+ }
15015
+ }
15016
+ return new Config(type, configKeyValue, configScopeValue, featureConstant);
15017
+ }
15018
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15019
+ evaluate(ctx) {
15020
+ const fqid = makeConfigFQID(this.key, this.scope, ctx.scope);
15021
+ const config = ctx.getConfig(fqid);
15022
+ if (!config) return null;
15023
+ const { type, value, values, minValue, maxValue, stepValue } = config;
15024
+ const defaultValue = config.default.evaluate(ctx);
15025
+ let result = defaultValue;
15026
+ if (value) {
15027
+ const originalScope = ctx.scope;
15028
+ ctx.scope = (originalScope || "").split(FQIDSeparator).slice(1).join(FQIDSeparator);
15029
+ result = value.evaluate(ctx);
15030
+ ctx.scope = originalScope;
15031
+ }
15032
+ if (type) {
15033
+ result = coerceValue(type, result);
15034
+ }
15035
+ if (result !== void 0 && (minValue !== void 0 || maxValue !== void 0 || stepValue !== void 0)) {
15036
+ if (typeof result === "number") {
15037
+ result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
15038
+ } else if (Array.isArray(result)) {
15039
+ result = result.map((item) => typeof item === "number" ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
15040
+ }
15041
+ }
15042
+ if (value !== void 0 && result !== void 0 && values && !values.includes(result)) {
15043
+ result = defaultValue;
15044
+ if (type) {
15045
+ result = coerceValue(type, result);
15046
+ }
15047
+ }
15048
+ if (type && type !== this.type || result !== void 0 && !typeEquals(typeOf(result), this.type)) {
15049
+ result = coerceValue(this.type.kind, result);
15050
+ }
15051
+ return result;
15052
+ }
15053
+ eachChild() {
15054
+ }
15055
+ outputDefined() {
15056
+ return false;
15057
+ }
15058
+ serialize() {
15059
+ const res = ["config", this.key];
15060
+ if (this.scope) {
15061
+ res.concat(this.scope);
15062
+ }
15063
+ return res;
15064
+ }
15065
+ }
15066
+
15067
+ function isFeatureConstant(e) {
15068
+ if (e instanceof CompoundExpression) {
15069
+ if (e.name === "get" && e.args.length === 1) {
15070
+ return false;
15071
+ } else if (e.name === "feature-state") {
15072
+ return false;
15073
+ } else if (e.name === "has" && e.args.length === 1) {
15074
+ return false;
15075
+ } else if (e.name === "properties" || e.name === "geometry-type" || e.name === "id") {
15076
+ return false;
15077
+ } else if (e.name.startsWith("filter-")) {
15078
+ return false;
15079
+ }
15080
+ }
15081
+ if (e instanceof Within) {
15082
+ return false;
15083
+ }
15084
+ if (e instanceof Distance) {
15085
+ return false;
15086
+ }
15087
+ if (e instanceof Config) {
15088
+ return e.featureConstant;
15089
+ }
15090
+ let result = true;
15091
+ e.eachChild((arg) => {
15092
+ if (result && !isFeatureConstant(arg)) {
15093
+ result = false;
15094
+ }
15095
+ });
15096
+ return result;
15097
+ }
15098
+ function isStateConstant(e) {
15099
+ if (e instanceof CompoundExpression) {
15100
+ if (e.name === "feature-state") {
15101
+ return false;
15102
+ }
15103
+ }
15104
+ let result = true;
15105
+ e.eachChild((arg) => {
15106
+ if (result && !isStateConstant(arg)) {
15107
+ result = false;
15108
+ }
15109
+ });
15110
+ return result;
15111
+ }
15112
+ function isGlobalPropertyConstantSet(e, properties) {
15113
+ if (e instanceof CompoundExpression && properties.has(e.name)) {
15114
+ return false;
15115
+ }
15116
+ let result = true;
15117
+ e.eachChild((arg) => {
15118
+ if (result && !isGlobalPropertyConstantSet(arg, properties)) {
15119
+ result = false;
15120
+ }
15121
+ });
15122
+ return result;
15123
+ }
15124
+ function isGlobalPropertyConstant(e, properties) {
15125
+ return isGlobalPropertyConstantSet(e, new Set(properties));
15126
+ }
15127
+
14884
15128
  const RE = 6378.137;
14885
15129
  const FE = 1 / 298.257223563;
14886
15130
  const E2 = FE * (2 - FE);
@@ -15416,245 +15660,94 @@
15416
15660
  function isTypeValid(type) {
15417
15661
  return type === "Point" || type === "MultiPoint" || type === "LineString" || type === "MultiLineString" || type === "Polygon" || type === "MultiPolygon";
15418
15662
  }
15419
- class Distance {
15420
- constructor(geojson, geometries) {
15421
- this.type = NumberType;
15422
- this.geojson = geojson;
15423
- this.geometries = geometries;
15424
- }
15425
- static parse(args, context) {
15426
- if (args.length !== 2) {
15427
- return context.error(`'distance' expression requires either one argument, but found ' ${args.length - 1} instead.`);
15428
- }
15429
- if (isValue(args[1])) {
15430
- const geojson = args[1];
15431
- if (geojson.type === "FeatureCollection") {
15432
- for (let i = 0; i < geojson.features.length; ++i) {
15433
- if (isTypeValid(geojson.features[i].geometry.type)) {
15434
- return new Distance(geojson, geojson.features[i].geometry);
15435
- }
15436
- }
15437
- } else if (geojson.type === "Feature") {
15438
- if (isTypeValid(geojson.geometry.type)) {
15439
- return new Distance(geojson, geojson.geometry);
15440
- }
15441
- } else if (isTypeValid(geojson.type)) {
15442
- return new Distance(geojson, geojson);
15443
- }
15444
- }
15445
- return context.error(
15446
- "'distance' expression needs to be an array with format ['Distance', GeoJSONObj]."
15447
- );
15448
- }
15449
- evaluate(ctx) {
15450
- const geometry = ctx.geometry();
15451
- const canonical = ctx.canonicalID();
15452
- if (geometry != null && canonical != null) {
15453
- if (ctx.geometryType() === "Point") {
15454
- return pointsToGeometryDistance(geometry, canonical, this.geometries);
15455
- }
15456
- if (ctx.geometryType() === "LineString") {
15457
- return linesToGeometryDistance(geometry, canonical, this.geometries);
15458
- }
15459
- if (ctx.geometryType() === "Polygon") {
15460
- return polygonsToGeometryDistance(geometry, canonical, this.geometries);
15461
- }
15462
- console.warn("Distance Expression: currently only evaluates valid Point/LineString/Polygon geometries.");
15463
- } else {
15464
- console.warn("Distance Expression: requires valid feature and canonical information.");
15465
- }
15663
+ function extractDistanceGeometry(value) {
15664
+ if (!isValue(value) || typeof value !== "object" || value === null || Array.isArray(value)) {
15466
15665
  return null;
15467
15666
  }
15468
- eachChild() {
15469
- }
15470
- outputDefined() {
15471
- return true;
15472
- }
15473
- serialize() {
15474
- return ["distance", this.geojson];
15475
- }
15476
- }
15477
-
15478
- function isFeatureConstant(e) {
15479
- if (e instanceof CompoundExpression) {
15480
- if (e.name === "get" && e.args.length === 1) {
15481
- return false;
15482
- } else if (e.name === "feature-state") {
15483
- return false;
15484
- } else if (e.name === "has" && e.args.length === 1) {
15485
- return false;
15486
- } else if (e.name === "properties" || e.name === "geometry-type" || e.name === "id") {
15487
- return false;
15488
- } else if (e.name.startsWith("filter-")) {
15489
- return false;
15667
+ const geojson = value;
15668
+ if (geojson.type === "FeatureCollection") {
15669
+ if (geojson.features.length === 0) return null;
15670
+ const geometries = [];
15671
+ for (const feature of geojson.features) {
15672
+ if (!isTypeValid(feature.geometry.type)) return null;
15673
+ geometries.push(feature.geometry);
15490
15674
  }
15675
+ return geometries;
15491
15676
  }
15492
- if (e instanceof Within) {
15493
- return false;
15677
+ if (geojson.type === "Feature") {
15678
+ return isTypeValid(geojson.geometry.type) ? [geojson.geometry] : null;
15494
15679
  }
15495
- if (e instanceof Distance) {
15496
- return false;
15680
+ if (isTypeValid(geojson.type)) {
15681
+ return [geojson];
15497
15682
  }
15498
- if (e instanceof Config) {
15499
- return e.featureConstant;
15500
- }
15501
- let result = true;
15502
- e.eachChild((arg) => {
15503
- if (result && !isFeatureConstant(arg)) {
15504
- result = false;
15505
- }
15506
- });
15507
- return result;
15508
- }
15509
- function isStateConstant(e) {
15510
- if (e instanceof CompoundExpression) {
15511
- if (e.name === "feature-state") {
15512
- return false;
15513
- }
15514
- }
15515
- let result = true;
15516
- e.eachChild((arg) => {
15517
- if (result && !isStateConstant(arg)) {
15518
- result = false;
15519
- }
15520
- });
15521
- return result;
15522
- }
15523
- function isGlobalPropertyConstantSet(e, properties) {
15524
- if (e instanceof CompoundExpression && properties.has(e.name)) {
15525
- return false;
15526
- }
15527
- let result = true;
15528
- e.eachChild((arg) => {
15529
- if (result && !isGlobalPropertyConstantSet(arg, properties)) {
15530
- result = false;
15531
- }
15532
- });
15533
- return result;
15534
- }
15535
- function isGlobalPropertyConstant(e, properties) {
15536
- return isGlobalPropertyConstantSet(e, new Set(properties));
15537
- }
15538
-
15539
- const FQIDSeparator = "";
15540
- function makeConfigFQID(id, ownScope, contextScope) {
15541
- return [id, ownScope, contextScope].filter(Boolean).join(FQIDSeparator);
15542
- }
15543
- function coerceValue(type, value) {
15544
- switch (type) {
15545
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
15546
- case "string":
15547
- return toString(value);
15548
- case "number":
15549
- return +value;
15550
- case "boolean":
15551
- return !!value;
15552
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
15553
- case "color":
15554
- return Color.parse(value);
15555
- case "formatted": {
15556
- return Formatted.fromString(toString(value));
15557
- }
15558
- case "resolvedImage": {
15559
- return ResolvedImage.build(toString(value));
15560
- }
15561
- }
15562
- return value;
15563
- }
15564
- function clampToAllowedNumber(value, min, max, step) {
15565
- if (step !== void 0) {
15566
- value = step * Math.round(value / step);
15567
- }
15568
- if (min !== void 0 && value < min) {
15569
- value = min;
15570
- }
15571
- if (max !== void 0 && value > max) {
15572
- value = max;
15573
- }
15574
- return value;
15683
+ return null;
15575
15684
  }
15576
- class Config {
15577
- constructor(type, key, scope, featureConstant = false) {
15578
- this.type = type;
15579
- this.key = key;
15580
- this.scope = scope;
15581
- this.featureConstant = featureConstant;
15685
+ class Distance {
15686
+ constructor(geojson) {
15687
+ this.type = NumberType;
15688
+ this.geojson = geojson;
15582
15689
  }
15583
15690
  static parse(args, context) {
15584
- let type = context.expectedType;
15585
- type ?? (type = ValueType);
15586
- if (args.length < 2 || args.length > 3) {
15587
- return context.error(`Invalid number of arguments for 'config' expression.`);
15588
- }
15589
- const configKey = context.parse(args[1], 1);
15590
- if (!(configKey instanceof Literal)) {
15591
- return context.error(`Key name of 'config' expression must be a string literal.`);
15691
+ if (args.length !== 2) {
15692
+ return context.error(`'distance' expression requires either one argument, but found ' ${args.length - 1} instead.`);
15592
15693
  }
15593
- let featureConstant = true;
15594
- let configScopeValue;
15595
- const configKeyValue = toString(configKey.value);
15596
- if (args.length >= 3) {
15597
- const configScope = context.parse(args[2], 2);
15598
- if (!(configScope instanceof Literal)) {
15599
- return context.error(`Scope of 'config' expression must be a string literal.`);
15694
+ const arg = args[1];
15695
+ const isBareGeoJSON = isValue(arg) && !Array.isArray(arg);
15696
+ const parsed = context.parse(isBareGeoJSON ? ["literal", arg] : arg, 1, ValueType);
15697
+ if (!parsed) return null;
15698
+ for (const [globalProperties, name] of [
15699
+ [["measure-light"], "brightness"],
15700
+ [["pitch"], "pitch"],
15701
+ [["distance-from-center"], "distance-from-center"]
15702
+ ]) {
15703
+ if (!isGlobalPropertyConstant(parsed, globalProperties)) {
15704
+ return context.error(`'distance' expression may not depend on ${name}.`);
15600
15705
  }
15601
- configScopeValue = toString(configScope.value);
15602
15706
  }
15603
- if (context.options) {
15604
- const fqid = makeConfigFQID(configKeyValue, configScopeValue, context._scope);
15605
- const config = context.options.get(fqid);
15606
- if (config) {
15607
- featureConstant = isFeatureConstant(config.value || config.default);
15608
- }
15707
+ if (!isStateConstant(parsed)) {
15708
+ return context.error(`'distance' expression may not depend on feature-state.`);
15609
15709
  }
15610
- return new Config(type, configKeyValue, configScopeValue, featureConstant);
15710
+ if (parsed instanceof Literal && !extractDistanceGeometry(parsed.value)) {
15711
+ return context.error(
15712
+ "'distance' expression needs to be an array with format ['Distance', GeoJSONObj]."
15713
+ );
15714
+ }
15715
+ return new Distance(parsed);
15611
15716
  }
15612
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15613
15717
  evaluate(ctx) {
15614
- const fqid = makeConfigFQID(this.key, this.scope, ctx.scope);
15615
- const config = ctx.getConfig(fqid);
15616
- if (!config) return null;
15617
- const { type, value, values, minValue, maxValue, stepValue } = config;
15618
- const defaultValue = config.default.evaluate(ctx);
15619
- let result = defaultValue;
15620
- if (value) {
15621
- const originalScope = ctx.scope;
15622
- ctx.scope = (originalScope || "").split(FQIDSeparator).slice(1).join(FQIDSeparator);
15623
- result = value.evaluate(ctx);
15624
- ctx.scope = originalScope;
15625
- }
15626
- if (type) {
15627
- result = coerceValue(type, result);
15718
+ const geometries = extractDistanceGeometry(this.geojson.evaluate(ctx));
15719
+ if (!geometries) {
15720
+ console.warn("Distance Expression: could not resolve a valid Point/LineString/Polygon GeoJSON geometry.");
15721
+ return null;
15628
15722
  }
15629
- if (result !== void 0 && (minValue !== void 0 || maxValue !== void 0 || stepValue !== void 0)) {
15630
- if (typeof result === "number") {
15631
- result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
15632
- } else if (Array.isArray(result)) {
15633
- result = result.map((item) => typeof item === "number" ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
15634
- }
15723
+ const geometry = ctx.geometry();
15724
+ const canonical = ctx.canonicalID();
15725
+ if (geometry == null || canonical == null) {
15726
+ console.warn("Distance Expression: requires valid feature and canonical information.");
15727
+ return null;
15635
15728
  }
15636
- if (value !== void 0 && result !== void 0 && values && !values.includes(result)) {
15637
- result = defaultValue;
15638
- if (type) {
15639
- result = coerceValue(type, result);
15640
- }
15729
+ const geometryType = ctx.geometryType();
15730
+ const distanceTo = geometryType === "Point" ? pointsToGeometryDistance : geometryType === "LineString" ? linesToGeometryDistance : geometryType === "Polygon" ? polygonsToGeometryDistance : null;
15731
+ if (!distanceTo) {
15732
+ console.warn("Distance Expression: currently only evaluates valid Point/LineString/Polygon geometries.");
15733
+ return null;
15641
15734
  }
15642
- if (type && type !== this.type || result !== void 0 && !typeEquals(typeOf(result), this.type)) {
15643
- result = coerceValue(this.type.kind, result);
15735
+ let dist = Infinity;
15736
+ for (const g of geometries) {
15737
+ const tempDist = distanceTo(geometry, canonical, g);
15738
+ if (tempDist == null || isNaN(tempDist)) return tempDist;
15739
+ if ((dist = Math.min(dist, tempDist)) === 0) break;
15644
15740
  }
15645
- return result;
15741
+ return dist;
15646
15742
  }
15647
- eachChild() {
15743
+ eachChild(fn) {
15744
+ fn(this.geojson);
15648
15745
  }
15649
15746
  outputDefined() {
15650
- return false;
15747
+ return true;
15651
15748
  }
15652
15749
  serialize() {
15653
- const res = ["config", this.key];
15654
- if (this.scope) {
15655
- res.concat(this.scope);
15656
- }
15657
- return res;
15750
+ return ["distance", this.geojson.serialize()];
15658
15751
  }
15659
15752
  }
15660
15753
 
@@ -17892,7 +17985,7 @@
17892
17985
  kind: "composite",
17893
17986
  interpolationType,
17894
17987
  interpolationFactor: Interpolate.interpolationFactor.bind(void 0, interpolationType),
17895
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
17988
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
17896
17989
  zoomStops: featureFunctionStops.map((s) => s[0]),
17897
17990
  evaluate({ zoom }, properties) {
17898
17991
  return evaluateExponentialFunction({
@@ -18023,15 +18116,16 @@
18023
18116
  this.isIndoorDependent = isIndoorDependent(expression);
18024
18117
  }
18025
18118
  evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData) {
18026
- this._evaluator.globals = globals;
18027
- this._evaluator.feature = feature;
18028
- this._evaluator.featureState = featureState;
18029
- this._evaluator.canonical = canonical || null;
18030
- this._evaluator.availableImages = availableImages || null;
18031
- this._evaluator.formattedSection = formattedSection;
18032
- this._evaluator.featureTileCoord = featureTileCoord || null;
18033
- this._evaluator.featureDistanceData = featureDistanceData || null;
18034
- return this.expression.evaluate(this._evaluator);
18119
+ const evaluator = this._evaluator;
18120
+ evaluator.globals = globals;
18121
+ evaluator.feature = feature;
18122
+ evaluator.featureState = featureState;
18123
+ evaluator.canonical = canonical || null;
18124
+ evaluator.availableImages = availableImages || null;
18125
+ evaluator.formattedSection = formattedSection;
18126
+ evaluator.featureTileCoord = featureTileCoord || null;
18127
+ evaluator.featureDistanceData = featureDistanceData || null;
18128
+ return this.expression.evaluate(evaluator);
18035
18129
  }
18036
18130
  evaluate(globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData, iconImageUseTheme) {
18037
18131
  if (!this._evaluator) {
@@ -18249,7 +18343,8 @@
18249
18343
  enum: StringType,
18250
18344
  boolean: BooleanType,
18251
18345
  formatted: FormattedType,
18252
- resolvedImage: ResolvedImageType
18346
+ resolvedImage: ResolvedImageType,
18347
+ object: ObjectType
18253
18348
  };
18254
18349
  if (spec.type === "array") {
18255
18350
  return array$1(types[spec.value] || ValueType, spec.length);
@@ -19513,17 +19608,23 @@ ${JSON.stringify(filterExp, null, 2)}
19513
19608
  const optionValue = options.value;
19514
19609
  const isArrayOption = isObject(optionValue) && unbundle(optionValue.array) === true;
19515
19610
  const declaredType = !isArrayOption && isObject(optionValue) ? unbundle(optionValue.type) : void 0;
19611
+ const validateDefault = (elementOptions) => {
19612
+ const defaultValue = elementOptions.value;
19613
+ if (isObject(defaultValue)) {
19614
+ return validate({ ...elementOptions, valueSpec: { ...elementOptions.valueSpec, type: "*", expression: void 0 } });
19615
+ }
19616
+ if (declaredType && Array.isArray(defaultValue)) {
19617
+ return validate({ ...elementOptions, valueSpec: { ...elementOptions.valueSpec, type: declaredType } });
19618
+ }
19619
+ return validate(elementOptions);
19620
+ };
19516
19621
  return validateObject({
19517
19622
  ...options,
19518
19623
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
19519
19624
  valueSpec: styleSpec.option,
19520
- objectElementValidators: declaredType ? {
19521
- // Only propagate the declared type when the default is an
19522
- // expression (array-form). Primitive defaults keep the previous
19523
- // permissive validation, mirroring the runtime parser's narrowing
19524
- // in style.ts/parser.cpp.
19525
- default: (elementOptions) => Array.isArray(elementOptions.value) ? validate({ ...elementOptions, valueSpec: { ...elementOptions.valueSpec, type: declaredType } }) : validate(elementOptions)
19526
- } : void 0
19625
+ objectElementValidators: {
19626
+ default: validateDefault
19627
+ }
19527
19628
  });
19528
19629
  }
19529
19630