@mapbox/mapbox-gl-style-spec 14.9.2 → 14.10.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.
@@ -24,7 +24,15 @@ function stringify(obj: any) {
24
24
  function getKey(layer: LayerSpecification) {
25
25
  let key = '';
26
26
  for (const k of refProperties) {
27
- key += `/${stringify((layer as any)[k])}`;
27
+ // Ignore minzoom and maxzoom for model layers so that multiple model layers
28
+ // referencing the same source (but with different zoom ranges) produce the same
29
+ // key. This ensures they get grouped into a single bucket, preventing a scenario
30
+ // where shared node data is serialized twice and triggers an assert in struct_array.ts.
31
+ if (layer.type === 'model' && (k === 'minzoom' || k === 'maxzoom')) {
32
+ continue;
33
+ } else {
34
+ key += `/${stringify((layer as any)[k])}`;
35
+ }
28
36
  }
29
37
  return key;
30
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/mapbox-gl-style-spec",
3
- "version": "14.9.2",
3
+ "version": "14.10.0",
4
4
  "description": "a specification for mapbox gl styles",
5
5
  "author": "Mapbox",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
package/reference/v8.json CHANGED
@@ -220,6 +220,13 @@
220
220
  "experimental": true,
221
221
  "type": "featuresets",
222
222
  "doc": "Defines sets of features for querying, interaction, and state management on the map, referencing individual layers or subsets of layers within the map's style.",
223
+ "sdk-support": {
224
+ "basic functionality": {
225
+ "js": "3.9.0",
226
+ "android": "11.9.0",
227
+ "ios": "11.9.0"
228
+ }
229
+ },
223
230
  "example": {
224
231
  "poi": {
225
232
  "selectors": [
@@ -246,10 +253,12 @@
246
253
  "featureset": {
247
254
  "experimental": true,
248
255
  "metadata": {
256
+ "experimental": true,
249
257
  "type": "*",
250
258
  "doc": "Arbitrary properties useful to track with the stylesheet, but do not influence rendering. Properties should be prefixed to avoid collisions, like 'mapbox:'."
251
259
  },
252
260
  "selectors": {
261
+ "experimental": true,
253
262
  "type": "array",
254
263
  "value": "selector",
255
264
  "doc": "A collection of categorized selectors."
@@ -258,24 +267,35 @@
258
267
  "selector": {
259
268
  "experimental": true,
260
269
  "layer": {
270
+ "experimental": true,
261
271
  "type": "string",
262
272
  "doc": "The ID of a layer that exists in the current style.",
263
273
  "required": true
264
274
  },
265
275
  "properties": {
276
+ "experimental": true,
266
277
  "type": "selectorProperty",
267
278
  "required": false,
268
279
  "doc": "Properties accessible to the end user through queried feautures. If properties are empty, no feature properties are exposed. If undefined, all original feature properties will be accessible."
269
280
  },
270
281
  "featureNamespace": {
282
+ "experimental": true,
271
283
  "type": "string",
272
284
  "required": false,
273
285
  "doc": "An optional field that represents the feature namespace defined by the selector within a featureset to which this feature belongs. If the underlying source is the same for multiple selectors within a featureset, the same featureNamespace should be used across those selectors."
286
+ },
287
+ "_uniqueFeatureID": {
288
+ "experimental": true,
289
+ "type": "boolean",
290
+ "private": true,
291
+ "required": false,
292
+ "doc": "Internal flag used for standard style, in case multiple features sharing the same featureId, only one feature will be returned for feature query."
274
293
  }
275
294
  },
276
295
  "selectorProperty": {
277
296
  "experimental": true,
278
297
  "*": {
298
+ "experimental": true,
279
299
  "type": "*",
280
300
  "doc": "The value of the property. It can be an expression that generates the returned value from the feature, or a constant value specifying the returned value."
281
301
  }
@@ -1713,6 +1733,31 @@
1713
1733
  },
1714
1734
  "property-type": "data-driven"
1715
1735
  },
1736
+ "circle-elevation-reference": {
1737
+ "type": "enum",
1738
+ "doc": "Selects the base of circle-elevation. Some modes might require precomputed elevation data in the tileset.",
1739
+ "values": {
1740
+ "none": {
1741
+ "doc": "Elevated rendering is disabled."
1742
+ },
1743
+ "hd-road-markup": {
1744
+ "doc": "Elevated rendering is enabled. Use this mode to describe additive and stackable features that should exist only on top of road polygons."
1745
+ }
1746
+ },
1747
+ "default": "none",
1748
+ "experimental": true,
1749
+ "transition": false,
1750
+ "sdk-support": {
1751
+ "basic functionality": {
1752
+ "android": "11.11.0",
1753
+ "ios": "11.11.0"
1754
+ }
1755
+ },
1756
+ "expression": {
1757
+ "interpolated": false
1758
+ },
1759
+ "property-type": "data-constant"
1760
+ },
1716
1761
  "visibility": {
1717
1762
  "type": "enum",
1718
1763
  "values": {
@@ -10165,8 +10210,8 @@
10165
10210
  },
10166
10211
  "promoteId": {
10167
10212
  "*": {
10168
- "type": "string",
10169
- "doc": "A name of a feature property to use as ID for feature state."
10213
+ "type": "*",
10214
+ "doc": "A feature property name to use as the ID, or an expression to evaluate as the ID for feature state."
10170
10215
  }
10171
10216
  }
10172
10217
  }
package/types.ts CHANGED
@@ -8,7 +8,7 @@ export type FormattedSpecification = string;
8
8
 
9
9
  export type ResolvedImageSpecification = string;
10
10
 
11
- export type PromoteIdSpecification = {[_: string]: string} | string;
11
+ export type PromoteIdSpecification = {[_: string]: string | ExpressionSpecification} | string | ExpressionSpecification;
12
12
 
13
13
  export type FilterSpecification =
14
14
  | ExpressionSpecification
@@ -274,7 +274,13 @@ export type FeaturesetsSpecification = {
274
274
  * @experimental This is experimental and subject to change in future versions.
275
275
  */
276
276
  export type FeaturesetSpecification = {
277
+ /**
278
+ * @experimental This property is experimental and subject to change in future versions.
279
+ */
277
280
  "metadata"?: unknown,
281
+ /**
282
+ * @experimental This property is experimental and subject to change in future versions.
283
+ */
278
284
  "selectors"?: Array<SelectorSpecification>
279
285
  }
280
286
 
@@ -282,15 +288,31 @@ export type FeaturesetSpecification = {
282
288
  * @experimental This is experimental and subject to change in future versions.
283
289
  */
284
290
  export type SelectorSpecification = {
291
+ /**
292
+ * @experimental This property is experimental and subject to change in future versions.
293
+ */
285
294
  "layer": string,
295
+ /**
296
+ * @experimental This property is experimental and subject to change in future versions.
297
+ */
286
298
  "properties"?: SelectorPropertySpecification,
287
- "featureNamespace"?: string
299
+ /**
300
+ * @experimental This property is experimental and subject to change in future versions.
301
+ */
302
+ "featureNamespace"?: string,
303
+ /**
304
+ * @experimental This property is experimental and subject to change in future versions.
305
+ */
306
+ "_uniqueFeatureID"?: boolean
288
307
  }
289
308
 
290
309
  /**
291
310
  * @experimental This is experimental and subject to change in future versions.
292
311
  */
293
312
  export type SelectorPropertySpecification = {
313
+ /**
314
+ * @experimental This property is experimental and subject to change in future versions.
315
+ */
294
316
  [_: string]: unknown
295
317
  }
296
318
 
@@ -730,6 +752,10 @@ export type CircleLayerSpecification = {
730
752
  "filter"?: FilterSpecification,
731
753
  "layout"?: {
732
754
  "circle-sort-key"?: DataDrivenPropertyValueSpecification<number>,
755
+ /**
756
+ * @experimental This property is experimental and subject to change in future versions.
757
+ */
758
+ "circle-elevation-reference"?: "none" | "hd-road-markup" | ExpressionSpecification,
733
759
  "visibility"?: "visible" | "none" | ExpressionSpecification
734
760
  },
735
761
  "paint"?: {
@@ -5,7 +5,7 @@ import {isFunction} from '../function/index';
5
5
  import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint';
6
6
  import {supportsLightExpression, supportsPropertyExpression, supportsZoomExpression} from '../util/properties';
7
7
  import {isGlobalPropertyConstant, isFeatureConstant, isStateConstant} from '../expression/is_constant';
8
- import {createPropertyExpression} from '../expression/index';
8
+ import {createPropertyExpression, isExpression} from '../expression/index';
9
9
 
10
10
  import type {ValidationOptions} from './validate';
11
11
 
@@ -28,6 +28,30 @@ export default function validateProperty(options: PropertyValidationOptions, pro
28
28
 
29
29
  const useThemeMatch = propertyKey.match(/^(.*)-use-theme$/);
30
30
  if (propertyType === 'paint' && useThemeMatch && layerSpec[useThemeMatch[1]]) {
31
+ if (isExpression(value)) {
32
+ const errors = [];
33
+ return errors.concat(validate({
34
+ key: options.key,
35
+ value,
36
+ valueSpec: {
37
+ "type": "string",
38
+ "expression": {
39
+ "interpolated": false,
40
+ "parameters": [
41
+ "zoom",
42
+ "feature"
43
+ ]
44
+ },
45
+ "property-type": "data-driven"
46
+ },
47
+ style,
48
+ styleSpec,
49
+ // @ts-expect-error - TS2353 - Object literal may only specify known properties, and 'expressionContext' does not exist in type 'ValidationOptions'.
50
+ expressionContext: 'property',
51
+ propertyType,
52
+ propertyKey
53
+ }));
54
+ }
31
55
  return validate({
32
56
  key,
33
57
  value,
@@ -1,10 +1,12 @@
1
1
  import {default as ValidationError, ValidationWarning} from '../error/validation_error';
2
- import {unbundle} from '../util/unbundle_jsonlint';
2
+ import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint';
3
3
  import validateObject from './validate_object';
4
4
  import validateEnum from './validate_enum';
5
5
  import validateExpression from './validate_expression';
6
6
  import validateString from './validate_string';
7
7
  import getType from '../util/get_type';
8
+ import {createExpression} from '../expression/index';
9
+ import * as isConstant from '../expression/is_constant';
8
10
 
9
11
  import type {StyleReference} from '../reference/latest';
10
12
  import type {ValidationOptions} from './validate';
@@ -125,10 +127,28 @@ function validatePromoteId({
125
127
  }: Partial<ValidationOptions>) {
126
128
  if (getType(value) === 'string') {
127
129
  return validateString({key, value});
130
+ } else if (Array.isArray(value)) {
131
+ const errors = [];
132
+ const unbundledValue = deepUnbundle(value);
133
+ const expression = createExpression(unbundledValue);
134
+ if (expression.result === 'error') {
135
+ expression.value.forEach((err) => {
136
+ errors.push(new ValidationError(`${key}${err.key}`, null, `${err.message}`));
137
+ });
138
+ }
139
+
140
+ // @ts-expect-error - TS2339: Property 'expression' does not exist on type 'ParsingError[] | StyleExpression'.
141
+ const parsed = expression.value.expression;
142
+ const onlyFeatureDependent = isConstant.isGlobalPropertyConstant(parsed, ['zoom', 'heatmap-density', 'line-progress', 'raster-value', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center', 'measure-light', 'raster-particle-speed']);
143
+ if (!onlyFeatureDependent) {
144
+ errors.push(new ValidationError(`${key}`, null, 'promoteId expression should be only feature dependent'));
145
+ }
146
+
147
+ return errors;
128
148
  } else {
129
149
  const errors = [];
130
150
  for (const prop in value) {
131
- errors.push(...validateString({key: `${key}.${prop}`, value: value[prop]}));
151
+ errors.push(...validatePromoteId({key: `${key}.${prop}`, value: value[prop]}));
132
152
  }
133
153
  return errors;
134
154
  }
@@ -40,9 +40,9 @@ function getSourceErrors(source: any, i: number): Array<ValidationError> {
40
40
 
41
41
  /*
42
42
  * Inlined sources are not supported by the Mapbox Styles API, so only
43
- * "type", "url", and "tileSize" properties are valid
43
+ * "type", "url", and "tileSize", "promoteId" properties are valid
44
44
  */
45
- const sourceKeys = ['type', 'url', 'tileSize'];
45
+ const sourceKeys = ['type', 'url', 'tileSize', 'promoteId'];
46
46
  errors.push(...getAllowedKeyErrors(source, sourceKeys, 'source'));
47
47
 
48
48
  /*