UNPKG

7.58 kBPlain TextView Raw
1import * as fs from 'fs';
2import * as properties from '../src/style-spec/util/properties';
3
4import spec from '../src/style-spec/reference/v8.json';
5
6function unionType(values) {
7 if (Array.isArray(values)) {
8 return values.map(v => JSON.stringify(v)).join(' | ');
9 } else {
10 return Object.keys(values).map(v => JSON.stringify(v)).join(' | ');
11 }
12}
13
14function propertyType(property) {
15 if (typeof property.type === 'function') {
16 return property.type();
17 }
18
19 const baseType = (() => {
20 switch (property.type) {
21 case 'string':
22 case 'number':
23 case 'boolean':
24 return property.type;
25 case 'enum':
26 return unionType(property.values);
27 case 'array': {
28 const elementType = propertyType(typeof property.value === 'string' ? {type: property.value, values: property.values} : property.value);
29 if (property.length) {
30 return `[${Array(property.length).fill(elementType).join(', ')}]`;
31 } else {
32 return `Array<${elementType}>`;
33 }
34 }
35 case 'light':
36 return 'LightSpecification';
37 case 'sources':
38 return '{[_: string]: SourceSpecification}';
39 case '*':
40 return 'unknown';
41 default:
42 return `${property.type.slice(0, 1).toUpperCase()}${property.type.slice(1)}Specification`;
43 }
44 })();
45
46 if (properties.supportsPropertyExpression(property)) {
47 return `DataDrivenPropertyValueSpecification<${baseType}>`;
48 } else if (properties.supportsZoomExpression(property)) {
49 return `PropertyValueSpecification<${baseType}>`;
50 } else if (property.expression) {
51 return 'ExpressionSpecificationArray';
52 } else {
53 return baseType;
54 }
55}
56
57function propertyDeclaration(key, property) {
58 return `"${key}"${property.required ? '' : '?'}: ${propertyType(property)}`;
59}
60
61function objectDeclaration(key, properties) {
62 return `export type ${key} = ${objectType(properties, '')};`;
63}
64
65function objectType(properties, indent) {
66 return `{
67${Object.keys(properties)
68 .filter(k => k !== '*')
69 .map(k => ` ${indent}${propertyDeclaration(k, properties[k])}`)
70 .join(',\n')}
71${indent}}`;
72}
73
74function sourceTypeName(key) {
75 return key.replace(/source_(.)(.*)/, (_, _1, _2) => `${_1.toUpperCase()}${_2}SourceSpecification`)
76 .replace(/_dem/, 'DEM')
77 .replace(/Geojson/, 'GeoJSON');
78}
79
80function layerTypeName(key) {
81 return key.split('-').map(k => k.replace(/(.)(.*)/, (_, _1, _2) => `${_1.toUpperCase()}${_2}`)).concat('LayerSpecification').join('');
82}
83
84function layerType(key) {
85 const layer = spec.layer as any;
86
87 layer.type = {
88 type: 'enum',
89 values: [key],
90 required: true
91 };
92
93 delete layer.ref;
94 delete layer['paint.*'];
95
96 layer.paint.type = () => {
97 return objectType(spec[`paint_${key}`], ' ');
98 };
99
100 layer.layout.type = () => {
101 return objectType(spec[`layout_${key}`], ' ');
102 };
103
104 if (key === 'background') {
105 delete layer.source;
106 delete layer['source-layer'];
107 delete layer.filter;
108 } else {
109 layer.source.required = true;
110 }
111
112 return objectDeclaration(layerTypeName(key), layer);
113}
114
115const layerTypes = Object.keys(spec.layer.type.values);
116
117fs.writeFileSync('src/style-spec/types.g.ts',
118 `// Generated code; do not edit. Edit build/generate-style-spec.ts instead.
119/* eslint-disable */
120
121export type ColorSpecification = string;
122
123export type FormattedSpecification = string;
124
125export type ResolvedImageSpecification = string;
126
127export type PromoteIdSpecification = {[_: string]: string} | string;
128
129export type FilterSpecificationInputType = string | number | boolean;
130export type FilterSpecification =
131 // Lookup
132 | ['at', number, (number |string)[]]
133 | ['get', string, Record<string, unknown>?]
134 | ['has', string, Record<string, unknown>?]
135 | ['in', ...FilterSpecificationInputType[], FilterSpecificationInputType | FilterSpecificationInputType[]]
136 | ['index-of', FilterSpecificationInputType, FilterSpecificationInputType | FilterSpecificationInputType[]]
137 | ['length', string | string[]]
138 | ['slice', string | string[], number]
139 // Decision
140 | ['!', FilterSpecification]
141 | ['!=', string | FilterSpecification, FilterSpecificationInputType]
142 | ['<', string | FilterSpecification, FilterSpecificationInputType]
143 | ['<=', string | FilterSpecification, FilterSpecificationInputType]
144 | ['==', string | FilterSpecification, FilterSpecificationInputType]
145 | ['>', string | FilterSpecification, FilterSpecificationInputType]
146 | ['>=', string | FilterSpecification, FilterSpecificationInputType]
147 | ["all", ...FilterSpecification[], FilterSpecificationInputType]
148 | ["any", ...FilterSpecification[], FilterSpecificationInputType]
149 | ["case", ...FilterSpecification[], FilterSpecificationInputType]
150 | ["coalesce", ...FilterSpecification[], FilterSpecificationInputType]
151 | ["match", ...FilterSpecification[], FilterSpecificationInputType]
152 | ["within", ...FilterSpecification[], FilterSpecificationInputType]
153 // Used in convert.ts
154 | ["!in", ...FilterSpecification[], FilterSpecificationInputType]
155 | ["!has", ...FilterSpecification[], FilterSpecificationInputType]
156 | ["none", ...FilterSpecification[], FilterSpecificationInputType]
157 // Fallbak for others
158 | Array<string | FilterSpecification>
159
160export type TransitionSpecification = {
161 duration?: number,
162 delay?: number
163};
164
165// Note: doesn't capture interpolatable vs. non-interpolatable types.
166
167export type CameraFunctionSpecification<T> =
168 { type: 'exponential', stops: Array<[number, T]> }
169 | { type: 'interval', stops: Array<[number, T]> };
170
171export type SourceFunctionSpecification<T> =
172 { type: 'exponential', stops: Array<[number, T]>, property: string, default?: T }
173 | { type: 'interval', stops: Array<[number, T]>, property: string, default?: T }
174 | { type: 'categorical', stops: Array<[string | number | boolean, T]>, property: string, default?: T }
175 | { type: 'identity', property: string, default?: T };
176
177export type CompositeFunctionSpecification<T> =
178 { type: 'exponential', stops: Array<[{zoom: number, value: number}, T]>, property: string, default?: T }
179 | { type: 'interval', stops: Array<[{zoom: number, value: number}, T]>, property: string, default?: T }
180 | { type: 'categorical', stops: Array<[{zoom: number, value: string | number | boolean}, T]>, property: string, default?: T };
181
182export type ExpressionSpecificationArray = Array<unknown>;
183
184export type PropertyValueSpecification<T> =
185 T
186 | CameraFunctionSpecification<T>
187 | ExpressionSpecificationArray;
188
189export type DataDrivenPropertyValueSpecification<T> =
190 T
191 | CameraFunctionSpecification<T>
192 | SourceFunctionSpecification<T>
193 | CompositeFunctionSpecification<T>
194 | ExpressionSpecificationArray;
195
196${objectDeclaration('StyleSpecification', spec.$root)}
197
198${objectDeclaration('LightSpecification', spec.light)}
199
200${spec.source.map(key => objectDeclaration(sourceTypeName(key), spec[key])).join('\n\n')}
201
202export type SourceSpecification =
203${spec.source.map(key => ` | ${sourceTypeName(key)}`).join('\n')}
204
205${layerTypes.map(key => layerType(key)).join('\n\n')}
206
207export type LayerSpecification =
208${layerTypes.map(key => ` | ${layerTypeName(key)}`).join('\n')};
209
210`);
211
\No newline at end of file