@math.gl/core 5.0.0-alpha.17 → 5.0.0-alpha.19

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.
Files changed (148) hide show
  1. package/README.md +4 -0
  2. package/dist/classes/base/math-array.d.ts +1 -1
  3. package/dist/classes/base/math-array.d.ts.map +1 -1
  4. package/dist/classes/base/matrix.d.ts +1 -1
  5. package/dist/classes/base/matrix.d.ts.map +1 -1
  6. package/dist/classes/base/vector.d.ts +1 -1
  7. package/dist/classes/base/vector.d.ts.map +1 -1
  8. package/dist/classes/euler.d.ts +1 -1
  9. package/dist/classes/euler.d.ts.map +1 -1
  10. package/dist/classes/matrix3.d.ts +1 -1
  11. package/dist/classes/matrix3.d.ts.map +1 -1
  12. package/dist/classes/matrix4.d.ts +1 -1
  13. package/dist/classes/matrix4.d.ts.map +1 -1
  14. package/dist/classes/pose.d.ts +1 -1
  15. package/dist/classes/pose.d.ts.map +1 -1
  16. package/dist/classes/quaternion.d.ts +1 -1
  17. package/dist/classes/quaternion.d.ts.map +1 -1
  18. package/dist/classes/vector2.d.ts +1 -1
  19. package/dist/classes/vector2.d.ts.map +1 -1
  20. package/dist/classes/vector3.d.ts +1 -1
  21. package/dist/classes/vector3.d.ts.map +1 -1
  22. package/dist/classes/vector4.d.ts +1 -1
  23. package/dist/classes/vector4.d.ts.map +1 -1
  24. package/dist/expressions/expression-eval.d.ts +98 -0
  25. package/dist/expressions/expression-eval.d.ts.map +1 -0
  26. package/dist/expressions/expression-eval.js +302 -0
  27. package/dist/expressions/expression-eval.js.map +1 -0
  28. package/dist/expressions/function-libraries.d.ts +60 -0
  29. package/dist/expressions/function-libraries.d.ts.map +1 -0
  30. package/dist/expressions/function-libraries.js +69 -0
  31. package/dist/expressions/function-libraries.js.map +1 -0
  32. package/dist/expressions/function-registry.d.ts +93 -0
  33. package/dist/expressions/function-registry.d.ts.map +1 -0
  34. package/dist/expressions/function-registry.js +131 -0
  35. package/dist/expressions/function-registry.js.map +1 -0
  36. package/dist/expressions/get.d.ts +9 -0
  37. package/dist/expressions/get.d.ts.map +1 -0
  38. package/dist/expressions/get.js +32 -0
  39. package/dist/expressions/get.js.map +1 -0
  40. package/dist/expressions/index.cjs +1483 -0
  41. package/dist/expressions/index.cjs.map +6 -0
  42. package/dist/expressions/index.d.ts +7 -0
  43. package/dist/expressions/index.d.ts.map +1 -0
  44. package/dist/expressions/index.js +8 -0
  45. package/dist/expressions/index.js.map +1 -0
  46. package/dist/expressions/parse-expression-string.d.ts +21 -0
  47. package/dist/expressions/parse-expression-string.d.ts.map +1 -0
  48. package/dist/expressions/parse-expression-string.js +61 -0
  49. package/dist/expressions/parse-expression-string.js.map +1 -0
  50. package/dist/expressions/vendor/jsep/runtime.d.ts +3 -0
  51. package/dist/expressions/vendor/jsep/runtime.d.ts.map +1 -0
  52. package/dist/expressions/vendor/jsep/runtime.js +972 -0
  53. package/dist/expressions/vendor/jsep/runtime.js.map +1 -0
  54. package/dist/expressions/vendor/jsep/types.d.ts +141 -0
  55. package/dist/expressions/vendor/jsep/types.d.ts.map +1 -0
  56. package/dist/expressions/vendor/jsep/types.js +4 -0
  57. package/dist/expressions/vendor/jsep/types.js.map +1 -0
  58. package/dist/gl-matrix/common.d.ts +1 -1
  59. package/dist/gl-matrix/vec2.d.ts +1 -1
  60. package/dist/gl-matrix/vec2.d.ts.map +1 -1
  61. package/dist/index.d.ts +3 -3
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/lib/common.d.ts +1 -1
  64. package/dist/lib/common.d.ts.map +1 -1
  65. package/dist/lib/gl-matrix-extras.d.ts +1 -1
  66. package/dist/lib/gl-matrix-extras.d.ts.map +1 -1
  67. package/dist/lib/validators.d.ts +1 -1
  68. package/dist/lib/validators.d.ts.map +1 -1
  69. package/dist/local-frame.d.ts +1 -1
  70. package/dist/local-frame.d.ts.map +1 -1
  71. package/dist/spheroid.d.ts +1 -1
  72. package/dist/spheroid.d.ts.map +1 -1
  73. package/dist/types/array-types.d.ts +98 -0
  74. package/dist/types/array-types.d.ts.map +1 -0
  75. package/dist/types/array-types.js +6 -0
  76. package/dist/types/array-types.js.map +1 -0
  77. package/dist/types/bigint.d.ts +21 -0
  78. package/dist/types/bigint.d.ts.map +1 -0
  79. package/dist/types/bigint.js +48 -0
  80. package/dist/types/bigint.js.map +1 -0
  81. package/dist/types/bounds-types.d.ts +11 -0
  82. package/dist/types/bounds-types.d.ts.map +1 -0
  83. package/dist/types/bounds-types.js +17 -0
  84. package/dist/types/bounds-types.js.map +1 -0
  85. package/dist/types/float16.d.ts +32 -0
  86. package/dist/types/float16.d.ts.map +1 -0
  87. package/dist/types/float16.js +41 -0
  88. package/dist/types/float16.js.map +1 -0
  89. package/dist/types/index.d.ts +6 -0
  90. package/dist/types/index.d.ts.map +1 -0
  91. package/dist/types/index.js +6 -0
  92. package/dist/types/index.js.map +1 -0
  93. package/dist/types/is-array.d.ts +22 -0
  94. package/dist/types/is-array.d.ts.map +1 -0
  95. package/dist/types/is-array.js +36 -0
  96. package/dist/types/is-array.js.map +1 -0
  97. package/dist/types/spheroid.d.ts +8 -0
  98. package/dist/types/spheroid.d.ts.map +1 -0
  99. package/dist/types/spheroid.js +5 -0
  100. package/dist/types/spheroid.js.map +1 -0
  101. package/dist/types/typed-array-brand.d.ts +2 -0
  102. package/dist/types/typed-array-brand.d.ts.map +1 -0
  103. package/dist/types/typed-array-brand.js +10 -0
  104. package/dist/types/typed-array-brand.js.map +1 -0
  105. package/dist/types.cjs +67 -0
  106. package/dist/types.cjs.map +6 -0
  107. package/dist/types.d.ts +2 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +5 -0
  110. package/dist/types.js.map +1 -0
  111. package/package.json +12 -5
  112. package/src/classes/base/math-array.ts +1 -1
  113. package/src/classes/base/matrix.ts +1 -1
  114. package/src/classes/base/vector.ts +1 -1
  115. package/src/classes/euler.ts +1 -1
  116. package/src/classes/matrix3.ts +1 -1
  117. package/src/classes/matrix4.ts +1 -1
  118. package/src/classes/pose.ts +1 -1
  119. package/src/classes/quaternion.ts +1 -1
  120. package/src/classes/vector2.ts +1 -1
  121. package/src/classes/vector3.ts +1 -1
  122. package/src/classes/vector4.ts +1 -1
  123. package/src/expressions/expression-eval.ts +435 -0
  124. package/src/expressions/function-libraries.ts +123 -0
  125. package/src/expressions/function-registry.ts +163 -0
  126. package/src/expressions/get.ts +37 -0
  127. package/src/expressions/index.ts +22 -0
  128. package/src/expressions/parse-expression-string.ts +80 -0
  129. package/src/expressions/vendor/jsep/LICENSE.txt +23 -0
  130. package/src/expressions/vendor/jsep/README.md +22 -0
  131. package/src/expressions/vendor/jsep/runtime.ts +949 -0
  132. package/src/expressions/vendor/jsep/types.ts +179 -0
  133. package/src/gl-matrix/vec2.ts +1 -1
  134. package/src/index.ts +3 -3
  135. package/src/lib/common.ts +1 -1
  136. package/src/lib/gl-matrix-extras.ts +1 -1
  137. package/src/lib/validators.ts +1 -1
  138. package/src/local-frame.ts +1 -1
  139. package/src/spheroid.ts +1 -1
  140. package/src/types/array-types.ts +148 -0
  141. package/src/types/bigint.ts +56 -0
  142. package/src/types/bounds-types.ts +29 -0
  143. package/src/types/float16.ts +47 -0
  144. package/src/types/index.ts +45 -0
  145. package/src/types/is-array.ts +41 -0
  146. package/src/types/spheroid.ts +11 -0
  147. package/src/types/typed-array-brand.ts +14 -0
  148. package/src/types.ts +5 -0
