This commit is contained in:
91
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate.js
generated
vendored
Normal file
91
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// @flow
|
||||
|
||||
import extend from '../util/extend.js';
|
||||
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
||||
import {isExpression} from '../expression/index.js';
|
||||
import {isFunction} from '../function/index.js';
|
||||
|
||||
import validateFunction from './validate_function.js';
|
||||
import validateExpression from './validate_expression.js';
|
||||
import validateObject from './validate_object.js';
|
||||
import validateArray from './validate_array.js';
|
||||
import validateBoolean from './validate_boolean.js';
|
||||
import validateNumber from './validate_number.js';
|
||||
import validateColor from './validate_color.js';
|
||||
import validateEnum from './validate_enum.js';
|
||||
import validateFilter from './validate_filter.js';
|
||||
import validateLayer from './validate_layer.js';
|
||||
import validateSource from './validate_source.js';
|
||||
import validateLight from './validate_light.js';
|
||||
import validateTerrain from './validate_terrain.js';
|
||||
import validateFog from './validate_fog.js';
|
||||
import validateString from './validate_string.js';
|
||||
import validateFormatted from './validate_formatted.js';
|
||||
import validateImage from './validate_image.js';
|
||||
import validateProjection from './validate_projection.js';
|
||||
|
||||
import type {StyleReference} from '../reference/latest.js';
|
||||
import type {StyleSpecification} from '../types.js';
|
||||
import type ValidationError from '../error/validation_error.js';
|
||||
|
||||
const VALIDATORS = {
|
||||
'*'() {
|
||||
return [];
|
||||
},
|
||||
'array': validateArray,
|
||||
'boolean': validateBoolean,
|
||||
'number': validateNumber,
|
||||
'color': validateColor,
|
||||
'enum': validateEnum,
|
||||
'filter': validateFilter,
|
||||
'function': validateFunction,
|
||||
'layer': validateLayer,
|
||||
'object': validateObject,
|
||||
'source': validateSource,
|
||||
'light': validateLight,
|
||||
'terrain': validateTerrain,
|
||||
'fog': validateFog,
|
||||
'string': validateString,
|
||||
'formatted': validateFormatted,
|
||||
'resolvedImage': validateImage,
|
||||
'projection': validateProjection
|
||||
};
|
||||
|
||||
// Main recursive validation function. Tracks:
|
||||
//
|
||||
// - key: string representing location of validation in style tree. Used only
|
||||
// for more informative error reporting.
|
||||
// - value: current value from style being evaluated. May be anything from a
|
||||
// high level object that needs to be descended into deeper or a simple
|
||||
// scalar value.
|
||||
// - valueSpec: current spec being evaluated. Tracks value.
|
||||
// - styleSpec: current full spec being evaluated.
|
||||
export type ValidationOptions = {
|
||||
key: string;
|
||||
value: Object;
|
||||
valueSpec: Object;
|
||||
style: $Shape<StyleSpecification>;
|
||||
styleSpec: StyleReference;
|
||||
}
|
||||
|
||||
export default function validate(options: ValidationOptions): Array<ValidationError> {
|
||||
const value = options.value;
|
||||
const valueSpec = options.valueSpec;
|
||||
const styleSpec = options.styleSpec;
|
||||
|
||||
if (valueSpec.expression && isFunction(unbundle(value))) {
|
||||
return validateFunction(options);
|
||||
|
||||
} else if (valueSpec.expression && isExpression(deepUnbundle(value))) {
|
||||
return validateExpression(options);
|
||||
|
||||
} else if (valueSpec.type && VALIDATORS[valueSpec.type]) {
|
||||
return VALIDATORS[valueSpec.type](options);
|
||||
|
||||
} else {
|
||||
const valid = validateObject(extend({}, options, {
|
||||
valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec
|
||||
}));
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
62
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_array.js
generated
vendored
Normal file
62
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_array.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// @flow
|
||||
|
||||
import getType from '../util/get_type.js';
|
||||
import validate from './validate.js';
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
type Options = ValidationOptions & {
|
||||
arrayElementValidator: Function;
|
||||
};
|
||||
|
||||
export default function validateArray(options: Options): Array<ValidationError> {
|
||||
const array = options.value;
|
||||
const arraySpec = options.valueSpec;
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
const key = options.key;
|
||||
const validateArrayElement = options.arrayElementValidator || validate;
|
||||
|
||||
if (getType(array) !== 'array') {
|
||||
return [new ValidationError(key, array, `array expected, ${getType(array)} found`)];
|
||||
}
|
||||
|
||||
if (arraySpec.length && array.length !== arraySpec.length) {
|
||||
return [new ValidationError(key, array, `array length ${arraySpec.length} expected, length ${array.length} found`)];
|
||||
}
|
||||
|
||||
if (arraySpec['min-length'] && array.length < arraySpec['min-length']) {
|
||||
return [new ValidationError(key, array, `array length at least ${arraySpec['min-length']} expected, length ${array.length} found`)];
|
||||
}
|
||||
|
||||
let arrayElementSpec = {
|
||||
"type": arraySpec.value,
|
||||
"values": arraySpec.values,
|
||||
"minimum": arraySpec.minimum,
|
||||
"maximum": arraySpec.maximum,
|
||||
function: undefined
|
||||
};
|
||||
|
||||
if (styleSpec.$version < 7) {
|
||||
arrayElementSpec.function = arraySpec.function;
|
||||
}
|
||||
|
||||
if (getType(arraySpec.value) === 'object') {
|
||||
arrayElementSpec = arraySpec.value;
|
||||
}
|
||||
|
||||
let errors = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
errors = errors.concat(validateArrayElement({
|
||||
array,
|
||||
arrayIndex: i,
|
||||
value: array[i],
|
||||
valueSpec: arrayElementSpec,
|
||||
style,
|
||||
styleSpec,
|
||||
key: `${key}[${i}]`
|
||||
}));
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
18
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_boolean.js
generated
vendored
Normal file
18
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_boolean.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import getType from '../util/get_type.js';
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateBoolean(options: ValidationOptions): Array<ValidationError> {
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
const type = getType(value);
|
||||
|
||||
if (type !== 'boolean') {
|
||||
return [new ValidationError(key, value, `boolean expected, ${type} found`)];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
23
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_color.js
generated
vendored
Normal file
23
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_color.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import {parseCSSColor} from 'csscolorparser';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateColor(options: ValidationOptions): Array<ValidationError> {
|
||||
const key = options.key;
|
||||
const value = options.value;
|
||||
const type = getType(value);
|
||||
|
||||
if (type !== 'string') {
|
||||
return [new ValidationError(key, value, `color expected, ${type} found`)];
|
||||
}
|
||||
|
||||
if (parseCSSColor(value) === null) {
|
||||
return [new ValidationError(key, value, `color expected, "${value}" found`)];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
24
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_enum.js
generated
vendored
Normal file
24
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_enum.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import {unbundle} from '../util/unbundle_jsonlint.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateEnum(options: ValidationOptions): Array<ValidationError> {
|
||||
const key = options.key;
|
||||
const value = options.value;
|
||||
const valueSpec = options.valueSpec;
|
||||
const errors = [];
|
||||
|
||||
if (Array.isArray(valueSpec.values)) { // <=v7
|
||||
if (valueSpec.values.indexOf(unbundle(value)) === -1) {
|
||||
errors.push(new ValidationError(key, value, `expected one of [${valueSpec.values.join(', ')}], ${JSON.stringify(value)} found`));
|
||||
}
|
||||
} else { // >=v8
|
||||
if (Object.keys(valueSpec.values).indexOf(unbundle(value)) === -1) {
|
||||
errors.push(new ValidationError(key, value, `expected one of [${Object.keys(valueSpec.values).join(', ')}], ${JSON.stringify(value)} found`));
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
77
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_expression.js
generated
vendored
Normal file
77
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_expression.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
|
||||
import {createExpression, createPropertyExpression} from '../expression/index.js';
|
||||
import {deepUnbundle} from '../util/unbundle_jsonlint.js';
|
||||
import {isStateConstant, isGlobalPropertyConstant, isFeatureConstant} from '../expression/is_constant.js';
|
||||
import CompoundExpression from '../expression/compound_expression.js';
|
||||
|
||||
import type {Expression} from '../expression/expression.js';
|
||||
|
||||
export default function validateExpression(options: any): Array<ValidationError> {
|
||||
const expression = (options.expressionContext === 'property' ? createPropertyExpression : createExpression)(deepUnbundle(options.value), options.valueSpec);
|
||||
if (expression.result === 'error') {
|
||||
return expression.value.map((error) => {
|
||||
return new ValidationError(`${options.key}${error.key}`, options.value, error.message);
|
||||
});
|
||||
}
|
||||
|
||||
const expressionObj = (expression.value: any).expression || (expression.value: any)._styleExpression.expression;
|
||||
|
||||
if (options.expressionContext === 'property' && (options.propertyKey === 'text-font') &&
|
||||
!expressionObj.outputDefined()) {
|
||||
return [new ValidationError(options.key, options.value, `Invalid data expression for "${options.propertyKey}". Output values must be contained as literals within the expression.`)];
|
||||
}
|
||||
|
||||
if (options.expressionContext === 'property' && options.propertyType === 'layout' &&
|
||||
(!isStateConstant(expressionObj))) {
|
||||
return [new ValidationError(options.key, options.value, '"feature-state" data expressions are not supported with layout properties.')];
|
||||
}
|
||||
|
||||
if (options.expressionContext === 'filter') {
|
||||
return disallowedFilterParameters(expressionObj, options);
|
||||
}
|
||||
|
||||
if (options.expressionContext && options.expressionContext.indexOf('cluster') === 0) {
|
||||
if (!isGlobalPropertyConstant(expressionObj, ['zoom', 'feature-state'])) {
|
||||
return [new ValidationError(options.key, options.value, '"zoom" and "feature-state" expressions are not supported with cluster properties.')];
|
||||
}
|
||||
if (options.expressionContext === 'cluster-initial' && !isFeatureConstant(expressionObj)) {
|
||||
return [new ValidationError(options.key, options.value, 'Feature data expressions are not supported with initial expression part of cluster properties.')];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export function disallowedFilterParameters(e: Expression, options: any): Array<ValidationError> {
|
||||
const disallowedParameters = new Set([
|
||||
'zoom',
|
||||
'feature-state',
|
||||
'pitch',
|
||||
'distance-from-center'
|
||||
]);
|
||||
|
||||
if (options.valueSpec && options.valueSpec.expression) {
|
||||
for (const param of options.valueSpec.expression.parameters) {
|
||||
disallowedParameters.delete(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (disallowedParameters.size === 0) {
|
||||
return [];
|
||||
}
|
||||
const errors = [];
|
||||
|
||||
if (e instanceof CompoundExpression) {
|
||||
if (disallowedParameters.has(e.name)) {
|
||||
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}`)];
|
||||
}
|
||||
}
|
||||
e.eachChild((arg) => {
|
||||
errors.push(...disallowedFilterParameters(arg, options));
|
||||
});
|
||||
|
||||
return errors;
|
||||
}
|
||||
127
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_filter.js
generated
vendored
Normal file
127
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_filter.js
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import validateExpression from './validate_expression.js';
|
||||
import validateEnum from './validate_enum.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
||||
import extend from '../util/extend.js';
|
||||
import {isExpressionFilter} from '../feature_filter/index.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
type Options = ValidationOptions & {
|
||||
layerType: string;
|
||||
}
|
||||
|
||||
export default function validateFilter(options: Options): Array<ValidationError> {
|
||||
if (isExpressionFilter(deepUnbundle(options.value))) {
|
||||
// We default to a layerType of `fill` because that points to a non-dynamic filter definition within the style-spec.
|
||||
const layerType = options.layerType || 'fill';
|
||||
|
||||
return validateExpression(extend({}, options, {
|
||||
expressionContext: 'filter',
|
||||
valueSpec: options.styleSpec[`filter_${layerType}`]
|
||||
}));
|
||||
} else {
|
||||
return validateNonExpressionFilter(options);
|
||||
}
|
||||
}
|
||||
|
||||
function validateNonExpressionFilter(options) {
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
|
||||
if (getType(value) !== 'array') {
|
||||
return [new ValidationError(key, value, `array expected, ${getType(value)} found`)];
|
||||
}
|
||||
|
||||
const styleSpec = options.styleSpec;
|
||||
let type;
|
||||
|
||||
let errors = [];
|
||||
|
||||
if (value.length < 1) {
|
||||
return [new ValidationError(key, value, 'filter array must have at least 1 element')];
|
||||
}
|
||||
|
||||
errors = errors.concat(validateEnum({
|
||||
key: `${key}[0]`,
|
||||
value: value[0],
|
||||
valueSpec: styleSpec.filter_operator,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
}));
|
||||
|
||||
switch (unbundle(value[0])) {
|
||||
case '<':
|
||||
case '<=':
|
||||
case '>':
|
||||
case '>=':
|
||||
if (value.length >= 2 && unbundle(value[1]) === '$type') {
|
||||
errors.push(new ValidationError(key, value, `"$type" cannot be use with operator "${value[0]}"`));
|
||||
}
|
||||
/* falls through */
|
||||
case '==':
|
||||
case '!=':
|
||||
if (value.length !== 3) {
|
||||
errors.push(new ValidationError(key, value, `filter array for operator "${value[0]}" must have 3 elements`));
|
||||
}
|
||||
/* falls through */
|
||||
case 'in':
|
||||
case '!in':
|
||||
if (value.length >= 2) {
|
||||
type = getType(value[1]);
|
||||
if (type !== 'string') {
|
||||
errors.push(new ValidationError(`${key}[1]`, value[1], `string expected, ${type} found`));
|
||||
}
|
||||
}
|
||||
for (let i = 2; i < value.length; i++) {
|
||||
type = getType(value[i]);
|
||||
if (unbundle(value[1]) === '$type') {
|
||||
errors = errors.concat(validateEnum({
|
||||
key: `${key}[${i}]`,
|
||||
value: value[i],
|
||||
valueSpec: styleSpec.geometry_type,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
}));
|
||||
} else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
|
||||
errors.push(new ValidationError(`${key}[${i}]`, value[i], `string, number, or boolean expected, ${type} found`));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'any':
|
||||
case 'all':
|
||||
case 'none':
|
||||
for (let i = 1; i < value.length; i++) {
|
||||
errors = errors.concat(validateNonExpressionFilter({
|
||||
key: `${key}[${i}]`,
|
||||
value: value[i],
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
}));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'has':
|
||||
case '!has':
|
||||
type = getType(value[1]);
|
||||
if (value.length !== 2) {
|
||||
errors.push(new ValidationError(key, value, `filter array for "${value[0]}" operator must have 2 elements`));
|
||||
} else if (type !== 'string') {
|
||||
errors.push(new ValidationError(`${key}[1]`, value[1], `string expected, ${type} found`));
|
||||
}
|
||||
break;
|
||||
case 'within':
|
||||
type = getType(value[1]);
|
||||
if (value.length !== 2) {
|
||||
errors.push(new ValidationError(key, value, `filter array for "${value[0]}" operator must have 2 elements`));
|
||||
} else if (type !== 'object') {
|
||||
errors.push(new ValidationError(`${key}[1]`, value[1], `object expected, ${type} found`));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
49
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_fog.js
generated
vendored
Normal file
49
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_fog.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import validate from './validate.js';
|
||||
import getType from '../util/get_type.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateFog(options: ValidationOptions): Array<ValidationError> {
|
||||
const fog = options.value;
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
const fogSpec = styleSpec.fog;
|
||||
let errors = [];
|
||||
|
||||
const rootType = getType(fog);
|
||||
if (fog === undefined) {
|
||||
return errors;
|
||||
} else if (rootType !== 'object') {
|
||||
errors = errors.concat([new ValidationError('fog', fog, `object expected, ${rootType} found`)]);
|
||||
return errors;
|
||||
}
|
||||
|
||||
for (const key in fog) {
|
||||
const transitionMatch = key.match(/^(.*)-transition$/);
|
||||
|
||||
if (transitionMatch && fogSpec[transitionMatch[1]] && fogSpec[transitionMatch[1]].transition) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: fog[key],
|
||||
valueSpec: styleSpec.transition,
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else if (fogSpec[key]) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: fog[key],
|
||||
valueSpec: fogSpec[key],
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else {
|
||||
errors = errors.concat([new ValidationError(key, fog[key], `unknown property "${key}"`)]);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
15
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_formatted.js
generated
vendored
Normal file
15
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_formatted.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// @flow
|
||||
|
||||
import validateExpression from './validate_expression.js';
|
||||
import validateString from './validate_string.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
import type ValidationError from '../error/validation_error.js';
|
||||
|
||||
export default function validateFormatted(options: ValidationOptions): Array<ValidationError> {
|
||||
if (validateString(options).length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return validateExpression(options);
|
||||
}
|
||||
216
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_function.js
generated
vendored
Normal file
216
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_function.js
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import validate from './validate.js';
|
||||
import validateObject from './validate_object.js';
|
||||
import validateArray from './validate_array.js';
|
||||
import validateNumber from './validate_number.js';
|
||||
import {isExpression} from '../expression/index.js';
|
||||
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
||||
import {
|
||||
supportsPropertyExpression,
|
||||
supportsZoomExpression,
|
||||
supportsInterpolation
|
||||
} from '../util/properties.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateFunction(options: ValidationOptions): any {
|
||||
const functionValueSpec = options.valueSpec;
|
||||
const functionType = unbundle(options.value.type);
|
||||
let stopKeyType;
|
||||
let stopDomainValues: {[string | number]: boolean} = {};
|
||||
let previousStopDomainValue;
|
||||
let previousStopDomainZoom;
|
||||
|
||||
const isZoomFunction = functionType !== 'categorical' && options.value.property === undefined;
|
||||
const isPropertyFunction = !isZoomFunction;
|
||||
const isZoomAndPropertyFunction =
|
||||
getType(options.value.stops) === 'array' &&
|
||||
getType(options.value.stops[0]) === 'array' &&
|
||||
getType(options.value.stops[0][0]) === 'object';
|
||||
|
||||
const errors = validateObject({
|
||||
key: options.key,
|
||||
value: options.value,
|
||||
valueSpec: options.styleSpec.function,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
objectElementValidators: {
|
||||
stops: validateFunctionStops,
|
||||
default: validateFunctionDefault
|
||||
}
|
||||
});
|
||||
|
||||
if (functionType === 'identity' && isZoomFunction) {
|
||||
errors.push(new ValidationError(options.key, options.value, 'missing required property "property"'));
|
||||
}
|
||||
|
||||
if (functionType !== 'identity' && !options.value.stops) {
|
||||
errors.push(new ValidationError(options.key, options.value, 'missing required property "stops"'));
|
||||
}
|
||||
|
||||
if (functionType === 'exponential' && options.valueSpec.expression && !supportsInterpolation(options.valueSpec)) {
|
||||
errors.push(new ValidationError(options.key, options.value, 'exponential functions not supported'));
|
||||
}
|
||||
|
||||
if (options.styleSpec.$version >= 8) {
|
||||
if (isPropertyFunction && !supportsPropertyExpression(options.valueSpec)) {
|
||||
errors.push(new ValidationError(options.key, options.value, 'property functions not supported'));
|
||||
} else if (isZoomFunction && !supportsZoomExpression(options.valueSpec)) {
|
||||
errors.push(new ValidationError(options.key, options.value, 'zoom functions not supported'));
|
||||
}
|
||||
}
|
||||
|
||||
if ((functionType === 'categorical' || isZoomAndPropertyFunction) && options.value.property === undefined) {
|
||||
errors.push(new ValidationError(options.key, options.value, '"property" property is required'));
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
||||
function validateFunctionStops(options: ValidationOptions) {
|
||||
if (functionType === 'identity') {
|
||||
return [new ValidationError(options.key, options.value, 'identity function may not have a "stops" property')];
|
||||
}
|
||||
|
||||
let errors = [];
|
||||
const value = options.value;
|
||||
|
||||
errors = errors.concat(validateArray({
|
||||
key: options.key,
|
||||
value,
|
||||
valueSpec: options.valueSpec,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
arrayElementValidator: validateFunctionStop
|
||||
}));
|
||||
|
||||
if (getType(value) === 'array' && value.length === 0) {
|
||||
errors.push(new ValidationError(options.key, value, 'array must have at least one stop'));
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
function validateFunctionStop(options: ValidationOptions) {
|
||||
let errors = [];
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
|
||||
if (getType(value) !== 'array') {
|
||||
return [new ValidationError(key, value, `array expected, ${getType(value)} found`)];
|
||||
}
|
||||
|
||||
if (value.length !== 2) {
|
||||
return [new ValidationError(key, value, `array length 2 expected, length ${value.length} found`)];
|
||||
}
|
||||
|
||||
if (isZoomAndPropertyFunction) {
|
||||
if (getType(value[0]) !== 'object') {
|
||||
return [new ValidationError(key, value, `object expected, ${getType(value[0])} found`)];
|
||||
}
|
||||
if (value[0].zoom === undefined) {
|
||||
return [new ValidationError(key, value, 'object stop key must have zoom')];
|
||||
}
|
||||
if (value[0].value === undefined) {
|
||||
return [new ValidationError(key, value, 'object stop key must have value')];
|
||||
}
|
||||
|
||||
const nextStopDomainZoom = unbundle(value[0].zoom);
|
||||
if (typeof nextStopDomainZoom !== 'number') {
|
||||
return [new ValidationError(key, value[0].zoom, 'stop zoom values must be numbers')];
|
||||
}
|
||||
|
||||
if (previousStopDomainZoom && previousStopDomainZoom > nextStopDomainZoom) {
|
||||
return [new ValidationError(key, value[0].zoom, 'stop zoom values must appear in ascending order')];
|
||||
}
|
||||
if (nextStopDomainZoom !== previousStopDomainZoom) {
|
||||
previousStopDomainZoom = nextStopDomainZoom;
|
||||
previousStopDomainValue = undefined;
|
||||
stopDomainValues = {};
|
||||
}
|
||||
errors = errors.concat(validateObject({
|
||||
key: `${key}[0]`,
|
||||
value: value[0],
|
||||
valueSpec: {zoom: {}},
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
objectElementValidators: {zoom: validateNumber, value: validateStopDomainValue}
|
||||
}));
|
||||
} else {
|
||||
errors = errors.concat(validateStopDomainValue({
|
||||
key: `${key}[0]`,
|
||||
value: value[0],
|
||||
valueSpec: {},
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
}, value));
|
||||
}
|
||||
|
||||
if (isExpression(deepUnbundle(value[1]))) {
|
||||
return errors.concat([new ValidationError(`${key}[1]`, value[1], 'expressions are not allowed in function stops.')]);
|
||||
}
|
||||
|
||||
return errors.concat(validate({
|
||||
key: `${key}[1]`,
|
||||
value: value[1],
|
||||
valueSpec: functionValueSpec,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
}));
|
||||
}
|
||||
|
||||
function validateStopDomainValue(options: ValidationOptions, stop) {
|
||||
const type = getType(options.value);
|
||||
const value = unbundle(options.value);
|
||||
|
||||
const reportValue = options.value !== null ? options.value : stop;
|
||||
|
||||
if (!stopKeyType) {
|
||||
stopKeyType = type;
|
||||
} else if (type !== stopKeyType) {
|
||||
return [new ValidationError(options.key, reportValue, `${type} stop domain type must match previous stop domain type ${stopKeyType}`)];
|
||||
}
|
||||
|
||||
if (type !== 'number' && type !== 'string' && type !== 'boolean' && typeof value !== 'number' && typeof value !== 'string' && typeof value !== 'boolean') {
|
||||
return [new ValidationError(options.key, reportValue, 'stop domain value must be a number, string, or boolean')];
|
||||
}
|
||||
|
||||
if (type !== 'number' && functionType !== 'categorical') {
|
||||
let message = `number expected, ${type} found`;
|
||||
if (supportsPropertyExpression(functionValueSpec) && functionType === undefined) {
|
||||
message += '\nIf you intended to use a categorical function, specify `"type": "categorical"`.';
|
||||
}
|
||||
return [new ValidationError(options.key, reportValue, message)];
|
||||
}
|
||||
|
||||
if (functionType === 'categorical' && type === 'number' && (typeof value !== 'number' || !isFinite(value) || Math.floor(value) !== value)) {
|
||||
return [new ValidationError(options.key, reportValue, `integer expected, found ${String(value)}`)];
|
||||
}
|
||||
|
||||
if (functionType !== 'categorical' && type === 'number' && typeof value === 'number' && typeof previousStopDomainValue === 'number' && previousStopDomainValue !== undefined && value < previousStopDomainValue) {
|
||||
return [new ValidationError(options.key, reportValue, 'stop domain values must appear in ascending order')];
|
||||
} else {
|
||||
previousStopDomainValue = value;
|
||||
}
|
||||
|
||||
if (functionType === 'categorical' && (value: any) in stopDomainValues) {
|
||||
return [new ValidationError(options.key, reportValue, 'stop domain values must be unique')];
|
||||
} else {
|
||||
stopDomainValues[(value: any)] = true;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function validateFunctionDefault(options: ValidationOptions) {
|
||||
return validate({
|
||||
key: options.key,
|
||||
value: options.value,
|
||||
valueSpec: functionValueSpec,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec
|
||||
});
|
||||
}
|
||||
}
|
||||
24
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_glyphs_url.js
generated
vendored
Normal file
24
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_glyphs_url.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import validateString from './validate_string.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function(options: ValidationOptions): Array<ValidationError> {
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
|
||||
const errors = validateString(options);
|
||||
if (errors.length) return errors;
|
||||
|
||||
if (value.indexOf('{fontstack}') === -1) {
|
||||
errors.push(new ValidationError(key, value, '"glyphs" url must include a "{fontstack}" token'));
|
||||
}
|
||||
|
||||
if (value.indexOf('{range}') === -1) {
|
||||
errors.push(new ValidationError(key, value, '"glyphs" url must include a "{range}" token'));
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
15
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_image.js
generated
vendored
Normal file
15
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_image.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// @flow
|
||||
|
||||
import validateExpression from './validate_expression.js';
|
||||
import validateString from './validate_string.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
import type ValidationError from '../error/validation_error.js';
|
||||
|
||||
export default function validateImage(options: ValidationOptions): Array<ValidationError> {
|
||||
if (validateString(options).length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return validateExpression(options);
|
||||
}
|
||||
149
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_layer.js
generated
vendored
Normal file
149
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_layer.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import {unbundle} from '../util/unbundle_jsonlint.js';
|
||||
import validateObject from './validate_object.js';
|
||||
import validateFilter from './validate_filter.js';
|
||||
import validatePaintProperty from './validate_paint_property.js';
|
||||
import validateLayoutProperty from './validate_layout_property.js';
|
||||
import validateSpec from './validate.js';
|
||||
import extend from '../util/extend.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
import type {LayerSpecification} from '../types.js';
|
||||
|
||||
type Options = ValidationOptions & {
|
||||
value: LayerSpecification;
|
||||
arrayIndex: number;
|
||||
}
|
||||
|
||||
export default function validateLayer(options: Options): Array<ValidationError> {
|
||||
let errors = [];
|
||||
|
||||
const layer = options.value;
|
||||
const key = options.key;
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
|
||||
if (!layer.type && !layer.ref) {
|
||||
errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required'));
|
||||
}
|
||||
let type = unbundle(layer.type);
|
||||
const ref = unbundle(layer.ref);
|
||||
|
||||
if (layer.id) {
|
||||
const layerId = unbundle(layer.id);
|
||||
for (let i = 0; i < options.arrayIndex; i++) {
|
||||
const otherLayer = style.layers[i];
|
||||
if (unbundle(otherLayer.id) === layerId) {
|
||||
// $FlowFixMe[prop-missing] - id.__line__ is added dynamically during the readStyle step
|
||||
errors.push(new ValidationError(key, layer.id, `duplicate layer id "${layer.id}", previously used at line ${otherLayer.id.__line__}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ('ref' in layer) {
|
||||
['type', 'source', 'source-layer', 'filter', 'layout'].forEach((p) => {
|
||||
if (p in layer) {
|
||||
errors.push(new ValidationError(key, layer[p], `"${p}" is prohibited for ref layers`));
|
||||
}
|
||||
});
|
||||
|
||||
let parent;
|
||||
|
||||
style.layers.forEach((layer) => {
|
||||
if (unbundle(layer.id) === ref) parent = layer;
|
||||
});
|
||||
|
||||
if (!parent) {
|
||||
if (typeof ref === 'string')
|
||||
errors.push(new ValidationError(key, layer.ref, `ref layer "${ref}" not found`));
|
||||
} else if (parent.ref) {
|
||||
errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
|
||||
} else {
|
||||
type = unbundle(parent.type);
|
||||
}
|
||||
} else if (!(type === 'background' || type === 'sky')) {
|
||||
if (!layer.source) {
|
||||
errors.push(new ValidationError(key, layer, 'missing required property "source"'));
|
||||
} else {
|
||||
const source = style.sources && style.sources[layer.source];
|
||||
const sourceType = source && unbundle(source.type);
|
||||
if (!source) {
|
||||
errors.push(new ValidationError(key, layer.source, `source "${layer.source}" not found`));
|
||||
} else if (sourceType === 'vector' && type === 'raster') {
|
||||
errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a raster source`));
|
||||
} else if (sourceType === 'raster' && type !== 'raster') {
|
||||
errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a vector source`));
|
||||
} else if (sourceType === 'vector' && !layer['source-layer']) {
|
||||
errors.push(new ValidationError(key, layer, `layer "${layer.id}" must specify a "source-layer"`));
|
||||
} else if (sourceType === 'raster-dem' && type !== 'hillshade') {
|
||||
errors.push(new ValidationError(key, layer.source, 'raster-dem source can only be used with layer type \'hillshade\'.'));
|
||||
} else if (type === 'line' && layer.paint && (layer.paint['line-gradient'] || layer.paint['line-trim-offset']) &&
|
||||
(sourceType !== 'geojson' || !source.lineMetrics)) {
|
||||
errors.push(new ValidationError(key, layer, `layer "${layer.id}" specifies a line-gradient, which requires a GeoJSON source with \`lineMetrics\` enabled.`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errors = errors.concat(validateObject({
|
||||
key,
|
||||
value: layer,
|
||||
valueSpec: styleSpec.layer,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
objectElementValidators: {
|
||||
'*'() {
|
||||
return [];
|
||||
},
|
||||
// We don't want to enforce the spec's `"requires": true` for backward compatibility with refs;
|
||||
// the actual requirement is validated above. See https://github.com/mapbox/mapbox-gl-js/issues/5772.
|
||||
type() {
|
||||
return validateSpec({
|
||||
key: `${key}.type`,
|
||||
value: layer.type,
|
||||
valueSpec: styleSpec.layer.type,
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
object: layer,
|
||||
objectKey: 'type'
|
||||
});
|
||||
},
|
||||
filter(options) {
|
||||
return validateFilter(extend({layerType: type}, options));
|
||||
},
|
||||
layout(options) {
|
||||
return validateObject({
|
||||
layer,
|
||||
key: options.key,
|
||||
value: options.value,
|
||||
valueSpec: {},
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
objectElementValidators: {
|
||||
'*'(options) {
|
||||
return validateLayoutProperty(extend({layerType: type}, options));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
paint(options) {
|
||||
return validateObject({
|
||||
layer,
|
||||
key: options.key,
|
||||
value: options.value,
|
||||
valueSpec: {},
|
||||
style: options.style,
|
||||
styleSpec: options.styleSpec,
|
||||
objectElementValidators: {
|
||||
'*'(options) {
|
||||
return validatePaintProperty(extend({layerType: type}, options));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
return errors;
|
||||
}
|
||||
10
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_layout_property.js
generated
vendored
Normal file
10
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_layout_property.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import validateProperty from './validate_property.js';
|
||||
|
||||
import type ValidationError from '../error/validation_error.js';
|
||||
import type {PropertyValidationOptions} from './validate_property.js';
|
||||
|
||||
export default function validateLayoutProperty(options: PropertyValidationOptions): Array<ValidationError> {
|
||||
return validateProperty(options, 'layout');
|
||||
}
|
||||
50
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_light.js
generated
vendored
Normal file
50
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_light.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import validate from './validate.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateLight(options: ValidationOptions): Array<ValidationError> {
|
||||
const light = options.value;
|
||||
const styleSpec = options.styleSpec;
|
||||
const lightSpec = styleSpec.light;
|
||||
const style = options.style;
|
||||
|
||||
let errors = [];
|
||||
|
||||
const rootType = getType(light);
|
||||
if (light === undefined) {
|
||||
return errors;
|
||||
} else if (rootType !== 'object') {
|
||||
errors = errors.concat([new ValidationError('light', light, `object expected, ${rootType} found`)]);
|
||||
return errors;
|
||||
}
|
||||
|
||||
for (const key in light) {
|
||||
const transitionMatch = key.match(/^(.*)-transition$/);
|
||||
|
||||
if (transitionMatch && lightSpec[transitionMatch[1]] && lightSpec[transitionMatch[1]].transition) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: light[key],
|
||||
valueSpec: styleSpec.transition,
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else if (lightSpec[key]) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: light[key],
|
||||
valueSpec: lightSpec[key],
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else {
|
||||
errors = errors.concat([new ValidationError(key, light[key], `unknown property "${key}"`)]);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
50
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_number.js
generated
vendored
Normal file
50
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_number.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// @flow
|
||||
|
||||
import getType from '../util/get_type.js';
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
type Options = ValidationOptions & {
|
||||
arrayIndex: number;
|
||||
}
|
||||
|
||||
export default function validateNumber(options: Options): Array<ValidationError> {
|
||||
const key = options.key;
|
||||
const value = options.value;
|
||||
const valueSpec = options.valueSpec;
|
||||
let type = getType(value);
|
||||
|
||||
// eslint-disable-next-line no-self-compare
|
||||
if (type === 'number' && value !== value) {
|
||||
type = 'NaN';
|
||||
}
|
||||
|
||||
if (type !== 'number') {
|
||||
return [new ValidationError(key, value, `number expected, ${type} found`)];
|
||||
}
|
||||
|
||||
if ('minimum' in valueSpec) {
|
||||
let specMin = valueSpec.minimum;
|
||||
if (getType(valueSpec.minimum) === 'array') {
|
||||
const i = options.arrayIndex;
|
||||
specMin = valueSpec.minimum[i];
|
||||
}
|
||||
if (value < specMin) {
|
||||
return [new ValidationError(key, value, `${value} is less than the minimum value ${specMin}`)];
|
||||
}
|
||||
}
|
||||
|
||||
if ('maximum' in valueSpec) {
|
||||
let specMax = valueSpec.maximum;
|
||||
if (getType(valueSpec.maximum) === 'array') {
|
||||
const i = options.arrayIndex;
|
||||
specMax = valueSpec.maximum[i];
|
||||
}
|
||||
if (value > specMax) {
|
||||
return [new ValidationError(key, value, `${value} is greater than the maximum value ${specMax}`)];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
71
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_object.js
generated
vendored
Normal file
71
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_object.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import validateSpec from './validate.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
type Options = ValidationOptions & {
|
||||
objectElementValidators?: Function;
|
||||
};
|
||||
|
||||
export default function validateObject(options: Options): Array<ValidationError> {
|
||||
const key = options.key;
|
||||
const object = options.value;
|
||||
const elementSpecs = options.valueSpec || {};
|
||||
const elementValidators = options.objectElementValidators || {};
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
let errors = [];
|
||||
|
||||
const type = getType(object);
|
||||
if (type !== 'object') {
|
||||
return [new ValidationError(key, object, `object expected, ${type} found`)];
|
||||
}
|
||||
|
||||
for (const objectKey in object) {
|
||||
const elementSpecKey = objectKey.split('.')[0]; // treat 'paint.*' as 'paint'
|
||||
const elementSpec = elementSpecs[elementSpecKey] || elementSpecs['*'];
|
||||
|
||||
let validateElement;
|
||||
if (elementValidators[elementSpecKey]) {
|
||||
validateElement = elementValidators[elementSpecKey];
|
||||
} else if (elementSpecs[elementSpecKey]) {
|
||||
validateElement = validateSpec;
|
||||
} else if (elementValidators['*']) {
|
||||
validateElement = elementValidators['*'];
|
||||
} else if (elementSpecs['*']) {
|
||||
validateElement = validateSpec;
|
||||
}
|
||||
|
||||
if (!validateElement) {
|
||||
errors.push(new ValidationError(key, object[objectKey], `unknown property "${objectKey}"`));
|
||||
continue;
|
||||
}
|
||||
|
||||
errors = errors.concat(validateElement({
|
||||
key: (key ? `${key}.` : key) + objectKey,
|
||||
value: object[objectKey],
|
||||
valueSpec: elementSpec,
|
||||
style,
|
||||
styleSpec,
|
||||
object,
|
||||
objectKey
|
||||
// $FlowFixMe[extra-arg]
|
||||
}, object));
|
||||
}
|
||||
|
||||
for (const elementSpecKey in elementSpecs) {
|
||||
// Don't check `required` when there's a custom validator for that property.
|
||||
if (elementValidators[elementSpecKey]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (elementSpecs[elementSpecKey].required && elementSpecs[elementSpecKey]['default'] === undefined && object[elementSpecKey] === undefined) {
|
||||
errors.push(new ValidationError(key, object, `missing required property "${elementSpecKey}"`));
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
10
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_paint_property.js
generated
vendored
Normal file
10
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_paint_property.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import validateProperty from './validate_property.js';
|
||||
|
||||
import type ValidationError from '../error/validation_error.js';
|
||||
import type {PropertyValidationOptions} from './validate_property.js';
|
||||
|
||||
export default function validatePaintProperty(options: PropertyValidationOptions): Array<ValidationError> {
|
||||
return validateProperty(options, 'paint');
|
||||
}
|
||||
34
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_projection.js
generated
vendored
Normal file
34
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_projection.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import validate from './validate.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateProjection(options: ValidationOptions): Array<ValidationError> {
|
||||
const projection = options.value;
|
||||
const styleSpec = options.styleSpec;
|
||||
const projectionSpec = styleSpec.projection;
|
||||
const style = options.style;
|
||||
|
||||
let errors = [];
|
||||
|
||||
const rootType = getType(projection);
|
||||
|
||||
if (rootType === 'object') {
|
||||
for (const key in projection) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: projection[key],
|
||||
valueSpec: projectionSpec[key],
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
}
|
||||
} else if (rootType !== 'string') {
|
||||
errors = errors.concat([new ValidationError('projection', projection, `object or string expected, ${rootType} found`)]);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
72
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_property.js
generated
vendored
Normal file
72
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_property.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// @flow
|
||||
|
||||
import validate from './validate.js';
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import {isFunction} from '../function/index.js';
|
||||
import {unbundle, deepUnbundle} from '../util/unbundle_jsonlint.js';
|
||||
import {supportsPropertyExpression} from '../util/properties.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export type PropertyValidationOptions = ValidationOptions & {
|
||||
objectKey: string;
|
||||
layerType: string;
|
||||
}
|
||||
|
||||
export default function validateProperty(options: PropertyValidationOptions, propertyType: string): Array<ValidationError> {
|
||||
const key = options.key;
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
const value = options.value;
|
||||
const propertyKey = options.objectKey;
|
||||
const layerSpec = styleSpec[`${propertyType}_${options.layerType}`];
|
||||
|
||||
if (!layerSpec) return [];
|
||||
|
||||
const transitionMatch = propertyKey.match(/^(.*)-transition$/);
|
||||
if (propertyType === 'paint' && transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) {
|
||||
return validate({
|
||||
key,
|
||||
value,
|
||||
valueSpec: styleSpec.transition,
|
||||
style,
|
||||
styleSpec
|
||||
});
|
||||
}
|
||||
|
||||
const valueSpec = options.valueSpec || layerSpec[propertyKey];
|
||||
if (!valueSpec) {
|
||||
return [new ValidationError(key, value, `unknown property "${propertyKey}"`)];
|
||||
}
|
||||
|
||||
let tokenMatch;
|
||||
if (getType(value) === 'string' && supportsPropertyExpression(valueSpec) && !valueSpec.tokens && (tokenMatch = /^{([^}]+)}$/.exec(value))) {
|
||||
return [new ValidationError(
|
||||
key, value,
|
||||
`"${propertyKey}" does not support interpolation syntax\n` +
|
||||
`Use an identity property function instead: \`{ "type": "identity", "property": ${JSON.stringify(tokenMatch[1])} }\`.`)];
|
||||
}
|
||||
|
||||
const errors = [];
|
||||
|
||||
if (options.layerType === 'symbol') {
|
||||
if (propertyKey === 'text-field' && style && !style.glyphs) {
|
||||
errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
|
||||
}
|
||||
if (propertyKey === 'text-font' && isFunction(deepUnbundle(value)) && unbundle(value.type) === 'identity') {
|
||||
errors.push(new ValidationError(key, value, '"text-font" does not support identity functions'));
|
||||
}
|
||||
}
|
||||
|
||||
return errors.concat(validate({
|
||||
key: options.key,
|
||||
value,
|
||||
valueSpec,
|
||||
style,
|
||||
styleSpec,
|
||||
expressionContext: 'property',
|
||||
propertyType,
|
||||
propertyKey
|
||||
}));
|
||||
}
|
||||
124
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_source.js
generated
vendored
Normal file
124
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_source.js
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import {unbundle} from '../util/unbundle_jsonlint.js';
|
||||
import validateObject from './validate_object.js';
|
||||
import validateEnum from './validate_enum.js';
|
||||
import validateExpression from './validate_expression.js';
|
||||
import validateString from './validate_string.js';
|
||||
import getType from '../util/get_type.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
const objectElementValidators = {
|
||||
promoteId: validatePromoteId
|
||||
};
|
||||
|
||||
export default function validateSource(options: ValidationOptions): Array<ValidationError> {
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
const styleSpec = options.styleSpec;
|
||||
const style = options.style;
|
||||
|
||||
if (!value.type) {
|
||||
return [new ValidationError(key, value, '"type" is required')];
|
||||
}
|
||||
|
||||
const type = unbundle(value.type);
|
||||
let errors;
|
||||
|
||||
switch (type) {
|
||||
case 'vector':
|
||||
case 'raster':
|
||||
case 'raster-dem':
|
||||
errors = validateObject({
|
||||
key,
|
||||
value,
|
||||
valueSpec: styleSpec[`source_${type.replace('-', '_')}`],
|
||||
style: options.style,
|
||||
styleSpec,
|
||||
objectElementValidators
|
||||
});
|
||||
return errors;
|
||||
|
||||
case 'geojson':
|
||||
errors = validateObject({
|
||||
key,
|
||||
value,
|
||||
valueSpec: styleSpec.source_geojson,
|
||||
style,
|
||||
styleSpec,
|
||||
objectElementValidators
|
||||
});
|
||||
if (value.cluster) {
|
||||
for (const prop in value.clusterProperties) {
|
||||
const [operator, mapExpr] = value.clusterProperties[prop];
|
||||
const reduceExpr = typeof operator === 'string' ? [operator, ['accumulated'], ['get', prop]] : operator;
|
||||
|
||||
errors.push(...validateExpression({
|
||||
key: `${key}.${prop}.map`,
|
||||
value: mapExpr,
|
||||
expressionContext: 'cluster-map'
|
||||
}));
|
||||
errors.push(...validateExpression({
|
||||
key: `${key}.${prop}.reduce`,
|
||||
value: reduceExpr,
|
||||
expressionContext: 'cluster-reduce'
|
||||
}));
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
|
||||
case 'video':
|
||||
return validateObject({
|
||||
key,
|
||||
value,
|
||||
valueSpec: styleSpec.source_video,
|
||||
style,
|
||||
styleSpec
|
||||
});
|
||||
|
||||
case 'image':
|
||||
return validateObject({
|
||||
key,
|
||||
value,
|
||||
valueSpec: styleSpec.source_image,
|
||||
style,
|
||||
styleSpec
|
||||
});
|
||||
|
||||
case 'canvas':
|
||||
return [new ValidationError(key, null, `Please use runtime APIs to add canvas sources, rather than including them in stylesheets.`, 'source.canvas')];
|
||||
|
||||
default:
|
||||
return validateEnum({
|
||||
key: `${key}.type`,
|
||||
value: value.type,
|
||||
valueSpec: {values: getSourceTypeValues(styleSpec)},
|
||||
style,
|
||||
styleSpec
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceTypeValues(styleSpec) {
|
||||
return styleSpec.source.reduce((memo, source) => {
|
||||
const sourceType = styleSpec[source];
|
||||
if (sourceType.type.type === 'enum') {
|
||||
memo = memo.concat(Object.keys(sourceType.type.values));
|
||||
}
|
||||
return memo;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function validatePromoteId({key, value}) {
|
||||
if (getType(value) === 'string') {
|
||||
return validateString({key, value});
|
||||
} else {
|
||||
const errors = [];
|
||||
for (const prop in value) {
|
||||
errors.push(...validateString({key: `${key}.${prop}`, value: value[prop]}));
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
18
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_string.js
generated
vendored
Normal file
18
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_string.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import getType from '../util/get_type.js';
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateString(options: $Shape<ValidationOptions>): Array<ValidationError> {
|
||||
const value = options.value;
|
||||
const key = options.key;
|
||||
const type = getType(value);
|
||||
|
||||
if (type !== 'string') {
|
||||
return [new ValidationError(key, value, `string expected, ${type} found`)];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
63
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_terrain.js
generated
vendored
Normal file
63
node_modules/@mapbox/mapbox-gl-style-spec/validate/validate_terrain.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// @flow
|
||||
|
||||
import ValidationError from '../error/validation_error.js';
|
||||
import validate from './validate.js';
|
||||
import getType from '../util/get_type.js';
|
||||
import {unbundle} from '../util/unbundle_jsonlint.js';
|
||||
|
||||
import type {ValidationOptions} from './validate.js';
|
||||
|
||||
export default function validateTerrain(options: ValidationOptions): Array<ValidationError> {
|
||||
const terrain = options.value;
|
||||
const key = options.key;
|
||||
const style = options.style;
|
||||
const styleSpec = options.styleSpec;
|
||||
const terrainSpec = styleSpec.terrain;
|
||||
let errors = [];
|
||||
|
||||
const rootType = getType(terrain);
|
||||
if (terrain === undefined) {
|
||||
return errors;
|
||||
} else if (rootType !== 'object') {
|
||||
errors = errors.concat([new ValidationError('terrain', terrain, `object expected, ${rootType} found`)]);
|
||||
return errors;
|
||||
}
|
||||
|
||||
for (const key in terrain) {
|
||||
const transitionMatch = key.match(/^(.*)-transition$/);
|
||||
|
||||
if (transitionMatch && terrainSpec[transitionMatch[1]] && terrainSpec[transitionMatch[1]].transition) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: terrain[key],
|
||||
valueSpec: styleSpec.transition,
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else if (terrainSpec[key]) {
|
||||
errors = errors.concat(validate({
|
||||
key,
|
||||
value: terrain[key],
|
||||
valueSpec: terrainSpec[key],
|
||||
style,
|
||||
styleSpec
|
||||
}));
|
||||
} else {
|
||||
errors = errors.concat([new ValidationError(key, terrain[key], `unknown property "${key}"`)]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!terrain.source) {
|
||||
errors.push(new ValidationError(key, terrain, `terrain is missing required property "source"`));
|
||||
} else {
|
||||
const source = style.sources && style.sources[terrain.source];
|
||||
const sourceType = source && unbundle(source.type);
|
||||
if (!source) {
|
||||
errors.push(new ValidationError(key, terrain.source, `source "${terrain.source}" not found`));
|
||||
} else if (sourceType !== 'raster-dem') {
|
||||
errors.push(new ValidationError(key, terrain.source, `terrain cannot be used with a source of type ${String(sourceType)}, it only be used with a "raster-dem" source type`));
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
Reference in New Issue
Block a user