@mapbox/mapbox-gl-style-spec 13.28.0 → 14.0.0-beta.2
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/LICENSE.txt +47 -0
- package/README.md +7 -0
- package/data/extent.js +18 -0
- package/deref.js +1 -1
- package/diff.js +36 -15
- package/dist/index.cjs +5839 -2015
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +5837 -2011
- package/dist/index.es.js.map +1 -1
- package/expression/compound_expression.js +2 -1
- package/expression/definitions/assertion.js +2 -2
- package/expression/definitions/coercion.js +54 -15
- package/expression/definitions/comparison.js +2 -0
- package/expression/definitions/distance.js +597 -0
- package/expression/definitions/format.js +2 -2
- package/expression/definitions/image.js +34 -14
- package/expression/definitions/index.js +122 -8
- package/expression/definitions/interpolate.js +1 -1
- package/expression/definitions/match.js +2 -2
- package/expression/definitions/within.js +21 -92
- package/expression/evaluation_context.js +12 -1
- package/expression/index.js +74 -43
- package/expression/is_constant.js +19 -1
- package/expression/parsing_context.js +20 -16
- package/expression/types/formatted.js +2 -2
- package/expression/types/resolved_image.js +19 -8
- package/expression/types.js +2 -1
- package/expression/values.js +25 -0
- package/feature_filter/convert.js +1 -1
- package/feature_filter/index.js +4 -4
- package/flow-typed/cheap-ruler.js +25 -0
- package/flow-typed/geojson.js +8 -7
- package/flow-typed/gl-matrix.js +4 -2
- package/flow-typed/kdbush.js +9 -0
- package/function/convert.js +23 -12
- package/group_by_layout.js +2 -2
- package/migrate/expressions.js +3 -0
- package/package.json +6 -3
- package/reference/v8.json +1771 -114
- package/style-spec.js +4 -3
- package/types.js +190 -24
- package/util/color.js +31 -0
- package/util/geometry_util.js +145 -0
- package/util/properties.js +10 -2
- package/util/random.js +12 -0
- package/validate/validate.js +17 -7
- package/validate/validate_array.js +1 -1
- package/validate/validate_filter.js +4 -12
- package/validate/validate_function.js +2 -2
- package/validate/validate_import.js +31 -0
- package/validate/validate_layer.js +3 -2
- package/validate/validate_lights.js +84 -0
- package/validate/validate_model.js +38 -0
- package/validate/validate_property.js +18 -4
- package/validate/validate_source.js +3 -2
- package/validate/validate_style.js +29 -0
- package/validate_mapbox_api_supported.js +55 -11
- package/validate_style.js +4 -0
- package/validate_style.min.js +11 -19
- package/visit.js +3 -2
package/util/properties.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import type {StylePropertySpecification} from '../style-spec.js';
|
|
3
|
+
import type {ExpressionSpecification, StylePropertySpecification} from '../style-spec.js';
|
|
4
|
+
|
|
5
|
+
function expressionHasParameter(expression: ?ExpressionSpecification, parameter: string): boolean {
|
|
6
|
+
return !!expression && !!expression.parameters && expression.parameters.indexOf(parameter) > -1;
|
|
7
|
+
}
|
|
4
8
|
|
|
5
9
|
export function supportsPropertyExpression(spec: StylePropertySpecification): boolean {
|
|
6
10
|
return spec['property-type'] === 'data-driven';
|
|
7
11
|
}
|
|
8
12
|
|
|
13
|
+
export function supportsLightExpression(spec: StylePropertySpecification): boolean {
|
|
14
|
+
return expressionHasParameter(spec.expression, 'measure-light');
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
export function supportsZoomExpression(spec: StylePropertySpecification): boolean {
|
|
10
|
-
return
|
|
18
|
+
return expressionHasParameter(spec.expression, 'zoom');
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export function supportsInterpolation(spec: StylePropertySpecification): boolean {
|
package/util/random.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
// Seeded pseudo random generator function
|
|
4
|
+
export function mulberry32(a: number): () => number {
|
|
5
|
+
return function () {
|
|
6
|
+
a |= 0;
|
|
7
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
8
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
9
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
10
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
11
|
+
};
|
|
12
|
+
}
|
package/validate/validate.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
3
|
import extend from '../util/extend.js';
|
|
4
|
+
import ValidationError from '../error/validation_error.js';
|
|
4
5
|
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
|
5
6
|
import {isExpression} from '../expression/index.js';
|
|
6
7
|
import {isFunction} from '../function/index.js';
|
|
7
8
|
|
|
9
|
+
import validateImport from './validate_import.js';
|
|
8
10
|
import validateFunction from './validate_function.js';
|
|
9
11
|
import validateExpression from './validate_expression.js';
|
|
10
12
|
import validateObject from './validate_object.js';
|
|
@@ -16,7 +18,9 @@ import validateEnum from './validate_enum.js';
|
|
|
16
18
|
import validateFilter from './validate_filter.js';
|
|
17
19
|
import validateLayer from './validate_layer.js';
|
|
18
20
|
import validateSource from './validate_source.js';
|
|
21
|
+
import validateModel from './validate_model.js';
|
|
19
22
|
import validateLight from './validate_light.js';
|
|
23
|
+
import validateLights from './validate_lights.js';
|
|
20
24
|
import validateTerrain from './validate_terrain.js';
|
|
21
25
|
import validateFog from './validate_fog.js';
|
|
22
26
|
import validateString from './validate_string.js';
|
|
@@ -26,7 +30,7 @@ import validateProjection from './validate_projection.js';
|
|
|
26
30
|
|
|
27
31
|
import type {StyleReference} from '../reference/latest.js';
|
|
28
32
|
import type {StyleSpecification} from '../types.js';
|
|
29
|
-
import
|
|
33
|
+
import getType from '../util/get_type.js';
|
|
30
34
|
|
|
31
35
|
const VALIDATORS = {
|
|
32
36
|
'*'() {
|
|
@@ -42,13 +46,16 @@ const VALIDATORS = {
|
|
|
42
46
|
'layer': validateLayer,
|
|
43
47
|
'object': validateObject,
|
|
44
48
|
'source': validateSource,
|
|
49
|
+
'model': validateModel,
|
|
45
50
|
'light': validateLight,
|
|
51
|
+
'light-3d': validateLights,
|
|
46
52
|
'terrain': validateTerrain,
|
|
47
53
|
'fog': validateFog,
|
|
48
54
|
'string': validateString,
|
|
49
55
|
'formatted': validateFormatted,
|
|
50
56
|
'resolvedImage': validateImage,
|
|
51
|
-
'projection': validateProjection
|
|
57
|
+
'projection': validateProjection,
|
|
58
|
+
'import': validateImport
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
// Main recursive validation function. Tracks:
|
|
@@ -68,20 +75,23 @@ export type ValidationOptions = {
|
|
|
68
75
|
styleSpec: StyleReference;
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
export default function validate(options: ValidationOptions): Array<ValidationError> {
|
|
78
|
+
export default function validate(options: ValidationOptions, arrayAsExpression: boolean = false): Array<ValidationError> {
|
|
72
79
|
const value = options.value;
|
|
73
80
|
const valueSpec = options.valueSpec;
|
|
74
81
|
const styleSpec = options.styleSpec;
|
|
75
82
|
|
|
76
83
|
if (valueSpec.expression && isFunction(unbundle(value))) {
|
|
77
84
|
return validateFunction(options);
|
|
78
|
-
|
|
79
85
|
} else if (valueSpec.expression && isExpression(deepUnbundle(value))) {
|
|
80
86
|
return validateExpression(options);
|
|
81
|
-
|
|
82
87
|
} else if (valueSpec.type && VALIDATORS[valueSpec.type]) {
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
const valid = VALIDATORS[valueSpec.type](options);
|
|
89
|
+
if (arrayAsExpression === true && valid.length > 0 && getType(options.value) === "array") {
|
|
90
|
+
// Try to validate as an expression
|
|
91
|
+
return validateExpression(options);
|
|
92
|
+
} else {
|
|
93
|
+
return valid;
|
|
94
|
+
}
|
|
85
95
|
} else {
|
|
86
96
|
const valid = validateObject(extend({}, options, {
|
|
87
97
|
valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec
|
|
@@ -11,7 +11,7 @@ import {isExpressionFilter} from '../feature_filter/index.js';
|
|
|
11
11
|
import type {ValidationOptions} from './validate.js';
|
|
12
12
|
|
|
13
13
|
type Options = ValidationOptions & {
|
|
14
|
-
layerType
|
|
14
|
+
layerType?: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export default function validateFilter(options: Options): Array<ValidationError> {
|
|
@@ -28,7 +28,7 @@ export default function validateFilter(options: Options): Array<ValidationError>
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function validateNonExpressionFilter(options) {
|
|
31
|
+
function validateNonExpressionFilter(options: Options) {
|
|
32
32
|
const value = options.value;
|
|
33
33
|
const key = options.key;
|
|
34
34
|
|
|
@@ -96,12 +96,12 @@ function validateNonExpressionFilter(options) {
|
|
|
96
96
|
case 'all':
|
|
97
97
|
case 'none':
|
|
98
98
|
for (let i = 1; i < value.length; i++) {
|
|
99
|
-
errors = errors.concat(validateNonExpressionFilter({
|
|
99
|
+
errors = errors.concat(validateNonExpressionFilter(({
|
|
100
100
|
key: `${key}[${i}]`,
|
|
101
101
|
value: value[i],
|
|
102
102
|
style: options.style,
|
|
103
103
|
styleSpec: options.styleSpec
|
|
104
|
-
}));
|
|
104
|
+
}: any)));
|
|
105
105
|
}
|
|
106
106
|
break;
|
|
107
107
|
|
|
@@ -114,14 +114,6 @@ function validateNonExpressionFilter(options) {
|
|
|
114
114
|
errors.push(new ValidationError(`${key}[1]`, value[1], `string expected, ${type} found`));
|
|
115
115
|
}
|
|
116
116
|
break;
|
|
117
|
-
case 'within':
|
|
118
|
-
type = getType(value[1]);
|
|
119
|
-
if (value.length !== 2) {
|
|
120
|
-
errors.push(new ValidationError(key, value, `filter array for "${value[0]}" operator must have 2 elements`));
|
|
121
|
-
} else if (type !== 'object') {
|
|
122
|
-
errors.push(new ValidationError(`${key}[1]`, value[1], `object expected, ${type} found`));
|
|
123
|
-
}
|
|
124
|
-
break;
|
|
125
117
|
}
|
|
126
118
|
return errors;
|
|
127
119
|
}
|
|
@@ -21,7 +21,7 @@ export default function validateFunction(options: ValidationOptions): any {
|
|
|
21
21
|
const functionType = unbundle(options.value.type);
|
|
22
22
|
let stopKeyType;
|
|
23
23
|
let stopDomainValues: {[string | number]: boolean} = {};
|
|
24
|
-
let previousStopDomainValue;
|
|
24
|
+
let previousStopDomainValue: ?mixed;
|
|
25
25
|
let previousStopDomainZoom;
|
|
26
26
|
|
|
27
27
|
const isZoomFunction = functionType !== 'categorical' && options.value.property === undefined;
|
|
@@ -161,7 +161,7 @@ export default function validateFunction(options: ValidationOptions): any {
|
|
|
161
161
|
}));
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
function validateStopDomainValue(options: ValidationOptions, stop) {
|
|
164
|
+
function validateStopDomainValue(options: ValidationOptions, stop: any) {
|
|
165
165
|
const type = getType(options.value);
|
|
166
166
|
const value = unbundle(options.value);
|
|
167
167
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import extend from '../util/extend.js';
|
|
4
|
+
import validateStyle from './validate_style.js';
|
|
5
|
+
import validateObject from './validate_object.js';
|
|
6
|
+
import ValidationError from '../error/validation_error.js';
|
|
7
|
+
|
|
8
|
+
import type {ValidationOptions} from './validate.js';
|
|
9
|
+
|
|
10
|
+
export default function validateImport(options: ValidationOptions): ValidationError[] {
|
|
11
|
+
const {value, styleSpec} = options;
|
|
12
|
+
const {data, ...importSpec} = value;
|
|
13
|
+
|
|
14
|
+
// Preserve __line__ from the value
|
|
15
|
+
Object.defineProperty(importSpec, '__line__', {
|
|
16
|
+
value: value.__line__,
|
|
17
|
+
enumerable: false
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
let errors = validateObject(extend({}, options, {
|
|
21
|
+
value: importSpec,
|
|
22
|
+
valueSpec: styleSpec.import
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
if (data) {
|
|
26
|
+
const key = `${options.key}.data`;
|
|
27
|
+
errors = errors.concat(validateStyle(data, styleSpec, {key}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return errors;
|
|
31
|
+
}
|
|
@@ -58,12 +58,13 @@ export default function validateLayer(options: Options): Array<ValidationError>
|
|
|
58
58
|
if (!parent) {
|
|
59
59
|
if (typeof ref === 'string')
|
|
60
60
|
errors.push(new ValidationError(key, layer.ref, `ref layer "${ref}" not found`));
|
|
61
|
+
// $FlowFixMe[prop-missing] - ref is not defined on the LayerSpecification subtypes
|
|
61
62
|
} else if (parent.ref) {
|
|
62
63
|
errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
|
|
63
64
|
} else {
|
|
64
65
|
type = unbundle(parent.type);
|
|
65
66
|
}
|
|
66
|
-
} else if (!(type === 'background' || type === 'sky')) {
|
|
67
|
+
} else if (!(type === 'background' || type === 'sky' || type === 'slot')) {
|
|
67
68
|
if (!layer.source) {
|
|
68
69
|
errors.push(new ValidationError(key, layer, 'missing required property "source"'));
|
|
69
70
|
} else {
|
|
@@ -137,7 +138,7 @@ export default function validateLayer(options: Options): Array<ValidationError>
|
|
|
137
138
|
styleSpec: options.styleSpec,
|
|
138
139
|
objectElementValidators: {
|
|
139
140
|
'*'(options) {
|
|
140
|
-
return validatePaintProperty(extend({layerType: type}, options));
|
|
141
|
+
return validatePaintProperty(extend({layerType: type, layer}, options));
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import ValidationError from '../error/validation_error.js';
|
|
4
|
+
import getType from '../util/get_type.js';
|
|
5
|
+
import validate from './validate.js';
|
|
6
|
+
|
|
7
|
+
import type {ValidationOptions} from './validate.js';
|
|
8
|
+
|
|
9
|
+
export default function validateLights(options: ValidationOptions): Array<ValidationError> {
|
|
10
|
+
const light = options.value;
|
|
11
|
+
let errors = [];
|
|
12
|
+
|
|
13
|
+
if (!light) {
|
|
14
|
+
return errors;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const type = getType(light);
|
|
18
|
+
if (type !== 'object') {
|
|
19
|
+
errors = errors.concat([new ValidationError('light-3d', light, `object expected, ${type} found`)]);
|
|
20
|
+
return errors;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const styleSpec = options.styleSpec;
|
|
24
|
+
const lightSpec = styleSpec['light-3d'];
|
|
25
|
+
const style = options.style;
|
|
26
|
+
|
|
27
|
+
for (const key of ['type', 'id']) {
|
|
28
|
+
if (!(key in light)) {
|
|
29
|
+
errors = errors.concat([new ValidationError('light-3d', light, `missing property ${key} on light`)]);
|
|
30
|
+
return errors;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const lightType = `properties_light_${light['type']}`;
|
|
35
|
+
if (!(lightType in styleSpec)) {
|
|
36
|
+
errors = errors.concat([new ValidationError('light-3d', light, `Invalid light type ${light['type']}`)]);
|
|
37
|
+
return errors;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const lightPropertySpec = styleSpec[lightType];
|
|
41
|
+
|
|
42
|
+
for (const key in light) {
|
|
43
|
+
if (key === 'properties') {
|
|
44
|
+
const properties = light[key];
|
|
45
|
+
const propertiesType = getType(properties);
|
|
46
|
+
if (propertiesType !== 'object') {
|
|
47
|
+
errors = errors.concat([new ValidationError('properties', properties, `object expected, ${propertiesType} found`)]);
|
|
48
|
+
return errors;
|
|
49
|
+
}
|
|
50
|
+
for (const propertyKey in properties) {
|
|
51
|
+
errors = errors.concat(validate({
|
|
52
|
+
key: propertyKey,
|
|
53
|
+
value: properties[propertyKey],
|
|
54
|
+
valueSpec: lightPropertySpec[propertyKey],
|
|
55
|
+
style,
|
|
56
|
+
styleSpec
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
const transitionMatch = key.match(/^(.*)-transition$/);
|
|
61
|
+
if (transitionMatch && lightSpec[transitionMatch[1]] && lightSpec[transitionMatch[1]].transition) {
|
|
62
|
+
errors = errors.concat(validate({
|
|
63
|
+
key,
|
|
64
|
+
value: light[key],
|
|
65
|
+
valueSpec: styleSpec.transition,
|
|
66
|
+
style,
|
|
67
|
+
styleSpec
|
|
68
|
+
}));
|
|
69
|
+
} else if (lightSpec[key]) {
|
|
70
|
+
errors = errors.concat(validate({
|
|
71
|
+
key,
|
|
72
|
+
value: light[key],
|
|
73
|
+
valueSpec: lightSpec[key],
|
|
74
|
+
style,
|
|
75
|
+
styleSpec
|
|
76
|
+
}));
|
|
77
|
+
} else {
|
|
78
|
+
errors = errors.concat([new ValidationError(key, light[key], `unknown property "${key}"`)]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return errors;
|
|
84
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import ValidationError from '../error/validation_error.js';
|
|
4
|
+
import getType from '../util/get_type.js';
|
|
5
|
+
|
|
6
|
+
import type {ValidationOptions} from './validate.js';
|
|
7
|
+
|
|
8
|
+
// Allow any URL, use dummy base, if it's a relative URL
|
|
9
|
+
function isValidUrl(str: string): boolean {
|
|
10
|
+
const isRelative = str.indexOf('://') === -1;
|
|
11
|
+
try {
|
|
12
|
+
new URL(str, isRelative ? 'http://example.com' : undefined);
|
|
13
|
+
return true;
|
|
14
|
+
} catch (_) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function validateModel(options: ValidationOptions): Array<ValidationError> {
|
|
20
|
+
const url = options.value;
|
|
21
|
+
let errors = [];
|
|
22
|
+
|
|
23
|
+
if (!url) {
|
|
24
|
+
return errors;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const type = getType(url);
|
|
28
|
+
if (type !== 'string') {
|
|
29
|
+
errors = errors.concat([new ValidationError(options.key, url, `string expected, "${type}" found`)]);
|
|
30
|
+
return errors;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!isValidUrl(url)) {
|
|
34
|
+
errors = errors.concat([new ValidationError(options.key, url, `invalid url "${url}"`)]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return errors;
|
|
38
|
+
}
|
|
@@ -5,18 +5,22 @@ import ValidationError from '../error/validation_error.js';
|
|
|
5
5
|
import getType from '../util/get_type.js';
|
|
6
6
|
import {isFunction} from '../function/index.js';
|
|
7
7
|
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
|
8
|
-
import {supportsPropertyExpression} from '../util/properties.js';
|
|
8
|
+
import {supportsLightExpression, supportsPropertyExpression, supportsZoomExpression} from '../util/properties.js';
|
|
9
|
+
import {isGlobalPropertyConstant} from '../expression/is_constant.js';
|
|
9
10
|
|
|
10
11
|
import type {ValidationOptions} from './validate.js';
|
|
12
|
+
import {createPropertyExpression} from '../expression/index.js';
|
|
11
13
|
|
|
12
14
|
export type PropertyValidationOptions = ValidationOptions & {
|
|
13
15
|
objectKey: string;
|
|
14
16
|
layerType: string;
|
|
17
|
+
layer: Object;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export default function validateProperty(options: PropertyValidationOptions, propertyType: string): Array<ValidationError> {
|
|
18
21
|
const key = options.key;
|
|
19
22
|
const style = options.style;
|
|
23
|
+
const layer = options.layer;
|
|
20
24
|
const styleSpec = options.styleSpec;
|
|
21
25
|
const value = options.value;
|
|
22
26
|
const propertyKey = options.objectKey;
|
|
@@ -40,23 +44,33 @@ export default function validateProperty(options: PropertyValidationOptions, pro
|
|
|
40
44
|
return [new ValidationError(key, value, `unknown property "${propertyKey}"`)];
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
let tokenMatch;
|
|
47
|
+
let tokenMatch: ?RegExp$matchResult;
|
|
44
48
|
if (getType(value) === 'string' && supportsPropertyExpression(valueSpec) && !valueSpec.tokens && (tokenMatch = /^{([^}]+)}$/.exec(value))) {
|
|
49
|
+
const example = `\`{ "type": "identity", "property": ${tokenMatch ? JSON.stringify(tokenMatch[1]) : '"_"'} }\``;
|
|
45
50
|
return [new ValidationError(
|
|
46
51
|
key, value,
|
|
47
52
|
`"${propertyKey}" does not support interpolation syntax\n` +
|
|
48
|
-
`Use an identity property function instead:
|
|
53
|
+
`Use an identity property function instead: ${example}.`)];
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const errors = [];
|
|
52
57
|
|
|
53
58
|
if (options.layerType === 'symbol') {
|
|
54
|
-
if (propertyKey === 'text-field' && style && !style.glyphs) {
|
|
59
|
+
if (propertyKey === 'text-field' && style && !style.glyphs && !style.imports) {
|
|
55
60
|
errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
|
|
56
61
|
}
|
|
57
62
|
if (propertyKey === 'text-font' && isFunction(deepUnbundle(value)) && unbundle(value.type) === 'identity') {
|
|
58
63
|
errors.push(new ValidationError(key, value, '"text-font" does not support identity functions'));
|
|
59
64
|
}
|
|
65
|
+
} else if (options.layerType === 'model' && propertyType === 'paint' && layer && layer.layout && layer.layout.hasOwnProperty('model-id')) {
|
|
66
|
+
if (supportsPropertyExpression(valueSpec) && (supportsLightExpression(valueSpec) || supportsZoomExpression(valueSpec))) {
|
|
67
|
+
// Performance related style spec limitation: zoom and light expressions are not allowed for e.g. trees.
|
|
68
|
+
const expression = createPropertyExpression(deepUnbundle(value), valueSpec);
|
|
69
|
+
const expressionObj = (expression.value: any).expression || (expression.value: any)._styleExpression.expression;
|
|
70
|
+
if (expressionObj && (!isGlobalPropertyConstant(expressionObj, ['zoom']) || !isGlobalPropertyConstant(expressionObj, ['measure-light']))) {
|
|
71
|
+
errors.push(new ValidationError(key, value, `${propertyKey} does not support zoom or measure-light expressions when the model layer source is vector tile or GeoJSON.`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
60
74
|
}
|
|
61
75
|
|
|
62
76
|
return errors.concat(validate({
|
|
@@ -8,6 +8,7 @@ import validateExpression from './validate_expression.js';
|
|
|
8
8
|
import validateString from './validate_string.js';
|
|
9
9
|
import getType from '../util/get_type.js';
|
|
10
10
|
|
|
11
|
+
import type {StyleReference} from '../reference/latest.js';
|
|
11
12
|
import type {ValidationOptions} from './validate.js';
|
|
12
13
|
|
|
13
14
|
const objectElementValidators = {
|
|
@@ -101,7 +102,7 @@ export default function validateSource(options: ValidationOptions): Array<Valida
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
function getSourceTypeValues(styleSpec) {
|
|
105
|
+
function getSourceTypeValues(styleSpec: StyleReference) {
|
|
105
106
|
return styleSpec.source.reduce((memo, source) => {
|
|
106
107
|
const sourceType = styleSpec[source];
|
|
107
108
|
if (sourceType.type.type === 'enum') {
|
|
@@ -111,7 +112,7 @@ function getSourceTypeValues(styleSpec) {
|
|
|
111
112
|
}, []);
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
function validatePromoteId({key, value}) {
|
|
115
|
+
function validatePromoteId({key, value}: $Shape<ValidationOptions>) {
|
|
115
116
|
if (getType(value) === 'string') {
|
|
116
117
|
return validateString({key, value});
|
|
117
118
|
} else {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import validate from './validate.js';
|
|
3
|
+
import latestStyleSpec from '../reference/latest.js';
|
|
4
|
+
import validateGlyphsURL from './validate_glyphs_url.js';
|
|
5
|
+
|
|
6
|
+
import ValidationError from '../error/validation_error.js';
|
|
7
|
+
|
|
8
|
+
import type {ValidationOptions} from './validate.js';
|
|
9
|
+
import type {StyleSpecification} from '../types.js';
|
|
10
|
+
|
|
11
|
+
type StyleValidationOptions = {
|
|
12
|
+
key?: ValidationOptions["key"]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function validateStyle(style: StyleSpecification, styleSpec: Object = latestStyleSpec, options: StyleValidationOptions = {}): ValidationError[] {
|
|
16
|
+
const errors = validate({
|
|
17
|
+
key: options.key || '',
|
|
18
|
+
value: style,
|
|
19
|
+
valueSpec: styleSpec.$root,
|
|
20
|
+
styleSpec,
|
|
21
|
+
style,
|
|
22
|
+
objectElementValidators: {
|
|
23
|
+
glyphs: validateGlyphsURL,
|
|
24
|
+
'*': () => []
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return errors;
|
|
29
|
+
}
|
|
@@ -36,7 +36,7 @@ function getAllowedKeyErrors(obj: Object, keys: Array<*>, path: ?string): Array<
|
|
|
36
36
|
return errors;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const acceptedSourceTypes = new Set(["vector", "raster", "raster-dem"]);
|
|
39
|
+
const acceptedSourceTypes = new Set(["vector", "raster", "raster-dem", "model", "batched-model"]);
|
|
40
40
|
function getSourceErrors(source: Object, i: number): Array<ValidationError> {
|
|
41
41
|
const errors = [];
|
|
42
42
|
|
|
@@ -68,26 +68,58 @@ function getSourceErrors(source: Object, i: number): Array<ValidationError> {
|
|
|
68
68
|
return errors;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
function
|
|
71
|
+
function getMaxSourcesErrors(sourcesCount: number): Array<ValidationError> {
|
|
72
72
|
const errors = [];
|
|
73
|
-
|
|
73
|
+
if (sourcesCount > MAX_SOURCES_IN_STYLE) {
|
|
74
|
+
errors.push(new ValidationError('sources', null, `Styles must contain ${MAX_SOURCES_IN_STYLE} or fewer sources`));
|
|
75
|
+
}
|
|
76
|
+
return errors;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getSourcesErrors(sources: Object): {errors: Array<ValidationError>, sourcesCount: number} {
|
|
80
|
+
const errors = [];
|
|
81
|
+
let sourcesCount = 0;
|
|
74
82
|
|
|
75
83
|
Object.keys(sources).forEach((s: string, i: number) => {
|
|
76
84
|
const sourceErrors = getSourceErrors(sources[s], i);
|
|
77
85
|
|
|
78
86
|
// If source has errors, skip counting
|
|
79
87
|
if (!sourceErrors.length) {
|
|
80
|
-
|
|
88
|
+
sourcesCount = sourcesCount + getSourceCount(sources[s]);
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
errors.push(...sourceErrors);
|
|
84
92
|
});
|
|
85
93
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
94
|
+
return {errors, sourcesCount};
|
|
95
|
+
}
|
|
89
96
|
|
|
90
|
-
|
|
97
|
+
function getImportErrors(imports: Array<Object> = []): {errors: Array<ValidationError>, sourcesCount: number} {
|
|
98
|
+
let errors: Array<ValidationError> = [];
|
|
99
|
+
|
|
100
|
+
let sourcesCount = 0;
|
|
101
|
+
const validateImports = (imports: Array<Object> = []) => {
|
|
102
|
+
for (const importSpec of imports) {
|
|
103
|
+
const style = importSpec.data;
|
|
104
|
+
if (!style) continue;
|
|
105
|
+
|
|
106
|
+
if (style.imports) {
|
|
107
|
+
validateImports(style.imports);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
errors = errors.concat(getRootErrors(style, Object.keys(v8.$root)));
|
|
111
|
+
|
|
112
|
+
if (style.sources) {
|
|
113
|
+
const sourcesErrors = getSourcesErrors(style.sources);
|
|
114
|
+
sourcesCount += sourcesErrors.sourcesCount;
|
|
115
|
+
errors = errors.concat(sourcesErrors.errors);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
validateImports(imports);
|
|
121
|
+
|
|
122
|
+
return {errors, sourcesCount};
|
|
91
123
|
}
|
|
92
124
|
|
|
93
125
|
function getRootErrors(style: Object, specKeys: Array<any>): Array<ValidationError> {
|
|
@@ -109,7 +141,9 @@ function getRootErrors(style: Object, specKeys: Array<any>): Array<ValidationErr
|
|
|
109
141
|
'created',
|
|
110
142
|
'modified',
|
|
111
143
|
'visibility',
|
|
112
|
-
'protected'
|
|
144
|
+
'protected',
|
|
145
|
+
'models',
|
|
146
|
+
'lights'
|
|
113
147
|
];
|
|
114
148
|
|
|
115
149
|
const allowedKeyErrors = getAllowedKeyErrors(style, [...specKeys, ...optionalRootProperties]);
|
|
@@ -178,10 +212,20 @@ export default function validateMapboxApiSupported(style: Object, styleSpec: Obj
|
|
|
178
212
|
let errors = validateStyle(s, styleSpec)
|
|
179
213
|
.concat(getRootErrors(s, Object.keys(v8.$root)));
|
|
180
214
|
|
|
215
|
+
let sourcesCount = 0;
|
|
181
216
|
if (s.sources) {
|
|
182
|
-
|
|
217
|
+
const sourcesErrors = getSourcesErrors(s.sources);
|
|
218
|
+
sourcesCount += sourcesErrors.sourcesCount;
|
|
219
|
+
errors = errors.concat(sourcesErrors.errors);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (s.imports) {
|
|
223
|
+
const importsErrors = getImportErrors(s.imports);
|
|
224
|
+
sourcesCount += importsErrors.sourcesCount;
|
|
225
|
+
errors = errors.concat(importsErrors.errors);
|
|
183
226
|
}
|
|
184
227
|
|
|
228
|
+
errors = errors.concat(getMaxSourcesErrors(sourcesCount));
|
|
229
|
+
|
|
185
230
|
return errors;
|
|
186
231
|
}
|
|
187
|
-
|
package/validate_style.js
CHANGED
|
@@ -36,9 +36,13 @@ export default function validateStyle(style: StyleSpecification | string | Buffe
|
|
|
36
36
|
|
|
37
37
|
export {
|
|
38
38
|
validateSource as source,
|
|
39
|
+
validateModel as model,
|
|
39
40
|
validateLight as light,
|
|
40
41
|
validateLayer as layer,
|
|
41
42
|
validateFilter as filter,
|
|
43
|
+
validateLights as lights,
|
|
44
|
+
validateTerrain as terrain,
|
|
45
|
+
validateFog as fog,
|
|
42
46
|
validatePaintProperty as paintProperty,
|
|
43
47
|
validateLayoutProperty as layoutProperty
|
|
44
48
|
} from './validate_style.min.js';
|