@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.
- package/deref.ts +3 -0
- package/diff.ts +63 -0
- package/dist/index.cjs +741 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +205 -40
- package/dist/index.es.js +741 -54
- package/dist/index.es.js.map +1 -1
- package/expression/compound_expression.ts +4 -0
- package/expression/definitions/assertion.ts +7 -0
- package/expression/definitions/case.ts +2 -1
- package/expression/definitions/coalesce.ts +4 -0
- package/expression/definitions/coercion.ts +12 -0
- package/expression/definitions/collator.ts +8 -5
- package/expression/definitions/comparison.ts +12 -5
- package/expression/definitions/config.ts +12 -0
- package/expression/definitions/distance.ts +13 -2
- package/expression/definitions/format.ts +10 -0
- package/expression/definitions/image.ts +3 -0
- package/expression/definitions/in.ts +5 -0
- package/expression/definitions/index.ts +62 -10
- package/expression/definitions/index_of.ts +6 -0
- package/expression/definitions/interpolate.ts +5 -1
- package/expression/definitions/length.ts +2 -0
- package/expression/definitions/let.ts +1 -0
- package/expression/definitions/match.ts +5 -0
- package/expression/definitions/number_format.ts +7 -0
- package/expression/definitions/slice.ts +4 -0
- package/expression/definitions/within.ts +1 -0
- package/expression/index.ts +28 -19
- package/expression/parsing_context.ts +2 -0
- package/expression/types/image_variant.ts +3 -0
- package/expression/types.ts +1 -2
- package/expression/values.ts +1 -0
- package/feature_filter/convert.ts +9 -1
- package/feature_filter/index.ts +41 -1
- package/format.ts +5 -0
- package/function/convert.ts +5 -0
- package/function/index.ts +79 -25
- package/group_by_layout.ts +4 -5
- package/migrate/v8.ts +42 -3
- package/migrate/v9.ts +5 -0
- package/migrate.ts +1 -0
- package/package.json +1 -1
- package/read_style.ts +2 -0
- package/reference/v8.json +463 -18
- package/rollup.config.js +1 -0
- package/style-spec.ts +187 -74
- package/test.js +4 -0
- package/types.ts +74 -5
- package/util/geometry_util.ts +4 -0
- package/validate/validate.ts +3 -8
- package/validate/validate_appearance.ts +101 -0
- package/validate/validate_array.ts +6 -4
- package/validate/validate_enum.ts +2 -7
- package/validate/validate_expression.ts +48 -3
- package/validate/validate_filter.ts +5 -3
- package/validate/validate_fog.ts +6 -0
- package/validate/validate_function.ts +2 -0
- package/validate/validate_iconset.ts +1 -0
- package/validate/validate_import.ts +2 -2
- package/validate/validate_layer.ts +37 -4
- package/validate/validate_light.ts +6 -0
- package/validate/validate_lights.ts +9 -0
- package/validate/validate_model.ts +1 -2
- package/validate/validate_number.ts +4 -4
- package/validate/validate_object.ts +7 -0
- package/validate/validate_projection.ts +2 -0
- package/validate/validate_property.ts +15 -4
- package/validate/validate_rain.ts +5 -0
- package/validate/validate_snow.ts +5 -0
- package/validate/validate_source.ts +13 -3
- package/validate/validate_style.ts +1 -0
- package/validate/validate_terrain.ts +6 -0
- package/validate_mapbox_api_supported.ts +1 -0
- package/visit.ts +2 -0
- package/util/extend.ts +0 -9
|
@@ -4,10 +4,10 @@ import {deepUnbundle} from '../util/unbundle_jsonlint';
|
|
|
4
4
|
import {isStateConstant, isGlobalPropertyConstant, isFeatureConstant} from '../expression/is_constant';
|
|
5
5
|
import CompoundExpression from '../expression/compound_expression';
|
|
6
6
|
|
|
7
|
+
import type {StylePropertySpecification} from '../../style-spec/style-spec';
|
|
7
8
|
import type {Expression} from '../expression/expression';
|
|
8
9
|
import type {StyleReference} from '../reference/latest';
|
|
9
10
|
import type {StyleSpecification} from '../types';
|
|
10
|
-
import type {StylePropertySpecification} from '../style-spec';
|
|
11
11
|
|
|
12
12
|
export type ExpressionValidatorOptions = {
|
|
13
13
|
key: string;
|
|
@@ -17,7 +17,7 @@ export type ExpressionValidatorOptions = {
|
|
|
17
17
|
propertyType?: 'layout' | 'paint' | 'filter';
|
|
18
18
|
style?: Partial<StyleSpecification>;
|
|
19
19
|
styleSpec?: StyleReference;
|
|
20
|
-
expressionContext?: 'property' | 'filter' | 'cluster-initial' | 'cluster-reduce' | 'cluster-map';
|
|
20
|
+
expressionContext?: 'property' | 'filter' | 'cluster-initial' | 'cluster-reduce' | 'cluster-map' | 'appearance';
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export default function validateExpression(options: ExpressionValidatorOptions): ValidationError[] {
|
|
@@ -28,27 +28,37 @@ export default function validateExpression(options: ExpressionValidatorOptions):
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
32
32
|
const expressionObj = (expression.value as any).expression || (expression.value as any)._styleExpression.expression;
|
|
33
33
|
|
|
34
34
|
if (options.expressionContext === 'property' && (options.propertyKey === 'text-font') &&
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
35
36
|
!expressionObj.outputDefined()) {
|
|
36
37
|
return [new ValidationError(options.key, options.value, `Invalid data expression for "${options.propertyKey}". Output values must be contained as literals within the expression.`)];
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
if (options.expressionContext === 'property' && options.propertyType === 'layout' &&
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
40
42
|
(!isStateConstant(expressionObj))) {
|
|
41
43
|
return [new ValidationError(options.key, options.value, '"feature-state" data expressions are not supported with layout properties.')];
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
if (options.expressionContext === 'filter') {
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
45
48
|
return disallowedFilterParameters(expressionObj, options);
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
if (options.expressionContext === 'appearance') {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
53
|
+
return checkDisallowedParameters(expressionObj, options);
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
if (options.expressionContext && options.expressionContext.indexOf('cluster') === 0) {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
49
58
|
if (!isGlobalPropertyConstant(expressionObj, ['zoom', 'feature-state'])) {
|
|
50
59
|
return [new ValidationError(options.key, options.value, '"zoom" and "feature-state" expressions are not supported with cluster properties.')];
|
|
51
60
|
}
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
52
62
|
if (options.expressionContext === 'cluster-initial' && !isFeatureConstant(expressionObj)) {
|
|
53
63
|
return [new ValidationError(options.key, options.value, 'Feature data expressions are not supported with initial expression part of cluster properties.')];
|
|
54
64
|
}
|
|
@@ -66,8 +76,11 @@ export function disallowedFilterParameters(e: Expression, options: any): Validat
|
|
|
66
76
|
'distance-from-center'
|
|
67
77
|
]);
|
|
68
78
|
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
69
80
|
if (options.valueSpec && options.valueSpec.expression) {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
70
82
|
for (const param of options.valueSpec.expression.parameters) {
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
71
84
|
disallowedParameters.delete(param);
|
|
72
85
|
}
|
|
73
86
|
}
|
|
@@ -79,6 +92,7 @@ export function disallowedFilterParameters(e: Expression, options: any): Validat
|
|
|
79
92
|
|
|
80
93
|
if (e instanceof CompoundExpression) {
|
|
81
94
|
if (disallowedParameters.has(e.name)) {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
82
96
|
return [new ValidationError(options.key, options.value, `["${e.name}"] expression is not supported in a filter for a ${options.object.type} layer with id: ${options.object.id}`)];
|
|
83
97
|
}
|
|
84
98
|
}
|
|
@@ -88,3 +102,34 @@ export function disallowedFilterParameters(e: Expression, options: any): Validat
|
|
|
88
102
|
|
|
89
103
|
return errors;
|
|
90
104
|
}
|
|
105
|
+
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
+
function checkDisallowedParameters(e: Expression, options: any): ValidationError[] {
|
|
108
|
+
const allowedParameters = new Set<string>();
|
|
109
|
+
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
111
|
+
if (options.valueSpec && options.valueSpec.expression) {
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
113
|
+
for (const param of options.valueSpec.expression.parameters) {
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
115
|
+
allowedParameters.add(param);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (allowedParameters.size === 0) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const errors: ValidationError[] = [];
|
|
123
|
+
|
|
124
|
+
if (e instanceof CompoundExpression) {
|
|
125
|
+
if (!allowedParameters.has(e.name)) {
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
127
|
+
return [new ValidationError(options.key, options.value, `["${e.name}"] is not an allowed parameter`)];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
e.eachChild((arg) => {
|
|
131
|
+
errors.push(...checkDisallowedParameters(arg, options));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return errors;
|
|
135
|
+
}
|
|
@@ -3,7 +3,6 @@ import validateExpression from './validate_expression';
|
|
|
3
3
|
import validateEnum from './validate_enum';
|
|
4
4
|
import {getType, isString, isNumber, isBoolean} from '../util/get_type';
|
|
5
5
|
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint';
|
|
6
|
-
import extend from '../util/extend';
|
|
7
6
|
import {isExpressionFilter} from '../feature_filter/index';
|
|
8
7
|
|
|
9
8
|
import type {StyleReference} from '../reference/latest';
|
|
@@ -26,8 +25,9 @@ export default function validateFilter(options: FilterValidatorOptions): Validat
|
|
|
26
25
|
// We default to a layerType of `fill` because that points to a non-dynamic filter definition within the style-spec.
|
|
27
26
|
const layerType = options.layerType || 'fill';
|
|
28
27
|
|
|
29
|
-
return validateExpression(
|
|
30
|
-
expressionContext: 'filter',
|
|
28
|
+
return validateExpression(Object.assign({}, options, {
|
|
29
|
+
expressionContext: 'filter' as const,
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
31
31
|
valueSpec: options.styleSpec[`filter_${layerType}`]
|
|
32
32
|
}));
|
|
33
33
|
} else {
|
|
@@ -51,6 +51,7 @@ function validateNonExpressionFilter(options: FilterValidatorOptions): Validatio
|
|
|
51
51
|
let errors: ValidationError[] = validateEnum({
|
|
52
52
|
key: `${key}[0]`,
|
|
53
53
|
value: value[0],
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
54
55
|
valueSpec: styleSpec.filter_operator
|
|
55
56
|
});
|
|
56
57
|
|
|
@@ -83,6 +84,7 @@ function validateNonExpressionFilter(options: FilterValidatorOptions): Validatio
|
|
|
83
84
|
errors = errors.concat(validateEnum({
|
|
84
85
|
key: `${key}[${i}]`,
|
|
85
86
|
value: value[i],
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
86
88
|
valueSpec: styleSpec.geometry_type
|
|
87
89
|
}));
|
|
88
90
|
} else if (!isString(value[i]) && !isNumber(value[i]) && !isBoolean(value[i])) {
|
package/validate/validate_fog.ts
CHANGED
|
@@ -16,6 +16,7 @@ export default function validateFog(options: FogValidatorOptions): ValidationErr
|
|
|
16
16
|
const fog = options.value;
|
|
17
17
|
const style = options.style;
|
|
18
18
|
const styleSpec = options.styleSpec;
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
19
20
|
const fogSpec = styleSpec.fog;
|
|
20
21
|
|
|
21
22
|
if (fog === undefined) {
|
|
@@ -31,6 +32,7 @@ export default function validateFog(options: FogValidatorOptions): ValidationErr
|
|
|
31
32
|
const transitionMatch = key.match(/^(.*)-transition$/);
|
|
32
33
|
const useThemeMatch = key.match(/^(.*)-use-theme$/);
|
|
33
34
|
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
34
36
|
if (useThemeMatch && fogSpec[useThemeMatch[1]]) {
|
|
35
37
|
errors = errors.concat(validate({
|
|
36
38
|
key,
|
|
@@ -39,18 +41,22 @@ export default function validateFog(options: FogValidatorOptions): ValidationErr
|
|
|
39
41
|
style,
|
|
40
42
|
styleSpec
|
|
41
43
|
}));
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
42
45
|
} else if (transitionMatch && fogSpec[transitionMatch[1]] && fogSpec[transitionMatch[1]].transition) {
|
|
43
46
|
errors = errors.concat(validate({
|
|
44
47
|
key,
|
|
45
48
|
value: fog[key],
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
46
50
|
valueSpec: styleSpec.transition,
|
|
47
51
|
style,
|
|
48
52
|
styleSpec
|
|
49
53
|
}));
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
50
55
|
} else if (fogSpec[key]) {
|
|
51
56
|
errors = errors.concat(validate({
|
|
52
57
|
key,
|
|
53
58
|
value: fog[key],
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
54
60
|
valueSpec: fogSpec[key],
|
|
55
61
|
style,
|
|
56
62
|
styleSpec
|
|
@@ -17,6 +17,7 @@ import type {StyleSpecification} from '../types';
|
|
|
17
17
|
import type {StylePropertySpecification} from '../style-spec';
|
|
18
18
|
|
|
19
19
|
function hasObjectStops(value: object): value is {stops: Array<Record<PropertyKey, unknown>>} {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
20
21
|
const stops = value['stops'];
|
|
21
22
|
return Array.isArray(stops) && Array.isArray(stops[0]) && isObject(stops[0][0]);
|
|
22
23
|
}
|
|
@@ -51,6 +52,7 @@ export default function validateFunction(options: FunctionValidatorOptions): Val
|
|
|
51
52
|
const errors = validateObject({
|
|
52
53
|
key: options.key,
|
|
53
54
|
value: options.value,
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
54
56
|
valueSpec: options.styleSpec.function,
|
|
55
57
|
style: options.style,
|
|
56
58
|
styleSpec: options.styleSpec,
|
|
@@ -38,6 +38,7 @@ export default function validateIconset(options: IconsetValidatorOptions): Valid
|
|
|
38
38
|
errors = errors.concat(validateObject({
|
|
39
39
|
key,
|
|
40
40
|
value: iconset,
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
41
42
|
valueSpec: styleSpec[`iconset_${type}`],
|
|
42
43
|
style,
|
|
43
44
|
styleSpec
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import extend from '../util/extend';
|
|
2
1
|
import validateStyle from './validate_style';
|
|
3
2
|
import validateObject from './validate_object';
|
|
4
3
|
import ValidationError from '../error/validation_error';
|
|
@@ -31,8 +30,9 @@ export default function validateImport(options: ImportValidatorOptions): Validat
|
|
|
31
30
|
enumerable: false
|
|
32
31
|
});
|
|
33
32
|
|
|
34
|
-
let errors = validateObject(
|
|
33
|
+
let errors = validateObject(Object.assign({}, options, {
|
|
35
34
|
value: importSpec,
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
36
36
|
valueSpec: styleSpec.import
|
|
37
37
|
}));
|
|
38
38
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import ValidationError from '../error/validation_error';
|
|
2
2
|
import {unbundle} from '../util/unbundle_jsonlint';
|
|
3
|
+
import validateArray from './validate_array';
|
|
3
4
|
import validateObject from './validate_object';
|
|
4
5
|
import validateFilter from './validate_filter';
|
|
6
|
+
import validateAppearance, {type AppearanceValidatorOptions} from './validate_appearance';
|
|
5
7
|
import validatePaintProperty from './validate_paint_property';
|
|
6
8
|
import validateLayoutProperty from './validate_layout_property';
|
|
7
9
|
import validateSpec from './validate';
|
|
8
|
-
import extend from '../util/extend';
|
|
9
10
|
import {isObject, isString} from '../util/get_type';
|
|
10
11
|
|
|
11
12
|
import type {StyleReference} from '../reference/latest';
|
|
@@ -64,9 +65,11 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
64
65
|
if (!parent) {
|
|
65
66
|
if (typeof ref === 'string')
|
|
66
67
|
errors.push(new ValidationError(key, layer.ref, `ref layer "${ref}" not found`));
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
67
69
|
} else if (parent.ref) {
|
|
68
70
|
errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
|
|
69
71
|
} else {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
70
73
|
type = unbundle(parent.type) as string;
|
|
71
74
|
}
|
|
72
75
|
} else if (!(type === 'background' || type === 'sky' || type === 'slot')) {
|
|
@@ -101,6 +104,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
101
104
|
errors = errors.concat(validateObject({
|
|
102
105
|
key,
|
|
103
106
|
value: layer,
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
104
108
|
valueSpec: styleSpec.layer,
|
|
105
109
|
style: options.style,
|
|
106
110
|
styleSpec: options.styleSpec,
|
|
@@ -114,6 +118,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
114
118
|
return validateSpec({
|
|
115
119
|
key: `${key}.type`,
|
|
116
120
|
value: layer.type,
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
117
122
|
valueSpec: styleSpec.layer.type,
|
|
118
123
|
style: options.style,
|
|
119
124
|
styleSpec: options.styleSpec,
|
|
@@ -122,7 +127,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
122
127
|
});
|
|
123
128
|
},
|
|
124
129
|
filter(options) {
|
|
125
|
-
return validateFilter(
|
|
130
|
+
return validateFilter(Object.assign({layerType: type}, options));
|
|
126
131
|
},
|
|
127
132
|
layout(options) {
|
|
128
133
|
return validateObject({
|
|
@@ -134,7 +139,7 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
134
139
|
styleSpec: options.styleSpec,
|
|
135
140
|
objectElementValidators: {
|
|
136
141
|
'*'(options) {
|
|
137
|
-
return validateLayoutProperty(
|
|
142
|
+
return validateLayoutProperty(Object.assign({layerType: type}, options));
|
|
138
143
|
}
|
|
139
144
|
}
|
|
140
145
|
});
|
|
@@ -149,10 +154,38 @@ export default function validateLayer(options: LayerValidatorOptions): Validatio
|
|
|
149
154
|
styleSpec: options.styleSpec,
|
|
150
155
|
objectElementValidators: {
|
|
151
156
|
'*'(options) {
|
|
152
|
-
return validatePaintProperty(
|
|
157
|
+
return validatePaintProperty(Object.assign({layerType: type, layer}, options));
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
160
|
});
|
|
161
|
+
},
|
|
162
|
+
appearances(options) {
|
|
163
|
+
const validationErrors = validateArray({
|
|
164
|
+
key: options.key,
|
|
165
|
+
value: options.value,
|
|
166
|
+
|
|
167
|
+
valueSpec: options.valueSpec,
|
|
168
|
+
style: options.style,
|
|
169
|
+
styleSpec: options.styleSpec,
|
|
170
|
+
arrayElementValidator: (options) => validateAppearance(Object.assign({layerType: type, layer}, options) as AppearanceValidatorOptions)
|
|
171
|
+
});
|
|
172
|
+
// Check non-repeated names on a given layer
|
|
173
|
+
const appearances = Array.isArray(options.value) ? options.value : [];
|
|
174
|
+
const dedupedNames = new Set<string>();
|
|
175
|
+
appearances.forEach((a, index) => {
|
|
176
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
177
|
+
const name: string | undefined = unbundle(a.name) as string | undefined;
|
|
178
|
+
if (name) {
|
|
179
|
+
if (dedupedNames.has(name)) {
|
|
180
|
+
const layerId = unbundle((layer as LayerSpecification).id) as string;
|
|
181
|
+
validationErrors.push(new ValidationError(options.key, name, `Duplicated appearance name "${name}" for layer "${layerId}"`));
|
|
182
|
+
} else {
|
|
183
|
+
dedupedNames.add(name);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return validationErrors;
|
|
156
189
|
}
|
|
157
190
|
}
|
|
158
191
|
}));
|
|
@@ -15,6 +15,7 @@ type LightValidatorOptions = {
|
|
|
15
15
|
export default function validateLight(options: LightValidatorOptions): ValidationError[] {
|
|
16
16
|
const light = options.value;
|
|
17
17
|
const styleSpec = options.styleSpec;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
18
19
|
const lightSpec = styleSpec.light;
|
|
19
20
|
const style = options.style;
|
|
20
21
|
|
|
@@ -31,6 +32,7 @@ export default function validateLight(options: LightValidatorOptions): Validatio
|
|
|
31
32
|
const transitionMatch = key.match(/^(.*)-transition$/);
|
|
32
33
|
const useThemeMatch = key.match(/^(.*)-use-theme$/);
|
|
33
34
|
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
34
36
|
if (useThemeMatch && lightSpec[useThemeMatch[1]]) {
|
|
35
37
|
errors = errors.concat(validate({
|
|
36
38
|
key,
|
|
@@ -39,18 +41,22 @@ export default function validateLight(options: LightValidatorOptions): Validatio
|
|
|
39
41
|
style,
|
|
40
42
|
styleSpec
|
|
41
43
|
}));
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
42
45
|
} else if (transitionMatch && lightSpec[transitionMatch[1]] && lightSpec[transitionMatch[1]].transition) {
|
|
43
46
|
errors = errors.concat(validate({
|
|
44
47
|
key,
|
|
45
48
|
value: light[key],
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
46
50
|
valueSpec: styleSpec.transition,
|
|
47
51
|
style,
|
|
48
52
|
styleSpec
|
|
49
53
|
}));
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
50
55
|
} else if (lightSpec[key]) {
|
|
51
56
|
errors = errors.concat(validate({
|
|
52
57
|
key,
|
|
53
58
|
value: light[key],
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
54
60
|
valueSpec: lightSpec[key],
|
|
55
61
|
style,
|
|
56
62
|
styleSpec
|
|
@@ -28,6 +28,7 @@ export default function validateLights(options: LightsValidatorOptions): Validat
|
|
|
28
28
|
|
|
29
29
|
let errors: ValidationError[] = [];
|
|
30
30
|
const styleSpec = options.styleSpec;
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
31
32
|
const lightSpec = styleSpec['light-3d'];
|
|
32
33
|
const style = options.style;
|
|
33
34
|
const lights = options.style.lights;
|
|
@@ -60,6 +61,7 @@ export default function validateLights(options: LightsValidatorOptions): Validat
|
|
|
60
61
|
return errors;
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
63
65
|
const lightPropertySpec = styleSpec[lightType];
|
|
64
66
|
|
|
65
67
|
for (const key in light) {
|
|
@@ -73,6 +75,7 @@ export default function validateLights(options: LightsValidatorOptions): Validat
|
|
|
73
75
|
const transitionMatch = propertyKey.match(/^(.*)-transition$/);
|
|
74
76
|
const useThemeMatch = propertyKey.match(/^(.*)-use-theme$/);
|
|
75
77
|
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
76
79
|
if (useThemeMatch && lightPropertySpec[useThemeMatch[1]]) {
|
|
77
80
|
errors = errors.concat(validate({
|
|
78
81
|
key,
|
|
@@ -81,20 +84,24 @@ export default function validateLights(options: LightsValidatorOptions): Validat
|
|
|
81
84
|
style,
|
|
82
85
|
styleSpec
|
|
83
86
|
}));
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
84
88
|
} else if (transitionMatch && lightPropertySpec[transitionMatch[1]] && lightPropertySpec[transitionMatch[1]].transition) {
|
|
85
89
|
errors = errors.concat(validate({
|
|
86
90
|
key,
|
|
87
91
|
value: light[key],
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
88
93
|
valueSpec: styleSpec.transition,
|
|
89
94
|
style,
|
|
90
95
|
styleSpec
|
|
91
96
|
}));
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
92
98
|
} else if (!lightPropertySpec[propertyKey]) {
|
|
93
99
|
errors = errors.concat([new ValidationWarning(options.key, properties[propertyKey], `unknown property "${propertyKey}"`)]);
|
|
94
100
|
} else {
|
|
95
101
|
errors = errors.concat(validate({
|
|
96
102
|
key: propertyKey,
|
|
97
103
|
value: properties[propertyKey],
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
98
105
|
valueSpec: lightPropertySpec[propertyKey],
|
|
99
106
|
style,
|
|
100
107
|
styleSpec
|
|
@@ -102,10 +109,12 @@ export default function validateLights(options: LightsValidatorOptions): Validat
|
|
|
102
109
|
}
|
|
103
110
|
}
|
|
104
111
|
} else {
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
105
113
|
if (lightSpec[key]) {
|
|
106
114
|
errors = errors.concat(validate({
|
|
107
115
|
key,
|
|
108
116
|
value: light[key],
|
|
117
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
109
118
|
valueSpec: lightSpec[key],
|
|
110
119
|
style,
|
|
111
120
|
styleSpec
|
|
@@ -10,8 +10,7 @@ export function isValidUrl(str: string, allowRelativeUrls: boolean): boolean {
|
|
|
10
10
|
try {
|
|
11
11
|
new URL(str, isRelative && allowRelativeUrls ? 'http://example.com' : undefined);
|
|
12
12
|
return true;
|
|
13
|
-
|
|
14
|
-
} catch (_: any) {
|
|
13
|
+
} catch (_: unknown) {
|
|
15
14
|
return false;
|
|
16
15
|
}
|
|
17
16
|
}
|
|
@@ -3,14 +3,12 @@ import ValidationError from '../error/validation_error';
|
|
|
3
3
|
|
|
4
4
|
import type {StyleReference} from '../reference/latest';
|
|
5
5
|
import type {StyleSpecification} from '../types';
|
|
6
|
+
import type {NumberPropertySpecification} from '../style-spec';
|
|
6
7
|
|
|
7
8
|
type NumberValidatorOptions = {
|
|
8
9
|
key: string;
|
|
9
10
|
value: unknown;
|
|
10
|
-
valueSpec:
|
|
11
|
-
minimum?: number;
|
|
12
|
-
maximum?: number
|
|
13
|
-
};
|
|
11
|
+
valueSpec: NumberPropertySpecification;
|
|
14
12
|
style: Partial<StyleSpecification>;
|
|
15
13
|
styleSpec: StyleReference;
|
|
16
14
|
arrayIndex: number;
|
|
@@ -34,6 +32,7 @@ export default function validateNumber(options: NumberValidatorOptions): Validat
|
|
|
34
32
|
let specMin = valueSpec.minimum;
|
|
35
33
|
if (Array.isArray(valueSpec.minimum)) {
|
|
36
34
|
const i = options.arrayIndex;
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
37
36
|
specMin = valueSpec.minimum[i];
|
|
38
37
|
}
|
|
39
38
|
if (value < specMin) {
|
|
@@ -45,6 +44,7 @@ export default function validateNumber(options: NumberValidatorOptions): Validat
|
|
|
45
44
|
let specMax = valueSpec.maximum;
|
|
46
45
|
if (Array.isArray(valueSpec.maximum)) {
|
|
47
46
|
const i = options.arrayIndex;
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
48
48
|
specMax = valueSpec.maximum[i];
|
|
49
49
|
}
|
|
50
50
|
if (value > specMax) {
|
|
@@ -8,8 +8,11 @@ import type {StyleSpecification, LayerSpecification} from '../types';
|
|
|
8
8
|
type ObjectElementValidatorOptions = {
|
|
9
9
|
key: string;
|
|
10
10
|
value: unknown;
|
|
11
|
+
valueSpec?: unknown;
|
|
11
12
|
style: Partial<StyleSpecification>;
|
|
12
13
|
styleSpec: StyleReference;
|
|
14
|
+
object?: object;
|
|
15
|
+
objectKey?: string;
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
type ObjectValidatorOptions = {
|
|
@@ -39,6 +42,7 @@ export default function validateObject(options: ObjectValidatorOptions): Validat
|
|
|
39
42
|
let errors: ValidationError[] = [];
|
|
40
43
|
for (const objectKey in object) {
|
|
41
44
|
const elementSpecKey = objectKey.split('.')[0]; // treat 'paint.*' as 'paint'
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
42
46
|
const elementSpec = elementSpecs[elementSpecKey] || elementSpecs['*'];
|
|
43
47
|
|
|
44
48
|
let validateElement;
|
|
@@ -57,9 +61,11 @@ export default function validateObject(options: ObjectValidatorOptions): Validat
|
|
|
57
61
|
continue;
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
|
|
60
65
|
errors = errors.concat(validateElement({
|
|
61
66
|
key: (key ? `${key}.` : key) + objectKey,
|
|
62
67
|
value: object[objectKey],
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
63
69
|
valueSpec: elementSpec,
|
|
64
70
|
style,
|
|
65
71
|
styleSpec,
|
|
@@ -74,6 +80,7 @@ export default function validateObject(options: ObjectValidatorOptions): Validat
|
|
|
74
80
|
continue;
|
|
75
81
|
}
|
|
76
82
|
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
77
84
|
if (elementSpecs[elementSpecKey].required && elementSpecs[elementSpecKey]['default'] === undefined && object[elementSpecKey] === undefined) {
|
|
78
85
|
errors.push(new ValidationError(key, object, `missing required property "${elementSpecKey}"`));
|
|
79
86
|
}
|
|
@@ -15,6 +15,7 @@ type ProjectionValidatorOptions = {
|
|
|
15
15
|
export default function validateProjection(options: ProjectionValidatorOptions): ValidationError[] {
|
|
16
16
|
const projection = options.value;
|
|
17
17
|
const styleSpec = options.styleSpec;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
18
19
|
const projectionSpec = styleSpec.projection;
|
|
19
20
|
const style = options.style;
|
|
20
21
|
|
|
@@ -25,6 +26,7 @@ export default function validateProjection(options: ProjectionValidatorOptions):
|
|
|
25
26
|
errors = errors.concat(validate({
|
|
26
27
|
key,
|
|
27
28
|
value: projection[key],
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
28
30
|
valueSpec: projectionSpec[key],
|
|
29
31
|
style,
|
|
30
32
|
styleSpec
|
|
@@ -13,12 +13,12 @@ import type {StyleSpecification, LayerSpecification} from '../types';
|
|
|
13
13
|
export type PropertyValidatorOptions = {
|
|
14
14
|
key: string;
|
|
15
15
|
value: unknown;
|
|
16
|
-
valueSpec
|
|
16
|
+
valueSpec?: unknown;
|
|
17
17
|
style: Partial<StyleSpecification>;
|
|
18
18
|
styleSpec: StyleReference;
|
|
19
|
-
objectKey
|
|
19
|
+
objectKey?: string;
|
|
20
20
|
layerType: string;
|
|
21
|
-
layer
|
|
21
|
+
layer?: Partial<LayerSpecification>;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
export default function validateProperty(options: PropertyValidatorOptions, propertyType: string): ValidationError[] {
|
|
@@ -28,11 +28,13 @@ export default function validateProperty(options: PropertyValidatorOptions, prop
|
|
|
28
28
|
const styleSpec = options.styleSpec;
|
|
29
29
|
const value = options.value;
|
|
30
30
|
const propertyKey = options.objectKey;
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
31
32
|
const layerSpec = styleSpec[`${propertyType}_${options.layerType}`];
|
|
32
33
|
|
|
33
34
|
if (!layerSpec) return [];
|
|
34
35
|
|
|
35
36
|
const useThemeMatch = propertyKey.match(/^(.*)-use-theme$/);
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
36
38
|
if (useThemeMatch && layerSpec[useThemeMatch[1]]) {
|
|
37
39
|
if (isExpression(value)) {
|
|
38
40
|
const errors: ValidationError[] = [];
|
|
@@ -67,22 +69,26 @@ export default function validateProperty(options: PropertyValidatorOptions, prop
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
const transitionMatch = propertyKey.match(/^(.*)-transition$/);
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
70
73
|
if (propertyType === 'paint' && transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) {
|
|
71
74
|
return validate({
|
|
72
75
|
key,
|
|
73
76
|
value,
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
74
78
|
valueSpec: styleSpec.transition,
|
|
75
79
|
style,
|
|
76
80
|
styleSpec
|
|
77
81
|
});
|
|
78
82
|
}
|
|
79
83
|
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
80
85
|
const valueSpec = options.valueSpec || layerSpec[propertyKey];
|
|
81
86
|
if (!valueSpec) {
|
|
82
87
|
return [new ValidationWarning(key, value, `unknown property "${propertyKey}"`)];
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
let tokenMatch: RegExpExecArray | undefined;
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
86
92
|
if (isString(value) && supportsPropertyExpression(valueSpec) && !valueSpec.tokens && (tokenMatch = /^{([^}]+)}$/.exec(value))) {
|
|
87
93
|
const example = `\`{ "type": "identity", "property": ${tokenMatch ? JSON.stringify(tokenMatch[1]) : '"_"'} }\``;
|
|
88
94
|
return [new ValidationError(
|
|
@@ -101,13 +107,17 @@ export default function validateProperty(options: PropertyValidatorOptions, prop
|
|
|
101
107
|
errors.push(new ValidationError(key, value, '"text-font" does not support identity functions'));
|
|
102
108
|
}
|
|
103
109
|
} else if (options.layerType === 'model' && propertyType === 'paint' && layer && layer.layout && layer.layout.hasOwnProperty('model-id')) {
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
104
111
|
if (supportsPropertyExpression(valueSpec) && (supportsLightExpression(valueSpec) || supportsZoomExpression(valueSpec))) {
|
|
105
112
|
// Performance related style spec limitation: zoom and light expressions are not allowed for e.g. trees.
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
106
114
|
const expression = createPropertyExpression(deepUnbundle(value), valueSpec);
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
108
116
|
const expressionObj = (expression.value as any).expression || (expression.value as any)._styleExpression.expression;
|
|
109
117
|
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
110
119
|
if (expressionObj && !isGlobalPropertyConstant(expressionObj, ['measure-light'])) {
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
111
121
|
if (propertyKey !== 'model-emissive-strength' || (!isFeatureConstant(expressionObj) || !isStateConstant(expressionObj))) {
|
|
112
122
|
errors.push(new ValidationError(key, value, `${propertyKey} does not support measure-light expressions when the model layer source is vector tile or GeoJSON.`));
|
|
113
123
|
}
|
|
@@ -118,6 +128,7 @@ export default function validateProperty(options: PropertyValidatorOptions, prop
|
|
|
118
128
|
return errors.concat(validate({
|
|
119
129
|
key: options.key,
|
|
120
130
|
value,
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
121
132
|
valueSpec,
|
|
122
133
|
style,
|
|
123
134
|
styleSpec,
|
|
@@ -16,6 +16,7 @@ export default function validateRain(options: RainValidatorOptions): ValidationE
|
|
|
16
16
|
const rain = options.value;
|
|
17
17
|
const style = options.style;
|
|
18
18
|
const styleSpec = options.styleSpec;
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
19
20
|
const rainSpec = styleSpec.rain;
|
|
20
21
|
|
|
21
22
|
if (rain === undefined) {
|
|
@@ -30,18 +31,22 @@ export default function validateRain(options: RainValidatorOptions): ValidationE
|
|
|
30
31
|
for (const key in rain) {
|
|
31
32
|
const transitionMatch = key.match(/^(.*)-transition$/);
|
|
32
33
|
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
33
35
|
if (transitionMatch && rainSpec[transitionMatch[1]] && rainSpec[transitionMatch[1]].transition) {
|
|
34
36
|
errors = errors.concat(validate({
|
|
35
37
|
key,
|
|
36
38
|
value: rain[key],
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
37
40
|
valueSpec: styleSpec.transition,
|
|
38
41
|
style,
|
|
39
42
|
styleSpec
|
|
40
43
|
}));
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
41
45
|
} else if (rainSpec[key]) {
|
|
42
46
|
errors = errors.concat(validate({
|
|
43
47
|
key,
|
|
44
48
|
value: rain[key],
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
45
50
|
valueSpec: rainSpec[key],
|
|
46
51
|
style,
|
|
47
52
|
styleSpec
|