@mapbox/mapbox-gl-style-spec 14.28.0 → 14.29.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.
Files changed (63) hide show
  1. package/composite.ts +5 -5
  2. package/diff.ts +38 -40
  3. package/dist/index.cjs +362 -238
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +101 -13
  6. package/dist/index.es.js +362 -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 +86 -5
  41. package/types/config_options.ts +1 -1
  42. package/types.ts +16 -6
  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
  },
@@ -8261,6 +8277,29 @@
8261
8277
  ]
8262
8278
  },
8263
8279
  "property-type": "data-constant"
8280
+ },
8281
+ "line-cutout-depth": {
8282
+ type: "number",
8283
+ "default": 0,
8284
+ minimum: 0,
8285
+ units: "meters",
8286
+ doc: "Depth offset along the camera, in meters. When set to a non-zero value, applied cutout opacity is 0.",
8287
+ experimental: true,
8288
+ "private": true,
8289
+ transition: true,
8290
+ "sdk-support": {
8291
+ "basic functionality": {
8292
+ android: "11.29.0",
8293
+ ios: "11.29.0"
8294
+ }
8295
+ },
8296
+ expression: {
8297
+ interpolated: true,
8298
+ parameters: [
8299
+ "zoom"
8300
+ ]
8301
+ },
8302
+ "property-type": "data-constant"
8264
8303
  }
8265
8304
  };
