maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
281 lines (235 loc) • 8.85 kB
text/typescript
import * as fs from 'fs';
import spec from '../src/style-spec/reference/v8.json' assert {type: 'json'};
function camelCase(str: string): string {
return str.replace(/-(.)/g, (_, x) => {
return x.toUpperCase();
});
}
function pascalCase(str: string): string {
const almostCamelized = camelCase(str);
return almostCamelized[0].toUpperCase() + almostCamelized.slice(1);
}
function nativeType(property) {
switch (property.type) {
case 'boolean':
return 'boolean';
case 'number':
return 'number';
case 'string':
return 'string';
case 'enum':
return Object.keys(property.values).map(v => JSON.stringify(v)).join(' | ');
case 'color':
return 'Color';
case 'padding':
return 'Padding';
case 'formatted':
return 'Formatted';
case 'resolvedImage':
return 'ResolvedImage';
case 'array':
if (property.length) {
return `[${new Array(property.length).fill(nativeType({type: property.value})).join(', ')}]`;
} else {
return `Array<${nativeType({type: property.value, values: property.values})}>`;
}
default: throw new Error(`unknown type for ${property.name}`);
}
}
function possiblyEvaluatedType(property) {
const propType = nativeType(property);
switch (property['property-type']) {
case 'color-ramp':
return 'ColorRampProperty';
case 'cross-faded':
return `CrossFaded<${propType}>`;
case 'cross-faded-data-driven':
return `PossiblyEvaluatedPropertyValue<CrossFaded<${propType}>>`;
case 'data-driven':
return `PossiblyEvaluatedPropertyValue<${propType}>`;
}
return propType;
}
function propertyType(property) {
switch (property['property-type']) {
case 'data-driven':
return `DataDrivenProperty<${nativeType(property)}>`;
case 'cross-faded':
return `CrossFadedProperty<${nativeType(property)}>`;
case 'cross-faded-data-driven':
return `CrossFadedDataDrivenProperty<${nativeType(property)}>`;
case 'color-ramp':
return 'ColorRampProperty';
case 'data-constant':
case 'constant':
return `DataConstantProperty<${nativeType(property)}>`;
default:
throw new Error(`unknown property-type "${property['property-type']}" for ${property.name}`);
}
}
function runtimeType(property) {
switch (property.type) {
case 'boolean':
return 'BooleanType';
case 'number':
return 'NumberType';
case 'string':
case 'enum':
return 'StringType';
case 'color':
return 'ColorType';
case 'padding':
return 'PaddingType';
case 'formatted':
return 'FormattedType';
case 'Image':
return 'ImageType';
case 'array':
if (property.length) {
return `array(${runtimeType({type: property.value})}, ${property.length})`;
} else {
return `array(${runtimeType({type: property.value})})`;
}
default: throw new Error(`unknown type for ${property.name}`);
}
}
function overrides(property) {
return `{ runtimeType: ${runtimeType(property)}, getOverride: (o) => o.${camelCase(property.name)}, hasOverride: (o) => !!o.${camelCase(property.name)} }`;
}
function propertyValue(property, type) {
const propertyAsSpec = `styleSpec["${type}_${property.layerType}"]["${property.name}"] as any as StylePropertySpecification`;
switch (property['property-type']) {
case 'data-driven':
if (property.overridable) {
return `new DataDrivenProperty(${propertyAsSpec}, ${overrides(property)})`;
} else {
return `new DataDrivenProperty(${propertyAsSpec})`;
}
case 'cross-faded':
return `new CrossFadedProperty(${propertyAsSpec})`;
case 'cross-faded-data-driven':
return `new CrossFadedDataDrivenProperty(${propertyAsSpec})`;
case 'color-ramp':
return `new ColorRampProperty(${propertyAsSpec})`;
case 'data-constant':
case 'constant':
return `new DataConstantProperty(${propertyAsSpec})`;
default:
throw new Error(`unknown property-type "${property['property-type']}" for ${property.name}`);
}
}
const layers = Object.keys(spec.layer.type.values).map((type) => {
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
if (name !== 'visibility') {
spec[`layout_${type}`][name].name = name;
spec[`layout_${type}`][name].layerType = type;
memo.push(spec[`layout_${type}`][name]);
}
return memo;
}, []);
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
spec[`paint_${type}`][name].name = name;
spec[`paint_${type}`][name].layerType = type;
memo.push(spec[`paint_${type}`][name]);
return memo;
}, []);
return {type, layoutProperties, paintProperties};
});
function emitlayerProperties(locals) {
const output = [];
const layerType = pascalCase(locals.type);
const {
layoutProperties,
paintProperties
} = locals;
output.push(
`// This file is generated. Edit build/generate-style-code.ts, then run 'npm run codegen'.
/* eslint-disable */
import styleSpec from '../../style-spec/reference/latest';
import {
Properties,
DataConstantProperty,
DataDrivenProperty,
CrossFadedDataDrivenProperty,
CrossFadedProperty,
ColorRampProperty,
PossiblyEvaluatedPropertyValue,
CrossFaded
} from '../properties';
import type Color from '../../style-spec/util/color';
import type Padding from '../../style-spec/util/padding';
import type Formatted from '../../style-spec/expression/types/formatted';
import type ResolvedImage from '../../style-spec/expression/types/resolved_image';
import {StylePropertySpecification} from '../../style-spec/style-spec';
`);
const overridables = paintProperties.filter(p => p.overridable);
if (overridables.length) {
output.push(
`import {
${overridables.reduce((imports, prop) => { imports.push(runtimeType(prop)); return imports; }, []).join(',\n ')}
} from '../../style-spec/expression/types';
`);
}
if (layoutProperties.length) {
output.push(
`export type ${layerType}LayoutProps = {`);
for (const property of layoutProperties) {
output.push(
` "${property.name}": ${propertyType(property)},`);
}
output.push(
`};
export type ${layerType}LayoutPropsPossiblyEvaluated = {`);
for (const property of layoutProperties) {
output.push(
` "${property.name}": ${possiblyEvaluatedType(property)},`);
}
output.push(
`};
const layout: Properties<${layerType}LayoutProps> = new Properties({`);
for (const property of layoutProperties) {
output.push(
` "${property.name}": ${propertyValue(property, 'layout')},`);
}
output.push(
'});');
}
if (paintProperties.length) {
output.push(
`
export type ${layerType}PaintProps = {`);
for (const property of paintProperties) {
output.push(
` "${property.name}": ${propertyType(property)},`);
}
output.push(
`};
export type ${layerType}PaintPropsPossiblyEvaluated = {`);
for (const property of paintProperties) {
output.push(
` "${property.name}": ${possiblyEvaluatedType(property)},`);
}
output.push(
'};');
} else {
output.push(
`export type ${layerType}PaintProps = {};`);
}
output.push(
`
const paint: Properties<${layerType}PaintProps> = new Properties({`);
for (const property of paintProperties) {
output.push(
` "${property.name}": ${propertyValue(property, 'paint')},`);
}
output.push(
`});
export default ({ paint${layoutProperties.length ? ', layout' : ''} } as {
paint: Properties<${layerType}PaintProps>${layoutProperties.length ? `,\n layout: Properties<${layerType}LayoutProps>` : ''}
});`);
return output.join('\n');
}
for (const layer of layers) {
fs.writeFileSync(`src/style/style_layer/${layer.type.replace('-', '_')}_style_layer_properties.g.ts`, emitlayerProperties(layer));
}
;