@mapbox/mapbox-gl-style-spec 14.15.0-beta.2 → 14.16.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/deref.ts +3 -0
  2. package/diff.ts +63 -0
  3. package/dist/index.cjs +741 -54
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +205 -40
  6. package/dist/index.es.js +741 -54
  7. package/dist/index.es.js.map +1 -1
  8. package/expression/compound_expression.ts +4 -0
  9. package/expression/definitions/assertion.ts +7 -0
  10. package/expression/definitions/case.ts +2 -1
  11. package/expression/definitions/coalesce.ts +4 -0
  12. package/expression/definitions/coercion.ts +12 -0
  13. package/expression/definitions/collator.ts +8 -5
  14. package/expression/definitions/comparison.ts +12 -5
  15. package/expression/definitions/config.ts +12 -0
  16. package/expression/definitions/distance.ts +13 -2
  17. package/expression/definitions/format.ts +10 -0
  18. package/expression/definitions/image.ts +3 -0
  19. package/expression/definitions/in.ts +5 -0
  20. package/expression/definitions/index.ts +62 -10
  21. package/expression/definitions/index_of.ts +6 -0
  22. package/expression/definitions/interpolate.ts +5 -1
  23. package/expression/definitions/length.ts +2 -0
  24. package/expression/definitions/let.ts +1 -0
  25. package/expression/definitions/match.ts +5 -0
  26. package/expression/definitions/number_format.ts +7 -0
  27. package/expression/definitions/slice.ts +4 -0
  28. package/expression/definitions/within.ts +1 -0
  29. package/expression/index.ts +28 -19
  30. package/expression/parsing_context.ts +2 -0
  31. package/expression/types/image_variant.ts +3 -0
  32. package/expression/types.ts +1 -2
  33. package/expression/values.ts +1 -0
  34. package/feature_filter/convert.ts +9 -1
  35. package/feature_filter/index.ts +41 -1
  36. package/format.ts +5 -0
  37. package/function/convert.ts +5 -0
  38. package/function/index.ts +79 -25
  39. package/group_by_layout.ts +4 -5
  40. package/migrate/v8.ts +42 -3
  41. package/migrate/v9.ts +5 -0
  42. package/migrate.ts +1 -0
  43. package/package.json +1 -1
  44. package/read_style.ts +2 -0
  45. package/reference/v8.json +463 -18
  46. package/rollup.config.js +1 -0
  47. package/style-spec.ts +187 -74
  48. package/test.js +4 -0
  49. package/types.ts +74 -5
  50. package/util/geometry_util.ts +4 -0
  51. package/validate/validate.ts +3 -8
  52. package/validate/validate_appearance.ts +101 -0
  53. package/validate/validate_array.ts +6 -4
  54. package/validate/validate_enum.ts +2 -7
  55. package/validate/validate_expression.ts +48 -3
  56. package/validate/validate_filter.ts +5 -3
  57. package/validate/validate_fog.ts +6 -0
  58. package/validate/validate_function.ts +2 -0
  59. package/validate/validate_iconset.ts +1 -0
  60. package/validate/validate_import.ts +2 -2
  61. package/validate/validate_layer.ts +37 -4
  62. package/validate/validate_light.ts +6 -0
  63. package/validate/validate_lights.ts +9 -0
  64. package/validate/validate_model.ts +1 -2
  65. package/validate/validate_number.ts +4 -4
  66. package/validate/validate_object.ts +7 -0
  67. package/validate/validate_projection.ts +2 -0
  68. package/validate/validate_property.ts +15 -4
  69. package/validate/validate_rain.ts +5 -0
  70. package/validate/validate_snow.ts +5 -0
  71. package/validate/validate_source.ts +13 -3
  72. package/validate/validate_style.ts +1 -0
  73. package/validate/validate_terrain.ts +6 -0
  74. package/validate_mapbox_api_supported.ts +1 -0
  75. package/visit.ts +2 -0
  76. package/util/extend.ts +0 -9
