UNPKG

8.66 kBPlain TextView Raw
1'use strict';
2
3import * as fs from 'fs';
4
5import spec from '../src/style-spec/reference/v8.json';
6
7function camelCase(str: string): string {
8 return str.replace(/-(.)/g, (_, x) => {
9 return x.toUpperCase();
10 });
11}
12
13function pascalCase(str: string): string {
14 const almostCamelized = camelCase(str);
15 return almostCamelized[0].toUpperCase() + almostCamelized.slice(1);
16}
17
18function nativeType(property) {
19 switch (property.type) {
20 case 'boolean':
21 return 'boolean';
22 case 'number':
23 return 'number';
24 case 'string':
25 return 'string';
26 case 'enum':
27 return Object.keys(property.values).map(v => JSON.stringify(v)).join(' | ');
28 case 'color':
29 return 'Color';
30 case 'formatted':
31 return 'Formatted';
32 case 'resolvedImage':
33 return 'ResolvedImage';
34 case 'array':
35 if (property.length) {
36 return `[${new Array(property.length).fill(nativeType({type: property.value})).join(', ')}]`;
37 } else {
38 return `Array<${nativeType({type: property.value, values: property.values})}>`;
39 }
40 default: throw new Error(`unknown type for ${property.name}`);
41 }
42}
43
44function possiblyEvaluatedType(property) {
45 const propType = nativeType(property);
46
47 switch (property['property-type']) {
48 case 'color-ramp':
49 return 'ColorRampProperty';
50 case 'cross-faded':
51 return `CrossFaded<${propType}>`;
52 case 'cross-faded-data-driven':
53 return `PossiblyEvaluatedPropertyValue<CrossFaded<${propType}>>`;
54 case 'data-driven':
55 return `PossiblyEvaluatedPropertyValue<${propType}>`;
56 }
57
58 return propType;
59}
60
61function propertyType(property) {
62 switch (property['property-type']) {
63 case 'data-driven':
64 return `DataDrivenProperty<${nativeType(property)}>`;
65 case 'cross-faded':
66 return `CrossFadedProperty<${nativeType(property)}>`;
67 case 'cross-faded-data-driven':
68 return `CrossFadedDataDrivenProperty<${nativeType(property)}>`;
69 case 'color-ramp':
70 return 'ColorRampProperty';
71 case 'data-constant':
72 case 'constant':
73 return `DataConstantProperty<${nativeType(property)}>`;
74 default:
75 throw new Error(`unknown property-type "${property['property-type']}" for ${property.name}`);
76 }
77}
78
79function runtimeType(property) {
80 switch (property.type) {
81 case 'boolean':
82 return 'BooleanType';
83 case 'number':
84 return 'NumberType';
85 case 'string':
86 case 'enum':
87 return 'StringType';
88 case 'color':
89 return 'ColorType';
90 case 'formatted':
91 return 'FormattedType';
92 case 'Image':
93 return 'ImageType';
94 case 'array':
95 if (property.length) {
96 return `array(${runtimeType({type: property.value})}, ${property.length})`;
97 } else {
98 return `array(${runtimeType({type: property.value})})`;
99 }
100 default: throw new Error(`unknown type for ${property.name}`);
101 }
102}
103
104function overrides(property) {
105 return `{ runtimeType: ${runtimeType(property)}, getOverride: (o) => o.${camelCase(property.name)}, hasOverride: (o) => !!o.${camelCase(property.name)} }`;
106}
107
108function propertyValue(property, type) {
109 const propertyAsSpec = `styleSpec["${type}_${property.layerType}"]["${property.name}"] as any as StylePropertySpecification`;
110
111 switch (property['property-type']) {
112 case 'data-driven':
113 if (property.overridable) {
114 return `new DataDrivenProperty(${propertyAsSpec}, ${overrides(property)})`;
115 } else {
116 return `new DataDrivenProperty(${propertyAsSpec})`;
117 }
118 case 'cross-faded':
119 return `new CrossFadedProperty(${propertyAsSpec})`;
120 case 'cross-faded-data-driven':
121 return `new CrossFadedDataDrivenProperty(${propertyAsSpec})`;
122 case 'color-ramp':
123 return `new ColorRampProperty(${propertyAsSpec})`;
124 case 'data-constant':
125 case 'constant':
126 return `new DataConstantProperty(${propertyAsSpec})`;
127 default:
128 throw new Error(`unknown property-type "${property['property-type']}" for ${property.name}`);
129 }
130}
131
132const layers = Object.keys(spec.layer.type.values).map((type) => {
133 const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
134 if (name !== 'visibility') {
135 spec[`layout_${type}`][name].name = name;
136 spec[`layout_${type}`][name].layerType = type;
137 memo.push(spec[`layout_${type}`][name]);
138 }
139 return memo;
140 }, []);
141
142 const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
143 spec[`paint_${type}`][name].name = name;
144 spec[`paint_${type}`][name].layerType = type;
145 memo.push(spec[`paint_${type}`][name]);
146 return memo;
147 }, []);
148
149 return {type, layoutProperties, paintProperties};
150});
151
152function emitlayerProperties(locals) {
153 const output = [];
154 const layerType = pascalCase(locals.type);
155 const {
156 layoutProperties,
157 paintProperties
158 } = locals;
159
160 output.push(
161 `// This file is generated. Edit build/generate-style-code.ts, then run 'npm run codegen'.
162/* eslint-disable */
163
164import styleSpec from '../../style-spec/reference/latest';
165
166import {
167 Properties,
168 DataConstantProperty,
169 DataDrivenProperty,
170 CrossFadedDataDrivenProperty,
171 CrossFadedProperty,
172 ColorRampProperty,
173 PossiblyEvaluatedPropertyValue,
174 CrossFaded
175} from '../properties';
176
177import type Color from '../../style-spec/util/color';
178
179import type Formatted from '../../style-spec/expression/types/formatted';
180
181import type ResolvedImage from '../../style-spec/expression/types/resolved_image';
182import {StylePropertySpecification} from '../../style-spec/style-spec';
183`);
184
185 const overridables = paintProperties.filter(p => p.overridable);
186 if (overridables.length) {
187 output.push(
188 `import {
189 ${overridables.reduce((imports, prop) => { imports.push(runtimeType(prop)); return imports; }, []).join(',\n ')}
190} from '../../style-spec/expression/types';
191`);
192 }
193
194 if (layoutProperties.length) {
195 output.push(
196 `export type ${layerType}LayoutProps = {`);
197
198 for (const property of layoutProperties) {
199 output.push(
200 ` "${property.name}": ${propertyType(property)},`);
201 }
202
203 output.push(
204 `};
205
206export type ${layerType}LayoutPropsPossiblyEvaluated = {`);
207
208 for (const property of layoutProperties) {
209 output.push(
210 ` "${property.name}": ${possiblyEvaluatedType(property)},`);
211 }
212
213 output.push(
214 `};
215
216const layout: Properties<${layerType}LayoutProps> = new Properties({`);
217
218 for (const property of layoutProperties) {
219 output.push(
220 ` "${property.name}": ${propertyValue(property, 'layout')},`);
221 }
222
223 output.push(
224 '});');
225 }
226
227 if (paintProperties.length) {
228 output.push(
229 `
230export type ${layerType}PaintProps = {`);
231
232 for (const property of paintProperties) {
233 output.push(
234 ` "${property.name}": ${propertyType(property)},`);
235 }
236
237 output.push(
238 `};
239
240export type ${layerType}PaintPropsPossiblyEvaluated = {`);
241
242 for (const property of paintProperties) {
243 output.push(
244 ` "${property.name}": ${possiblyEvaluatedType(property)},`);
245 }
246
247 output.push(
248 '};');
249 } else {
250 output.push(
251 `export type ${layerType}PaintProps = {};`);
252 }
253
254 output.push(
255 `
256const paint: Properties<${layerType}PaintProps> = new Properties({`);
257
258 for (const property of paintProperties) {
259 output.push(
260 ` "${property.name}": ${propertyValue(property, 'paint')},`);
261 }
262
263 output.push(
264 `});
265
266export default ({ paint${layoutProperties.length ? ', layout' : ''} } as {
267 paint: Properties<${layerType}PaintProps>${layoutProperties.length ? `,\n layout: Properties<${layerType}LayoutProps>` : ''}
268});`);
269
270 return output.join('\n');
271}
272
273for (const layer of layers) {
274 fs.writeFileSync(`src/style/style_layer/${layer.type.replace('-', '_')}_style_layer_properties.g.ts`, emitlayerProperties(layer));
275}
276
\No newline at end of file