@mapwhit/style-expressions
Version:
Process expressions in map style.
86 lines (79 loc) • 1.92 kB
JavaScript
const NullType = { kind: 'null' };
const NumberType = { kind: 'number' };
const StringType = { kind: 'string' };
const BooleanType = { kind: 'boolean' };
const ColorType = { kind: 'color' };
const ObjectType = { kind: 'object' };
const ValueType = { kind: 'value' };
const ErrorType = { kind: 'error' };
const CollatorType = { kind: 'collator' };
const FormattedType = { kind: 'formatted' };
export {
NullType,
NumberType,
StringType,
BooleanType,
ColorType,
FormattedType,
ObjectType,
ValueType,
ErrorType,
CollatorType
};
export function array(itemType, N) {
return {
kind: 'array',
itemType,
N
};
}
export function toString(type) {
if (type.kind === 'array') {
const itemType = toString(type.itemType);
return typeof type.N === 'number'
? `array<${itemType}, ${type.N}>`
: type.itemType.kind === 'value'
? 'array'
: `array<${itemType}>`;
}
return type.kind;
}
const valueMemberTypes = [
NullType,
NumberType,
StringType,
BooleanType,
ColorType,
FormattedType,
ObjectType,
array(ValueType)
];
/**
* Returns null if `t` is a subtype of `expected`; otherwise returns an
* error message.
* @private
*/
export function checkSubtype(expected, t) {
if (t.kind === 'error') {
// Error is a subtype of every type
return null;
}
if (expected.kind === 'array') {
if (
t.kind === 'array' &&
((t.N === 0 && t.itemType.kind === 'value') || !checkSubtype(expected.itemType, t.itemType)) &&
(typeof expected.N !== 'number' || expected.N === t.N)
) {
return null;
}
} else if (expected.kind === t.kind) {
return null;
} else if (expected.kind === 'value') {
for (const memberType of valueMemberTypes) {
if (!checkSubtype(memberType, t)) {
return null;
}
}
}
return `Expected ${toString(expected)} but found ${toString(t)} instead.`;
}