package/style-spec.ts CHANGED
@@ -1,77 +1,3 @@
1
- type ExpressionType = 'data-driven' | 'color-ramp' | 'data-constant' | 'constant';
2
- type ExpressionParameters = Array<'zoom' | 'feature' | 'feature-state' | 'heatmap-density' | 'line-progress' | 'raster-value' | 'sky-radial-progress' | 'pitch' | 'distance-from-center' | 'measure-light' | 'raster-particle-speed'>;
3
-
4
- export type ExpressionSpecification = {
5
- interpolated: boolean,
6
- parameters?: ExpressionParameters,
7
- relaxZoomRestriction?: boolean
8
- };
9
-
10
- export type StylePropertySpecification = {
11
- type: 'number',
12
- 'property-type': ExpressionType,
13
- expression?: ExpressionSpecification,
14
- transition?: boolean,
15
- default?: number,
16
- tokens: never
17
- } | {
18
- type: 'string',
19
- 'property-type': ExpressionType,
20
- expression?: ExpressionSpecification,
21
- transition?: boolean,
22
- default?: string,
23
- tokens?: boolean
24
- } | {
25
- type: 'boolean',
26
- 'property-type': ExpressionType,
27
- expression?: ExpressionSpecification,
28
- transition?: boolean,
29
- overridable?: boolean,
30
- default?: boolean,
31
- tokens?: never
32
- } | {
33
- type: 'enum',
34
- 'property-type': ExpressionType,
35
- expression?: ExpressionSpecification,
36
- values: {[_: string]: unknown},
37
- transition?: boolean,
38
- default?: string,
39
- tokens: never
40
- } | {
41
- type: 'color',
42
- 'property-type': ExpressionType,
43
- expression?: ExpressionSpecification,
44
- transition?: boolean,
45
- default?: string,
46
- tokens: never,
47
- overridable: boolean
48
- } | {
49
- type: 'array',
50
- value: 'number',
51
- 'property-type': ExpressionType,
52
- expression?: ExpressionSpecification,
53
- length?: number,
54
- transition?: boolean,
55
- default?: Array<number>,
56
- tokens: never
57
- } | {
58
- type: 'array',
59
- value: 'string',
60
- 'property-type': ExpressionType,
61
- expression?: ExpressionSpecification,
62
- length?: number,
63
- transition?: boolean,
64
- default?: Array<string>,
65
- tokens: never
66
- } | {
67
- type: 'resolvedImage',
68
- 'property-type': ExpressionType,
69
- expression?: ExpressionSpecification,
70
- transition?: boolean,
71
- default?: string,
72
- tokens: never
73
- };
74
-
75
1
  import v8 from './reference/v8.json';
76
2
  import latest from './reference/latest';
77
3
  import format from './format';
@@ -91,6 +17,193 @@ import {eachSource, eachLayer, eachProperty} from './visit';
91
17
  import validate from './validate_style';
92
18
  import validateMapboxApiSupported from './validate_mapbox_api_supported';
93
19
 
