ol 8.1.1-dev.1694687206621 → 8.1.1-dev.1694712969002

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/expr/cpu.js CHANGED
@@ -187,14 +187,8 @@ function compileAssertionExpression(expression, context) {
187
187
  * @return {ExpressionEvaluator} The evaluator function.
188
188
  */
189
189
  function compileAccessorExpression(expression, context) {
190
- const nameExpression = expression.args[0];
191
- if (!(nameExpression instanceof LiteralExpression)) {
192
- throw new Error('Expected literal name');
193
- }
194
- const name = nameExpression.value;
195
- if (typeof name !== 'string') {
196
- throw new Error('Expected string name');
197
- }
190
+ const nameExpression = /** @type {LiteralExpression} */ (expression.args[0]);
191
+ const name = /** @type {string} */ (nameExpression.value);
198
192
  switch (expression.operator) {
199
193
  case Ops.Get: {
200
194
  return (context) => context.properties[name];
@@ -29,6 +29,7 @@ export function isType(type: number, expected: number): boolean;
29
29
  * @typedef {Object} ParsingContext
30
30
  * @property {Set<string>} variables Variables referenced with the 'var' operator.
31
31
  * @property {Set<string>} properties Properties referenced with the 'get' operator.
32
+ * @property {import("../style/literal").LiteralStyle} style The style being parsed
32
33
  */
33
34
  /**
34
35
  * @return {ParsingContext} A new parsing context.
@@ -40,9 +41,10 @@ export function newParsingContext(): ParsingContext;
40
41
  /**
41
42
  * @param {EncodedExpression} encoded The encoded expression.
42
43
  * @param {ParsingContext} context The parsing context.
44
+ * @param {number} [typeHint] Optional type hint
43
45
  * @return {Expression} The parsed expression result.
44
46
  */
45
- export function parse(encoded: EncodedExpression, context: ParsingContext): Expression;
47
+ export function parse(encoded: EncodedExpression, context: ParsingContext, typeHint?: number | undefined): Expression;
46
48
  export const NoneType: 0;
47
49
  export const BooleanType: number;
48
50
  export const NumberType: number;
@@ -89,9 +91,22 @@ export type ParsingContext = {
89
91
  * Properties referenced with the 'get' operator.
90
92
  */
91
93
  properties: Set<string>;
94
+ /**
95
+ * The style being parsed
96
+ */
97
+ style: import("../style/literal").LiteralStyle;
92
98
  };
93
99
  export type EncodedExpression = LiteralValue | any[];
94
- export type ArgValidator = (arg0: any[], arg1: ParsingContext) => Array<Expression>;
100
+ /**
101
+ * An argument validator applies various checks to an encoded expression arguments
102
+ * Returns the parsed arguments if any.
103
+ * Third argument is the array of parsed arguments from previous validators
104
+ * Fourth argument is an optional type hint
105
+ */
106
+ export type ArgValidator = (arg0: Array<EncodedExpression>, arg1: ParsingContext, arg2: Array<Expression>, arg3: number | null) => Array<Expression> | void;
95
107
  export type LiteralValue = boolean | number | string | Array<number>;
96
- export type Parser = (arg0: any[], arg1: ParsingContext) => Expression;
108
+ /**
109
+ * Third argument is a type hint
110
+ */
111
+ export type Parser = (arg0: any[], arg1: ParsingContext, arg2: number) => Expression;
97
112
  //# sourceMappingURL=expression.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["expression.js"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,+BAHW,MAAM,GACL,MAAM,CAgBjB;AAED;;;;GAIG;AACH,oCAJW,MAAM,YACN,MAAM,GACL,OAAO,CAIlB;AAED;;;;GAIG;AACH,sCAJW,MAAM,aACN,MAAM,GACL,OAAO,CAIlB;AAED;;;;GAIG;AACH,6BAJW,MAAM,YACN,MAAM,GACL,OAAO,CAIlB;AA8BD;;GAEG;AAEH;;;;GAIG;AAEH;;GAEG;AACH,qCAFY,cAAc,CAOzB;AAED;;GAEG;AAEH;;;;GAIG;AACH,+BAJW,iBAAiB,WACjB,cAAc,GACb,UAAU,CA0CrB;AAnKD,yBAA0B;AAC1B,iCAA2C;AAC3C,gCAA0C;AAC1C,gCAA0C;AAC1C,+BAAyC;AACzC,qCAA+C;AAC/C,6BAAiD;AA4DjD;;GAEG;AAEH;IACE;;;OAGG;IACH,kBAHW,MAAM,SACN,YAAY,EAKtB;IAFC,aAAgB;IAChB,oBAAkB;CAErB;AAED;IACE;;;;OAIG;IACH,kBAJW,MAAM,YACN,MAAM,WACH,UAAU,IAMvB;IAHC,aAAgB;IAChB,iBAAwB;IACxB,mBAAgB;CAEnB;AAyED;;GAEG;AACH;QAFiB,MAAM,GAAE,MAAM;EAiC7B;yBAxGW,iBAAiB,GAAC,cAAc;;;;;eAK/B,IAAI,MAAM,CAAC;;;;gBACX,IAAI,MAAM,CAAC;;gCAcZ,YAAY,QAAM;+CAqIF,cAAc,KAAE,MAAM,UAAU,CAAC;2BArLjD,OAAO,GAAC,MAAM,GAAC,MAAM,GAAC,MAAM,MAAM,CAAC;yCAuInB,cAAc,KAAE,UAAU"}
1
+ {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["expression.js"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,+BAHW,MAAM,GACL,MAAM,CAgBjB;AAED;;;;GAIG;AACH,oCAJW,MAAM,YACN,MAAM,GACL,OAAO,CAIlB;AAED;;;;GAIG;AACH,sCAJW,MAAM,aACN,MAAM,GACL,OAAO,CAIlB;AAED;;;;GAIG;AACH,6BAJW,MAAM,YACN,MAAM,GACL,OAAO,CAIlB;AA8BD;;GAEG;AAEH;;;;;GAKG;AAEH;;GAEG;AACH,qCAFY,cAAc,CAQzB;AAED;;GAEG;AAEH;;;;;GAKG;AACH,+BALW,iBAAiB,WACjB,cAAc,kCAEb,UAAU,CA8CrB;AA1KD,yBAA0B;AAC1B,iCAA2C;AAC3C,gCAA0C;AAC1C,gCAA0C;AAC1C,+BAAyC;AACzC,qCAA+C;AAC/C,6BAAiD;AA4DjD;;GAEG;AAEH;IACE;;;OAGG;IACH,kBAHW,MAAM,SACN,YAAY,EAKtB;IAFC,aAAgB;IAChB,oBAAkB;CAErB;AAED;IACE;;;;OAIG;IACH,kBAJW,MAAM,YACN,MAAM,WACH,UAAU,IAMvB;IAHC,aAAgB;IAChB,iBAAwB;IACxB,mBAAgB;CAEnB;AAgFD;;GAEG;AACH;QAFiB,MAAM,GAAE,MAAM;EA0C7B;yBAxHW,iBAAiB,GAAC,cAAc;;;;;eAK/B,IAAI,MAAM,CAAC;;;;gBACX,IAAI,MAAM,CAAC;;;;WACX,OAAO,kBAAkB,EAAE,YAAY;;gCAexC,YAAY,QAAM;;;;;;;kCA2TT,MAAM,iBAAiB,CAAC,QAAE,cAAc,QAAE,MAAM,UAAU,CAAC,QAAE,MAAM,YAAG,MAAM,UAAU,CAAC,GAAC,IAAI;2BA7WrG,OAAO,GAAC,MAAM,GAAC,MAAM,GAAC,MAAM,MAAM,CAAC;;;;yCAuJnB,cAAc,QAAE,MAAM,KAAE,UAAU"}
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @module ol/expr/expression
3
3
  */
4
-
5
4
  import {ascending} from '../array.js';
5
+ import {isStringColor} from '../color.js';
6
6
 
7
7
  /**
8
8
  * @fileoverview This module includes types and functions for parsing array encoded expressions.
@@ -114,6 +114,7 @@ export class CallExpression {
114
114
  * @typedef {Object} ParsingContext
115
115
  * @property {Set<string>} variables Variables referenced with the 'var' operator.
116
116
  * @property {Set<string>} properties Properties referenced with the 'get' operator.
117
+ * @property {import("../style/literal").LiteralStyle} style The style being parsed
117
118
  */
118
119
 
119
120
  /**
@@ -123,6 +124,7 @@ export function newParsingContext() {
123
124
  return {
124
125
  variables: new Set(),
125
126
  properties: new Set(),
127
+ style: {},
126
128
  };
127
129
  }
128
130
 
@@ -133,9 +135,10 @@ export function newParsingContext() {
133
135
  /**
134
136
  * @param {EncodedExpression} encoded The encoded expression.
135
137
  * @param {ParsingContext} context The parsing context.
138
+ * @param {number} [typeHint] Optional type hint
136
139
  * @return {Expression} The parsed expression result.
137
140
  */
138
- export function parse(encoded, context) {
141
+ export function parse(encoded, context, typeHint) {
139
142
  switch (typeof encoded) {
140
143
  case 'boolean': {
141
144
  return new LiteralExpression(BooleanType, encoded);
@@ -144,7 +147,11 @@ export function parse(encoded, context) {
144
147
  return new LiteralExpression(NumberType, encoded);
145
148
  }
146
149
  case 'string': {
147
- return new LiteralExpression(StringType, encoded);
150
+ let type = StringType;
151
+ if (isStringColor(encoded)) {
152
+ type |= ColorType;
153
+ }
154
+ return new LiteralExpression(type, encoded);
148
155
  }
149
156
  default: {
150
157
  // pass
@@ -160,7 +167,7 @@ export function parse(encoded, context) {
160
167
  }
161
168
 
162
169
  if (typeof encoded[0] === 'string') {
163
- return parseCallExpression(encoded, context);
170
+ return parseCallExpression(encoded, context, typeHint);
164
171
  }
165
172
 
166
173
  for (const item of encoded) {
@@ -181,14 +188,15 @@ export function parse(encoded, context) {
181
188
  * @type {Object<string, string>}
182
189
  */
183
190
  export const Ops = {
184
- Number: 'number',
185
- String: 'string',
186
191
  Get: 'get',
187
192
  Var: 'var',
193
+ GeometryType: 'geometry-type',
188
194
  Any: 'any',
189
195
  All: 'all',
190
196
  Not: '!',
191
197
  Resolution: 'resolution',
198
+ Zoom: 'zoom',
199
+ Time: 'time',
192
200
  Equal: '==',
193
201
  NotEqual: '!=',
194
202
  GreaterThan: '>',
@@ -211,65 +219,242 @@ export const Ops = {
211
219
  Atan: 'atan',
212
220
  Sqrt: 'sqrt',
213
221
  Match: 'match',
222
+ Between: 'between',
223
+ Interpolate: 'interpolate',
224
+ Case: 'case',
225
+ In: 'in',
226
+ Number: 'number',
227
+ String: 'string',
228
+ Array: 'array',
229
+ Color: 'color',
214
230
  };
215
231
 
216
232
  /**
217
- * @typedef {function(Array, ParsingContext):Expression} Parser
233
+ * @typedef {function(Array, ParsingContext, number):Expression} Parser
234
+ * Third argument is a type hint
218
235
  */
219
236
 
220
237
  /**
221
238
  * @type {Object<string, Parser>}
222
239
  */
223
240
  const parsers = {
224
- [Ops.Number]: createParser(withArgs(1, Infinity, AnyType), NumberType),
225
- [Ops.String]: createParser(withArgs(1, Infinity, AnyType), StringType),
226
- [Ops.Get]: createParser(withGetArgs, AnyType),
227
- [Ops.Var]: createParser(withVarArgs, AnyType),
228
- [Ops.Resolution]: createParser(withNoArgs, NumberType),
229
- [Ops.Any]: createParser(withArgs(2, Infinity, BooleanType), BooleanType),
230
- [Ops.All]: createParser(withArgs(2, Infinity, BooleanType), BooleanType),
231
- [Ops.Not]: createParser(withArgs(1, 1, BooleanType), BooleanType),
232
- [Ops.Equal]: createParser(withArgs(2, 2, AnyType), BooleanType),
233
- [Ops.NotEqual]: createParser(withArgs(2, 2, AnyType), BooleanType),
234
- [Ops.GreaterThan]: createParser(withArgs(2, 2, AnyType), BooleanType),
241
+ [Ops.Get]: createParser(AnyType, withArgsCount(1, 1), withGetArgs),
242
+ [Ops.Var]: createParser(AnyType, withArgsCount(1, 1), withVarArgs),
243
+ [Ops.GeometryType]: createParser(StringType, withNoArgs),
244
+ [Ops.Resolution]: createParser(NumberType, withNoArgs),
245
+ [Ops.Zoom]: createParser(NumberType, withNoArgs),
246
+ [Ops.Time]: createParser(NumberType, withNoArgs),
247
+ [Ops.Any]: createParser(
248
+ BooleanType,
249
+ withArgsCount(2, Infinity),
250
+ parseArgsOfType(BooleanType)
251
+ ),
252
+ [Ops.All]: createParser(
253
+ BooleanType,
254
+ withArgsCount(2, Infinity),
255
+ parseArgsOfType(BooleanType)
256
+ ),
257
+ [Ops.Not]: createParser(
258
+ BooleanType,
259
+ withArgsCount(1, 1),
260
+ parseArgsOfType(BooleanType)
261
+ ),
262
+ [Ops.Equal]: createParser(
263
+ BooleanType,
264
+ withArgsCount(2, 2),
265
+ parseArgsOfType(AnyType),
266
+ narrowArgsType
267
+ ),
268
+ [Ops.NotEqual]: createParser(
269
+ BooleanType,
270
+ withArgsCount(2, 2),
271
+ parseArgsOfType(AnyType),
272
+ narrowArgsType
273
+ ),
274
+ [Ops.GreaterThan]: createParser(
275
+ BooleanType,
276
+ withArgsCount(2, 2),
277
+ parseArgsOfType(AnyType),
278
+ narrowArgsType
279
+ ),
235
280
  [Ops.GreaterThanOrEqualTo]: createParser(
236
- withArgs(2, 2, AnyType),
237
- BooleanType
238
- ),
239
- [Ops.LessThan]: createParser(withArgs(2, 2, AnyType), BooleanType),
240
- [Ops.LessThanOrEqualTo]: createParser(withArgs(2, 2, AnyType), BooleanType),
241
- [Ops.Multiply]: createParser(withArgs(2, Infinity, NumberType), NumberType),
242
- [Ops.Divide]: createParser(withArgs(2, 2, NumberType), NumberType),
243
- [Ops.Add]: createParser(withArgs(2, Infinity, NumberType), NumberType),
244
- [Ops.Subtract]: createParser(withArgs(2, 2, NumberType), NumberType),
245
- [Ops.Clamp]: createParser(withArgs(3, 3, NumberType), NumberType),
246
- [Ops.Mod]: createParser(withArgs(2, 2, NumberType), NumberType),
247
- [Ops.Pow]: createParser(withArgs(2, 2, NumberType), NumberType),
248
- [Ops.Abs]: createParser(withArgs(1, 1, NumberType), NumberType),
249
- [Ops.Floor]: createParser(withArgs(1, 1, NumberType), NumberType),
250
- [Ops.Ceil]: createParser(withArgs(1, 1, NumberType), NumberType),
251
- [Ops.Round]: createParser(withArgs(1, 1, NumberType), NumberType),
252
- [Ops.Sin]: createParser(withArgs(1, 1, NumberType), NumberType),
253
- [Ops.Cos]: createParser(withArgs(1, 1, NumberType), NumberType),
254
- [Ops.Atan]: createParser(withArgs(1, 2, NumberType), NumberType),
255
- [Ops.Sqrt]: createParser(withArgs(1, 1, NumberType), NumberType),
281
+ BooleanType,
282
+ withArgsCount(2, 2),
283
+ parseArgsOfType(AnyType),
284
+ narrowArgsType
285
+ ),
286
+ [Ops.LessThan]: createParser(
287
+ BooleanType,
288
+ withArgsCount(2, 2),
289
+ parseArgsOfType(AnyType),
290
+ narrowArgsType
291
+ ),
292
+ [Ops.LessThanOrEqualTo]: createParser(
293
+ BooleanType,
294
+ withArgsCount(2, 2),
295
+ parseArgsOfType(AnyType),
296
+ narrowArgsType
297
+ ),
298
+ [Ops.Multiply]: createParser(
299
+ (parsedArgs) => {
300
+ let outputType = NumberType | ColorType;
301
+ for (let i = 0; i < parsedArgs.length; i++) {
302
+ outputType &= parsedArgs[i].type;
303
+ }
304
+ return outputType;
305
+ },
306
+ withArgsCount(2, Infinity),
307
+ parseArgsOfType(NumberType | ColorType),
308
+ narrowArgsType
309
+ ),
310
+ [Ops.Divide]: createParser(
311
+ NumberType,
312
+ withArgsCount(2, 2),
313
+ parseArgsOfType(NumberType)
314
+ ),
315
+ [Ops.Add]: createParser(
316
+ NumberType,
317
+ withArgsCount(2, Infinity),
318
+ parseArgsOfType(NumberType)
319
+ ),
320
+ [Ops.Subtract]: createParser(
321
+ NumberType,
322
+ withArgsCount(2, 2),
323
+ parseArgsOfType(NumberType)
324
+ ),
325
+ [Ops.Clamp]: createParser(
326
+ NumberType,
327
+ withArgsCount(3, 3),
328
+ parseArgsOfType(NumberType)
329
+ ),
330
+ [Ops.Mod]: createParser(
331
+ NumberType,
332
+ withArgsCount(2, 2),
333
+ parseArgsOfType(NumberType)
334
+ ),
335
+ [Ops.Pow]: createParser(
336
+ NumberType,
337
+ withArgsCount(2, 2),
338
+ parseArgsOfType(NumberType)
339
+ ),
340
+ [Ops.Abs]: createParser(
341
+ NumberType,
342
+ withArgsCount(1, 1),
343
+ parseArgsOfType(NumberType)
344
+ ),
345
+ [Ops.Floor]: createParser(
346
+ NumberType,
347
+ withArgsCount(1, 1),
348
+ parseArgsOfType(NumberType)
349
+ ),
350
+ [Ops.Ceil]: createParser(
351
+ NumberType,
352
+ withArgsCount(1, 1),
353
+ parseArgsOfType(NumberType)
354
+ ),
355
+ [Ops.Round]: createParser(
356
+ NumberType,
357
+ withArgsCount(1, 1),
358
+ parseArgsOfType(NumberType)
359
+ ),
360
+ [Ops.Sin]: createParser(
361
+ NumberType,
362
+ withArgsCount(1, 1),
363
+ parseArgsOfType(NumberType)
364
+ ),
365
+ [Ops.Cos]: createParser(
366
+ NumberType,
367
+ withArgsCount(1, 1),
368
+ parseArgsOfType(NumberType)
369
+ ),
370
+ [Ops.Atan]: createParser(
371
+ NumberType,
372
+ withArgsCount(1, 2),
373
+ parseArgsOfType(NumberType)
374
+ ),
375
+ [Ops.Sqrt]: createParser(
376
+ NumberType,
377
+ withArgsCount(1, 1),
378
+ parseArgsOfType(NumberType)
379
+ ),
256
380
  [Ops.Match]: createParser(
257
- withArgs(4, Infinity, StringType | NumberType),
258
- AnyType
381
+ (parsedArgs) => {
382
+ let type = AnyType;
383
+ for (let i = 2; i < parsedArgs.length; i += 2) {
384
+ type &= parsedArgs[i].type;
385
+ }
386
+ type &= parsedArgs[parsedArgs.length - 1].type;
387
+ return type;
388
+ },
389
+ withArgsCount(4, Infinity),
390
+ withEvenArgs,
391
+ parseMatchArgs
392
+ ),
393
+ [Ops.Between]: createParser(
394
+ BooleanType,
395
+ withArgsCount(3, 3),
396
+ parseArgsOfType(NumberType)
397
+ ),
398
+ [Ops.Interpolate]: createParser(
399
+ (parsedArgs) => {
400
+ let type = ColorType | NumberType;
401
+ for (let i = 3; i < parsedArgs.length; i += 2) {
402
+ type &= parsedArgs[i].type;
403
+ }
404
+ return type;
405
+ },
406
+ withArgsCount(6, Infinity),
407
+ withEvenArgs,
408
+ parseInterpolateArgs
409
+ ),
410
+ [Ops.Case]: createParser(
411
+ (parsedArgs) => {
412
+ let type = AnyType;
413
+ for (let i = 1; i < parsedArgs.length; i += 2) {
414
+ type &= parsedArgs[i].type;
415
+ }
416
+ type &= parsedArgs[parsedArgs.length - 1].type;
417
+ return type;
418
+ },
419
+ withArgsCount(3, Infinity),
420
+ withOddArgs,
421
+ parseCaseArgs
422
+ ),
423
+ [Ops.In]: createParser(BooleanType, withArgsCount(2, 2), parseInArgs),
424
+ [Ops.Number]: createParser(
425
+ NumberType,
426
+ withArgsCount(1, Infinity),
427
+ parseArgsOfType(AnyType)
428
+ ),
429
+ [Ops.String]: createParser(
430
+ StringType,
431
+ withArgsCount(1, Infinity),
432
+ parseArgsOfType(AnyType)
433
+ ),
434
+ [Ops.Array]: createParser(
435
+ NumberArrayType,
436
+ withArgsCount(1, Infinity),
437
+ parseArgsOfType(NumberType)
438
+ ),
439
+ [Ops.Color]: createParser(
440
+ ColorType,
441
+ withArgsCount(3, 4),
442
+ parseArgsOfType(NumberType)
259
443
  ),
260
444
  };
261
445
 
262
446
  /**
263
- * @typedef {function(Array, ParsingContext):Array<Expression>} ArgValidator
447
+ * @typedef {function(Array<EncodedExpression>, ParsingContext, Array<Expression>, number?):Array<Expression>|void} ArgValidator
448
+ * An argument validator applies various checks to an encoded expression arguments
449
+ * Returns the parsed arguments if any.
450
+ * Third argument is the array of parsed arguments from previous validators
451
+ * Fourth argument is an optional type hint
264
452
  */
265
453
 
266
454
  /**
267
455
  * @type ArgValidator
268
456
  */
269
457
  function withGetArgs(encoded, context) {
270
- if (encoded.length !== 2) {
271
- throw new Error('Expected 1 argument for get operation');
272
- }
273
458
  const arg = parse(encoded[1], context);
274
459
  if (!(arg instanceof LiteralExpression)) {
275
460
  throw new Error('Expected a literal argument for get operation');
@@ -285,9 +470,6 @@ function withGetArgs(encoded, context) {
285
470
  * @type ArgValidator
286
471
  */
287
472
  function withVarArgs(encoded, context) {
288
- if (encoded.length !== 2) {
289
- throw new Error('Expected 1 argument for var operation');
290
- }
291
473
  const arg = parse(encoded[1], context);
292
474
  if (!(arg instanceof LiteralExpression)) {
293
475
  throw new Error('Expected a literal argument for var operation');
@@ -313,10 +495,9 @@ function withNoArgs(encoded, context) {
313
495
  /**
314
496
  * @param {number} minArgs The minimum number of arguments.
315
497
  * @param {number} maxArgs The maximum number of arguments.
316
- * @param {number} argType The argument type.
317
498
  * @return {ArgValidator} The argument validator
318
499
  */
319
- function withArgs(minArgs, maxArgs, argType) {
500
+ function withArgsCount(minArgs, maxArgs) {
320
501
  return function (encoded, context) {
321
502
  const operation = encoded[0];
322
503
  const argCount = encoded.length - 1;
@@ -332,13 +513,23 @@ function withArgs(minArgs, maxArgs, argType) {
332
513
  `Expected ${minArgs} to ${maxArgs} arguments for operation ${operation}, got ${argCount}`
333
514
  );
334
515
  }
516
+ };
517
+ }
335
518
 
519
+ /**
520
+ * @param {number} argType The argument type.
521
+ * @return {ArgValidator} The argument validator
522
+ */
523
+ function parseArgsOfType(argType) {
524
+ return function (encoded, context, parsedArgs, typeHint) {
525
+ const operation = encoded[0];
526
+ const argCount = encoded.length - 1;
336
527
  /**
337
528
  * @type {Array<Expression>}
338
529
  */
339
530
  const args = new Array(argCount);
340
531
  for (let i = 0; i < argCount; ++i) {
341
- const expression = parse(encoded[i + 1], context);
532
+ const expression = parse(encoded[i + 1], context, typeHint);
342
533
  if (!overlapsType(argType, expression.type)) {
343
534
  const gotType = typeName(argType);
344
535
  const expectedType = typeName(expression.type);
@@ -349,35 +540,205 @@ function withArgs(minArgs, maxArgs, argType) {
349
540
  }
350
541
  args[i] = expression;
351
542
  }
352
-
353
543
  return args;
354
544
  };
355
545
  }
356
546
 
357
547
  /**
358
- * @param {ArgValidator} argValidator The argument validator.
359
- * @param {number} returnType The return type.
548
+ * @type {ArgValidator}
549
+ */
550
+ function narrowArgsType(encoded, context, parsedArgs, typeHint) {
551
+ const operation = encoded[0];
552
+ const argCount = encoded.length - 1;
553
+
554
+ // first pass to determine a narrowed down type
555
+ let sameType = typeHint !== undefined ? typeHint : AnyType;
556
+ for (let i = 0; i < parsedArgs.length; ++i) {
557
+ sameType &= parsedArgs[i].type;
558
+ }
559
+
560
+ if (sameType === NoneType) {
561
+ throw new Error(
562
+ `No common type could be found for arguments of ${operation} operation`
563
+ );
564
+ }
565
+
566
+ // re-parse args
567
+ const args = new Array(argCount);
568
+ for (let i = 0; i < argCount; ++i) {
569
+ args[i] = parse(encoded[i + 1], context, sameType);
570
+ }
571
+ return args;
572
+ }
573
+
574
+ /**
575
+ * @type {ArgValidator}
576
+ */
577
+ function withOddArgs(encoded, context) {
578
+ const operation = encoded[0];
579
+ const argCount = encoded.length - 1;
580
+ if (argCount % 2 === 0) {
581
+ throw new Error(
582
+ `An odd amount of arguments was expected for operation ${operation}, got ${JSON.stringify(
583
+ argCount
584
+ )} instead`
585
+ );
586
+ }
587
+ }
588
+
589
+ /**
590
+ * @type {ArgValidator}
591
+ */
592
+ function withEvenArgs(encoded, context) {
593
+ const operation = encoded[0];
594
+ const argCount = encoded.length - 1;
595
+ if (argCount % 2 === 1) {
596
+ throw new Error(
597
+ `An even amount of arguments was expected for operation ${operation}, got ${JSON.stringify(
598
+ argCount
599
+ )} instead`
600
+ );
601
+ }
602
+ }
603
+
604
+ /**
605
+ * @type ArgValidator
606
+ */
607
+ function parseMatchArgs(encoded, context, typeHint) {
608
+ const argsCount = encoded.length - 1;
609
+
610
+ const input = parse(encoded[1], context);
611
+ let inputType = input.type;
612
+ const fallback = parse(encoded[encoded.length - 1], context);
613
+
614
+ const args = new Array(argsCount - 2);
615
+ for (let i = 0; i < argsCount - 2; i += 2) {
616
+ const match = parse(encoded[i + 2], context);
617
+ const output = parse(encoded[i + 3], context);
618
+ inputType &= match.type;
619
+ args[i] = match;
620
+ args[i + 1] = output;
621
+ }
622
+ const expectedInputType = StringType | NumberType | BooleanType;
623
+ if (!overlapsType(expectedInputType, inputType)) {
624
+ throw new Error(
625
+ `Expected an input of type ${typeName(
626
+ expectedInputType
627
+ )} for the interpolate operation` + ` : got ${inputType} instead`
628
+ );
629
+ }
630
+
631
+ return [input, ...args, fallback];
632
+ }
633
+
634
+ /**
635
+ * @type ArgValidator
636
+ */
637
+ function parseInterpolateArgs(encoded, context) {
638
+ const interpolationType = encoded[1];
639
+ let interpolation;
640
+ switch (interpolationType[0]) {
641
+ case 'linear':
642
+ interpolation = 1;
643
+ break;
644
+ case 'exponential':
645
+ interpolation = interpolationType[1];
646
+ break;
647
+ default:
648
+ interpolation = null;
649
+ }
650
+ if (!interpolation) {
651
+ throw new Error(
652
+ `Invalid interpolation type: ${JSON.stringify(interpolationType)}`
653
+ );
654
+ }
655
+
656
+ const parsedArgs = [
657
+ parse(interpolation, context),
658
+ ...encoded.slice(2).map((arg) => parse(arg, context)),
659
+ ];
660
+
661
+ // check input types
662
+ const input = parsedArgs[0];
663
+ if (!overlapsType(NumberType, input.type)) {
664
+ throw new Error(
665
+ `Expected an input of type number for the interpolate operation` +
666
+ ` : got ${typeName(input.type)} instead`
667
+ );
668
+ }
669
+
670
+ return parsedArgs;
671
+ }
672
+
673
+ /**
674
+ * @type ArgValidator
675
+ */
676
+ function parseCaseArgs(encoded, context) {
677
+ const parsedArgs = encoded.slice(1).map((arg) => parse(arg, context));
678
+
679
+ // check condition types
680
+ for (let i = 0; i < parsedArgs.length - 1; i += 2) {
681
+ if (!overlapsType(BooleanType, parsedArgs[i].type)) {
682
+ throw new Error(
683
+ `Expected all conditions in the case operation to be of type boolean` +
684
+ ` : got ${typeName(parsedArgs[i].type)} at position ${i} instead`
685
+ );
686
+ }
687
+ }
688
+
689
+ return encoded.slice(1).map((arg) => parse(arg, context));
690
+ }
691
+
692
+ /**
693
+ * @type ArgValidator
694
+ */
695
+ function parseInArgs(encoded, context) {
696
+ return encoded.slice(1).map((arg) => parse(arg, context));
697
+ }
698
+
699
+ /**
700
+ * @param {number|function(Array<Expression>):number} returnType The return type of the operator; can be a fixed value or a callback taking the parsed
701
+ * arguments
702
+ * @param {Array<ArgValidator>} argValidators A chain of argument validators; the return value of the last validator
703
+ * will be used as parsed arguments
360
704
  * @return {Parser} The parser.
361
705
  */
362
- function createParser(argValidator, returnType) {
363
- return function (encoded, context) {
706
+ function createParser(returnType, ...argValidators) {
707
+ return function (encoded, context, typeHint) {
364
708
  const operator = encoded[0];
365
- const args = argValidator(encoded, context);
366
- return new CallExpression(returnType, operator, ...args);
709
+ let parsedArgs = [];
710
+ for (let i = 0; i < argValidators.length; i++) {
711
+ parsedArgs =
712
+ argValidators[i](encoded, context, parsedArgs, typeHint) || parsedArgs;
713
+ }
714
+ let actualType =
715
+ typeof returnType === 'function' ? returnType(parsedArgs) : returnType;
716
+ if (typeHint !== undefined) {
717
+ actualType &= typeHint;
718
+ }
719
+ if (actualType === NoneType) {
720
+ throw new Error(
721
+ `No matching type was found for the following expression: ${JSON.stringify(
722
+ encoded
723
+ )}`
724
+ );
725
+ }
726
+ return new CallExpression(actualType, operator, ...parsedArgs);
367
727
  };
368
728
  }
369
729
 
370
730
  /**
371
731
  * @param {Array} encoded The encoded expression.
372
732
  * @param {ParsingContext} context The parsing context.
733
+ * @param {number} [typeHint] Optional type hint
373
734
  * @return {Expression} The parsed expression.
374
735
  */
375
- function parseCallExpression(encoded, context) {
736
+ function parseCallExpression(encoded, context, typeHint) {
376
737
  const operator = encoded[0];
377
738
 
378
739
  const parser = parsers[operator];
379
740
  if (!parser) {
380
741
  throw new Error(`Unknown operator: ${operator}`);
381
742
  }
382
- return parser(encoded, context);
743
+ return parser(encoded, context, typeHint);
383
744
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ol",
3
- "version": "8.1.1-dev.1694687206621",
3
+ "version": "8.1.1-dev.1694712969002",
4
4
  "description": "OpenLayers mapping library",
5
5
  "keywords": [
6
6
  "map",