@mapbox/mapbox-gl-style-spec
Version:
a specification for mapbox gl styles
102 lines (83 loc) • 3.82 kB
text/typescript
import validateObject from './validate_object';
import ValidationError from '../error/validation_error';
import validateProperty from './validate_property';
import {unbundle} from '../util/unbundle_jsonlint';
import validateExpression from './validate_expression';
import latest from '../reference/latest';
import type {StyleSpecification, LayerSpecification, AppearanceSpecification} from '../types';
import type {StyleReference} from '../reference/latest';
export type AppearanceValidatorOptions = {
key: string;
value: unknown;
style: Partial<StyleSpecification>;
styleSpec: StyleReference;
object?: object;
objectKey?: string;
layer: LayerSpecification;
layerType: string;
};
export default function validateAppearance(options: AppearanceValidatorOptions): Array<ValidationError> {
const {key, layer, layerType} = options;
const value = unbundle(options.value) as AppearanceSpecification;
const name = unbundle(value.name);
const condition = unbundle(value.condition);
const errors = validateObject({
key,
value,
valueSpec: options.styleSpec.appearance as object,
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: {
condition: (options) => validateCondition(Object.assign({layer, layerType}, options)),
properties: (options) => validateProperties(Object.assign({layer, layerType}, options)),
}
});
if (name !== 'hidden' && !condition) {
errors.push(new ValidationError(options.key, 'name', `Appearance with name different than "hidden" must have a condition`));
}
return errors;
}
function validateProperties(options: AppearanceValidatorOptions): Array<ValidationError> {
const errors: Array<ValidationError> = [];
const {styleSpec, layer, layerType} = options;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const paintProperties = styleSpec[`paint_${layerType}`];
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const layoutProperties = styleSpec[`layout_${layerType}`];
const properties = options.object[options.objectKey] as object;
for (const propertyKey in properties) {
const propertyType =
propertyKey in paintProperties ? 'paint' :
propertyKey in layoutProperties ? 'layout' :
undefined;
if (!propertyType) {
errors.push(new ValidationError(options.key, propertyKey, `unknown property "${propertyKey}" for layer type "${layerType}"`));
continue;
}
const propertyValidationOptions = Object.assign({}, options, {
key: `${options.key}.${propertyKey}`,
object: properties,
objectKey: propertyKey,
layer,
layerType,
value: properties[propertyKey] as unknown,
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
valueSpec: (propertyType === 'paint' ? paintProperties[propertyKey] : layoutProperties[propertyKey]) as object,
});
errors.push(...validateProperty(propertyValidationOptions, propertyType));
}
return errors;
}
function validateCondition(options: AppearanceValidatorOptions): Array<ValidationError> {
const errors: Array<ValidationError> = [];
const appearance = options.object as AppearanceSpecification;
const condition = appearance.condition;
errors.push(...validateExpression({
key: options.key,
value: condition,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
valueSpec: latest['appearance']['condition'],
expressionContext: 'appearance'
}));
return errors;
}