@mapbox/mapbox-gl-style-spec 14.25.0 → 14.26.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.
@@ -10,7 +10,7 @@ import CollatorExpression from './definitions/collator';
10
10
  import Within from './definitions/within';
11
11
  import Distance from './definitions/distance';
12
12
  import Config from './definitions/config';
13
- import {isGlobalPropertyConstant, isFeatureConstant} from './is_constant';
13
+ import {isGlobalPropertyConstantSet, isFeatureConstant} from './is_constant';
14
14
  import Var from './definitions/var';
15
15
 
16
16
  import type {Expression, ExpressionRegistry} from './expression';
@@ -36,9 +36,6 @@ class ParsingContext {
36
36
  // `expectedType`.
37
37
  expectedType: Type | null | undefined;
38
38
 
39
- // `key` is only consulted on the error path, so compute it lazily.
40
- private _key: string | undefined;
41
-
42
39
  constructor(
43
40
  registry: ExpressionRegistry,
44
41
  path: Array<number | string> = [],
@@ -60,16 +57,12 @@ class ParsingContext {
60
57
  }
61
58
 
62
59
  get key(): string {
63
- if (this._key === undefined) {
64
- const path = this.path;
65
- let key = '';
66
- for (let i = 0; i < path.length; i++) {
67
- const part = path[i];
68
- key += typeof part === 'string' ? `['${part}']` : `[${part}]`;
69
- }
70
- this._key = key;
60
+ let key = '';
61
+ for (let i = 0; i < this.path.length; i++) {
62
+ const part = this.path[i];
63
+ key += typeof part === 'string' ? `['${part}']` : `[${part}]`;
71
64
  }
72
- return this._key;
65
+ return key;
73
66
  }
74
67
 
75
68
  /**
@@ -89,7 +82,17 @@ class ParsingContext {
89
82
  } = {},
90
83
  ): Expression | null | void {
91
84
  if (index || expectedType) {
92
- return this.concat(index, null, expectedType, bindings)._parse(expr, options);
85
+ const prevExpectedType = this.expectedType;
86
+ const prevScope = this.scope;
87
+ if (bindings) this.scope = this.scope.concat(bindings);
88
+ this.expectedType = expectedType || null;
89
+ const pushed = typeof index === 'number';
90
+ if (pushed) this.path.push(index);
91
+ const result = this._parse(expr, options);
92
+ if (pushed) this.path.pop();
93
+ this.expectedType = prevExpectedType;
94
+ this.scope = prevScope;
95
+ return result;
93
96
  }
94
97
  return this._parse(expr, options);
95
98
  }
@@ -112,7 +115,18 @@ class ParsingContext {
112
115
  typeAnnotation?: 'assert' | 'coerce' | 'omit';
113
116
  } = {},
114
117
  ): Expression | null | void {
115
- return this.concat(index, key, expectedType, bindings)._parse(expr, options);
118
+ const prevExpectedType = this.expectedType;
119
+ const prevScope = this.scope;
120
+ if (bindings) this.scope = this.scope.concat(bindings);
121
+ this.expectedType = expectedType || null;
122
+ this.path.push(index);
123
+ this.path.push(key);
124
+ const result = this._parse(expr, options);
125
+ this.path.pop();
126
+ this.path.pop();
127
+ this.expectedType = prevExpectedType;
128
+ this.scope = prevScope;
129
+ return result;
116
130
  }
117
131
 
118
132
  _parse(
@@ -125,16 +139,6 @@ class ParsingContext {
125
139
  expr = ['literal', expr];
126
140
  }
127
141
 
128
- function annotate(parsed: Expression, type: Type, typeAnnotation: 'assert' | 'coerce' | 'omit') {
129
- if (typeAnnotation === 'assert') {
130
- return new Assertion(type, [parsed]);
131
- } else if (typeAnnotation === 'coerce') {
132
- return new Coercion(type, [parsed]);
133
- } else {
134
- return parsed;
135
- }
136
- }
137
-
138
142
  if (Array.isArray(expr)) {
139
143
  if (expr.length === 0) {
140
144
  return this.error(`Expected an array with at least one element. If you wanted a literal array, use ["literal", []].`);
@@ -209,9 +213,10 @@ class ParsingContext {
209
213
  expectedType?: Type | null,
210
214
  bindings?: Array<[string, Expression]>,
211
215
  ): ParsingContext {
212
- let path = typeof index === 'number' ? this.path.concat(index) : this.path;
213
- path = typeof key === 'string' ? path.concat(key) : path;
214
216
  const scope = bindings ? this.scope.concat(bindings) : this.scope;
217
+ const path = this.path.slice();
218
+ if (typeof index === 'number') path.push(index);
219
+ if (typeof key === 'string') path.push(key);
215
220
  return new ParsingContext(
216
221
  this.registry,
217
222
  path,
@@ -224,6 +229,25 @@ class ParsingContext {
224
229
  );
225
230
  }
226
231
 
232
+ /**
233
+ * Returns a fresh context that shares the same path position as this one
234
+ * but has an empty errors array. Used by CompoundExpression to probe
235
+ * overload signatures without polluting the parent errors list.
236
+ * @private
237
+ */
238
+ _forkForSignature(): ParsingContext {
239
+ return new ParsingContext(
240
+ this.registry,
241
+ this.path.slice(),
242
+ null,
243
+ this.scope,
244
+ [],
245
+ this._scope,
246
+ this.options,
247
+ this.iconImageUseTheme
248
+ );
249
+ }
250
+
227
251
  /**
228
252
  * Push a parsing (or type checking) error into the `this.errors`
229
253
  * @param error The message
@@ -249,6 +273,22 @@ class ParsingContext {
249
273
 
250
274
  export default ParsingContext;
251
275
 
276
+ const CONSTANT_FOLD_EXCLUDED_GLOBALS = new Set([
277
+ 'zoom', 'heatmap-density', 'worldview', 'line-progress', 'raster-value',
278
+ 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch',
279
+ 'distance-from-center', 'measure-light', 'raster-particle-speed', 'is-active-floor',
280
+ ]);
281
+
282
+ function annotate(parsed: Expression, type: Type, typeAnnotation: 'assert' | 'coerce' | 'omit') {
283
+ if (typeAnnotation === 'assert') {
284
+ return new Assertion(type, [parsed]);
285
+ } else if (typeAnnotation === 'coerce') {
286
+ return new Coercion(type, [parsed]);
287
+ } else {
288
+ return parsed;
289
+ }
290
+ }
291
+
252
292
  function isConstant(expression: Expression) {
253
293
  if (expression instanceof Var) {
254
294
  return isConstant(expression.boundExpression);
@@ -290,5 +330,5 @@ function isConstant(expression: Expression) {
290
330
  }
291
331
 
292
332
  return isFeatureConstant(expression) &&
293
- isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'worldview', 'line-progress', 'raster-value', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center', 'measure-light', 'raster-particle-speed', 'is-active-floor']);
333
+ isGlobalPropertyConstantSet(expression, CONSTANT_FOLD_EXCLUDED_GLOBALS);
294
334
  }
package/function/index.ts CHANGED
@@ -33,7 +33,7 @@ export function createFunction(parameters, propertySpec) {
33
33
 
34
34
  if (isColor) {
35
35
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
36
- parameters = Object.assign({}, parameters);
36
+ parameters = {...parameters};
37
37
 
38
38
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
39
39
  if (parameters.stops) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/mapbox-gl-style-spec",
3
- "version": "14.25.0",
3
+ "version": "14.26.0",
4
4
  "description": "a specification for mapbox gl styles",
5
5
  "author": "Mapbox",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -46,7 +46,6 @@
46
46
  "dependencies": {
47
47
  "@mapbox/point-geometry": "^1.1.0",
48
48
  "@mapbox/unitbezier": "^1.0.0",
49
- "cheap-ruler": "^4.0.0",
50
49
  "csscolorparser": "~1.0.3",
51
50
  "json-stringify-pretty-compact": "^4.0.0",
52
51
  "quickselect": "^3.0.0",
package/reference/v8.json CHANGED
@@ -1335,6 +1335,24 @@
1335
1335
  "units": "degrees",
1336
1336
  "doc": "Override the orientation of the model node in euler angles [x, y, z]."
1337
1337
  }
1338
+ },
1339
+ "modelLightOverrides": {
1340
+ "light-ambient-color": {
1341
+ "type": "color",
1342
+ "doc": "Override the color of ambient lights."
1343
+ },
1344
+ "light-ambient-intensity": {
1345
+ "type": "number",
1346
+ "doc": "Override the intensity of light-ambient-color (on a scale from 0 to 1)."
1347
+ },
1348
+ "light-directional-color": {
1349
+ "type": "color",
1350
+ "doc": "Override the color of directional lights."
1351
+ },
1352
+ "light-directional-intensity": {
1353
+ "type": "number",
1354
+ "doc": "Override the intensity of light-directional-color (on a scale from 0 to 1)."
1355
+ }
1338
1356
  },
1339
1357
  "modelNodeOverrides": {
1340
1358
  "*": {
@@ -1393,6 +1411,11 @@
1393
1411
  "units": "degrees",
1394
1412
  "doc": "Orientation of the model in euler angles [x, y, z]."
1395
1413
  },
1414
+ "lightOverrides": {
1415
+ "type": "modelLightOverrides",
1416
+ "required": false,
1417
+ "doc": "A collection of light overrides."
1418
+ },
1396
1419
  "nodeOverrides": {
1397
1420
  "type": "modelNodeOverrides",
1398
1421
  "required": false,
@@ -6653,13 +6676,6 @@
6653
6676
  "doc": "Projection where objects are of the same scale regardless of whether they are far away or near to the camera. Parallel lines remains parallel and there is no vanishing point."
6654
6677
  }
6655
6678
  },
6656
- "transition": true,
6657
- "expression": {
6658
- "interpolated": true,
6659
- "parameters": [
6660
- "zoom"
6661
- ]
6662
- },
6663
6679
  "sdk-support": {
6664
6680
  "basic functionality": {
6665
6681
  "js": "3.0.0",
package/types.ts CHANGED
@@ -130,6 +130,12 @@ export type ModelsSpecification = {
130
130
  [_: string]: ModelSpecification
131
131
  };
132
132
 
133
+ export type ModelLightOverridesSpecification = {
134
+ "light-ambient-color"?: ColorSpecification,
135
+ "light-ambient-intensity"?: number,
136
+ "light-directional-color"?: ColorSpecification,
137
+ "light-directional-intensity"?: number
138
+ };
133
139
  export type ModelNodeOverrideSpecification = {
134
140
  "orientation"?: [number, number, number]
135
141
  };
@@ -152,6 +158,7 @@ export type ModelSourceModelSpecification = {
152
158
  "uri": string,
153
159
  "position"?: [number, number],
154
160
  "orientation"?: [number, number, number],
161
+ "lightOverrides"?: ModelLightOverridesSpecification,
155
162
  "nodeOverrides"?: ModelNodeOverridesSpecification,
156
163
  "materialOverrides"?: ModelMaterialOverridesSpecification,
157
164
  "nodeOverrideNames"?: Array<string>,
@@ -310,8 +317,7 @@ export type RainSpecification = {
310
317
  };
311
318
 
312
319
  export type CameraSpecification = {
313
- "camera-projection"?: PropertyValueSpecification<"perspective" | "orthographic">,
314
- "camera-projection-transition"?: TransitionSpecification
320
+ "camera-projection"?: "perspective" | "orthographic"
315
321
  };
316
322
 
317
323
  export type ColorThemeSpecification = {
@@ -14,15 +14,15 @@ export type BBox = [number, number, number, number];
14
14
  export function calculateSignedArea(ring: Ring): number {
15
15
  let sum = 0;
16
16
  for (let i = 0, len = ring.length, j = len - 1, p1: Point, p2: Point; i < len; j = i++) {
17
- p1 = ring[i];
18
- p2 = ring[j];
17
+ p1 = ring[i] as Point;
18
+ p2 = ring[j] as Point;
19
19
  sum += (p2.x - p1.x) * (p1.y + p2.y);
20
20
  }
21
21
  return sum;
22
22
  }
23
23
 
24
24
  function compareAreas(a: Ring, b: Ring): number {
25
- return b.area - a.area;
25
+ return (b.area as number) - (a.area as number);
26
26
  }
27
27
 
28
28
  // classifies an array of rings into polygons with outer rings and holes
@@ -32,22 +32,22 @@ export function classifyRings(rings: Array<Ring>, maxRings: number): Array<Array
32
32
  if (len <= 1) return [rings];
33
33
 
34
34
  const polygons: Array<Array<Ring>> = [];
35
- let polygon: Array<Ring>,
36
- ccw: boolean;
35
+ let polygon: Array<Ring> | undefined,
36
+ ccw: boolean | undefined;
37
37
 
38
38
  for (let i = 0; i < len; i++) {
39
- const area = calculateSignedArea(rings[i]);
39
+ const area = calculateSignedArea(rings[i] as Ring);
40
40
  if (area === 0) continue;
41
41
 
42
- rings[i].area = Math.abs(area);
42
+ (rings[i] as Ring).area = Math.abs(area);
43
43
 
44
44
  if (ccw === undefined) ccw = area < 0;
45
45
 
46
46
  if (ccw === area < 0) {
47
47
  if (polygon) polygons.push(polygon);
48
- polygon = [rings[i]];
48
+ polygon = [rings[i] as Ring];
49
49
  } else {
50
- (polygon).push(rings[i]);
50
+ (polygon as Array<Ring>).push(rings[i] as Ring);
51
51
  }
52
52
  }
53
53
  if (polygon) polygons.push(polygon);
@@ -56,9 +56,10 @@ export function classifyRings(rings: Array<Ring>, maxRings: number): Array<Array
56
56
  // reason, we limit strip out all but the `maxRings` largest rings.
57
57
  if (maxRings > 1) {
58
58
  for (let j = 0; j < polygons.length; j++) {
59
- if (polygons[j].length <= maxRings) continue;
60
- quickselect(polygons[j], maxRings, 1, polygons[j].length - 1, compareAreas);
61
- polygons[j] = polygons[j].slice(0, maxRings);
59
+ const currentPolygon = polygons[j] as Array<Ring>;
60
+ if (currentPolygon.length <= maxRings) continue;
61
+ quickselect(currentPolygon, maxRings, 1, currentPolygon.length - 1, compareAreas);
62
+ polygons[j] = currentPolygon.slice(0, maxRings);
62
63
  }
63
64
  }
64
65
 
@@ -66,10 +67,10 @@ export function classifyRings(rings: Array<Ring>, maxRings: number): Array<Array
66
67
  }
67
68
 
68
69
  export function updateBBox(bbox: BBox, coord: GeoJSON.Position) {
69
- bbox[0] = Math.min(bbox[0], coord[0]);
70
- bbox[1] = Math.min(bbox[1], coord[1]);
71
- bbox[2] = Math.max(bbox[2], coord[0]);
72
- bbox[3] = Math.max(bbox[3], coord[1]);
70
+ bbox[0] = Math.min(bbox[0], coord[0] as number);
71
+ bbox[1] = Math.min(bbox[1], coord[1] as number);
72
+ bbox[2] = Math.max(bbox[2], coord[0] as number);
73
+ bbox[3] = Math.max(bbox[3], coord[1] as number);
73
74
  }
74
75
 
75
76
  export function boxWithinBox(bbox1: BBox, bbox2: BBox): boolean {
@@ -81,15 +82,15 @@ export function boxWithinBox(bbox1: BBox, bbox2: BBox): boolean {
81
82
  }
82
83
 
83
84
  function onBoundary(p: GeoJSON.Position, p1: GeoJSON.Position, p2: GeoJSON.Position) {
84
- const x1 = p[0] - p1[0];
85
- const y1 = p[1] - p1[1];
86
- const x2 = p[0] - p2[0];
87
- const y2 = p[1] - p2[1];
85
+ const x1 = (p[0] as number) - (p1[0] as number);
86
+ const y1 = (p[1] as number) - (p1[1] as number);
87
+ const x2 = (p[0] as number) - (p2[0] as number);
88
+ const y2 = (p[1] as number) - (p2[1] as number);
88
89
  return (x1 * y2 - x2 * y1 === 0) && (x1 * x2 <= 0) && (y1 * y2 <= 0);
89
90
  }
90
91
 
91
92
  function rayIntersect(p: GeoJSON.Position, p1: GeoJSON.Position, p2: GeoJSON.Position) {
92
- return ((p1[1] > p[1]) !== (p2[1] > p[1])) && (p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]);
93
+ return (((p1[1] as number) > (p[1] as number)) !== ((p2[1] as number) > (p[1] as number))) && ((p[0] as number) < ((p2[0] as number) - (p1[0] as number)) * ((p[1] as number) - (p1[1] as number)) / ((p2[1] as number) - (p1[1] as number)) + (p1[0] as number));
93
94
  }
94
95
 
95
96
  // ray casting algorithm for detecting if point is in polygon
@@ -100,10 +101,10 @@ export function pointWithinPolygon(
100
101
  ): boolean {
101
102
  let inside = false;
102
103
  for (let i = 0, len = rings.length; i < len; i++) {
103
- const ring = rings[i];
104
+ const ring = rings[i] as Array<GeoJSON.Position>;
104
105
  for (let j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
105
- const q1 = ring[k];
106
- const q2 = ring[j];
106
+ const q1 = ring[k] as GeoJSON.Position;
107
+ const q2 = ring[j] as GeoJSON.Position;
107
108
  if (onBoundary(point, q1, q2)) return trueOnBoundary;
108
109
  if (rayIntersect(point, q1, q2)) inside = !inside;
109
110
  }
@@ -112,18 +113,18 @@ export function pointWithinPolygon(
112
113
  }
113
114
 
114
115
  function perp(v1: GeoJSON.Position, v2: GeoJSON.Position) {
115
- return v1[0] * v2[1] - v1[1] * v2[0];
116
+ return (v1[0] as number) * (v2[1] as number) - (v1[1] as number) * (v2[0] as number);
116
117
  }
117
118
 
118
119
  // check if p1 and p2 are in different sides of line segment q1->q2
119
120
  function twoSided(p1: GeoJSON.Position, p2: GeoJSON.Position, q1: GeoJSON.Position, q2: GeoJSON.Position) {
120
121
  // q1->p1 (x1, y1), q1->p2 (x2, y2), q1->q2 (x3, y3)
121
- const x1 = p1[0] - q1[0];
122
- const y1 = p1[1] - q1[1];
123
- const x2 = p2[0] - q1[0];
124
- const y2 = p2[1] - q1[1];
125
- const x3 = q2[0] - q1[0];
126
- const y3 = q2[1] - q1[1];
122
+ const x1 = (p1[0] as number) - (q1[0] as number);
123
+ const y1 = (p1[1] as number) - (q1[1] as number);
124
+ const x2 = (p2[0] as number) - (q1[0] as number);
125
+ const y2 = (p2[1] as number) - (q1[1] as number);
126
+ const x3 = (q2[0] as number) - (q1[0] as number);
127
+ const y3 = (q2[1] as number) - (q1[1] as number);
127
128
  const det1 = x1 * y3 - x3 * y1;
128
129
  const det2 = x2 * y3 - x3 * y2;
129
130
  if ((det1 > 0 && det2 < 0) || (det1 < 0 && det2 > 0)) return true;
@@ -139,8 +140,8 @@ export function segmentIntersectSegment(
139
140
  // check if two segments are parallel or not
140
141
  // precondition is end point a, b is inside polygon, if line a->b is
141
142
  // parallel to polygon edge c->d, then a->b won't intersect with c->d
142
- const vectorP = [b[0] - a[0], b[1] - a[1]];
143
- const vectorQ = [d[0] - c[0], d[1] - c[1]];
143
+ const vectorP = [(b[0] as number) - (a[0] as number), (b[1] as number) - (a[1] as number)];
144
+ const vectorQ = [(d[0] as number) - (c[0] as number), (d[1] as number) - (c[1] as number)];
144
145
  if (perp(vectorQ, vectorP) === 0) return false;
145
146
 
146
147
  // If lines are intersecting with each other, the relative location should be:
@@ -159,7 +160,7 @@ export function computeBounds(points: Point[][]): Bounds {
159
160
  const min = new Point(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
160
161
  const max = new Point(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
161
162
 
162
- for (const point of points[0]) {
163
+ for (const point of points[0] as Point[]) {
163
164
  if (min.x > point.x) min.x = point.x;
164
165
  if (min.y > point.y) min.y = point.y;
165
166
  if (max.x < point.x) max.x = point.x;
@@ -14,6 +14,6 @@ export function color(from: Color, to: Color, t: number): Color {
14
14
 
15
15
  export function array(from: Array<number>, to: Array<number>, t: number): Array<number> {
16
16
  return from.map((d, i) => {
17
- return number(d, to[i], t);
17
+ return number(d, to[i] as number, t);
18
18
  });
19
19
  }
@@ -117,10 +117,11 @@ export default function validate(options: ValidatorOptions, arrayAsExpression: b
117
117
  return errors;
118
118
  }
119
119
 
120
- const errors = validateObject(Object.assign({}, options, {
120
+ const errors = validateObject({
121
+ ...options,
121
122
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
122
123
  valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec
123
- }));
124
+ });
124
125
 
125
126
  return errors;
126
127
  }
@@ -33,8 +33,8 @@ export default function validateAppearance(options: AppearanceValidatorOptions):
33
33
  style: options.style,
34
34
  styleSpec: options.styleSpec,
35
35
  objectElementValidators: {
36
- condition: (options) => validateCondition(Object.assign({layer, layerType}, options)),
37
- properties: (options) => validateProperties(Object.assign({layer, layerType}, options)),
36
+ condition: (options) => validateCondition({layer, layerType, ...options}),
37
+ properties: (options) => validateProperties({layer, layerType, ...options}),
38
38
  }
39
39
  });
40
40
 
@@ -65,7 +65,8 @@ function validateProperties(options: AppearanceValidatorOptions): Array<Validati
65
65
  continue;
66
66
  }
67
67
 
68
- const propertyValidationOptions = Object.assign({}, options, {
68
+ const propertyValidationOptions = {
69
+ ...options,
69
70
  key: `${options.key}.${propertyKey}`,
70
71
  object: properties,
71
72
  objectKey: propertyKey,
@@ -73,7 +74,7 @@ function validateProperties(options: AppearanceValidatorOptions): Array<Validati
73
74
  layerType,
74
75
  value: properties[propertyKey] as unknown,
75
76
  valueSpec: (propertyType === 'paint' ? paintProperties[propertyKey] : layoutProperties[propertyKey]),
76
- });
77
+ };
77
78
 
78
79
  errors.push(...validateProperty(propertyValidationOptions, propertyType));
79
80
  }
@@ -25,11 +25,12 @@ export default function validateFilter(options: FilterValidatorOptions): Validat
25
25
  // We default to a layerType of `fill` because that points to a non-dynamic filter definition within the style-spec.
26
26
  const layerType = options.layerType || 'fill';
27
27
 
28
- return validateExpression(Object.assign({}, options, {
28
+ return validateExpression({
29
+ ...options,
29
30
  expressionContext: 'filter' as const,
30
31
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
31
32
  valueSpec: options.styleSpec[`filter_${layerType}`]
32
- }));
33
+ });
33
34
  } else {
34
35
  return validateNonExpressionFilter(options);
35
36
  }
@@ -30,11 +30,12 @@ export default function validateImport(options: ImportValidatorOptions): Validat
30
30
  enumerable: false
31
31
  });
32
32
 
33
- let errors = validateObject(Object.assign({}, options, {
33
+ let errors = validateObject({
34
+ ...options,
34
35
  value: importSpec,
35
36
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
36
37
  valueSpec: styleSpec.import
37
- }));
38
+ });
38
39
 
39
40
  // Empty string is reserved for the root style id
40
41
  if (unbundle(importSpec.id) === '') {
@@ -132,7 +132,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
132
132
  });
133
133
  },
134
134
  filter(options) {
135
- return validateFilter(Object.assign({layerType: type}, options));
135
+ return validateFilter({layerType: type, ...options});
136
136
  },
137
137
  layout(options) {
138
138
  return validateObject({
@@ -144,7 +144,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
144
144
  styleSpec: options.styleSpec,
145
145
  objectElementValidators: {
146
146
  '*'(options: PropertyValidatorOptions) {
147
- return validateLayoutProperty(Object.assign({layerType: type}, options));
147
+ return validateLayoutProperty({layerType: type, ...options});
148
148
  }
149
149
  }
150
150
  });
@@ -159,7 +159,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
159
159
  styleSpec: options.styleSpec,
160
160
  objectElementValidators: {
161
161
  '*'(options: PropertyValidatorOptions) {
162
- return validatePaintProperty(Object.assign({layerType: type, layer}, options));
162
+ return validatePaintProperty({layerType: type, layer, ...options});
163
163
  }
164
164
  }
165
165
  });
@@ -172,7 +172,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
172
172
  valueSpec: options.valueSpec,
173
173
  style: options.style,
174
174
  styleSpec: options.styleSpec,
175
- arrayElementValidator: (options) => validateAppearance(Object.assign({layerType: type, layer}, options) as AppearanceValidatorOptions)
175
+ arrayElementValidator: (options) => validateAppearance(({layerType: type, layer, ...(options as object)}) as AppearanceValidatorOptions)
176
176
  });
177
177
  // Check non-repeated names on a given layer
178
178
  const appearances = Array.isArray(options.value) ? options.value : [];
@@ -19,7 +19,8 @@ export default function validateOption(options: ValidatorOptions): ValidationErr
19
19
  const isArrayOption = isObject(optionValue) && unbundle(optionValue.array) === true;
20
20
  const declaredType = !isArrayOption && isObject(optionValue) ? unbundle(optionValue.type) : undefined;
21
21
 
22
- return validateObject(Object.assign({}, options, {
22
+ return validateObject({
23
+ ...options,
23
24
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
24
25
  valueSpec: styleSpec.option,
25
26
  objectElementValidators: declaredType ? {
@@ -28,10 +29,8 @@ export default function validateOption(options: ValidatorOptions): ValidationErr
28
29
  // permissive validation, mirroring the runtime parser's narrowing
29
30
  // in style.ts/parser.cpp.
30
31
  default: (elementOptions: ValidatorOptions): ValidationError[] => (Array.isArray(elementOptions.value) ?
31
- validateSpec(Object.assign({}, elementOptions, {
32
- valueSpec: Object.assign({}, elementOptions.valueSpec, {type: declaredType}),
33
- })) :
32
+ validateSpec({...elementOptions, valueSpec: {...elementOptions.valueSpec, type: declaredType} as typeof elementOptions.valueSpec}) :
34
33
  validateSpec(elementOptions)),
35
34
  } : undefined,
36
- }));
35
+ });
37
36
  }
@@ -14,12 +14,11 @@ export default function validateStyle(style: unknown, styleSpec: StyleReference
14
14
  key: options.key || '',
15
15
  value: style,
16
16
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
17
- valueSpec: Object.assign(
18
- {},
19
- styleSpec.$root,
17
+ valueSpec: {
18
+ ...styleSpec.$root,
20
19
  // Skip validation of the root properties that are not defined in the style spec (e.g. 'owner').
21
- {'*': {type: '*'}},
22
- ),
20
+ '*': {type: '*'},
21
+ },
23
22
  styleSpec,
24
23
  style,
25
24
  objectElementValidators: {