20
+ type ExpressionType = 'data-driven' | 'color-ramp' | 'data-constant' | 'constant';
21
+
22
+ type ExpressionParameter =
23
+ | 'zoom'
24
+ | 'pitch'
25
+ | 'feature'
26
+ | 'raster-value'
27
+ | 'feature-state'
28
+ | 'line-progress'
29
+ | 'measure-light'
30
+ | 'heatmap-density'
31
+ | 'sky-radial-progress'
32
+ | 'distance-from-center'
33
+ | 'raster-particle-speed';
34
+
35
+ export type ExpressionSpecification = {
36
+ interpolated: boolean,
37
+ parameters?: ExpressionParameter[],
38
+ relaxZoomRestriction?: boolean
39
+ };
40
+
41
+ export type ArrayPropertySpecification =
42
+ {
43
+ type: 'array';
44
+ 'property-type': ExpressionType;
45
+ value: 'enum';
46
+ expression?: ExpressionSpecification,
47
+ transition?: boolean,
48
+ default?: string[],
49
+ length?: number,
50
+ values?: {[_: string]: unknown},
51
+ experimental?: boolean,
52
+ private?: boolean,
53
+ requires?: unknown,
54
+ appearance?: boolean,
55
+ tokens?: never,
56
+ minimum?: never,
57
+ maximum?: never,
58
+ } | {
59
+ type: 'array';
60
+ 'property-type': ExpressionType;
61
+ value: 'number';
62
+ expression?: ExpressionSpecification;
63
+ transition?: boolean;
64
+ default?: number[];
65
+ minimum?: number;
66
+ maximum?: number;
67
+ length?: number;
68
+ period?: number;
69
+ units?: string;
70
+ experimental?: boolean;
71
+ private?: boolean;
72
+ requires?: unknown;
73
+ appearance?: boolean;
74
+ tokens?: never;
75
+ values?: never;
76
+ } | {
77
+ type: 'array';
78
+ 'property-type': ExpressionType;
79
+ value: 'string';
80
+ expression?: ExpressionSpecification;
81
+ transition?: boolean;
82
+ default?: string[];
83
+ length?: number;
84
+ experimental?: boolean;
85
+ private?: boolean;
86
+ requires?: unknown;
87
+ appearance?: boolean;
88
+ tokens?: never;
89
+ minimum?: never;
90
+ maximum?: never;
91
+ values?: never;
92
+ };
93
+
94
+ export type BooleanPropertySpecification = {
95
+ type: 'boolean';
96
+ 'property-type': ExpressionType;
97
+ expression?: ExpressionSpecification;
98
+ transition?: boolean;
99
+ default?: boolean;
100
+ overridable?: boolean;
101
+ experimental?: boolean;
102
+ private?: boolean;
103
+ requires?: unknown;
104
+ appearance?: boolean;
105
+ tokens?: never;
106
+ };
107
+
108
+ export type ColorPropertySpecification = {
109
+ type: 'color';
110
+ 'property-type': ExpressionType;
111
+ expression?: ExpressionSpecification;
112
+ transition?: boolean;
113
+ default?: string;
114
+ 'use-theme'?: boolean;
115
+ overridable?: boolean;
116
+ experimental?: boolean;
117
+ private?: boolean;
118
+ requires?: unknown;
119
+ appearance?: boolean;
120
+ tokens?: never;
121
+ };
122
+
123
+ export type EnumPropertySpecification = {
124
+ type: 'enum';
125
+ 'property-type': ExpressionType;
126
+ expression?: ExpressionSpecification;
127
+ transition?: boolean;
128
+ default?: string;
129
+ values?: {[_: string]: unknown};
130
+ experimental?: boolean;
131
+ private?: boolean;
132
+ requires?: unknown;
133
+ appearance?: boolean;
134
+ tokens?: never;
135
+ };
136
+
137
+ export type FormattedPropertySpecification = {
138
+ type: 'formatted';
139
+ 'property-type': ExpressionType;
140
+ expression?: ExpressionSpecification;
141
+ transition?: boolean;
142
+ default?: string;
143
+ tokens?: boolean;
144
+ experimental?: boolean;
145
+ private?: boolean;
146
+ requires?: unknown;
147
+ appearance?: boolean;
148
+ };
149
+
150
+ export type NumberPropertySpecification = {
151
+ type: 'number';
152
+ 'property-type': ExpressionType;
153
+ expression?: ExpressionSpecification;
154
+ transition?: boolean;
155
+ default?: number;
156
+ minimum?: number;
157
+ maximum?: number;
158
+ period?: number;
159
+ units?: string;
160
+ experimental?: boolean;
161
+ private?: boolean;
162
+ requires?: unknown;
163
+ appearance?: boolean;
164
+ tokens?: never;
165
+ };
166
+
167
+ export type ResolvedImagePropertySpecification = {
168
+ type: 'resolvedImage';
169
+ 'property-type': ExpressionType;
170
+ expression?: ExpressionSpecification;
171
+ transition?: boolean;
172
+ default?: string;
173
+ tokens?: boolean;
174
+ 'use-theme'?: boolean;
175
+ experimental?: boolean;
176
+ private?: boolean;
177
+ requires?: unknown;
178
+ appearance?: boolean;
179
+ };
180
+
181
+ export type StringPropertySpecification = {
182
+ type: 'string';
183
+ 'property-type': ExpressionType;
184
+ expression?: ExpressionSpecification;
185
+ transition?: boolean;
186
+ default?: string;
187
+ tokens?: boolean;
188
+ experimental?: boolean;
189
+ private?: boolean;
190
+ requires?: unknown;
191
+ appearance?: boolean;
192
+ };
193
+
194
+ /**
195
+ * A style property specification is used to describe a value of some style property reference in the v8.json
196
+ */
197
+ export type StylePropertySpecification =
198
+ | ArrayPropertySpecification
199
+ | BooleanPropertySpecification
200
+ | ColorPropertySpecification
201
+ | EnumPropertySpecification
202
+ | FormattedPropertySpecification
203
+ | NumberPropertySpecification
204
+ | ResolvedImagePropertySpecification
205
+ | StringPropertySpecification;
206
+
94
207
  const expression = {
95
208
  StyleExpression,
96
209
  isExpression,
package/test.js CHANGED
@@ -4,6 +4,7 @@ import fs from 'fs';
4
4
  import {execSync} from 'child_process';
5
5
  import {createRequire} from 'module';
6
6
 
7
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
7
8
  const packageJson = JSON.parse(fs.readFileSync('./package.json').toString());
8
9
 
9
10
  process.on('unhandledRejection', (/** @type {Error} */ error) => {
@@ -17,7 +18,9 @@ const require = createRequire(import.meta.url);
17
18
  const stylePath = require.resolve('mapbox-gl-styles/styles/basic-v9.json');
18
19
 
19
20
  try {
21
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
20
22
  for (const bin in packageJson.bin) {
23
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
21
24
  const script = packageJson.bin[bin];
22
25
  const command = [script, stylePath].join(' ');
23
26
 
@@ -25,6 +28,7 @@ try {
25
28
  execSync(command).toString();
26
29
  }
27
30
  } catch (error) {
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
28
32
  console.log(error.message);
29
33
  process.exit(1);
30
34
  }
package/types.ts CHANGED
@@ -130,6 +130,35 @@ export type ModelsSpecification = {
130
130
  [_: string]: ModelSpecification
131
131
  };
132
132
 
133
+ export type ModelNodeOverrideSpecification = {
134
+ "orientation"?: [number, number, number]
135
+ };
136
+ export type ModelNodeOverridesSpecification = {
137
+ [_: string]: ModelNodeOverrideSpecification
138
+ };
139
+ export type ModelMaterialOverrideSpecification = {
140
+ "model-color"?: ColorSpecification,
141
+ "model-color-mix-intensity"?: number,
142
+ "model-opacity"?: number,
143
+ "model-emissive-strength"?: number
144
+ };
145
+ export type ModelMaterialOverridesSpecification = {
146
+ [_: string]: ModelMaterialOverrideSpecification
147
+ };
148
+ export type ModelSourceModelsSpecification = {
149
+ [_: string]: ModelSourceModelSpecification
150
+ };
151
+ export type ModelSourceModelSpecification = {
152
+ "uri": string,
153
+ "position"?: [number, number],
154
+ "orientation"?: [number, number, number],
155
+ "nodeOverrides"?: ModelNodeOverridesSpecification,
156
+ "materialOverrides"?: ModelMaterialOverridesSpecification,
157
+ "nodeOverrideNames"?: Array<string>,
158
+ "materialOverrideNames"?: Array<string>,
159
+ "featureProperties"?: unknown
160
+ };
161
+
133
162
  export type IconsetsSpecification = {
134
163
  [_: string]: IconsetSpecification
135
164
  };
@@ -383,7 +412,7 @@ export type SelectorPropertySpecification = {
383
412
  };
384
413
 
385
414
  export type AppearanceSpecification = {
386
- "condition"?: ExpressionSpecification,
415
+ "condition"?: DataDrivenPropertyValueSpecification<boolean>,
387
416
  "name"?: string,
388
417
  "properties"?: unknown
389
418
  };
@@ -499,7 +528,8 @@ export type ModelSourceSpecification = {
499
528
  "type": "model" | "batched-model",
500
529
  "maxzoom"?: number,
501
530
  "minzoom"?: number,
502
- "tiles"?: Array<string>
531
+ "tiles"?: Array<string>,
532
+ "models"?: ModelSourceModelsSpecification
503
533
  };
504
534
 
505
535
  export type SourceSpecification =
@@ -1099,6 +1129,10 @@ export type BuildingLayerSpecification = {
1099
1129
  * @experimental This property is experimental and subject to change in future versions.
1100
1130
  */
1101
1131
  "building-facade-floors"?: DataDrivenPropertyValueSpecification<number>,
1132
+ /**
1133
+ * @experimental This property is experimental and subject to change in future versions.
1134
+ */
1135
+ "building-facade-unit-width"?: DataDrivenPropertyValueSpecification<number>,
1102
1136
  /**
1103
1137
  * @experimental This property is experimental and subject to change in future versions.
1104
1138
  */
@@ -1116,7 +1150,22 @@ export type BuildingLayerSpecification = {
1116
1150
  * @experimental This property is experimental and subject to change in future versions.
1117
1151
  */
1118
1152
  "building-base"?: DataDrivenPropertyValueSpecification<number>,
1119
- "building-base-transition"?: TransitionSpecification
1153
+ "building-base-transition"?: TransitionSpecification,
1154
+ /**
1155
+ * @experimental This property is experimental and subject to change in future versions.
1156
+ */
1157
+ "building-flood-light-wall-radius"?: DataDrivenPropertyValueSpecification<number>,
1158
+ "building-flood-light-wall-radius-transition"?: TransitionSpecification,
1159
+ /**
1160
+ * @experimental This property is experimental and subject to change in future versions.
1161
+ */
1162
+ "building-flood-light-ground-radius"?: DataDrivenPropertyValueSpecification<number>,
1163
+ "building-flood-light-ground-radius-transition"?: TransitionSpecification,
1164
+ /**
1165
+ * @experimental This property is experimental and subject to change in future versions.
1166
+ */
1167
+ "building-flip-roof-orientation"?: DataDrivenPropertyValueSpecification<boolean>,
1168
+ "building-flip-roof-orientation-transition"?: TransitionSpecification
1120
1169
  },
1121
1170
  "paint"?: {
1122
1171
  /**
@@ -1166,7 +1215,23 @@ export type BuildingLayerSpecification = {
1166
1215
  * @experimental This property is experimental and subject to change in future versions.
1167
1216
  */
1168
1217
  "building-facade-emissive-chance"?: PropertyValueSpecification<number>,
1169
- "building-cutoff-fade-range"?: ExpressionSpecification
1218
+ "building-cutoff-fade-range"?: ExpressionSpecification,
1219
+ /**
1220
+ * @experimental This property is experimental and subject to change in future versions.
1221
+ */
1222
+ "building-flood-light-color"?: PropertyValueSpecification<ColorSpecification>,
1223
+ "building-flood-light-color-transition"?: TransitionSpecification,
1224
+ "building-flood-light-color-use-theme"?: PropertyValueSpecification<string>,
1225
+ /**
1226
+ * @experimental This property is experimental and subject to change in future versions.
1227
+ */
1228
+ "building-flood-light-intensity"?: PropertyValueSpecification<number>,
1229
+ "building-flood-light-intensity-transition"?: TransitionSpecification,
1230
+ /**
1231
+ * @experimental This property is experimental and subject to change in future versions.
1232
+ */
1233
+ "building-flood-light-ground-attenuation"?: PropertyValueSpecification<number>,
1234
+ "building-flood-light-ground-attenuation-transition"?: TransitionSpecification
1170
1235
  },
1171
1236
  "appearances"?: Array<AppearanceSpecification>
1172
1237
  };
@@ -1363,7 +1428,11 @@ export type ModelLayerSpecification = {
1363
1428
  "model-height-based-emissive-strength-multiplier"?: DataDrivenPropertyValueSpecification<[number, number, number, number, number]>,
1364
1429
  "model-height-based-emissive-strength-multiplier-transition"?: TransitionSpecification,
1365
1430
  "model-cutoff-fade-range"?: ExpressionSpecification,
1366
- "model-front-cutoff"?: PropertyValueSpecification<[number, number, number]>
1431
+ "model-front-cutoff"?: PropertyValueSpecification<[number, number, number]>,
1432
+ /**
1433
+ * @experimental This property is experimental and subject to change in future versions.
1434
+ */
1435
+ "model-elevation-reference"?: "sea" | "ground" | "hd-road-markup" | ExpressionSpecification
1367
1436
  },
1368
1437
  "appearances"?: Array<AppearanceSpecification>
1369
1438
  };
@@ -16,6 +16,7 @@ function calculateSignedArea(ring: Ring): number {
16
16
  for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
17
17
  p1 = ring[i];
18
18
  p2 = ring[j];
19
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
19
20
  sum += (p2.x - p1.x) * (p1.y + p2.y);
20
21
  }
21
22
  return sum;
@@ -44,13 +45,16 @@ export function classifyRings(rings: Array<Ring>, maxRings: number): Array<Array
44
45
  if (ccw === undefined) ccw = area < 0;
45
46
 
46
47
  if (ccw === area < 0) {
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
47
49
  if (polygon) polygons.push(polygon);
48
50
  polygon = [rings[i]];
49
51
 
50
52
  } else {
53
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
51
54
  (polygon).push(rings[i]);
52
55
  }
53
56
  }
57
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
54
58
  if (polygon) polygons.push(polygon);
55
59
 
56
60
  // Earcut performance degrades with the # of rings in a polygon. For this
@@ -28,6 +28,7 @@ import type ValidationError from '../error/validation_error';
28
28
  import type {StyleReference} from '../reference/latest';
29
29
  import type {StyleSpecification} from '../types';
30
30
  import type {FunctionValidatorOptions} from './validate_function';
31
+ import type {StylePropertySpecification} from '../style-spec';
31
32
  import type {ExpressionValidatorOptions} from './validate_expression';
32
33
 
33
34
  const VALIDATORS: Record<string, (...args: unknown[]) => ValidationError[]> = {
@@ -72,14 +73,7 @@ export type ValidatorOptions = {
72
73
  /**
73
74
  * Current spec being evaluated. Tracks value.
74
75
  */
75
- valueSpec?: {
76
- type?: string;
77
- expression?: {
78
- interpolated?: boolean;
79
- parameters?: Array<'zoom' | 'feature'>;
80
- };
81
- 'property-type'?: 'data-driven';
82
- };
76
+ valueSpec?: Partial<StylePropertySpecification>;
83
77
 
84
78
  /**
85
79
  * Current full spec being evaluated.
@@ -122,6 +116,7 @@ export default function validate(options: ValidatorOptions, arrayAsExpression: b
122
116
  }
123
117
 
124
118
  const errors = validateObject(Object.assign({}, options, {
119
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
125
120
  valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec
126
121
  }));
127
122
 
@@ -0,0 +1,101 @@
1
+ import validateObject from './validate_object';
2
+ import ValidationError from '../error/validation_error';
3
+ import validateProperty from './validate_property';
4
+ import {unbundle} from '../util/unbundle_jsonlint';
5
+ import validateExpression from './validate_expression';
6
+ import latest from '../reference/latest';
7
+
8
+ import type {StyleSpecification, LayerSpecification, AppearanceSpecification} from '../types';
9
+ import type {StyleReference} from '../reference/latest';
10
+
11
+ export type AppearanceValidatorOptions = {
12
+ key: string;
13
+ value: unknown;
14
+ style: Partial<StyleSpecification>;
15
+ styleSpec: StyleReference;
16
+ object?: object;
17
+ objectKey?: string;
18
+ layer: LayerSpecification;
19
+ layerType: string;
20
+ };
21
+
22
+ export default function validateAppearance(options: AppearanceValidatorOptions): Array<ValidationError> {
23
+ const {key, layer, layerType} = options;
24
+ const value = unbundle(options.value) as AppearanceSpecification;
25
+ const name = unbundle(value.name);
26
+ const condition = unbundle(value.condition);
27
+
28
+ const errors = validateObject({
29
+ key,
30
+ value,
31
+ valueSpec: options.styleSpec.appearance as object,
32
+ style: options.style,
33
+ styleSpec: options.styleSpec,
34
+ objectElementValidators: {
35
+ condition: (options) => validateCondition(Object.assign({layer, layerType}, options)),
36
+ properties: (options) => validateProperties(Object.assign({layer, layerType}, options)),
37
+ }
38
+ });
39
+
40
+ if (name !== 'hidden' && !condition) {
41
+ errors.push(new ValidationError(options.key, 'name', `Appearance with name different than "hidden" must have a condition`));
42
+ }
43
+
44
+ return errors;
45
+ }
46
+
47
+ function validateProperties(options: AppearanceValidatorOptions): Array<ValidationError> {
48
+ const errors: Array<ValidationError> = [];
49
+
50
+ const {styleSpec, layer, layerType} = options;
51
+
52
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
53
+ const paintProperties = styleSpec[`paint_${layerType}`];
54
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
55
+ const layoutProperties = styleSpec[`layout_${layerType}`];
56
+ const properties = options.object[options.objectKey] as object;
57
+
58
+ for (const propertyKey in properties) {
59
+ const propertyType =
60
+ propertyKey in paintProperties ? 'paint' :
61
+ propertyKey in layoutProperties ? 'layout' :
62
+ undefined;
63
+
64
+ if (!propertyType) {
65
+ errors.push(new ValidationError(options.key, propertyKey, `unknown property "${propertyKey}" for layer type "${layerType}"`));
66
+ continue;
67
+ }
68
+
69
+ const propertyValidationOptions = Object.assign({}, options, {
70
+ key: `${options.key}.${propertyKey}`,
71
+ object: properties,
72
+ objectKey: propertyKey,
73
+ layer,
74
+ layerType,
75
+ value: properties[propertyKey] as unknown,
76
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
77
+ valueSpec: (propertyType === 'paint' ? paintProperties[propertyKey] : layoutProperties[propertyKey]) as object,
78
+ });
79
+
80
+ errors.push(...validateProperty(propertyValidationOptions, propertyType));
81
+ }
82
+
83
+ return errors;
84
+ }
85
+
86
+ function validateCondition(options: AppearanceValidatorOptions): Array<ValidationError> {
87
+ const errors: Array<ValidationError> = [];
88
+
89
+ const appearance = options.object as AppearanceSpecification;
90
+ const condition = appearance.condition;
91
+
92
+ errors.push(...validateExpression({
93
+ key: options.key,
94
+ value: condition,
95
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
96
+ valueSpec: latest['appearance']['condition'],
97
+ expressionContext: 'appearance'
98
+ }));
99
+
100
+ return errors;
101
+ }
@@ -4,10 +4,11 @@ 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';
7
8
 
8
9
  type ArraySpec = {
9
10
  value?: unknown;
10
- values?: unknown[];
11
+ values?: unknown[] | {[_: string]: unknown};
11
12
  length?: number;
12
13
  minimum?: number;
13
14
  maximum?: number;
@@ -16,7 +17,7 @@ type ArraySpec = {
16
17
 
17
18
  type ArrayElementSpec<T = unknown> = {
18
19
  type: string;
19
- values: T[];
20
+ values: T[] | {[_: string]: unknown};
20
21
  minimum: number;
21
22
  maximum: number;
22
23
  function: unknown;
@@ -25,7 +26,7 @@ type ArrayElementSpec<T = unknown> = {
25
26
  type ArrayValidatorOptions<T = unknown> = {
26
27
  key: string;
27
28
  value: T;
28
- valueSpec: ArraySpec;
29
+ valueSpec: ArrayPropertySpecification | ArraySpec;
29
30
  style: Partial<StyleSpecification>;
30
31
  styleSpec: StyleReference;
31
32
  arrayElementValidator: (...args: unknown[]) => ValidationError[];
@@ -60,7 +61,7 @@ export default function validateArray(options: ArrayValidatorOptions): Validatio
60
61
  };
61
62
 
62
63
  if (styleSpec.$version < 7) {
63
- arrayElementSpec.function = arraySpec.function;
64
+ arrayElementSpec.function = (arraySpec as ArraySpec).function;
64
65
  }
65
66
 
66
67
  if (isObject(arraySpec.value)) {
@@ -72,6 +73,7 @@ export default function validateArray(options: ArrayValidatorOptions): Validatio
72
73
  errors = errors.concat(validateArrayElement({
73
74
  array,
74
75
  arrayIndex: i,
76
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
75
77
  value: array[i],
76
78
  valueSpec: arrayElementSpec,
77
79
  style,
@@ -1,17 +1,12 @@
1
1
  import ValidationError from '../error/validation_error';
2
2
  import {unbundle} from '../util/unbundle_jsonlint';
3
3
 
4
- import type {StyleReference} from '../reference/latest';
5
- import type {StyleSpecification} from '../types';
4
+ import type {EnumPropertySpecification} from '../style-spec';
6
5
 
7
6
  type EnumValidatorOptions = {
8
7
  key: string;
9
8
  value: unknown;
10
- valueSpec?: {
11
- values: unknown[];
12
- };
13
- style?: Partial<StyleSpecification>;
14
- styleSpec?: StyleReference;
9
+ valueSpec: EnumPropertySpecification | {values: unknown[] | {[_: string]: unknown}};
15
10
  };
16
11
 
17
12
  export default function validateEnum(options: EnumValidatorOptions): ValidationError[] {