@mapbox/mapbox-gl-style-spec 13.28.0 → 14.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +47 -0
- package/README.md +7 -0
- package/data/extent.js +18 -0
- package/deref.js +1 -1
- package/diff.js +36 -15
- package/dist/index.cjs +5839 -2015
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +5837 -2011
- package/dist/index.es.js.map +1 -1
- package/expression/compound_expression.js +2 -1
- package/expression/definitions/assertion.js +2 -2
- package/expression/definitions/coercion.js +54 -15
- package/expression/definitions/comparison.js +2 -0
- package/expression/definitions/distance.js +597 -0
- package/expression/definitions/format.js +2 -2
- package/expression/definitions/image.js +34 -14
- package/expression/definitions/index.js +122 -8
- package/expression/definitions/interpolate.js +1 -1
- package/expression/definitions/match.js +2 -2
- package/expression/definitions/within.js +21 -92
- package/expression/evaluation_context.js +12 -1
- package/expression/index.js +74 -43
- package/expression/is_constant.js +19 -1
- package/expression/parsing_context.js +20 -16
- package/expression/types/formatted.js +2 -2
- package/expression/types/resolved_image.js +19 -8
- package/expression/types.js +2 -1
- package/expression/values.js +25 -0
- package/feature_filter/convert.js +1 -1
- package/feature_filter/index.js +4 -4
- package/flow-typed/cheap-ruler.js +25 -0
- package/flow-typed/geojson.js +8 -7
- package/flow-typed/gl-matrix.js +4 -2
- package/flow-typed/kdbush.js +9 -0
- package/function/convert.js +23 -12
- package/group_by_layout.js +2 -2
- package/migrate/expressions.js +3 -0
- package/package.json +6 -3
- package/reference/v8.json +1771 -114
- package/style-spec.js +4 -3
- package/types.js +190 -24
- package/util/color.js +31 -0
- package/util/geometry_util.js +145 -0
- package/util/properties.js +10 -2
- package/util/random.js +12 -0
- package/validate/validate.js +17 -7
- package/validate/validate_array.js +1 -1
- package/validate/validate_filter.js +4 -12
- package/validate/validate_function.js +2 -2
- package/validate/validate_import.js +31 -0
- package/validate/validate_layer.js +3 -2
- package/validate/validate_lights.js +84 -0
- package/validate/validate_model.js +38 -0
- package/validate/validate_property.js +18 -4
- package/validate/validate_source.js +3 -2
- package/validate/validate_style.js +29 -0
- package/validate_mapbox_api_supported.js +55 -11
- package/validate_style.js +4 -0
- package/validate_style.min.js +11 -19
- package/visit.js +3 -2
package/expression/index.js
CHANGED
|
@@ -15,7 +15,12 @@ import definitions from './definitions/index.js';
|
|
|
15
15
|
import * as isConstant from './is_constant.js';
|
|
16
16
|
import RuntimeError from './runtime_error.js';
|
|
17
17
|
import {success, error} from '../util/result.js';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
supportsPropertyExpression,
|
|
20
|
+
supportsZoomExpression,
|
|
21
|
+
supportsLightExpression,
|
|
22
|
+
supportsInterpolation
|
|
23
|
+
} from '../util/properties.js';
|
|
19
24
|
|
|
20
25
|
import type {Type, EvaluationKind} from './types.js';
|
|
21
26
|
import type {Value} from './values.js';
|
|
@@ -29,25 +34,27 @@ import type Point from '@mapbox/point-geometry';
|
|
|
29
34
|
import type {CanonicalTileID} from '../../source/tile_id.js';
|
|
30
35
|
import type {FeatureDistanceData} from '../feature_filter/index.js';
|
|
31
36
|
|
|
32
|
-
export
|
|
33
|
-
+type: 1 | 2 | 3 | 'Unknown' | 'Point' | 'LineString' | 'Polygon'
|
|
34
|
-
+id?: number | null
|
|
35
|
-
+properties: {[_: string]: any}
|
|
36
|
-
+patterns?: {[_: string]: string}
|
|
37
|
-
+geometry?: Array<Array<Point
|
|
38
|
-
}
|
|
37
|
+
export interface Feature {
|
|
38
|
+
+type: 1 | 2 | 3 | 'Unknown' | 'Point' | 'LineString' | 'Polygon';
|
|
39
|
+
+id?: number | null;
|
|
40
|
+
+properties: {[_: string]: any};
|
|
41
|
+
+patterns?: {[_: string]: string};
|
|
42
|
+
+geometry?: Array<Array<Point>>;
|
|
43
|
+
}
|
|
39
44
|
|
|
40
45
|
export type FeatureState = {[_: string]: any};
|
|
41
46
|
|
|
42
|
-
export
|
|
47
|
+
export interface GlobalProperties {
|
|
43
48
|
zoom: number,
|
|
44
49
|
pitch?: number,
|
|
45
50
|
heatmapDensity?: number,
|
|
46
51
|
lineProgress?: number,
|
|
52
|
+
rasterValue?: number,
|
|
47
53
|
skyRadialProgress?: number,
|
|
48
|
-
isSupportedScript?: (_: string) => boolean,
|
|
49
|
-
accumulated?: Value
|
|
50
|
-
|
|
54
|
+
+isSupportedScript?: (_: string) => boolean,
|
|
55
|
+
accumulated?: Value,
|
|
56
|
+
brightness?: number
|
|
57
|
+
}
|
|
51
58
|
|
|
52
59
|
export class StyleExpression {
|
|
53
60
|
expression: Expression;
|
|
@@ -57,10 +64,10 @@ export class StyleExpression {
|
|
|
57
64
|
_warningHistory: {[key: string]: boolean};
|
|
58
65
|
_enumValues: ?{[_: string]: any};
|
|
59
66
|
|
|
60
|
-
constructor(expression: Expression, propertySpec: ?StylePropertySpecification) {
|
|
67
|
+
constructor(expression: Expression, propertySpec: ?StylePropertySpecification, options?: ?Map<string, Expression>) {
|
|
61
68
|
this.expression = expression;
|
|
62
69
|
this._warningHistory = {};
|
|
63
|
-
this._evaluator = new EvaluationContext();
|
|
70
|
+
this._evaluator = new EvaluationContext(options);
|
|
64
71
|
this._defaultValue = propertySpec ? getDefaultValue(propertySpec) : null;
|
|
65
72
|
this._enumValues = propertySpec && propertySpec.type === 'enum' ? propertySpec.values : null;
|
|
66
73
|
}
|
|
@@ -124,8 +131,8 @@ export function isExpression(expression: mixed): boolean {
|
|
|
124
131
|
*
|
|
125
132
|
* @private
|
|
126
133
|
*/
|
|
127
|
-
export function createExpression(expression: mixed, propertySpec: ?StylePropertySpecification): Result<StyleExpression, Array<ParsingError>> {
|
|
128
|
-
const parser = new ParsingContext(definitions, [], propertySpec ? getExpectedType(propertySpec) : undefined);
|
|
134
|
+
export function createExpression(expression: mixed, propertySpec: ?StylePropertySpecification, options?: ?Map<string, Expression>): Result<StyleExpression, Array<ParsingError>> {
|
|
135
|
+
const parser = new ParsingContext(definitions, [], propertySpec ? getExpectedType(propertySpec) : undefined, undefined, undefined, options);
|
|
129
136
|
|
|
130
137
|
// For string-valued properties, coerce to string at the top level rather than asserting.
|
|
131
138
|
const parsed = parser.parse(expression, undefined, undefined, undefined,
|
|
@@ -136,18 +143,22 @@ export function createExpression(expression: mixed, propertySpec: ?StyleProperty
|
|
|
136
143
|
return error(parser.errors);
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
return success(new StyleExpression(parsed, propertySpec));
|
|
146
|
+
return success(new StyleExpression(parsed, propertySpec, options));
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
export class ZoomConstantExpression<Kind: EvaluationKind> {
|
|
143
150
|
kind: Kind;
|
|
144
151
|
isStateDependent: boolean;
|
|
152
|
+
isConfigDependent: boolean;
|
|
145
153
|
_styleExpression: StyleExpression;
|
|
154
|
+
isLightConstant: ?boolean;
|
|
146
155
|
|
|
147
|
-
constructor(kind: Kind, expression: StyleExpression) {
|
|
156
|
+
constructor(kind: Kind, expression: StyleExpression, isLightConstant: ?boolean) {
|
|
148
157
|
this.kind = kind;
|
|
149
158
|
this._styleExpression = expression;
|
|
159
|
+
this.isLightConstant = isLightConstant;
|
|
150
160
|
this.isStateDependent = kind !== ('constant': EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
|
161
|
+
this.isConfigDependent = !isConstant.isConfigConstant(expression.expression);
|
|
151
162
|
}
|
|
152
163
|
|
|
153
164
|
evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection): any {
|
|
@@ -163,15 +174,19 @@ export class ZoomDependentExpression<Kind: EvaluationKind> {
|
|
|
163
174
|
kind: Kind;
|
|
164
175
|
zoomStops: Array<number>;
|
|
165
176
|
isStateDependent: boolean;
|
|
177
|
+
isLightConstant: ?boolean;
|
|
178
|
+
isConfigDependent: boolean;
|
|
166
179
|
|
|
167
180
|
_styleExpression: StyleExpression;
|
|
168
181
|
interpolationType: ?InterpolationType;
|
|
169
182
|
|
|
170
|
-
constructor(kind: Kind, expression: StyleExpression, zoomStops: Array<number>, interpolationType?: InterpolationType) {
|
|
183
|
+
constructor(kind: Kind, expression: StyleExpression, zoomStops: Array<number>, interpolationType?: InterpolationType, isLightConstant: ?boolean) {
|
|
171
184
|
this.kind = kind;
|
|
172
185
|
this.zoomStops = zoomStops;
|
|
173
186
|
this._styleExpression = expression;
|
|
174
187
|
this.isStateDependent = kind !== ('camera': EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
|
188
|
+
this.isLightConstant = isLightConstant;
|
|
189
|
+
this.isConfigDependent = !isConstant.isConfigConstant(expression.expression);
|
|
175
190
|
this.interpolationType = interpolationType;
|
|
176
191
|
}
|
|
177
192
|
|
|
@@ -192,33 +207,40 @@ export class ZoomDependentExpression<Kind: EvaluationKind> {
|
|
|
192
207
|
}
|
|
193
208
|
}
|
|
194
209
|
|
|
195
|
-
export type ConstantExpression = {
|
|
210
|
+
export type ConstantExpression = interface {
|
|
196
211
|
kind: 'constant',
|
|
212
|
+
isConfigDependent: boolean,
|
|
197
213
|
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>) => any,
|
|
198
214
|
}
|
|
199
215
|
|
|
200
|
-
export type SourceExpression = {
|
|
216
|
+
export type SourceExpression = interface {
|
|
201
217
|
kind: 'source',
|
|
202
218
|
isStateDependent: boolean,
|
|
219
|
+
isLightConstant: ?boolean;
|
|
220
|
+
isConfigDependent: boolean,
|
|
203
221
|
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection) => any,
|
|
204
222
|
};
|
|
205
223
|
|
|
206
|
-
export type CameraExpression = {
|
|
224
|
+
export type CameraExpression = interface {
|
|
207
225
|
kind: 'camera',
|
|
226
|
+
isStateDependent: boolean,
|
|
227
|
+
isConfigDependent: boolean,
|
|
208
228
|
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>) => any,
|
|
209
229
|
+interpolationFactor: (input: number, lower: number, upper: number) => number,
|
|
210
230
|
zoomStops: Array<number>,
|
|
211
231
|
interpolationType: ?InterpolationType
|
|
212
232
|
};
|
|
213
233
|
|
|
214
|
-
export
|
|
215
|
-
kind: 'composite'
|
|
216
|
-
isStateDependent: boolean
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
234
|
+
export interface CompositeExpression {
|
|
235
|
+
kind: 'composite';
|
|
236
|
+
isStateDependent: boolean;
|
|
237
|
+
isLightConstant: ?boolean;
|
|
238
|
+
isConfigDependent: boolean;
|
|
239
|
+
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection) => any;
|
|
240
|
+
+interpolationFactor: (input: number, lower: number, upper: number) => number;
|
|
241
|
+
zoomStops: Array<number>;
|
|
242
|
+
interpolationType: ?InterpolationType;
|
|
243
|
+
}
|
|
222
244
|
|
|
223
245
|
export type StylePropertyExpression =
|
|
224
246
|
| ConstantExpression
|
|
@@ -226,8 +248,8 @@ export type StylePropertyExpression =
|
|
|
226
248
|
| CameraExpression
|
|
227
249
|
| CompositeExpression;
|
|
228
250
|
|
|
229
|
-
export function createPropertyExpression(expression: mixed, propertySpec: StylePropertySpecification): Result<StylePropertyExpression, Array<ParsingError>> {
|
|
230
|
-
expression = createExpression(expression, propertySpec);
|
|
251
|
+
export function createPropertyExpression(expression: mixed, propertySpec: StylePropertySpecification, options?: ?Map<string, Expression>): Result<StylePropertyExpression, Array<ParsingError>> {
|
|
252
|
+
expression = createExpression(expression, propertySpec, options);
|
|
231
253
|
if (expression.result === 'error') {
|
|
232
254
|
return expression;
|
|
233
255
|
}
|
|
@@ -244,9 +266,15 @@ export function createPropertyExpression(expression: mixed, propertySpec: StyleP
|
|
|
244
266
|
return error([new ParsingError('', 'zoom expressions not supported')]);
|
|
245
267
|
}
|
|
246
268
|
|
|
269
|
+
const isLightConstant = isConstant.isGlobalPropertyConstant(parsed, ['measure-light']);
|
|
270
|
+
if (!isLightConstant && !supportsLightExpression(propertySpec)) {
|
|
271
|
+
return error([new ParsingError('', 'measure-light expression not supported')]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const canRelaxZoomRestriction = propertySpec.expression && propertySpec.expression.relaxZoomRestriction;
|
|
247
275
|
const zoomCurve = findZoomCurve(parsed);
|
|
248
|
-
if (!zoomCurve && !isZoomConstant) {
|
|
249
|
-
return error([new ParsingError('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.')]);
|
|
276
|
+
if (!zoomCurve && !isZoomConstant && !canRelaxZoomRestriction) {
|
|
277
|
+
return error([new ParsingError('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression, or in the properties of atmosphere.')]);
|
|
250
278
|
} else if (zoomCurve instanceof ParsingError) {
|
|
251
279
|
return error([zoomCurve]);
|
|
252
280
|
} else if (zoomCurve instanceof Interpolate && !supportsInterpolation(propertySpec)) {
|
|
@@ -255,15 +283,19 @@ export function createPropertyExpression(expression: mixed, propertySpec: StyleP
|
|
|
255
283
|
|
|
256
284
|
if (!zoomCurve) {
|
|
257
285
|
return success(isFeatureConstant ?
|
|
258
|
-
|
|
259
|
-
(new ZoomConstantExpression('
|
|
286
|
+
// $FlowFixMe[method-unbinding]
|
|
287
|
+
(new ZoomConstantExpression('constant', expression.value, isLightConstant): ConstantExpression) :
|
|
288
|
+
// $FlowFixMe[method-unbinding]
|
|
289
|
+
(new ZoomConstantExpression('source', expression.value, isLightConstant): SourceExpression));
|
|
260
290
|
}
|
|
261
291
|
|
|
262
292
|
const interpolationType = zoomCurve instanceof Interpolate ? zoomCurve.interpolation : undefined;
|
|
263
293
|
|
|
264
294
|
return success(isFeatureConstant ?
|
|
265
|
-
|
|
266
|
-
(new ZoomDependentExpression('
|
|
295
|
+
// $FlowFixMe[method-unbinding]
|
|
296
|
+
(new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType, isLightConstant): CameraExpression) :
|
|
297
|
+
// $FlowFixMe[method-unbinding]
|
|
298
|
+
(new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType, isLightConstant): CompositeExpression));
|
|
267
299
|
}
|
|
268
300
|
|
|
269
301
|
import {isFunction, createFunction} from '../function/index.js';
|
|
@@ -298,12 +330,12 @@ export class StylePropertyFunction<T> {
|
|
|
298
330
|
}
|
|
299
331
|
}
|
|
300
332
|
|
|
301
|
-
export function normalizePropertyExpression<T>(value: PropertyValueSpecification<T>, specification: StylePropertySpecification): StylePropertyExpression {
|
|
333
|
+
export function normalizePropertyExpression<T>(value: PropertyValueSpecification<T>, specification: StylePropertySpecification, options?: ?Map<string, Expression>): StylePropertyExpression {
|
|
302
334
|
if (isFunction(value)) {
|
|
303
335
|
return (new StylePropertyFunction(value, specification): any);
|
|
304
336
|
|
|
305
|
-
} else if (isExpression(value)) {
|
|
306
|
-
const expression = createPropertyExpression(value, specification);
|
|
337
|
+
} else if (isExpression(value) || (Array.isArray(value) && value.length > 0)) {
|
|
338
|
+
const expression = createPropertyExpression(value, specification, options);
|
|
307
339
|
if (expression.result === 'error') {
|
|
308
340
|
// this should have been caught in validation
|
|
309
341
|
throw new Error(expression.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
|
@@ -317,6 +349,7 @@ export function normalizePropertyExpression<T>(value: PropertyValueSpecification
|
|
|
317
349
|
}
|
|
318
350
|
return {
|
|
319
351
|
kind: 'constant',
|
|
352
|
+
isConfigDependent: false,
|
|
320
353
|
evaluate: () => constant
|
|
321
354
|
};
|
|
322
355
|
}
|
|
@@ -353,8 +386,6 @@ function findZoomCurve(expression: Expression): Step | Interpolate | ParsingErro
|
|
|
353
386
|
const childResult = findZoomCurve(child);
|
|
354
387
|
if (childResult instanceof ParsingError) {
|
|
355
388
|
result = childResult;
|
|
356
|
-
} else if (!result && childResult) {
|
|
357
|
-
result = new ParsingError('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.');
|
|
358
389
|
} else if (result && childResult && result !== childResult) {
|
|
359
390
|
result = new ParsingError('', 'Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.');
|
|
360
391
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import CompoundExpression from './compound_expression.js';
|
|
4
4
|
import Within from './definitions/within.js';
|
|
5
|
+
import Distance from './definitions/distance.js';
|
|
5
6
|
import type {Expression} from './expression.js';
|
|
6
7
|
|
|
7
8
|
function isFeatureConstant(e: Expression): boolean {
|
|
@@ -27,6 +28,10 @@ function isFeatureConstant(e: Expression): boolean {
|
|
|
27
28
|
return false;
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
if (e instanceof Distance) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
let result = true;
|
|
31
36
|
e.eachChild(arg => {
|
|
32
37
|
if (result && !isFeatureConstant(arg)) { result = false; }
|
|
@@ -47,6 +52,19 @@ function isStateConstant(e: Expression): boolean {
|
|
|
47
52
|
return result;
|
|
48
53
|
}
|
|
49
54
|
|
|
55
|
+
function isConfigConstant(e: Expression): boolean {
|
|
56
|
+
if (e instanceof CompoundExpression) {
|
|
57
|
+
if (e.name === 'config') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let result = true;
|
|
62
|
+
e.eachChild(arg => {
|
|
63
|
+
if (result && !isConfigConstant(arg)) { result = false; }
|
|
64
|
+
});
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
50
68
|
function isGlobalPropertyConstant(e: Expression, properties: Array<string>): boolean {
|
|
51
69
|
if (e instanceof CompoundExpression && properties.indexOf(e.name) >= 0) { return false; }
|
|
52
70
|
let result = true;
|
|
@@ -56,4 +74,4 @@ function isGlobalPropertyConstant(e: Expression, properties: Array<string>): boo
|
|
|
56
74
|
return result;
|
|
57
75
|
}
|
|
58
76
|
|
|
59
|
-
export {isFeatureConstant, isGlobalPropertyConstant, isStateConstant};
|
|
77
|
+
export {isFeatureConstant, isGlobalPropertyConstant, isStateConstant, isConfigConstant};
|
|
@@ -10,6 +10,7 @@ import EvaluationContext from './evaluation_context.js';
|
|
|
10
10
|
import CompoundExpression from './compound_expression.js';
|
|
11
11
|
import CollatorExpression from './definitions/collator.js';
|
|
12
12
|
import Within from './definitions/within.js';
|
|
13
|
+
import Distance from './definitions/distance.js';
|
|
13
14
|
import {isGlobalPropertyConstant, isFeatureConstant} from './is_constant.js';
|
|
14
15
|
import Var from './definitions/var.js';
|
|
15
16
|
|
|
@@ -26,6 +27,7 @@ class ParsingContext {
|
|
|
26
27
|
key: string;
|
|
27
28
|
scope: Scope;
|
|
28
29
|
errors: Array<ParsingError>;
|
|
30
|
+
options: ?Map<string, Expression>;
|
|
29
31
|
|
|
30
32
|
// The expected type of this expression. Provided only to allow Expression
|
|
31
33
|
// implementations to infer argument types: Expression#parse() need not
|
|
@@ -38,7 +40,8 @@ class ParsingContext {
|
|
|
38
40
|
path: Array<number> = [],
|
|
39
41
|
expectedType: ?Type,
|
|
40
42
|
scope: Scope = new Scope(),
|
|
41
|
-
errors: Array<ParsingError> = []
|
|
43
|
+
errors: Array<ParsingError> = [],
|
|
44
|
+
options?: ?Map<string, Expression>
|
|
42
45
|
) {
|
|
43
46
|
this.registry = registry;
|
|
44
47
|
this.path = path;
|
|
@@ -46,6 +49,7 @@ class ParsingContext {
|
|
|
46
49
|
this.scope = scope;
|
|
47
50
|
this.errors = errors;
|
|
48
51
|
this.expectedType = expectedType;
|
|
52
|
+
this.options = options;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
/**
|
|
@@ -62,7 +66,7 @@ class ParsingContext {
|
|
|
62
66
|
bindings?: Array<[string, Expression]>,
|
|
63
67
|
options: {typeAnnotation?: 'assert' | 'coerce' | 'omit'} = {}
|
|
64
68
|
): ?Expression {
|
|
65
|
-
if (index) {
|
|
69
|
+
if (index || expectedType) {
|
|
66
70
|
return this.concat(index, expectedType, bindings)._parse(expr, options);
|
|
67
71
|
}
|
|
68
72
|
return this._parse(expr, options);
|
|
@@ -73,7 +77,7 @@ class ParsingContext {
|
|
|
73
77
|
expr = ['literal', expr];
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
function annotate(parsed, type, typeAnnotation: 'assert' | 'coerce' | 'omit') {
|
|
80
|
+
function annotate(parsed: Expression, type: Type, typeAnnotation: 'assert' | 'coerce' | 'omit') {
|
|
77
81
|
if (typeAnnotation === 'assert') {
|
|
78
82
|
return new Assertion(type, [parsed]);
|
|
79
83
|
} else if (typeAnnotation === 'coerce') {
|
|
@@ -88,13 +92,7 @@ class ParsingContext {
|
|
|
88
92
|
return this.error(`Expected an array with at least one element. If you wanted a literal array, use ["literal", []].`);
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
const
|
|
92
|
-
if (typeof op !== 'string') {
|
|
93
|
-
this.error(`Expression name must be a string, but found ${typeof op} instead. If you wanted a literal array, use ["literal", [...]].`, 0);
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const Expr = this.registry[op];
|
|
95
|
+
const Expr = typeof expr[0] === 'string' ? this.registry[expr[0]] : undefined;
|
|
98
96
|
if (Expr) {
|
|
99
97
|
let parsed = Expr.parse(expr, this);
|
|
100
98
|
if (!parsed) return null;
|
|
@@ -125,7 +123,7 @@ class ParsingContext {
|
|
|
125
123
|
// parsed/compiled result. Expressions that expect an image should
|
|
126
124
|
// not be resolved here so we can later get the available images.
|
|
127
125
|
if (!(parsed instanceof Literal) && (parsed.type.kind !== 'resolvedImage') && isConstant(parsed)) {
|
|
128
|
-
const ec = new EvaluationContext();
|
|
126
|
+
const ec = new EvaluationContext(this.options);
|
|
129
127
|
try {
|
|
130
128
|
parsed = new Literal(parsed.type, parsed.evaluate(ec));
|
|
131
129
|
} catch (e) {
|
|
@@ -137,7 +135,8 @@ class ParsingContext {
|
|
|
137
135
|
return parsed;
|
|
138
136
|
}
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
// Try to parse as array
|
|
139
|
+
return Coercion.parse(['to-array', expr], this);
|
|
141
140
|
} else if (typeof expr === 'undefined') {
|
|
142
141
|
return this.error(`'undefined' value invalid. Use null instead.`);
|
|
143
142
|
} else if (typeof expr === 'object') {
|
|
@@ -155,7 +154,7 @@ class ParsingContext {
|
|
|
155
154
|
* parsing, is copied by reference rather than cloned.
|
|
156
155
|
* @private
|
|
157
156
|
*/
|
|
158
|
-
concat(index: number, expectedType?: ?Type, bindings?: Array<[string, Expression]>): ParsingContext {
|
|
157
|
+
concat(index: ?number, expectedType?: ?Type, bindings?: Array<[string, Expression]>): ParsingContext {
|
|
159
158
|
const path = typeof index === 'number' ? this.path.concat(index) : this.path;
|
|
160
159
|
const scope = bindings ? this.scope.concat(bindings) : this.scope;
|
|
161
160
|
return new ParsingContext(
|
|
@@ -163,7 +162,8 @@ class ParsingContext {
|
|
|
163
162
|
path,
|
|
164
163
|
expectedType || null,
|
|
165
164
|
scope,
|
|
166
|
-
this.errors
|
|
165
|
+
this.errors,
|
|
166
|
+
this.options
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -197,12 +197,16 @@ function isConstant(expression: Expression) {
|
|
|
197
197
|
return isConstant(expression.boundExpression);
|
|
198
198
|
} else if (expression instanceof CompoundExpression && expression.name === 'error') {
|
|
199
199
|
return false;
|
|
200
|
+
} else if (expression instanceof CompoundExpression && expression.name === 'config') {
|
|
201
|
+
return false;
|
|
200
202
|
} else if (expression instanceof CollatorExpression) {
|
|
201
203
|
// Although the results of a Collator expression with fixed arguments
|
|
202
204
|
// generally shouldn't change between executions, we can't serialize them
|
|
203
205
|
// as constant expressions because results change based on environment.
|
|
204
206
|
return false;
|
|
205
|
-
}
|
|
207
|
+
} else if (expression instanceof Within) {
|
|
208
|
+
return false;
|
|
209
|
+
} else if (expression instanceof Distance) {
|
|
206
210
|
return false;
|
|
207
211
|
}
|
|
208
212
|
|
|
@@ -229,5 +233,5 @@ function isConstant(expression: Expression) {
|
|
|
229
233
|
}
|
|
230
234
|
|
|
231
235
|
return isFeatureConstant(expression) &&
|
|
232
|
-
isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'line-progress', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center']);
|
|
236
|
+
isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'line-progress', 'raster-value', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center', 'measure-light']);
|
|
233
237
|
}
|
|
@@ -33,7 +33,7 @@ export default class Formatted {
|
|
|
33
33
|
isEmpty(): boolean {
|
|
34
34
|
if (this.sections.length === 0) return true;
|
|
35
35
|
return !this.sections.some(section => section.text.length !== 0 ||
|
|
36
|
-
(section.image && section.image.
|
|
36
|
+
(section.image && section.image.namePrimary.length !== 0));
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
static factory(text: Formatted | string): Formatted {
|
|
@@ -53,7 +53,7 @@ export default class Formatted {
|
|
|
53
53
|
const serialized: Array<mixed> = ["format"];
|
|
54
54
|
for (const section of this.sections) {
|
|
55
55
|
if (section.image) {
|
|
56
|
-
serialized.push(["image", section.image.
|
|
56
|
+
serialized.push(["image", section.image.namePrimary]);
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
59
|
serialized.push(section.text);
|
|
@@ -1,29 +1,40 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
3
|
export type ResolvedImageOptions = {
|
|
4
|
-
|
|
4
|
+
namePrimary: string,
|
|
5
|
+
nameSecondary: ?string,
|
|
5
6
|
available: boolean
|
|
6
7
|
};
|
|
7
8
|
|
|
8
9
|
export default class ResolvedImage {
|
|
9
|
-
|
|
10
|
+
namePrimary: string;
|
|
11
|
+
nameSecondary: ?string;
|
|
10
12
|
available: boolean;
|
|
11
13
|
|
|
12
14
|
constructor(options: ResolvedImageOptions) {
|
|
13
|
-
this.
|
|
15
|
+
this.namePrimary = options.namePrimary;
|
|
16
|
+
if (options.nameSecondary) {
|
|
17
|
+
this.nameSecondary = options.nameSecondary;
|
|
18
|
+
}
|
|
14
19
|
this.available = options.available;
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
toString(): string {
|
|
18
|
-
|
|
23
|
+
if (this.nameSecondary) {
|
|
24
|
+
return `[${this.namePrimary},${this.nameSecondary}]`;
|
|
25
|
+
}
|
|
26
|
+
return this.namePrimary;
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
static fromString(
|
|
22
|
-
if (!
|
|
23
|
-
return new ResolvedImage({
|
|
29
|
+
static fromString(namePrimary: string, nameSecondary: ?string): ResolvedImage | null {
|
|
30
|
+
if (!namePrimary) return null; // treat empty values as no image
|
|
31
|
+
return new ResolvedImage({namePrimary, nameSecondary, available: false});
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
serialize(): Array<string> {
|
|
27
|
-
|
|
35
|
+
if (this.nameSecondary) {
|
|
36
|
+
return ["image", this.namePrimary, this.nameSecondary];
|
|
37
|
+
}
|
|
38
|
+
return ["image", this.namePrimary];
|
|
28
39
|
}
|
|
29
40
|
}
|
package/expression/types.js
CHANGED
package/expression/values.js
CHANGED
|
@@ -29,6 +29,31 @@ export function validateRGBA(r: mixed, g: mixed, b: mixed, a?: mixed): string |
|
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export function validateHSLA(h: mixed, s: mixed, l: mixed, a?: mixed): string | null {
|
|
33
|
+
if (!(
|
|
34
|
+
typeof h === 'number' && h >= 0 && h <= 360
|
|
35
|
+
)) {
|
|
36
|
+
const value = typeof a === 'number' ? [h, s, l, a] : [h, s, l];
|
|
37
|
+
return `Invalid hsla value [${value.join(', ')}]: 'h' must be between 0 and 360.`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!(
|
|
41
|
+
typeof s === 'number' && s >= 0 && s <= 100 &&
|
|
42
|
+
typeof l === 'number' && l >= 0 && l <= 100
|
|
43
|
+
)) {
|
|
44
|
+
const value = typeof a === 'number' ? [h, s, l, a] : [h, s, l];
|
|
45
|
+
return `Invalid hsla value [${value.join(', ')}]: 's', and 'l' must be between 0 and 100.`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!(
|
|
49
|
+
typeof a === 'undefined' || (typeof a === 'number' && a >= 0 && a <= 1)
|
|
50
|
+
)) {
|
|
51
|
+
return `Invalid hsla value [${[h, s, l, a].join(', ')}]: 'a' must be between 0 and 1.`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
export type Value = null | string | boolean | number | Color | Collator | Formatted | ResolvedImage | $ReadOnlyArray<Value> | { +[string]: Value }
|
|
33
58
|
|
|
34
59
|
export function isValue(mixed: mixed): boolean {
|
|
@@ -161,7 +161,7 @@ function convertComparisonOp(property: string, value: any, op: string, expectedT
|
|
|
161
161
|
return [op, get, value];
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
function convertInOp(property: string, values: Array<any>, negate = false) {
|
|
164
|
+
function convertInOp(property: string, values: Array<any>, negate: boolean = false) {
|
|
165
165
|
if (values.length === 0) return negate;
|
|
166
166
|
|
|
167
167
|
let get;
|
package/feature_filter/index.js
CHANGED
|
@@ -73,6 +73,7 @@ function createFilter(filter: any, layerType?: string = 'fill'): FeatureFilter {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
if (!isExpressionFilter(filter)) {
|
|
76
|
+
// $FlowFixMe[incompatible-call]
|
|
76
77
|
filter = convertFilter(filter);
|
|
77
78
|
}
|
|
78
79
|
const filterExp = ((filter: any): string[] | string | boolean);
|
|
@@ -253,13 +254,13 @@ function collapsedExpression(expression: any): any {
|
|
|
253
254
|
}
|
|
254
255
|
|
|
255
256
|
// Comparison function to sort numbers and strings
|
|
256
|
-
function compare(a, b) {
|
|
257
|
+
function compare(a: number, b: number) {
|
|
257
258
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
258
259
|
}
|
|
259
260
|
|
|
260
|
-
function geometryNeeded(filter) {
|
|
261
|
+
function geometryNeeded(filter: Array<any> | boolean) {
|
|
261
262
|
if (!Array.isArray(filter)) return false;
|
|
262
|
-
if (filter[0] === 'within') return true;
|
|
263
|
+
if (filter[0] === 'within' || filter[0] === 'distance') return true;
|
|
263
264
|
for (let index = 1; index < filter.length; index++) {
|
|
264
265
|
if (geometryNeeded(filter[index])) return true;
|
|
265
266
|
}
|
|
@@ -284,7 +285,6 @@ function convertFilter(filter: ?Array<any>): mixed {
|
|
|
284
285
|
op === '!in' ? convertNegation(convertInOp(filter[1], filter.slice(2))) :
|
|
285
286
|
op === 'has' ? convertHasOp(filter[1]) :
|
|
286
287
|
op === '!has' ? convertNegation(convertHasOp(filter[1])) :
|
|
287
|
-
op === 'within' ? filter :
|
|
288
288
|
true;
|
|
289
289
|
return converted;
|
|
290
290
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// @flow strict
|
|
2
|
+
|
|
3
|
+
declare module 'cheap-ruler' {
|
|
4
|
+
import type { GeoJSONPosition} from '@mapbox/geojson-types';
|
|
5
|
+
declare export default class CheapRuler {
|
|
6
|
+
kx: number;
|
|
7
|
+
ky: number;
|
|
8
|
+
constructor(lat: number, units: string): CheapRuler;
|
|
9
|
+
distance(a: GeoJSONPosition, b: GeoJSONPosition): number;
|
|
10
|
+
bearing(a: GeoJSONPosition, b: GeoJSONPosition): number;
|
|
11
|
+
destination(p: GeoJSONPosition, dist: number , bearing: number): GeoJSONPosition;
|
|
12
|
+
offset(p: GeoJSONPosition, dx: number, dy: number): GeoJSONPosition;
|
|
13
|
+
lineDistance(points: Array<GeoJSONPosition>): number;
|
|
14
|
+
area(polygon: Array<Array<GeoJSONPosition>>): number;
|
|
15
|
+
along(line: Array<GeoJSONPosition>, dist: number): GeoJSONPosition;
|
|
16
|
+
pointToSegmentDistance(p: GeoJSONPosition, a: GeoJSONPosition, b: GeoJSONPosition): number;
|
|
17
|
+
pointOnLine(line: Array<GeoJSONPosition>, p: GeoJSONPosition): Object;
|
|
18
|
+
lineSlice(start: GeoJSONPosition, stop: GeoJSONPosition, line: Array<GeoJSONPosition>): Array<GeoJSONPosition>;
|
|
19
|
+
lineSliceAlong(start: GeoJSONPosition, stop: GeoJSONPosition, line: Array<GeoJSONPosition>): Array<GeoJSONPosition>;
|
|
20
|
+
bufferPoint(p: GeoJSONPosition, buffer: number): GeoJSONPosition;
|
|
21
|
+
bufferBBox(bbox: GeoJSONPosition, buffer: number): GeoJSONPosition;
|
|
22
|
+
insideBBox(p: GeoJSONPosition, bbox: GeoJSONPosition): boolean;
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
}
|
package/flow-typed/geojson.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @flow strict
|
|
2
2
|
|
|
3
|
-
type GeoJSONPosition = [number, number] | [number, number, number];
|
|
4
3
|
type Geometry<T, C> = { type: T, coordinates: C }
|
|
5
4
|
|
|
6
5
|
declare module "@mapbox/geojson-types" {
|
|
6
|
+
declare export type GeoJSONPosition = [number, number] | [number, number, number];
|
|
7
|
+
|
|
7
8
|
declare export type GeoJSONPoint = Geometry<'Point', GeoJSONPosition>;
|
|
8
9
|
declare export type GeoJSONMultiPoint = Geometry<'MultiPoint', Array<GeoJSONPosition>>;
|
|
9
10
|
|
|
@@ -27,12 +28,12 @@ declare module "@mapbox/geojson-types" {
|
|
|
27
28
|
geometries: Array<GeoJSONGeometry>
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
declare export
|
|
31
|
-
type: 'Feature'
|
|
32
|
-
geometry: ?GeoJSONGeometry
|
|
33
|
-
properties: ?{}
|
|
34
|
-
id?: number | string
|
|
35
|
-
}
|
|
31
|
+
declare export interface GeoJSONFeature {
|
|
32
|
+
type: 'Feature';
|
|
33
|
+
geometry: ?GeoJSONGeometry;
|
|
34
|
+
properties: ?{};
|
|
35
|
+
id?: number | string;
|
|
36
|
+
}
|
|
36
37
|
|
|
37
38
|
declare export type GeoJSONFeatureCollection = {
|
|
38
39
|
type: 'FeatureCollection',
|