forked from mapbox/mapbox-gl-js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-flow-typed-style-spec.js
184 lines (148 loc) · 6.09 KB
/
generate-flow-typed-style-spec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
const spec = require('../src/style-spec/reference/v8.json');
const properties = require('../src/style-spec/util/properties');
const fs = require('fs');
function flowEnum(values) {
if (Array.isArray(values)) {
return values.map(JSON.stringify).join(' | ');
} else {
return Object.keys(values).map(JSON.stringify).join(' | ');
}
}
function flowType(property) {
if (typeof property.type === 'function') {
return property.type();
}
const baseType = (() => {
switch (property.type) {
case 'string':
case 'number':
case 'boolean':
return property.type;
case 'enum':
return flowEnum(property.values);
case 'array':
const elementType = flowType(typeof property.value === 'string' ? {type: property.value, values: property.values} : property.value)
if (property.length) {
return `[${Array(property.length).fill(elementType).join(', ')}]`;
} else {
return `Array<${elementType}>`;
}
case 'light':
return 'LightSpecification';
case 'sources':
return '{[string]: SourceSpecification}';
case '*':
return 'mixed';
default:
return `${property.type.slice(0, 1).toUpperCase()}${property.type.slice(1)}Specification`;
}
})();
if (properties.supportsPropertyExpression(property)) {
return `DataDrivenPropertyValueSpecification<${baseType}>`;
} else if (properties.supportsZoomExpression(property)) {
return `PropertyValueSpecification<${baseType}>`;
} else if (property.expression) {
return `ExpressionSpecification`;
} else {
return baseType;
}
}
function flowProperty(key, property) {
return `"${key}"${property.required ? '' : '?'}: ${flowType(property)}`;
}
function flowObjectDeclaration(key, properties) {
return `export type ${key} = ${flowObject(properties, '', '*' in properties ? '' : '|')}`;
}
function flowObject(properties, indent, sealing = '') {
return `{${sealing}
${Object.keys(properties)
.filter(k => k !== '*')
.map(k => ` ${indent}${flowProperty(k, properties[k])}`)
.join(',\n')}
${indent}${sealing}}`
}
function flowSourceTypeName(key) {
return key.replace(/source_(.)(.*)/, (_, _1, _2) => `${_1.toUpperCase()}${_2}SourceSpecification`)
.replace(/_dem/, 'DEM')
.replace(/Geojson/, 'GeoJSON');
}
function flowLayerTypeName(key) {
return key.split('-').map(k => k.replace(/(.)(.*)/, (_, _1, _2) => `${_1.toUpperCase()}${_2}`)).concat('LayerSpecification').join('');
}
function flowLayer(key) {
const layer = spec.layer;
layer.type = {
type: 'enum',
values: [key],
required: true
};
delete layer.ref;
delete layer['paint.*'];
layer.paint.type = () => {
return flowObject(spec[`paint_${key}`], ' ', '|');
};
layer.layout.type = () => {
return flowObject(spec[`layout_${key}`], ' ', '|');
};
if (key === 'background') {
delete layer.source;
delete layer['source-layer'];
delete layer.filter;
} else {
layer.source.required = true;
}
return flowObjectDeclaration(flowLayerTypeName(key), layer);
}
const layerTypes = Object.keys(spec.layer.type.values);
fs.writeFileSync('src/style-spec/types.js', `// @flow
// Generated code; do not edit. Edit build/generate-flow-typed-style-spec.js instead.
/* eslint-disable */
export type ColorSpecification = string;
export type FormattedSpecification = string;
export type FilterSpecification =
| ['has', string]
| ['!has', string]
| ['==', string, string | number | boolean]
| ['!=', string, string | number | boolean]
| ['>', string, string | number | boolean]
| ['>=', string, string | number | boolean]
| ['<', string, string | number | boolean]
| ['<=', string, string | number | boolean]
| Array<string | FilterSpecification>; // Can't type in, !in, all, any, none -- https://github.com/facebook/flow/issues/2443
export type TransitionSpecification = {
duration?: number,
delay?: number
};
// Note: doesn't capture interpolatable vs. non-interpolatable types.
export type CameraFunctionSpecification<T> =
| {| type: 'exponential', stops: Array<[number, T]> |}
| {| type: 'interval', stops: Array<[number, T]> |};
export type SourceFunctionSpecification<T> =
| {| type: 'exponential', stops: Array<[number, T]>, property: string, default?: T |}
| {| type: 'interval', stops: Array<[number, T]>, property: string, default?: T |}
| {| type: 'categorical', stops: Array<[string | number | boolean, T]>, property: string, default?: T |}
| {| type: 'identity', property: string, default?: T |};
export type CompositeFunctionSpecification<T> =
| {| type: 'exponential', stops: Array<[{zoom: number, value: number}, T]>, property: string, default?: T |}
| {| type: 'interval', stops: Array<[{zoom: number, value: number}, T]>, property: string, default?: T |}
| {| type: 'categorical', stops: Array<[{zoom: number, value: string | number | boolean}, T]>, property: string, default?: T |};
export type ExpressionSpecification = Array<mixed>;
export type PropertyValueSpecification<T> =
| T
| CameraFunctionSpecification<T>
| ExpressionSpecification;
export type DataDrivenPropertyValueSpecification<T> =
| T
| CameraFunctionSpecification<T>
| SourceFunctionSpecification<T>
| CompositeFunctionSpecification<T>
| ExpressionSpecification;
${flowObjectDeclaration('StyleSpecification', spec.$root)}
${flowObjectDeclaration('LightSpecification', spec.light)}
${spec.source.map(key => flowObjectDeclaration(flowSourceTypeName(key), spec[key])).join('\n\n')}
export type SourceSpecification =
${spec.source.map(key => ` | ${flowSourceTypeName(key)}`).join('\n')}
${layerTypes.map(key => flowLayer(key)).join('\n\n')}
export type LayerSpecification =
${layerTypes.map(key => ` | ${flowLayerTypeName(key)}`).join('\n')};
`);