UNPKG

@maplibre/maplibre-gl-style-spec

Version:
107 lines (90 loc) 3.15 kB
import { ObjectType, ValueType, StringType, NumberType, BooleanType, checkSubtype, typeToString, array } from '../types'; import {RuntimeError} from '../runtime_error'; import {typeOf} from '../values'; import type {Expression} from '../expression'; import type {ParsingContext} from '../parsing_context'; import type {EvaluationContext} from '../evaluation_context'; import type {Type} from '../types'; const types = { string: StringType, number: NumberType, boolean: BooleanType, object: ObjectType }; export class Assertion implements Expression { type: Type; args: Array<Expression>; constructor(type: Type, args: Array<Expression>) { this.type = type; this.args = args; } static parse(args: ReadonlyArray<unknown>, context: ParsingContext): Expression { if (args.length < 2) return context.error('Expected at least one argument.') as null; let i = 1; let type; const name: string = (args[0] as any); if (name === 'array') { let itemType; if (args.length > 2) { const type = args[1]; if (typeof type !== 'string' || !(type in types) || type === 'object') return context.error('The item type argument of "array" must be one of string, number, boolean', 1) as null; itemType = types[type]; i++; } else { itemType = ValueType; } let N; if (args.length > 3) { if (args[2] !== null && (typeof args[2] !== 'number' || args[2] < 0 || args[2] !== Math.floor(args[2])) ) { return context.error('The length argument to "array" must be a positive integer literal', 2) as null; } N = args[2]; i++; } type = array(itemType, N); } else { if (!types[name]) throw new Error(`Types doesn't contain name = ${name}`); type = types[name]; } const parsed = []; for (; i < args.length; i++) { const input = context.parse(args[i], i, ValueType); if (!input) return null; parsed.push(input); } return new Assertion(type, parsed); } evaluate(ctx: EvaluationContext) { for (let i = 0; i < this.args.length; i++) { const value = this.args[i].evaluate(ctx); const error = checkSubtype(this.type, typeOf(value)); if (!error) { return value; } else if (i === this.args.length - 1) { throw new RuntimeError(`Expected value to be of type ${typeToString(this.type)}, but found ${typeToString(typeOf(value))} instead.`); } } throw new Error(); } eachChild(fn: (_: Expression) => void) { this.args.forEach(fn); } outputDefined(): boolean { return this.args.every(arg => arg.outputDefined()); } }