@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
@@ -112,7 +112,7 @@ ${JSON.stringify(filterExp, null, 2)}
112
112
  }
113
113
 
114
114
  // Compile the static component of the filter
115
- let filterFunc = null;
115
+ let filterFunc: PropertyDescriptor['value'] = null;
116
116
  let filterSpec = null;
117
117
  if (layerType !== 'background' && layerType !== 'sky' && layerType !== 'slot') {
118
118
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -131,7 +131,7 @@ ${JSON.stringify(filterExp, null, 2)}
131
131
 
132
132
  // If the static component is not equal to the entire filter then we have a dynamic component
133
133
  // Compile the dynamic component separately
134
- let dynamicFilterFunc = null;
134
+ let dynamicFilterFunc: PropertyDescriptor['value'] = null;
135
135
  let needFeature = null;
136
136
  if (staticFilter !== filterExp) {
137
137
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
@@ -189,7 +189,7 @@ function collapseDynamicBooleanExpressions(expression: any): any {
189
189
  return collapsed;
190
190
  } else {
191
191
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
192
- return collapsed.map((subExpression) => collapseDynamicBooleanExpressions(subExpression));
192
+ return collapsed.map((subExpression: unknown) => collapseDynamicBooleanExpressions(subExpression));
193
193
  }
194
194
  }
195
195
 
@@ -19,7 +19,7 @@ export default function convertFunction<T>(parameters: FunctionSpecification<T>,
19
19
  return convertIdentityFunction(parameters, propertySpec);
20
20
  }
21
21
 
22
- const zoomAndFeatureDependent = stops && typeof stops[0][0] === 'object';
22
+ const zoomAndFeatureDependent = stops && typeof stops[0]![0] === 'object';
23
23
  const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
24
24
  const zoomDependent = zoomAndFeatureDependent || !featureDependent;
25
25
 
@@ -51,7 +51,7 @@ function convertIdentityFunction<T>(parameters: FunctionSpecification<T>, proper
51
51
  return [
52
52
  'match',
53
53
  get,
54
- Object.keys(propertySpec.values),
54
+ Object.keys(propertySpec.values!),
55
55
  get,
56
56
  parameters.default
57
57
  ];
@@ -83,7 +83,7 @@ function convertZoomAndPropertyFunction<T>(
83
83
  const featureFunctionStops: Record<string, any> = {};
84
84
  const zoomStops = [];
85
85
  for (let s = 0; s < stops.length; s++) {
86
- const stop = stops[s];
86
+ const stop = stops[s]!;
87
87
  const zoom = stop[0].zoom;
88
88
  if (featureFunctionParameters[zoom] === undefined) {
89
89
  featureFunctionParameters[zoom] = {
@@ -103,12 +103,12 @@ function convertZoomAndPropertyFunction<T>(
103
103
  // function is determined directly from the style property specification
104
104
  // for which it's being used: linear for interpolatable properties, step
105
105
  // otherwise.
106
- const functionType = getFunctionType({} as FunctionSpecification<unknown>, propertySpec);
106
+ const functionType = getFunctionType({}, propertySpec);
107
107
  if (functionType === 'exponential') {
108
108
  const expression: ExpressionSpecification = [getInterpolateOperator(parameters), ['linear'], ['zoom']];
109
109
 
110
110
  for (const z of zoomStops) {
111
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
111
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
112
112
  const output = convertPropertyFunction(featureFunctionParameters[z], propertySpec, featureFunctionStops[z]);
113
113
  appendStopPair(expression, z, output, false);
114
114
  }
@@ -118,7 +118,7 @@ function convertZoomAndPropertyFunction<T>(
118
118
  const expression: ExpressionSpecification = ['step', ['zoom']];
119
119
 
120
120
  for (const z of zoomStops) {
121
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
121
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
122
122
  const output = convertPropertyFunction(featureFunctionParameters[z], propertySpec, featureFunctionStops[z]);
123
123
  appendStopPair(expression, z, output, true);
124
124
  }
@@ -156,7 +156,7 @@ function convertPropertyFunction<T>(
156
156
  ): ExpressionSpecification {
157
157
  const type = getFunctionType(parameters, propertySpec);
158
158
  const get: ExpressionSpecification = ['get', parameters.property];
159
- if (type === 'categorical' && typeof stops[0][0] === 'boolean') {
159
+ if (type === 'categorical' && typeof stops[0]![0] === 'boolean') {
160
160
  assert(parameters.stops.length > 0 && parameters.stops.length <= 2);
161
161
  const expression: ExpressionSpecification = ['case'];
162
162
  for (const stop of stops) {
@@ -251,7 +251,7 @@ function appendStopPair(curve: ExpressionSpecification, input: unknown, output:
251
251
  curve.push(output);
252
252
  }
253
253
 
254
- function getFunctionType<T>(parameters: FunctionSpecification<T>, propertySpec: StylePropertySpecification): string {
254
+ function getFunctionType(parameters: Pick<FunctionSpecification<unknown>, 'type'>, propertySpec: StylePropertySpecification): string {
255
255
  if (parameters.type) {
256
256
  return parameters.type;
257
257
  } else {
package/function/index.ts CHANGED
@@ -11,6 +11,8 @@ import ResolvedImage from '../expression/types/resolved_image';
11
11
  import {supportsInterpolation} from '../util/properties';
12
12
  import {findStopLessThanOrEqualTo} from '../expression/stops';
13
13
 
14
+ import type {FunctionSpecification} from '../types';
15
+
14
16
  export function isFunction(value) {
15
17
  return typeof value === 'object' && value !== null && !Array.isArray(value);
16
18
  }
@@ -24,7 +26,7 @@ export function createFunction(parameters, propertySpec) {
24
26
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
25
27
  const isColor = propertySpec.type === 'color';
26
28
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
27
- const zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
29
+ const zoomAndFeatureDependent = (parameters.stops as FunctionSpecification<unknown>['stops'] | undefined) && typeof parameters.stops[0][0] === 'object';
28
30
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
29
31
  const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
30
32
  const zoomDependent = zoomAndFeatureDependent || !featureDependent;
@@ -132,7 +134,7 @@ export function createFunction(parameters, propertySpec) {
132
134
  interpolationType,
133
135
 
134
136
  interpolationFactor: Interpolate.interpolationFactor.bind(undefined, interpolationType),
135
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
137
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
136
138
  zoomStops: featureFunctionStops.map(s => s[0]),
137
139
  evaluate({zoom}, properties) {
138
140
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
@@ -2,6 +2,8 @@ import refProperties from './util/ref_properties';
2
2
 
3
3
  import type {LayerSpecification} from './types';
4
4
 
5
+ type IndexableLayer = LayerSpecification & Record<string, unknown>;
6
+
5
7
  function stringify(obj: unknown) {
6
8
  if (typeof obj === 'number' || typeof obj === 'boolean' || typeof obj === 'string' || obj === undefined || obj === null)
7
9
  return JSON.stringify(obj);
@@ -15,13 +17,13 @@ function stringify(obj: unknown) {
15
17
  }
16
18
 
17
19
  let str = '{';
18
- for (const key of Object.keys(obj as Record<string, unknown>).sort()) {
20
+ for (const key of Object.keys(obj).sort()) {
19
21
  str += `${key}:${stringify((obj as Record<string, unknown>)[key])},`;
20
22
  }
21
23
  return `${str}}`;
22
24
  }
23
25
 
24
- function getKey(layer: LayerSpecification) {
26
+ function getKey(layer: IndexableLayer) {
25
27
  let key = '';
26
28
  for (const k of refProperties) {
27
29
  key += `/${stringify(layer[k])}`;
@@ -72,7 +74,7 @@ export default function groupByLayout(
72
74
  const groups = Object.create(null) as Record<string, LayerSpecification[]>;
73
75
 
74
76
  for (let i = 0; i < layers.length; i++) {
75
- const layer = layers[i];
77
+ const layer = layers[i]!;
76
78
  let k = cachedKeys && cachedKeys[layer.id];
77
79
 
78
80
  if (!k) {
@@ -112,7 +114,7 @@ export default function groupByLayout(
112
114
  const result: LayerSpecification[][] = [];
113
115
 
114
116
  for (const k in groups) {
115
- result.push(groups[k]);
117
+ result.push(groups[k]!);
116
118
  }
117
119
 
118
120
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/mapbox-gl-style-spec",
3
- "version": "14.28.0",
3
+ "version": "14.29.0",
4
4
  "description": "a specification for mapbox gl styles",
5
5
  "author": "Mapbox",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
package/read_style.ts CHANGED
@@ -87,7 +87,7 @@ function parseTokens(s: string, tokens: number[]) {
87
87
  let lo = 0, hi = lineOffsets.length - 1;
88
88
  while (lo < hi) {
89
89
  const mid = (lo + hi + 1) >> 1;
90
- if (lineOffsets[mid] <= pos) lo = mid;
90
+ if (lineOffsets[mid]! <= pos) lo = mid;
91
91
  else hi = mid - 1;
92
92
  }
93
93
  return lo + 1;
@@ -104,7 +104,7 @@ function parseTokens(s: string, tokens: number[]) {
104
104
  const end = tokens[i + 2];
105
105
  i += 3;
106
106
 
107
- const line = lineNum(start);
107
+ const line = lineNum(start!);
108
108
 
109
109
  if (type === LBRACE) {
110
110
  const obj = setLine({}, line);
package/reference/v8.json CHANGED
@@ -380,6 +380,16 @@
380
380
  },
381
381
  "color": {
382
382
  "doc": "The result will be coerced to a color."
383
+ },
384
+ "object": {
385
+ "doc": "The result will be coerced to an object.",
386
+ "sdk-support": {
387
+ "basic functionality": {
388
+ "js": "3.29.0",
389
+ "android": "11.29.0",
390
+ "ios": "11.29.0"
391
+ }
392
+ }
383
393
  }
384
394
  }
385
395
  },
@@ -3092,6 +3102,7 @@
3092
3102
  "experimental": true,
3093
3103
  "sdk-support": {
3094
3104
  "basic functionality": {
3105
+ "js": "3.7.0",
3095
3106
  "android": "11.9.0",
3096
3107
  "ios": "11.9.0"
3097
3108
  }
@@ -5636,13 +5647,18 @@
5636
5647
  }
5637
5648
  },
5638
5649
  "distance": {
5639
- "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.",
5650
+ "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.",
5640
5651
  "group": "Math",
5641
5652
  "sdk-support": {
5642
5653
  "basic functionality": {
5643
5654
  "js": "3.0.0",
5644
5655
  "android": "9.2.0",
5645
5656
  "ios": "5.9.0"
5657
+ },
5658
+ "expressions support": {
5659
+ "js": "3.29.0",
5660
+ "android": "11.29.0",
5661
+ "ios": "11.29.0"
5646
5662
  }
5647
5663
  }
5648
5664
  },
@@ -9058,6 +9074,29 @@
9058
9074
  ]
9059
9075
  },
9060
9076
  "property-type": "data-constant"
9077
+ },
9078
+ "line-cutout-depth": {
9079
+ "type": "number",
9080
+ "default": 0,
9081
+ "minimum": 0,
9082
+ "units": "meters",
9083
+ "doc": "Depth offset along the camera, in meters. When set to a non-zero value, applied cutout opacity is 0.",
9084
+ "experimental": true,
9085
+ "private": true,
9086
+ "transition": true,
9087
+ "sdk-support": {
9088
+ "basic functionality": {
9089
+ "android": "11.29.0",
9090
+ "ios": "11.29.0"
9091
+ }
9092
+ },
9093
+ "expression": {
9094
+ "interpolated": true,
9095
+ "parameters": [
9096
+ "zoom"
9097
+ ]
9098
+ },
9099
+ "property-type": "data-constant"
9061
9100
  }
9062
9101
  },
9063
9102
  "paint_circle": {
@@ -10251,7 +10290,6 @@
10251
10290
  "default": 0,
10252
10291
  "minimum": 0,
10253
10292
  "transition": true,
10254
- "experimental": true,
10255
10293
  "appearance": true,
10256
10294
  "sdk-support": {
10257
10295
  "basic functionality": {
@@ -10305,7 +10343,7 @@
10305
10343
  },
10306
10344
  "raster-color": {
10307
10345
  "type": "color",
10308
- "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`.",
10346
+ "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.",
10309
10347
  "use-theme": true,
10310
10348
  "transition": false,
10311
10349
  "sdk-support": {
@@ -10345,7 +10383,7 @@
10345
10383
  "zoom"
10346
10384
  ]
10347
10385
  },
10348
- "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.",
10386
+ "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.",
10349
10387
  "example": [
10350
10388
  0.2126,
10351
10389
  0.7152,
@@ -10375,7 +10413,7 @@
10375
10413
  "zoom"
10376
10414
  ]
10377
10415
  },
10378
- "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.",
10416
+ "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.",
10379
10417
  "example": [
10380
10418
  0.5,
10381
10419
  10
@@ -10388,6 +10426,34 @@
10388
10426
  }
10389
10427
  }
10390
10428
  },
10429
+ "raster-color-scale": {
10430
+ "type": "enum",
10431
+ "doc": "When `raster-color` is active, specifies how raster values are distributed across the color ramp over the range specified by `raster-color-range`.",
10432
+ "values": {
10433
+ "linear": {
10434
+ "doc": "Raster values are spaced evenly across the color ramp."
10435
+ },
10436
+ "log": {
10437
+ "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."
10438
+ }
10439
+ },
10440
+ "default": "linear",
10441
+ "requires": [
10442
+ "raster-color",
10443
+ {"source": "raster-array"}
10444
+ ],
10445
+ "expression": {
10446
+ "interpolated": false,
10447
+ "parameters": []
10448
+ },
10449
+ "property-type": "data-constant",
10450
+ "experimental": true,
10451
+ "sdk-support": {
10452
+ "basic functionality": {
10453
+ "js": "3.29.0"
10454
+ }
10455
+ }
10456
+ },
10391
10457
  "raster-hue-rotate": {
10392
10458
  "type": "number",
10393
10459
  "default": 0,
@@ -10641,6 +10707,21 @@
10641
10707
  "interpolated": false
10642
10708
  },
10643
10709
  "property-type": "data-constant"
10710
+ },
10711
+ "raster-allow-draping": {
10712
+ "type": "boolean",
10713
+ "default": true,
10714
+ "experimental": true,
10715
+ "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.",
10716
+ "transition": false,
10717
+ "property-type": "data-constant",
10718
+ "sdk-support": {
10719
+ "basic functionality": {
10720
+ "js": "3.28.0",
10721
+ "android": "11.28.0",
10722
+ "ios": "11.28.0"
10723
+ }
10724
+ }
10644
10725
  }
10645
10726
  },
10646
10727
  "paint_raster-particle": {
@@ -7,7 +7,7 @@ export type ConfigOptionValue = {
7
7
  minValue?: number;
8
8
  maxValue?: number;
9
9
  stepValue?: number;
10
- type?: 'string' | 'number' | 'boolean' | 'color';
10
+ type?: 'string' | 'number' | 'boolean' | 'color' | 'object';
11
11
  };
12
12
 
13
13
  export type ConfigOptions = Map<string, ConfigOptionValue>;
package/types.ts CHANGED
@@ -366,7 +366,7 @@ export type SchemaSpecification = {
366
366
 
367
367
  export type OptionSpecification = {
368
368
  "default": unknown | ExpressionSpecification,
369
- "type"?: "string" | "number" | "boolean" | "color",
369
+ "type"?: "string" | "number" | "boolean" | "color" | "object",
370
370
  "array"?: boolean,
371
371
  "minValue"?: number,
372
372
  "maxValue"?: number,
@@ -771,7 +771,12 @@ export type LineLayerSpecification = {
771
771
  /**
772
772
  * @experimental This property is experimental and subject to change in future versions.
773
773
  */
774
- "line-blend-additive-clamp"?: PropertyValueSpecification<number>
774
+ "line-blend-additive-clamp"?: PropertyValueSpecification<number>,
775
+ /**
776
+ * @experimental This property is experimental and subject to change in future versions.
777
+ */
778
+ "line-cutout-depth"?: PropertyValueSpecification<number>,
779
+ "line-cutout-depth-transition"?: TransitionSpecification
775
780
  },
776
781
  "appearances"?: Array<AppearanceSpecification>
777
782
  };
@@ -898,9 +903,6 @@ export type SymbolLayerSpecification = {
898
903
  "icon-color-contrast"?: number | ExpressionSpecification,
899
904
  "icon-color-brightness-min"?: number | ExpressionSpecification,
900
905
  "icon-color-brightness-max"?: number | ExpressionSpecification,
901
- /**
902
- * @experimental This property is experimental and subject to change in future versions.
903
- */
904
906
  "symbol-z-offset"?: DataDrivenPropertyValueSpecification<number>,
905
907
  "symbol-z-offset-transition"?: TransitionSpecification
906
908
  },
@@ -1230,6 +1232,10 @@ export type RasterLayerSpecification = {
1230
1232
  "raster-color-mix-transition"?: TransitionSpecification,
1231
1233
  "raster-color-range"?: PropertyValueSpecification<[number, number]>,
1232
1234
  "raster-color-range-transition"?: TransitionSpecification,
1235
+ /**
1236
+ * @experimental This property is experimental and subject to change in future versions.
1237
+ */
1238
+ "raster-color-scale"?: "linear" | "log" | ExpressionSpecification,
1233
1239
  "raster-hue-rotate"?: PropertyValueSpecification<number>,
1234
1240
  "raster-hue-rotate-transition"?: TransitionSpecification,
1235
1241
  "raster-brightness-min"?: PropertyValueSpecification<number>,
@@ -1256,7 +1262,11 @@ export type RasterLayerSpecification = {
1256
1262
  /**
1257
1263
  * @experimental This property is experimental and subject to change in future versions.
1258
1264
  */
1259
- "raster-elevation-reference"?: "sea" | "ground" | ExpressionSpecification
1265
+ "raster-elevation-reference"?: "sea" | "ground" | ExpressionSpecification,
1266
+ /**
1267
+ * @experimental This property is experimental and subject to change in future versions.
1268
+ */
1269
+ "raster-allow-draping"?: boolean
1260
1270
  },
1261
1271
  "appearances"?: Array<AppearanceSpecification>
1262
1272
  };
@@ -3,7 +3,7 @@ import type {PropertyExpressionSpecification, StylePropertySpecification} from '
3
3
  export const TRANSITION_KEY_RE = /^(.*)-transition$/;
4
4
  export const USE_THEME_KEY_RE = /^(.*)-use-theme$/;
5
5
 
6
- type ExpressionParameter = PropertyExpressionSpecification['parameters'][number];
6
+ type ExpressionParameter = NonNullable<PropertyExpressionSpecification['parameters']>[number];
7
7
 
8
8
  function expressionHasParameter(
9
9
  expression: PropertyExpressionSpecification | null | undefined,
@@ -28,11 +28,21 @@ import validateIconset from './validate_iconset';
28
28
  import type ValidationError from '../error/validation_error';
29
29
  import type {StyleReference} from '../reference/latest';
30
30
  import type {StyleSpecification} from '../types';
31
- import type {FunctionValidatorOptions} from './validate_function';
32
31
  import type {StylePropertySpecification} from '../style-spec';
33
32
  import type {ExpressionValidatorOptions} from './validate_expression';
34
33
 
35
- const VALIDATORS: Record<string, (...args: unknown[]) => ValidationError[]> = {
34
+ type Validator = {
35
+ // eslint-disable-next-line @typescript-eslint/method-signature-style
36
+ validate(options: {
37
+ key: string;
38
+ value: unknown;
39
+ valueSpec?: unknown;
40
+ style?: Partial<StyleSpecification>;
41
+ styleSpec?: StyleReference;
42
+ }): ValidationError[];
43
+ }['validate'];
44
+
45
+ const VALIDATORS: Record<string, Validator> = {
36
46
  '*': () => [],
37
47
  'array': validateArray,
38
48
  'boolean': validateBoolean,
@@ -99,16 +109,16 @@ export type ValidatorOptions = {
99
109
  */
100
110
  export default function validate(options: ValidatorOptions, arrayAsExpression: boolean = false): ValidationError[] {
101
111
  const value = options.value;
102
- const valueSpec = options.valueSpec;
112
+ const valueSpec = options.valueSpec!;
103
113
  const styleSpec = options.styleSpec;
104
114
 
105
115
  if (valueSpec.expression) {
106
- if (isFunction(unbundle(value))) return validateFunction(options as unknown as FunctionValidatorOptions);
116
+ if (isFunction(unbundle(value))) return validateFunction(options);
107
117
  if (isExpression(deepUnbundle(value))) return validateExpression(options as unknown as ExpressionValidatorOptions);
108
118
  }
109
119
 
110
120
  if (valueSpec.type && VALIDATORS[valueSpec.type]) {
111
- const errors = VALIDATORS[valueSpec.type](options);
121
+ const errors = VALIDATORS[valueSpec.type]!(options);
112
122
  if (arrayAsExpression === true && errors.length > 0 && Array.isArray(options.value)) {
113
123
  // Try to validate as an expression
114
124
  return validateExpression(options as unknown as ExpressionValidatorOptions);
@@ -29,7 +29,7 @@ export default function validateAppearance(options: AppearanceValidatorOptions):
29
29
  const errors = validateObject({
30
30
  key,
31
31
  value,
32
- valueSpec: options.styleSpec.appearance as object,
32
+ valueSpec: options.styleSpec.appearance as Record<PropertyKey, unknown>,
33
33
  style: options.style,
34
34
  styleSpec: options.styleSpec,
35
35
  objectElementValidators: {
@@ -52,12 +52,12 @@ function validateProperties(options: AppearanceValidatorOptions): Array<Validati
52
52
 
53
53
  const paintProperties = styleSpec[`paint_${layerType}`] as Record<string, StylePropertySpecification> | undefined;
54
54
  const layoutProperties = styleSpec[`layout_${layerType}`] as Record<string, StylePropertySpecification> | undefined;
55
- const properties = options.object[options.objectKey] as object;
55
+ const properties = (options.object as Record<string, unknown>)[options.objectKey!] as Record<string, unknown>;
56
56
 
57
57
  for (const propertyKey in properties) {
58
58
  const propertyType =
59
- propertyKey in paintProperties ? 'paint' :
60
- propertyKey in layoutProperties ? 'layout' :
59
+ propertyKey in paintProperties! ? 'paint' :
60
+ propertyKey in layoutProperties! ? 'layout' :
61
61
  undefined;
62
62
 
63
63
  if (!propertyType) {
@@ -72,8 +72,8 @@ function validateProperties(options: AppearanceValidatorOptions): Array<Validati
72
72
  objectKey: propertyKey,
73
73
  layer,
74
74
  layerType,
75
- value: properties[propertyKey] as unknown,
76
- valueSpec: (propertyType === 'paint' ? paintProperties[propertyKey] : layoutProperties[propertyKey]),
75
+ value: properties[propertyKey],
76
+ valueSpec: (propertyType === 'paint' ? paintProperties![propertyKey] : layoutProperties![propertyKey]),
77
77
  };
78
78
 
79
79
  errors.push(...validateProperty(propertyValidationOptions, propertyType));
@@ -91,7 +91,7 @@ function validateCondition(options: AppearanceValidatorOptions): Array<Validatio
91
91
  errors.push(...validateExpression({
92
92
  key: options.key,
93
93
  value: condition,
94
- valueSpec: (latest['appearance'] as Record<string, unknown>)['condition'],
94
+ valueSpec: (latest['appearance'] as Record<string, Partial<StylePropertySpecification>>)['condition'],
95
95
  expressionContext: 'appearance'
96
96
  }));
97
97
 
@@ -4,29 +4,29 @@ import ValidationError from '../error/validation_error';
4
4
 
5
5
  import type {StyleReference} from '../reference/latest';
6
6
  import type {StyleSpecification} from '../types';
7
- import type {ArrayPropertySpecification} from '../style-spec';
8
7
 
9
- type ArraySpec = {
8
+ export type ArraySpec = {
10
9
  value?: unknown;
11
10
  values?: unknown[] | {[_: string]: unknown};
12
11
  length?: number;
13
12
  minimum?: number;
14
13
  maximum?: number;
15
14
  function?: unknown;
15
+ 'min-length'?: number;
16
16
  };
17
17
 
18
18
  type ArrayElementSpec<T = unknown> = {
19
19
  type: string;
20
- values: T[] | {[_: string]: unknown};
21
- minimum: number;
22
- maximum: number;
20
+ values?: T[] | {[_: string]: unknown};
21
+ minimum?: number;
22
+ maximum?: number;
23
23
  function: unknown;
24
24
  };
25
25
 
26
26
  type ArrayValidatorOptions<T = unknown> = {
27
27
  key: string;
28
28
  value: T;
29
- valueSpec: ArrayPropertySpecification | ArraySpec;
29
+ valueSpec: ArraySpec;
30
30
  style: Partial<StyleSpecification>;
31
31
  styleSpec: StyleReference;
32
32
  arrayElementValidator: (...args: unknown[]) => ValidationError[];
@@ -61,7 +61,7 @@ export default function validateArray(options: ArrayValidatorOptions): Validatio
61
61
  };
62
62
 
63
63
  if (styleSpec.$version < 7) {
64
- arrayElementSpec.function = (arraySpec as ArraySpec).function;
64
+ arrayElementSpec.function = arraySpec.function;
65
65
  }
66
66
 
67
67
  if (isObject(arraySpec.value)) {
@@ -17,12 +17,11 @@ export default function validateEnum(options: EnumValidatorOptions): ValidationE
17
17
  const errors: ValidationError[] = [];
18
18
  if (Array.isArray(valueSpec.values)) { // <=v7
19
19
  if (!valueSpec.values.includes(unbundle(value))) {
20
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
21
20
  errors.push(new ValidationError(key, value, `expected one of [${valueSpec.values.join(', ')}], ${JSON.stringify(value)} found`));
22
21
  }
23
22
  } else { // >=v8
24
- if (!Object.keys(valueSpec.values).includes(unbundle(value) as string)) {
25
- errors.push(new ValidationError(key, value, `expected one of [${Object.keys(valueSpec.values).join(', ')}], ${JSON.stringify(value)} found`));
23
+ if (!Object.keys(valueSpec.values!).includes(unbundle(value) as string)) {
24
+ errors.push(new ValidationError(key, value, `expected one of [${Object.keys(valueSpec.values!).join(', ')}], ${JSON.stringify(value)} found`));
26
25
  }
27
26
  }
28
27
 
@@ -34,7 +34,7 @@ export default function validateFog(options: FogValidatorOptions): ValidationErr
34
34
  const useThemeMatch = key.match(USE_THEME_KEY_RE);
35
35
 
36
36
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
37
- if (useThemeMatch && fogSpec[useThemeMatch[1]]) {
37
+ if (useThemeMatch && fogSpec[useThemeMatch[1]!]) {
38
38
  errors = errors.concat(validate({
39
39
  key,
40
40
  value: fog[key],
@@ -43,7 +43,7 @@ export default function validateFog(options: FogValidatorOptions): ValidationErr
43
43
  styleSpec
44
44
  }));
45
45
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
46
- } else if (transitionMatch && fogSpec[transitionMatch[1]] && fogSpec[transitionMatch[1]].transition) {
46
+ } else if (transitionMatch && fogSpec[transitionMatch[1]!] && fogSpec[transitionMatch[1]!].transition) {
47
47
  errors = errors.concat(validate({
48
48
  key,
49
49
  value: fog[key],