@@ -0,0 +1,435 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) 2013 Stephen Oney
4
+ // SPDX-FileCopyrightText: Copyright (c) 2023 Don McCurdy
5
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
6
+ // SPDX-FileComment: Sources include jsep and expression-eval under MIT. Original source credits retained below.
7
+
8
+ /**
9
+ * Sources:
10
+ * - Copyright (c) 2013 Stephen Oney, http://jsep.from.so/, MIT License
11
+ * - Copyright (c) 2023 Don McCurdy, https://github.com/donmccurdy/expression-eval, MIT License
12
+ */
13
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/restrict-plus-operands */
14
+
15
+ import jsepRuntime from './vendor/jsep/runtime';
16
+ import type {Jsep as JsepTypes} from './vendor/jsep/types';
17
+ import {mergeFunctionLibraries, type ExpressionEvaluationOptions} from './function-libraries';
18
+
19
+ const jsep: typeof JsepTypes = jsepRuntime;
20
+
21
+ /**
22
+ * Named values and functions available while evaluating an expression.
23
+ */
24
+ export type ExpressionContext = Record<string, unknown>;
25
+
26
+ /**
27
+ * A JSEP abstract syntax tree node supported by the evaluator.
28
+ */
29
+ export type Expression =
30
+ | JsepTypes.ArrayExpression
31
+ | JsepTypes.BinaryExpression
32
+ | JsepTypes.CallExpression
33
+ | JsepTypes.ConditionalExpression
34
+ | JsepTypes.Identifier
35
+ | JsepTypes.Literal
36
+ | JsepTypes.MemberExpression
37
+ | JsepTypes.ThisExpression
38
+ | JsepTypes.UnaryExpression;
39
+
40
+ /**
41
+ * Evaluator implementation for a custom unary operator.
42
+ *
43
+ * @param operand - Value produced by the operator's operand expression.
44
+ * @returns The operator result.
45
+ */
46
+ export type UnaryOperator = (operand: any) => any;
47
+
48
+ /**
49
+ * Evaluator implementation for a custom binary operator.
50
+ *
51
+ * @param left - Value produced by the left operand expression.
52
+ * @param right - Value produced by the right operand expression.
53
+ * @returns The operator result.
54
+ */
55
+ export type BinaryOperator = (left: any, right: any) => any;
56
+
57
+ type Callable = (...args: any[]) => any;
58
+
59
+ const DEFAULT_PRECEDENCE: Record<string, number> = {
60
+ '||': 1,
61
+ '&&': 2,
62
+ '|': 3,
63
+ '^': 4,
64
+ '&': 5,
65
+ '==': 6,
66
+ '!=': 6,
67
+ '===': 6,
68
+ '!==': 6,
69
+ '<': 7,
70
+ '>': 7,
71
+ '<=': 7,
72
+ '>=': 7,
73
+ '<<': 8,
74
+ '>>': 8,
75
+ '>>>': 8,
76
+ '+': 9,
77
+ '-': 9,
78
+ '*': 10,
79
+ '/': 10,
80
+ '%': 10
81
+ };
82
+
83
+ const binops: Record<string, (...args: any[]) => any> = {
84
+ '||': (a: unknown, b: unknown) => a || b,
85
+ '&&': (a: unknown, b: unknown) => a && b,
86
+ '|': (a: number, b: number) => a | b,
87
+ '^': (a: number, b: number) => a ^ b,
88
+ '&': (a: number, b: number) => a & b,
89
+ '==': (a: unknown, b: unknown) => {
90
+ // biome-ignore lint/suspicious/noDoubleEquals: this operator implements JavaScript loose equality.
91
+ return a == b;
92
+ },
93
+ '!=': (a: unknown, b: unknown) => {
94
+ // biome-ignore lint/suspicious/noDoubleEquals: this operator implements JavaScript loose inequality.
95
+ return a != b;
96
+ },
97
+ '===': (a: unknown, b: unknown) => a === b,
98
+ '!==': (a: unknown, b: unknown) => a !== b,
99
+ '<': (a: number | string, b: number | string) => a < b,
100
+ '>': (a: number | string, b: number | string) => a > b,
101
+ '<=': (a: number | string, b: number | string) => a <= b,
102
+ '>=': (a: number | string, b: number | string) => a >= b,
103
+ '<<': (a: number, b: number) => a << b,
104
+ '>>': (a: number, b: number) => a >> b,
105
+ '>>>': (a: number, b: number) => a >>> b,
106
+ '+': (a: unknown, b: unknown) => {
107
+ // @ts-expect-error Addition intentionally supports JS coercion semantics.
108
+ return a + b;
109
+ },
110
+ '-': (a: number, b: number) => a - b,
111
+ '*': (a: number, b: number) => a * b,
112
+ '/': (a: number, b: number) => a / b,
113
+ '%': (a: number, b: number) => a % b
114
+ };
115
+
116
+ const unops: Record<string, (...args: any[]) => any> = {
117
+ '-': (a: number) => -a,
118
+ '+': (a: unknown) => {
119
+ // eslint-disable-next-line no-implicit-coercion
120
+ return +a;
121
+ },
122
+ '~': (a: number) => ~a,
123
+ '!': (a: unknown) => !a
124
+ };
125
+
126
+ function evaluateArray(list: JsepTypes.Expression[], context: ExpressionContext): unknown[] {
127
+ return list.map(value => evaluate(value, context));
128
+ }
129
+
130
+ /** Evaluates each expression in an array concurrently. */
131
+ async function evaluateArrayAsync(
132
+ list: JsepTypes.Expression[],
133
+ context: ExpressionContext
134
+ ): Promise<unknown[]> {
135
+ return await Promise.all(list.map(value => evalAsync(value, context)));
136
+ }
137
+
138
+ /** Resolves a member expression and preserves its receiver for method calls. */
139
+ function evaluateMember(
140
+ node: JsepTypes.MemberExpression,
141
+ context: ExpressionContext
142
+ ): [Record<string, unknown>, unknown] {
143
+ const object = evaluate(node.object, context) as Record<string, unknown>;
144
+ const key = node.computed
145
+ ? (evaluate(node.property, context) as string)
146
+ : (node.property as JsepTypes.Identifier).name;
147
+
148
+ if (/^__proto__|prototype|constructor$/.test(key)) {
149
+ throw new Error(`Access to member "${key}" disallowed.`);
150
+ }
151
+
152
+ return [object, object?.[key]];
153
+ }
154
+
155
+ /** Asynchronously resolves a member expression and its receiver. */
156
+ async function evaluateMemberAsync(
157
+ node: JsepTypes.MemberExpression,
158
+ context: ExpressionContext
159
+ ): Promise<[Record<string, unknown>, unknown]> {
160
+ const object = (await evalAsync(node.object, context)) as Record<string, unknown>;
161
+ const key = node.computed
162
+ ? ((await evalAsync(node.property, context)) as string)
163
+ : (node.property as JsepTypes.Identifier).name;
164
+
165
+ if (/^__proto__|prototype|constructor$/.test(key)) {
166
+ throw new Error(`Access to member "${key}" disallowed.`);
167
+ }
168
+
169
+ return [object, object?.[key]];
170
+ }
171
+
172
+ /** Evaluates one expression node synchronously. */
173
+ // eslint-disable-next-line complexity
174
+ function evaluateExpression(
175
+ node: JsepTypes.Expression,
176
+ context: ExpressionContext,
177
+ options?: ExpressionEvaluationOptions
178
+ ): unknown {
179
+ const expression = node as Expression;
180
+ const mergedContext = mergeFunctionLibraries(context, options);
181
+
182
+ switch (expression.type) {
183
+ case 'ArrayExpression':
184
+ return evaluateArray(expression.elements, mergedContext);
185
+
186
+ case 'BinaryExpression':
187
+ if (expression.operator === '||') {
188
+ return (
189
+ evaluate(expression.left, mergedContext) || evaluate(expression.right, mergedContext)
190
+ );
191
+ }
192
+ if (expression.operator === '&&') {
193
+ return (
194
+ evaluate(expression.left, mergedContext) && evaluate(expression.right, mergedContext)
195
+ );
196
+ }
197
+ return binops[expression.operator](
198
+ evaluate(expression.left, mergedContext),
199
+ evaluate(expression.right, mergedContext)
200
+ );
201
+
202
+ case 'CallExpression': {
203
+ let caller: Record<string, unknown> | undefined;
204
+ let fn: Callable | undefined;
205
+
206
+ if (expression.callee.type === 'MemberExpression') {
207
+ const member = evaluateMember(
208
+ expression.callee as JsepTypes.MemberExpression,
209
+ mergedContext
210
+ );
211
+ caller = member[0];
212
+ fn = member[1] as Callable | undefined;
213
+ } else {
214
+ fn = evaluate(expression.callee, mergedContext) as Callable | undefined;
215
+ }
216
+
217
+ if (typeof fn !== 'function') {
218
+ return undefined;
219
+ }
220
+
221
+ return fn.apply(caller, evaluateArray(expression.arguments, mergedContext));
222
+ }
223
+
224
+ case 'ConditionalExpression':
225
+ return evaluate(expression.test, mergedContext)
226
+ ? evaluate(expression.consequent, mergedContext)
227
+ : evaluate(expression.alternate, mergedContext);
228
+
229
+ case 'Identifier':
230
+ return mergedContext[expression.name];
231
+
232
+ case 'Literal':
233
+ return expression.value;
234
+
235
+ case 'MemberExpression':
236
+ return evaluateMember(expression, mergedContext)[1];
237
+
238
+ case 'ThisExpression':
239
+ return mergedContext;
240
+
241
+ case 'UnaryExpression':
242
+ return unops[expression.operator](evaluate(expression.argument, mergedContext));
243
+
244
+ default:
245
+ return undefined;
246
+ }
247
+ }
248
+
249
+ /** Evaluates a nested expression using an already-merged context. */
250
+ function evaluate(node: JsepTypes.Expression, context: ExpressionContext): unknown {
251
+ return evaluateExpression(node, context);
252
+ }
253
+
254
+ /**
255
+ * Evaluates a parsed expression asynchronously.
256
+ *
257
+ * @param node - Expression AST to evaluate.
258
+ * @param context - Named values and functions available to the expression.
259
+ * @param options - Function libraries to add to the context.
260
+ * @returns The resolved expression value.
261
+ *
262
+ * @remarks
263
+ * Function calls are awaited, including calls nested inside arrays, member
264
+ * expressions, conditionals, unary expressions, and binary expressions.
265
+ */
266
+ // eslint-disable-next-line complexity
267
+ export async function evalAsync(
268
+ node: JsepTypes.Expression,
269
+ context: ExpressionContext,
270
+ options?: ExpressionEvaluationOptions
271
+ ): Promise<unknown> {
272
+ const expression = node as Expression;
273
+ const mergedContext = mergeFunctionLibraries(context, options);
274
+
275
+ switch (expression.type) {
276
+ case 'ArrayExpression':
277
+ return await evaluateArrayAsync(expression.elements, mergedContext);
278
+
279
+ case 'BinaryExpression':
280
+ if (expression.operator === '||') {
281
+ return (
282
+ (await evalAsync(expression.left, mergedContext)) ||
283
+ (await evalAsync(expression.right, mergedContext))
284
+ );
285
+ }
286
+ if (expression.operator === '&&') {
287
+ return (
288
+ (await evalAsync(expression.left, mergedContext)) &&
289
+ (await evalAsync(expression.right, mergedContext))
290
+ );
291
+ }
292
+ return binops[expression.operator](
293
+ await evalAsync(expression.left, mergedContext),
294
+ await evalAsync(expression.right, mergedContext)
295
+ );
296
+
297
+ case 'CallExpression': {
298
+ let caller: Record<string, unknown> | undefined;
299
+ let fn: Callable | undefined;
300
+
301
+ if (expression.callee.type === 'MemberExpression') {
302
+ const member = await evaluateMemberAsync(
303
+ expression.callee as JsepTypes.MemberExpression,
304
+ mergedContext
305
+ );
306
+ caller = member[0];
307
+ fn = member[1] as Callable | undefined;
308
+ } else {
309
+ fn = (await evalAsync(expression.callee, mergedContext)) as Callable | undefined;
310
+ }
311
+
312
+ if (typeof fn !== 'function') {
313
+ return undefined;
314
+ }
315
+
316
+ return await fn.apply(caller, await evaluateArrayAsync(expression.arguments, mergedContext));
317
+ }
318
+
319
+ case 'ConditionalExpression':
320
+ return (await evalAsync(expression.test, mergedContext))
321
+ ? await evalAsync(expression.consequent, mergedContext)
322
+ : await evalAsync(expression.alternate, mergedContext);
323
+
324
+ case 'Identifier':
325
+ return mergedContext[expression.name];
326
+
327
+ case 'Literal':
328
+ return expression.value;
329
+
330
+ case 'MemberExpression':
331
+ return (await evaluateMemberAsync(expression, mergedContext))[1];
332
+
333
+ case 'ThisExpression':
334
+ return mergedContext;
335
+
336
+ case 'UnaryExpression':
337
+ return unops[expression.operator](await evalAsync(expression.argument, mergedContext));
338
+
339
+ default:
340
+ return undefined;
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Compiles an expression into a reusable synchronous evaluator.
346
+ *
347
+ * @param expression - Expression source or a previously parsed AST.
348
+ * @param options - Function libraries to add to each evaluation context.
349
+ * @returns A function that evaluates the expression against a context.
350
+ */
351
+ export function compile(
352
+ expression: string | JsepTypes.Expression,
353
+ options?: ExpressionEvaluationOptions
354
+ ): (context: ExpressionContext) => unknown {
355
+ const ast = parse(expression);
356
+ return (context: ExpressionContext) => evaluateExpression(ast, context, options);
357
+ }
358
+
359
+ /**
360
+ * Compiles an expression into a reusable asynchronous evaluator.
361
+ *
362
+ * @param expression - Expression source or a previously parsed AST.
363
+ * @param options - Function libraries to add to each evaluation context.
364
+ * @returns A function that asynchronously evaluates the expression.
365
+ */
366
+ export function compileAsync(
367
+ expression: string | JsepTypes.Expression,
368
+ options?: ExpressionEvaluationOptions
369
+ ): (context: ExpressionContext) => Promise<unknown> {
370
+ const ast = parse(expression);
371
+ return (context: ExpressionContext) => evalAsync(ast, context, options);
372
+ }
373
+
374
+ /**
375
+ * Registers a custom unary operator with the parser and evaluator.
376
+ *
377
+ * @param operator - Operator token to register.
378
+ * @param fn - Evaluator implementation for the operator.
379
+ *
380
+ * @remarks
381
+ * Registration changes module-global parser state and affects subsequent
382
+ * calls to {@link parse}.
383
+ */
384
+ export function addUnaryOp(operator: string, fn: UnaryOperator): void {
385
+ jsep.addUnaryOp(operator);
386
+ unops[operator] = fn;
387
+ }
388
+
389
+ /**
390
+ * Registers a custom binary operator with the parser and evaluator.
391
+ *
392
+ * @param operator - Operator token to register.
393
+ * @param precedenceOrFn - Parser precedence, or the evaluator implementation
394
+ * when using the default precedence for a built-in operator.
395
+ * @param fn - Evaluator implementation when an explicit precedence is given.
396
+ *
397
+ * @remarks
398
+ * Registration changes module-global parser state and affects subsequent
399
+ * calls to {@link parse}. New operators should provide explicit precedence.
400
+ */
401
+ export function addBinaryOp(
402
+ operator: string,
403
+ precedenceOrFn: number | BinaryOperator,
404
+ fn?: BinaryOperator
405
+ ): void {
406
+ if (fn) {
407
+ jsep.addBinaryOp(operator, precedenceOrFn as number);
408
+ binops[operator] = fn;
409
+ return;
410
+ }
411
+
412
+ jsep.addBinaryOp(operator, DEFAULT_PRECEDENCE[operator] || 1);
413
+ binops[operator] = precedenceOrFn as BinaryOperator;
414
+ }
415
+
416
+ /**
417
+ * Parses expression source into a JSEP abstract syntax tree.
418
+ *
419
+ * @param expression - Expression source or an existing AST.
420
+ * @returns A parsed AST, or the supplied AST unchanged.
421
+ * @throws If the expression string is not valid JSEP syntax.
422
+ */
423
+ export function parse(expression: string | JsepTypes.Expression): JsepTypes.Expression {
424
+ return typeof expression === 'string' ? jsep(expression) : expression;
425
+ }
426
+
427
+ /**
428
+ * Evaluates a parsed expression synchronously.
429
+ *
430
+ * @param node - Expression AST to evaluate.
431
+ * @param context - Named values and functions available to the expression.
432
+ * @param options - Function libraries to add to the context.
433
+ * @returns The expression value.
434
+ */
435
+ export {evaluateExpression as eval};
@@ -0,0 +1,123 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // SPDX-FileCopyrightText: Copyright (c) vis.gl contributors
4
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
5
+
6
+ import {
7
+ clamp,
8
+ degrees,
9
+ lerp,
10
+ normalizeAngle,
11
+ radians,
12
+ safeMod,
13
+ toDegrees,
14
+ toRadians
15
+ } from '../lib/common';
16
+ import type {ExpressionFunctionRegistry} from './function-registry';
17
+
18
+ /**
19
+ * A function that can be exposed to evaluated expressions.
20
+ *
21
+ * @param args - Arguments supplied by a call expression.
22
+ * @returns The value made available to the expression.
23
+ */
24
+ export type ExpressionFunction = (...args: any[]) => any;
25
+
26
+ /**
27
+ * A named collection of functions that can be supplied to an expression
28
+ * evaluator through {@link ExpressionEvaluationOptions}.
29
+ */
30
+ export type ExpressionFunctionLibrary = Record<string, ExpressionFunction>;
31
+
32
+ /**
33
+ * Options shared by the synchronous and asynchronous expression evaluators.
34
+ */
35
+ export type ExpressionEvaluationOptions = {
36
+ /**
37
+ * Instance-scoped registry of named functions available to the expression.
38
+ */
39
+ registry?: ExpressionFunctionRegistry;
40
+
41
+ /**
42
+ * Function libraries to add to the evaluation context.
43
+ *
44
+ * Libraries are merged from left to right. Functions in later libraries
45
+ * replace functions with the same name in earlier libraries. Values in the
46
+ * expression context replace functions with the same name in any library.
47
+ */
48
+ libraries?: ExpressionFunctionLibrary[];
49
+ };
50
+
51
+ /**
52
+ * General-purpose mathematical functions for expression evaluation.
53
+ *
54
+ * Includes JavaScript `Math` functions and math.gl helpers such as `clamp`,
55
+ * `lerp`, `normalizeAngle`, `safeMod`, `toDegrees`, and `toRadians`.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const evaluate = compile("clamp(sin(angle), 0, 1)", {
60
+ * libraries: [BASIC_MATH_FUNCTION_LIBRARY]
61
+ * });
62
+ * evaluate({angle: Math.PI / 2});
63
+ * ```
64
+ */
65
+ export const BASIC_MATH_FUNCTION_LIBRARY: ExpressionFunctionLibrary = {
66
+ abs: Math.abs,
67
+ acos: Math.acos,
68
+ asin: Math.asin,
69
+ atan: Math.atan,
70
+ ceil: Math.ceil,
71
+ clamp,
72
+ cos: Math.cos,
73
+ degrees,
74
+ exp: Math.exp,
75
+ floor: Math.floor,
76
+ lerp,
77
+ log: Math.log,
78
+ max: Math.max,
79
+ min: Math.min,
80
+ normalizeAngle,
81
+ pow: Math.pow,
82
+ radians,
83
+ round: Math.round,
84
+ safeMod,
85
+ sign: Math.sign,
86
+ sin: Math.sin,
87
+ sqrt: Math.sqrt,
88
+ tan: Math.tan,
89
+ toDegrees,
90
+ toRadians,
91
+ trunc: Math.trunc
92
+ };
93
+
94
+ /**
95
+ /**
96
+ * Adds configured function libraries to an expression context.
97
+ *
98
+ * @param context - Values available to the expression.
99
+ * @param options - Function libraries to merge into the context.
100
+ * @returns The original context when no libraries are supplied, or a new
101
+ * context containing the libraries and context values.
102
+ *
103
+ * @remarks
104
+ * Libraries are merged from left to right, then overlaid with `context`.
105
+ * Registry functions have the lowest precedence. The input objects are not modified.
106
+ */
107
+ export function mergeFunctionLibraries(
108
+ context: Record<string, unknown>,
109
+ options?: ExpressionEvaluationOptions
110
+ ): Record<string, unknown> {
111
+ if (!options?.libraries?.length) {
112
+ if (!options?.registry) {
113
+ return context;
114
+ }
115
+ }
116
+
117
+ return Object.assign(
118
+ {},
119
+ options.registry?.getFunctionTable(),
120
+ ...(options.libraries || []),
121
+ context
122
+ );
123
+ }