8266
8305
  var paint_circle = {
@@ -9455,7 +9494,6 @@
9455
9494
  "default": 0,
9456
9495
  minimum: 0,
9457
9496
  transition: true,
9458
- experimental: true,
9459
9497
  appearance: true,
9460
9498
  "sdk-support": {
9461
9499
  "basic functionality": {
@@ -9509,7 +9547,7 @@
9509
9547
  },
9510
9548
  "raster-color": {
9511
9549
  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`.",
9550
+ 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
9551
  "use-theme": true,
9514
9552
  transition: false,
9515
9553
  "sdk-support": {
@@ -9550,7 +9588,7 @@
9550
9588
  "zoom"
9551
9589
  ]
9552
9590
  },
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.",
9591
+ 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
9592
  example: [
9555
9593
  0.2126,
9556
9594
  0.7152,
@@ -9580,7 +9618,7 @@
9580
9618
  "zoom"
9581
9619
  ]
9582
9620
  },
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.",
9621
+ 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
9622
  example: [
9585
9623
  0.5,
9586
9624
  10
@@ -9593,6 +9631,37 @@
9593
9631
  }
9594
9632
  }
9595
9633
  },
9634
+ "raster-color-scale": {
9635
+ type: "enum",
9636
+ doc: "When `raster-color` is active, specifies how raster values are distributed across the color ramp over the range specified by `raster-color-range`.",
9637
+ values: {
9638
+ linear: {
9639
+ doc: "Raster values are spaced evenly across the color ramp."
9640
+ },
9641
+ log: {
9642
+ 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."
9643
+ }
9644
+ },
9645
+ "default": "linear",
9646
+ requires: [
9647
+ "raster-color",
9648
+ {
9649
+ source: "raster-array"
9650
+ }
9651
+ ],
9652
+ expression: {
9653
+ interpolated: false,
9654
+ parameters: [
9655
+ ]
9656
+ },
9657
+ "property-type": "data-constant",
9658
+ experimental: true,
9659
+ "sdk-support": {
9660
+ "basic functionality": {
9661
+ js: "3.29.0"
9662
+ }
9663
+ }
9664
+ },
9596
9665
  "raster-hue-rotate": {
9597
9666
  type: "number",
9598
9667
  "default": 0,
@@ -9846,6 +9915,21 @@
9846
9915
  interpolated: false
9847
9916
  },
9848
9917
  "property-type": "data-constant"
9918
+ },
9919
+ "raster-allow-draping": {
9920
+ type: "boolean",
9921
+ "default": true,
9922
+ experimental: true,
9923
+ 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.",
9924
+ transition: false,
9925
+ "property-type": "data-constant",
9926
+ "sdk-support": {
9927
+ "basic functionality": {
9928
+ js: "3.28.0",
9929
+ android: "11.28.0",
9930
+ ios: "11.28.0"
9931
+ }
9932
+ }
9849
9933
  }
9850
9934
  };
9851
9935
  var paint_hillshade = {
@@ -14881,6 +14965,189 @@
14881
14965
 
14882
14966
  var EXTENT = 8192;
14883
14967
 
14968
+ const FQIDSeparator = "";
14969
+ function makeConfigFQID(id, ownScope, contextScope) {
14970
+ return [id, ownScope, contextScope].filter(Boolean).join(FQIDSeparator);
14971
+ }
14972
+ function coerceValue(type, value) {
14973
+ switch (type) {
14974
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
14975
+ case "string":
14976
+ return toString(value);
14977
+ case "number":
14978
+ return +value;
14979
+ case "boolean":
14980
+ return !!value;
14981
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
14982
+ case "color":
14983
+ return Color.parse(value);
14984
+ case "formatted": {
14985
+ return Formatted.fromString(toString(value));
14986
+ }
14987
+ case "resolvedImage": {
14988
+ return ResolvedImage.build(toString(value));
14989
+ }
14990
+ }
14991
+ return value;
14992
+ }
14993
+ function clampToAllowedNumber(value, min, max, step) {
14994
+ if (step !== void 0) {
14995
+ value = step * Math.round(value / step);
14996
+ }
14997
+ if (min !== void 0 && value < min) {
14998
+ value = min;
14999
+ }
15000
+ if (max !== void 0 && value > max) {
15001
+ value = max;
15002
+ }
15003
+ return value;
15004
+ }
15005
+ class Config {
15006
+ constructor(type, key, scope, featureConstant = false) {
15007
+ this.type = type;
15008
+ this.key = key;
15009
+ this.scope = scope;
15010
+ this.featureConstant = featureConstant;
15011
+ }
15012
+ static parse(args, context) {
15013
+ let type = context.expectedType;
15014
+ type ?? (type = ValueType);
15015
+ if (args.length < 2 || args.length > 3) {
15016
+ return context.error(`Invalid number of arguments for 'config' expression.`);
15017
+ }
15018
+ const configKey = context.parse(args[1], 1);
15019
+ if (!(configKey instanceof Literal)) {
15020
+ return context.error(`Key name of 'config' expression must be a string literal.`);
15021
+ }
15022
+ let featureConstant = true;
15023
+ let configScopeValue;
15024
+ const configKeyValue = toString(configKey.value);
15025
+ if (args.length >= 3) {
15026
+ const configScope = context.parse(args[2], 2);
15027
+ if (!(configScope instanceof Literal)) {
15028
+ return context.error(`Scope of 'config' expression must be a string literal.`);
15029
+ }
15030
+ configScopeValue = toString(configScope.value);
15031
+ }
15032
+ if (context.options) {
15033
+ const fqid = makeConfigFQID(configKeyValue, configScopeValue, context._scope);
15034
+ const config = context.options.get(fqid);
15035
+ if (config) {
15036
+ featureConstant = isFeatureConstant(config.value || config.default);
15037
+ }
15038
+ }
15039
+ return new Config(type, configKeyValue, configScopeValue, featureConstant);
15040
+ }
15041
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15042
+ evaluate(ctx) {
15043
+ const fqid = makeConfigFQID(this.key, this.scope, ctx.scope);
15044
+ const config = ctx.getConfig(fqid);
15045
+ if (!config) return null;
15046
+ const { type, value, values, minValue, maxValue, stepValue } = config;
15047
+ const defaultValue = config.default.evaluate(ctx);
15048
+ let result = defaultValue;
15049
+ if (value) {
15050
+ const originalScope = ctx.scope;
15051
+ ctx.scope = (originalScope || "").split(FQIDSeparator).slice(1).join(FQIDSeparator);
15052
+ result = value.evaluate(ctx);
15053
+ ctx.scope = originalScope;
15054
+ }
15055
+ if (type) {
15056
+ result = coerceValue(type, result);
15057
+ }
15058
+ if (result !== void 0 && (minValue !== void 0 || maxValue !== void 0 || stepValue !== void 0)) {
15059
+ if (typeof result === "number") {
15060
+ result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
15061
+ } else if (Array.isArray(result)) {
15062
+ result = result.map((item) => typeof item === "number" ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
15063
+ }
15064
+ }
15065
+ if (value !== void 0 && result !== void 0 && values && !values.includes(result)) {
15066
+ result = defaultValue;
15067
+ if (type) {
15068
+ result = coerceValue(type, result);
15069
+ }
15070
+ }
15071
+ if (type && type !== this.type || result !== void 0 && !typeEquals(typeOf(result), this.type)) {
15072
+ result = coerceValue(this.type.kind, result);
15073
+ }
15074
+ return result;
15075
+ }
15076
+ eachChild() {
15077
+ }
15078
+ outputDefined() {
15079
+ return false;
15080
+ }
15081
+ serialize() {
15082
+ const res = ["config", this.key];
15083
+ if (this.scope) {
15084
+ res.concat(this.scope);
15085
+ }
15086
+ return res;
15087
+ }
15088
+ }
15089
+
15090
+ function isFeatureConstant(e) {
15091
+ if (e instanceof CompoundExpression) {
15092
+ if (e.name === "get" && e.args.length === 1) {
15093
+ return false;
15094
+ } else if (e.name === "feature-state") {
15095
+ return false;
15096
+ } else if (e.name === "has" && e.args.length === 1) {
15097
+ return false;
15098
+ } else if (e.name === "properties" || e.name === "geometry-type" || e.name === "id") {
15099
+ return false;
15100
+ } else if (e.name.startsWith("filter-")) {
15101
+ return false;
15102
+ }
15103
+ }
15104
+ if (e instanceof Within) {
15105
+ return false;
15106
+ }
15107
+ if (e instanceof Distance) {
15108
+ return false;
15109
+ }
15110
+ if (e instanceof Config) {
15111
+ return e.featureConstant;
15112
+ }
15113
+ let result = true;
15114
+ e.eachChild((arg) => {
15115
+ if (result && !isFeatureConstant(arg)) {
15116
+ result = false;
15117
+ }
15118
+ });
15119
+ return result;
15120
+ }
15121
+ function isStateConstant(e) {
15122
+ if (e instanceof CompoundExpression) {
15123
+ if (e.name === "feature-state") {
15124
+ return false;
15125
+ }
15126
+ }
15127
+ let result = true;
15128
+ e.eachChild((arg) => {
15129
+ if (result && !isStateConstant(arg)) {
15130
+ result = false;
15131
+ }
15132
+ });
15133
+ return result;
15134
+ }
15135
+ function isGlobalPropertyConstantSet(e, properties) {
15136
+ if (e instanceof CompoundExpression && properties.has(e.name)) {
15137
+ return false;
15138
+ }
15139
+ let result = true;
15140
+ e.eachChild((arg) => {
15141
+ if (result && !isGlobalPropertyConstantSet(arg, properties)) {
15142
+ result = false;
15143
+ }
15144
+ });
15145
+ return result;
15146
+ }
15147
+ function isGlobalPropertyConstant(e, properties) {
15148
+ return isGlobalPropertyConstantSet(e, new Set(properties));
15149
+ }
15150
+
14884
15151
  const RE = 6378.137;
14885
15152
  const FE = 1 / 298.257223563;
14886
15153
  const E2 = FE * (2 - FE);
@@ -15416,245 +15683,94 @@
15416
15683
  function isTypeValid(type) {
15417
15684
  return type === "Point" || type === "MultiPoint" || type === "LineString" || type === "MultiLineString" || type === "Polygon" || type === "MultiPolygon";
15418
15685
  }
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
- }
15686
+ function extractDistanceGeometry(value) {
15687
+ if (!isValue(value) || typeof value !== "object" || value === null || Array.isArray(value)) {
15466
15688
  return null;
15467
15689
  }
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;
15490
- }
15491
- }
15492
- if (e instanceof Within) {
15493
- return false;
15494
- }
15495
- if (e instanceof Distance) {
15496
- return false;
15497
- }
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));
15690
+ const geojson = value;
15691
+ if (geojson.type === "FeatureCollection") {
15692
+ if (geojson.features.length === 0) return null;
15693
+ const geometries = [];
15694
+ for (const feature of geojson.features) {
15695
+ if (!isTypeValid(feature.geometry.type)) return null;
15696
+ geometries.push(feature.geometry);
15557
15697
  }
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);
15698
+ return geometries;
15567
15699
  }
15568
- if (min !== void 0 && value < min) {
15569
- value = min;
15700
+ if (geojson.type === "Feature") {
15701
+ return isTypeValid(geojson.geometry.type) ? [geojson.geometry] : null;
15570
15702
  }
15571
- if (max !== void 0 && value > max) {
15572
- value = max;
15703
+ if (isTypeValid(geojson.type)) {
15704
+ return [geojson];
15573
15705
  }
15574
- return value;
15706
+ return null;
15575
15707
  }
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;
15708
+ class Distance {
15709
+ constructor(geojson) {
15710
+ this.type = NumberType;
15711
+ this.geojson = geojson;
15582
15712
  }
15583
15713
  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.`);
15714
+ if (args.length !== 2) {
15715
+ return context.error(`'distance' expression requires either one argument, but found ' ${args.length - 1} instead.`);
15592
15716
  }
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.`);
15717
+ const arg = args[1];
15718
+ const isBareGeoJSON = isValue(arg) && !Array.isArray(arg);
15719
+ const parsed = context.parse(isBareGeoJSON ? ["literal", arg] : arg, 1, ValueType);
15720
+ if (!parsed) return null;
15721
+ for (const [globalProperties, name] of [
15722
+ [["measure-light"], "brightness"],
15723
+ [["pitch"], "pitch"],
15724
+ [["distance-from-center"], "distance-from-center"]
15725
+ ]) {
15726
+ if (!isGlobalPropertyConstant(parsed, globalProperties)) {
15727
+ return context.error(`'distance' expression may not depend on ${name}.`);
15600
15728
  }
15601
- configScopeValue = toString(configScope.value);
15602
15729
  }
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
- }
15730
+ if (!isStateConstant(parsed)) {
15731
+ return context.error(`'distance' expression may not depend on feature-state.`);
15609
15732
  }
15610
- return new Config(type, configKeyValue, configScopeValue, featureConstant);
15733
+ if (parsed instanceof Literal && !extractDistanceGeometry(parsed.value)) {
15734
+ return context.error(
15735
+ "'distance' expression needs to be an array with format ['Distance', GeoJSONObj]."
15736
+ );
15737
+ }
15738
+ return new Distance(parsed);
15611
15739
  }
15612
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15613
15740
  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);
15741
+ const geometries = extractDistanceGeometry(this.geojson.evaluate(ctx));
15742
+ if (!geometries) {
15743
+ console.warn("Distance Expression: could not resolve a valid Point/LineString/Polygon GeoJSON geometry.");
15744
+ return null;
15628
15745
  }
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
- }
15746
+ const geometry = ctx.geometry();
15747
+ const canonical = ctx.canonicalID();
15748
+ if (geometry == null || canonical == null) {
15749
+ console.warn("Distance Expression: requires valid feature and canonical information.");
15750
+ return null;
15635
15751
  }
15636
- if (value !== void 0 && result !== void 0 && values && !values.includes(result)) {
15637
- result = defaultValue;
15638
- if (type) {
15639
- result = coerceValue(type, result);
15640
- }
15752
+ const geometryType = ctx.geometryType();
15753
+ const distanceTo = geometryType === "Point" ? pointsToGeometryDistance : geometryType === "LineString" ? linesToGeometryDistance : geometryType === "Polygon" ? polygonsToGeometryDistance : null;
15754
+ if (!distanceTo) {
15755
+ console.warn("Distance Expression: currently only evaluates valid Point/LineString/Polygon geometries.");
15756
+ return null;
15641
15757
  }
15642
- if (type && type !== this.type || result !== void 0 && !typeEquals(typeOf(result), this.type)) {
15643
- result = coerceValue(this.type.kind, result);
15758
+ let dist = Infinity;
15759
+ for (const g of geometries) {
15760
+ const tempDist = distanceTo(geometry, canonical, g);
15761
+ if (tempDist == null || isNaN(tempDist)) return tempDist;
15762
+ if ((dist = Math.min(dist, tempDist)) === 0) break;
15644
15763
  }
15645
- return result;
15764
+ return dist;
15646
15765
  }
15647
- eachChild() {
15766
+ eachChild(fn) {
15767
+ fn(this.geojson);
15648
15768
  }
15649
15769
  outputDefined() {
15650
- return false;
15770
+ return true;
15651
15771
  }
15652
15772
  serialize() {
15653
- const res = ["config", this.key];
15654
- if (this.scope) {
15655
- res.concat(this.scope);
15656
- }
15657
- return res;
15773
+ return ["distance", this.geojson.serialize()];
15658
15774
  }
15659
15775
  }
15660
15776
 
@@ -17892,7 +18008,7 @@
17892
18008
  kind: "composite",
17893
18009
  interpolationType,
17894
18010
  interpolationFactor: Interpolate.interpolationFactor.bind(void 0, interpolationType),
17895
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
18011
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
17896
18012
  zoomStops: featureFunctionStops.map((s) => s[0]),
17897
18013
  evaluate({ zoom }, properties) {
17898
18014
  return evaluateExponentialFunction({
@@ -18023,15 +18139,16 @@
18023
18139
  this.isIndoorDependent = isIndoorDependent(expression);
18024
18140
  }
18025
18141
  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);
18142
+ const evaluator = this._evaluator;
18143
+ evaluator.globals = globals;
18144
+ evaluator.feature = feature;
18145
+ evaluator.featureState = featureState;
18146
+ evaluator.canonical = canonical || null;
18147
+ evaluator.availableImages = availableImages || null;
18148
+ evaluator.formattedSection = formattedSection;
18149
+ evaluator.featureTileCoord = featureTileCoord || null;
18150
+ evaluator.featureDistanceData = featureDistanceData || null;
18151
+ return this.expression.evaluate(evaluator);
18035
18152
  }
18036
18153
  evaluate(globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData, iconImageUseTheme) {
18037
18154
  if (!this._evaluator) {
@@ -18249,7 +18366,8 @@
18249
18366
  enum: StringType,
18250
18367
  boolean: BooleanType,
18251
18368
  formatted: FormattedType,
18252
- resolvedImage: ResolvedImageType
18369
+ resolvedImage: ResolvedImageType,
18370
+ object: ObjectType
18253
18371
  };
18254
18372
  if (spec.type === "array") {
18255
18373
  return array$1(types[spec.value] || ValueType, spec.length);
@@ -19513,17 +19631,23 @@ ${JSON.stringify(filterExp, null, 2)}
19513
19631
  const optionValue = options.value;
19514
19632
  const isArrayOption = isObject(optionValue) && unbundle(optionValue.array) === true;
19515
19633
  const declaredType = !isArrayOption && isObject(optionValue) ? unbundle(optionValue.type) : void 0;
19634
+ const validateDefault = (elementOptions) => {
19635
+ const defaultValue = elementOptions.value;
19636
+ if (isObject(defaultValue)) {
19637
+ return validate({ ...elementOptions, valueSpec: { ...elementOptions.valueSpec, type: "*", expression: void 0 } });
19638
+ }
19639
+ if (declaredType && Array.isArray(defaultValue)) {
19640
+ return validate({ ...elementOptions, valueSpec: { ...elementOptions.valueSpec, type: declaredType } });
19641
+ }
19642
+ return validate(elementOptions);
19643
+ };
19516
19644
  return validateObject({
19517
19645
  ...options,
19518
19646
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
19519
19647
  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
19648
+ objectElementValidators: {
19649
+ default: validateDefault
19650
+ }
19527
19651
  });
19528
19652
  }
19529
19653