fig-tree-evaluator 2.23.2 → 3.0.0-preview.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/README.md +214 -148
- package/build/chunks/shared.js +1 -0
- package/build/editor-hints/index.d.ts +35 -0
- package/build/editor-hints/index.js +1 -0
- package/build/format/index.d.ts +86 -0
- package/build/format/index.js +1 -0
- package/build/index.d.ts +783 -240
- package/build/index.js +1 -0
- package/build/migrate/index.d.ts +55 -0
- package/build/migrate/index.js +1 -0
- package/package.json +97 -50
- package/CHANGELOG.md +0 -134
- package/build/index.cjs.js +0 -1
- package/build/index.esm.js +0 -1
package/README.md
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
**FigTree
|
|
5
|
+
_This is an early preview release for **FigTree v3**. Full documentation will be added as we get closer to release, but for those interested, look in the repo on the `v3.0-dev` branch, under `/docs-artifacts`, for an explanation and reference._
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
_The documentation below is still for `v2.x`_
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**FigTree Evaluator** is a module to evaluate JSON-structured expression trees.
|
|
12
|
+
|
|
13
|
+
A typical use case would be for evaluating **configuration** files, where you need to store dynamic values or arbitrary logic without allowing users to inject executable code (perhaps in a .json file, say). Examples could include:
|
|
8
14
|
|
|
9
15
|
- a [form-builder app](https://github.com/openmsupply/conforma-web-app) might need to allow complex conditional logic for form element visibility based on previous responses, or for validation beyond what is available in standard validation libraries.
|
|
10
16
|
- configure a [decision tree](https://en.wikipedia.org/wiki/Decision_tree) to implement branching logic. (See implementation in `20_match.test.ts`)
|
|
@@ -12,13 +18,14 @@ A typical use case would be for evaluating **configuration** files, where you ne
|
|
|
12
18
|
|
|
13
19
|
A range of built-in operators are available, from simple logic, arithmetic and string manipulation, to data fetching from local sources or remote APIs. Plus, you can extend functionality with your own [custom operators](#custom-functionsoperators)
|
|
14
20
|
|
|
15
|
-
<!-- omit in toc -->
|
|
16
|
-
## [Try the Demo/Playground](https://carlosnz.github.io/fig-tree-evaluator/)
|
|
21
|
+
## [Try the Demo/Playground](https://carlosnz.github.io/fig-tree-evaluator/) <!-- omit in toc -->
|
|
17
22
|
|
|
18
23
|
The demo is powered by [fig-tree-editor-react](https://github.com/CarlosNZ/fig-tree-editor-react), a React component for editing FigTree expressions.
|
|
19
24
|
|
|
20
25
|
## Contents <!-- omit in toc -->
|
|
26
|
+
|
|
21
27
|
<!-- TOC -->
|
|
28
|
+
|
|
22
29
|
- [The basics](#the-basics)
|
|
23
30
|
- [Install](#install)
|
|
24
31
|
- [Usage](#usage)
|
|
@@ -68,6 +75,7 @@ The demo is powered by [fig-tree-editor-react](https://github.com/CarlosNZ/fig-t
|
|
|
68
75
|
- [Credit](#credit)
|
|
69
76
|
|
|
70
77
|
<!-- /TOC -->
|
|
78
|
+
|
|
71
79
|
## The basics
|
|
72
80
|
|
|
73
81
|
Fig-tree evaluates expressions structured in a JSON/Javascript object [expression tree](https://www.geeksforgeeks.org/expression-tree/). A single "node" of the tree consists of an **Operator**, with associated parameters (or child nodes), each of which can itself be another Operator node -- i.e. a recursive tree structure of arbitrary depth and complexity.
|
|
@@ -85,6 +93,7 @@ For example:
|
|
|
85
93
|
```
|
|
86
94
|
|
|
87
95
|
Or, with a deeper structure that results in the same final output:
|
|
96
|
+
|
|
88
97
|
```js
|
|
89
98
|
{
|
|
90
99
|
operator: '+',
|
|
@@ -132,19 +141,22 @@ or\
|
|
|
132
141
|
import { FigTreeEvaluator } from 'fig-tree-evaluator'
|
|
133
142
|
|
|
134
143
|
// New evaluator instance
|
|
135
|
-
const fig = new FigTreeEvaluator([
|
|
144
|
+
const fig = new FigTreeEvaluator([options]) // See available options below
|
|
136
145
|
|
|
137
146
|
// Evaluate expressions
|
|
138
|
-
fig
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
147
|
+
fig
|
|
148
|
+
.evaluate(expression, [options]) // Options over-ride initial options for this evaluation
|
|
149
|
+
.then((result) => {
|
|
150
|
+
// "evaluate" is async method
|
|
151
|
+
// Do something with result
|
|
152
|
+
})
|
|
142
153
|
|
|
143
154
|
// Or within async function:
|
|
144
155
|
const result = await fig.evaluate(expression, [options])
|
|
145
156
|
```
|
|
146
157
|
|
|
147
158
|
FigTreeEvaluator is written in **Typescript**, and the following types are available to import from the package:
|
|
159
|
+
|
|
148
160
|
- `FigTreeOptions`: `options` object, as per [options](#available-options) below
|
|
149
161
|
- `Operator`: string literal canonical [Operator](#operator-nodes) names (`AND`, `OR`, `EQUAL`, etc.)
|
|
150
162
|
- `EvaluatorNode`: Evaluator input
|
|
@@ -154,20 +166,20 @@ FigTreeEvaluator is written in **Typescript**, and the following types are avail
|
|
|
154
166
|
|
|
155
167
|
The `options` parameter is an object with the following available properties (all optional):
|
|
156
168
|
|
|
157
|
-
- `data` -- a single object containing any
|
|
158
|
-
- `functions` -- a single object containing any
|
|
169
|
+
- `data` -- a single object containing any _objects_ in your application that may wish to be inspected using the [objectProperties](#object_properties) operator. (See [playground](LINK) for examples). If these objects are regularly changing, you'll probably want to pass them into each separate evaluation rather than with the initial constructor.
|
|
170
|
+
- `functions` -- a single object containing any _custom functions_ available for use by [custom functions/operators](#custom_functions).
|
|
159
171
|
- `fragments` -- commonly-used expressions (with optional parameters) that can be re-used in any other expression. See [Fragments](#fragments)
|
|
160
|
-
- `httpClient` -- pass your http client in here in order to use the HTTP-based operators ([`GET`](#get), [`POST`](#post), [`GraphQL`](#graphql)) (uses browser's native `fetch` by default).
|
|
172
|
+
- `httpClient` -- pass your http client in here in order to use the HTTP-based operators ([`GET`](#get), [`POST`](#post), [`GraphQL`](#graphql)) (uses browser's native `fetch` by default).
|
|
161
173
|
- `graphQLConnection` -- a GraphQL connection object, if using the [`graphQL` operator](#graphql). See operator details below.
|
|
162
174
|
- `sqlConnection` -- if you wish to make calls to an SQL database using the [`SQL` operator](#sql), pass a connection to the database here. See operator details below.
|
|
163
175
|
- `baseEndpoint` -- If specified, any partial urls specified in the http-based operators (`GET`, `POST`) will be relative to to this base. Useful if you expect most http requests to be to the same server.
|
|
164
|
-
- `headers` -- A general http headers object that will be passed to
|
|
176
|
+
- `headers` -- A general http headers object that will be passed to _all_ http-based operators (`GET`, `POST`, `GraphQL`). Useful for authentication headers, for example. Each operator and instance can have its own headers, though, so see specific operator reference for details.
|
|
165
177
|
- `returnErrorAsString` -- by default the evaluator will throw errors with invalid evaluation expressions (with helpful error messages indicating the node which threw the error and what the problem was). But if you have `returnErrorAsString: true` set, the evaluator will never throw, but instead return error messages as a valid string output. (See also the [`fallback`](#other-common-properties) parameter below). See [Error handling](#error-handling) section for more detail.
|
|
166
178
|
- `allowJSONStringInput` -- the evaluator is expecting the input expression to be a javascript object. However, it will also accept JSON strings if this option is set to `true`. We have to perform additional logic on every evaluation input to determine if a string is a JSON expression or a standard string, so this is skipped by default for performance reasons. However, if you want to send (for example) user input directly to the evaluator without running it through your own `JSON.parse()`, then enable this option.
|
|
167
179
|
- `skipRuntimeTypeCheck` -- we perform comprehensive type checking at runtime to ensure that each operator only performs its operation on valid inputs. If type checking fails, we throw an error detailing the explicit problem. However, if `skipRuntimeTypeCheck` is set to `true`, then all inputs are passed to the operator regardless, and any errors will come from whatever standard javascript errors might be encountered (e.g. trying to pass a primitive value when an array is expected => `.map is not a function`)
|
|
168
|
-
- `caseInsensitive` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
|
|
169
|
-
- `nullEqualsUndefined` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
|
|
170
|
-
- `evaluateFullObject` -- by default, FigTree expects the root of an input expression to be an [Operator Node](#operator-nodes), and if not, will return the input unmodified. However, you may have cases where the evaluation expressions are deep within a larger structure (such as a JSON schema, for example). In this case, you can set `evaluateFullObject` to `true` and the evaluator will find
|
|
180
|
+
- `caseInsensitive` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
|
|
181
|
+
- `nullEqualsUndefined` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
|
|
182
|
+
- `evaluateFullObject` -- by default, FigTree expects the root of an input expression to be an [Operator Node](#operator-nodes), and if not, will return the input unmodified. However, you may have cases where the evaluation expressions are deep within a larger structure (such as a JSON schema, for example). In this case, you can set `evaluateFullObject` to `true` and the evaluator will find _any_ operator nodes within the structure and evaluate them within the object tree.
|
|
171
183
|
- `excludeOperators` -- an array of operator names (or [aliases](#operator--property-aliases)) to prohibit from being used in expressions. You may wish to restrict (for example) database access via FigTree configurations, in which case these exclusions can be defined when instantiating the FigTree instance (or updated on the fly).
|
|
172
184
|
- `useCache` -- caches the results from certain operators to avoid repeated network requests with the same input values. By default, this is set to `true`, and it can be overridden for specific nodes. See [Memoization/Caching section](#caching-memoization) for more detail
|
|
173
185
|
- `maxCacheSize` -- the maximum number of results that will be held in the aforementioned cache (default: `50`)
|
|
@@ -188,7 +200,7 @@ It's also possible to run one-off evaluations by importing the evaluation method
|
|
|
188
200
|
import { evaluateExpression } from 'fig-tree-evaluator'
|
|
189
201
|
|
|
190
202
|
evaluateExpression(expression, [options]).then((result) => {
|
|
191
|
-
|
|
203
|
+
// Do something with result
|
|
192
204
|
})
|
|
193
205
|
```
|
|
194
206
|
|
|
@@ -232,12 +244,12 @@ Most of the time named properties would be preferable; however there are occasio
|
|
|
232
244
|
|
|
233
245
|
In each operator node, as well as the operator-specific properties, the following three optional properties can be provided:
|
|
234
246
|
|
|
235
|
-
- `fallback`: if the operation throws an error, the `fallback` value will be returned instead. The `fallback` property can be provided at any level of the expression tree and bubbled up from where errors are caught to parent nodes.
|
|
236
|
-
See [Error handling](#error-handling)
|
|
247
|
+
- `fallback`: if the operation throws an error, the `fallback` value will be returned instead. The `fallback` property can be provided at any level of the expression tree and bubbled up from where errors are caught to parent nodes. _Fallbacks are strongly recommended if there is any chance of an error (e.g. a network "GET" request that doesn't yet have its parameters defined)._
|
|
248
|
+
See [Error handling](#error-handling)
|
|
237
249
|
- `outputType` (or `type`): will convert the result of the current node to the specified `outputType`. Valid values are `string`, `number`, `boolean` (or `bool`), and `array`. You can experiment in the [demo app](https://carlosnz.github.io/fig-tree-evaluator/) to see the outcome of applying different `outputType` values to various results.
|
|
238
250
|
- `useCache`: Overrides the global `useCache` value (from [options](#available-options)) for this node only. See [Caching/Memoization](#caching-memoization) below for more info.
|
|
239
251
|
|
|
240
|
-
Remember that
|
|
252
|
+
Remember that _all_ operator node properties can themselves be operator nodes, _including_ the `fallback` and `outputType` properties.
|
|
241
253
|
|
|
242
254
|
e.g.
|
|
243
255
|
|
|
@@ -275,7 +287,7 @@ The full list of available operators and their associated properties:
|
|
|
275
287
|
|
|
276
288
|
### AND
|
|
277
289
|
|
|
278
|
-
|
|
290
|
+
_Logical AND_
|
|
279
291
|
|
|
280
292
|
Aliases: `and`, `&`, `&&`
|
|
281
293
|
|
|
@@ -284,6 +296,7 @@ Aliases: `and`, `&`, `&&`
|
|
|
284
296
|
- `values`<sup>*</sup>: (array) -- any number of elements; will be compared using Javascript `&&` operator
|
|
285
297
|
|
|
286
298
|
e.g.
|
|
299
|
+
|
|
287
300
|
```js
|
|
288
301
|
{
|
|
289
302
|
operator: '&',
|
|
@@ -294,10 +307,11 @@ e.g.
|
|
|
294
307
|
|
|
295
308
|
`children` array: `[...values]`
|
|
296
309
|
|
|
297
|
-
|
|
310
|
+
---
|
|
311
|
+
|
|
298
312
|
### OR
|
|
299
313
|
|
|
300
|
-
|
|
314
|
+
_Logical OR_
|
|
301
315
|
|
|
302
316
|
Aliases: `or`, `|`, `||`
|
|
303
317
|
|
|
@@ -306,6 +320,7 @@ Aliases: `or`, `|`, `||`
|
|
|
306
320
|
- `values`<sup>*</sup>: (array) -- any number of elements; will be compared using Javascript `||` operator
|
|
307
321
|
|
|
308
322
|
e.g.
|
|
323
|
+
|
|
309
324
|
```js
|
|
310
325
|
{
|
|
311
326
|
operator: 'or',
|
|
@@ -323,10 +338,11 @@ e.g.
|
|
|
323
338
|
|
|
324
339
|
`children` array: `[...values]`
|
|
325
340
|
|
|
326
|
-
|
|
341
|
+
---
|
|
342
|
+
|
|
327
343
|
### EQUAL
|
|
328
344
|
|
|
329
|
-
|
|
345
|
+
_Equality_
|
|
330
346
|
|
|
331
347
|
Aliases: `=`, `eq`, `equal`, `equals`
|
|
332
348
|
|
|
@@ -337,6 +353,7 @@ Aliases: `=`, `eq`, `equal`, `equals`
|
|
|
337
353
|
- `nullEqualsUndefined`: (boolean, default `false`) -- there are times when it is convenient for `null` to be considered equal to `undefined`. If this is desired, set this property to `true`, otherwise all equality checks will be "strict" equality. If you find that you want this setting enabled globally, then you can set it in the overall [evaluator options](#available-options) instead of having to add this additional property to every equality expression.
|
|
338
354
|
|
|
339
355
|
e.g.
|
|
356
|
+
|
|
340
357
|
```js
|
|
341
358
|
{
|
|
342
359
|
operator: '=',
|
|
@@ -347,10 +364,11 @@ e.g.
|
|
|
347
364
|
|
|
348
365
|
`children` array: `[...values]`
|
|
349
366
|
|
|
350
|
-
|
|
367
|
+
---
|
|
368
|
+
|
|
351
369
|
### NOT_EQUAL
|
|
352
370
|
|
|
353
|
-
|
|
371
|
+
_Non-equality_
|
|
354
372
|
|
|
355
373
|
Aliases: `!=`, `!`, `ne`, `notEqual`
|
|
356
374
|
|
|
@@ -361,6 +379,7 @@ Aliases: `!=`, `!`, `ne`, `notEqual`
|
|
|
361
379
|
- `nullEqualsUndefined`: (boolean, default `false`) -- as [above](#equal)
|
|
362
380
|
|
|
363
381
|
e.g.
|
|
382
|
+
|
|
364
383
|
```js
|
|
365
384
|
{
|
|
366
385
|
operator: '=',
|
|
@@ -371,19 +390,21 @@ e.g.
|
|
|
371
390
|
|
|
372
391
|
`children` array: `[...values]`
|
|
373
392
|
|
|
374
|
-
|
|
393
|
+
---
|
|
394
|
+
|
|
375
395
|
### PLUS
|
|
376
396
|
|
|
377
|
-
|
|
397
|
+
_Addition, concatenation, merging_
|
|
378
398
|
|
|
379
399
|
Aliases: `+`, `add`, `concat`, `join`, `merge`
|
|
380
400
|
|
|
381
401
|
#### Properties
|
|
382
402
|
|
|
383
403
|
- `values`<sup>*</sup>: (array) -- any number of elements. Will be added (numbers), concatenated (strings, arrays) or merged (objects) according their type.
|
|
384
|
-
- `type`: (`'string' | 'array'`) -- if specified, operator will treat the `values` as though they were this type. E.g. if `string`, it will concatenate the values, even if they're all numbers. The difference between this property and the common [`outputType` property](#other-common-properties) is that `outputType` converts the result, whereas this `type` property converts each element
|
|
404
|
+
- `type`: (`'string' | 'array'`) -- if specified, operator will treat the `values` as though they were this type. E.g. if `string`, it will concatenate the values, even if they're all numbers. The difference between this property and the common [`outputType` property](#other-common-properties) is that `outputType` converts the result, whereas this `type` property converts each element _before_ the "PLUS" operation.
|
|
385
405
|
|
|
386
406
|
e.g.
|
|
407
|
+
|
|
387
408
|
```js
|
|
388
409
|
{
|
|
389
410
|
operator: '+',
|
|
@@ -421,10 +442,11 @@ e.g.
|
|
|
421
442
|
|
|
422
443
|
`children` array: `[...values]`
|
|
423
444
|
|
|
424
|
-
|
|
445
|
+
---
|
|
446
|
+
|
|
425
447
|
### SUBTRACT
|
|
426
448
|
|
|
427
|
-
|
|
449
|
+
_Subtraction_
|
|
428
450
|
|
|
429
451
|
Aliases: `-`, `subtract`, `minus`, `takeaway`
|
|
430
452
|
|
|
@@ -433,6 +455,7 @@ Aliases: `-`, `subtract`, `minus`, `takeaway`
|
|
|
433
455
|
- `values`<sup>*</sup>: (array) -- exactly 2 numerical elements; the second will be subtracted from the first. (If non-numerical elements are provided, the operator will return `NaN`)
|
|
434
456
|
|
|
435
457
|
e.g.
|
|
458
|
+
|
|
436
459
|
```js
|
|
437
460
|
{
|
|
438
461
|
operator: '-',
|
|
@@ -455,18 +478,20 @@ e.g.
|
|
|
455
478
|
|
|
456
479
|
`children` array: `[originalValue, valueToSubtract]` (same as `values`)
|
|
457
480
|
|
|
458
|
-
|
|
481
|
+
---
|
|
482
|
+
|
|
459
483
|
### MULTIPLY
|
|
460
484
|
|
|
461
|
-
|
|
485
|
+
_Multiplication_
|
|
462
486
|
|
|
463
487
|
Aliases: `*`, `x`, `multiply`, `times`
|
|
464
488
|
|
|
465
489
|
#### Properties
|
|
466
490
|
|
|
467
|
-
- `values`<sup>*</sup>: (array) -- any number of numerical elements. Returns the product of all elements.
|
|
491
|
+
- `values`<sup>*</sup>: (array) -- any number of numerical elements. Returns the product of all elements. (If non-numerical elements are provided, the operator will return `NaN`)
|
|
468
492
|
|
|
469
493
|
e.g.
|
|
494
|
+
|
|
470
495
|
```js
|
|
471
496
|
{
|
|
472
497
|
operator: '*',
|
|
@@ -489,23 +514,25 @@ e.g.
|
|
|
489
514
|
|
|
490
515
|
`children` array: `[...values]`
|
|
491
516
|
|
|
492
|
-
|
|
517
|
+
---
|
|
518
|
+
|
|
493
519
|
### DIVIDE
|
|
494
520
|
|
|
495
|
-
|
|
521
|
+
_Division_
|
|
496
522
|
|
|
497
523
|
Aliases: `/`, `divide`, `÷`
|
|
498
524
|
|
|
499
525
|
#### Properties
|
|
500
526
|
|
|
501
|
-
- `values`: (array) -- exactly 2 numerical elements; the first will be divided by the second.
|
|
527
|
+
- `values`: (array) -- exactly 2 numerical elements; the first will be divided by the second. (If non-numerical elements are provided, the operator will return `NaN`)
|
|
502
528
|
- `dividend` (or `divide`): (number) -- the number that will be divided
|
|
503
529
|
- `divisor` (or `by`): (number) -- the number to divide `dividend` by
|
|
504
|
-
- `output` (`'quotient' | 'remainder'
|
|
530
|
+
- `output` (`'quotient' | 'remainder'`) -- by default, the operator returns a floating point value. However, if `quotient` is specified, it will return the integer part of the result; if `remainder` is specified, it will return the remainder after division (i.e. `value1 % value2`)
|
|
505
531
|
|
|
506
|
-
Note that the input values can be provided as
|
|
532
|
+
Note that the input values can be provided as _either_ a `values` array _or_ `dividend`/`divisor` properties. If both are provided, `values` takes precedence.
|
|
507
533
|
|
|
508
534
|
e.g.
|
|
535
|
+
|
|
509
536
|
```js
|
|
510
537
|
{
|
|
511
538
|
operator: '/',
|
|
@@ -517,7 +544,7 @@ e.g.
|
|
|
517
544
|
operator: '/',
|
|
518
545
|
divide: 20,
|
|
519
546
|
by: 3,
|
|
520
|
-
output: 'quotient'
|
|
547
|
+
output: 'quotient'
|
|
521
548
|
}
|
|
522
549
|
// => 6
|
|
523
550
|
|
|
@@ -532,10 +559,11 @@ e.g.
|
|
|
532
559
|
|
|
533
560
|
`children` array: `[dividend, divisor]` (same as `values`)
|
|
534
561
|
|
|
535
|
-
|
|
562
|
+
---
|
|
563
|
+
|
|
536
564
|
### GREATER_THAN
|
|
537
565
|
|
|
538
|
-
|
|
566
|
+
_Greater than (or equal to)_
|
|
539
567
|
|
|
540
568
|
Aliases: `>`, `greaterThan`, `higher`, `larger`
|
|
541
569
|
|
|
@@ -545,6 +573,7 @@ Aliases: `>`, `greaterThan`, `higher`, `larger`
|
|
|
545
573
|
- `strict`: (boolean, default `false`) -- if `true`, value 1 must be strictly greater than value 2 (i.e. `>`). Otherwise it will be compared with "greater than or equal to" (i.e. `>=`)
|
|
546
574
|
|
|
547
575
|
e.g.
|
|
576
|
+
|
|
548
577
|
```js
|
|
549
578
|
{
|
|
550
579
|
operator: '>',
|
|
@@ -568,10 +597,11 @@ e.g.
|
|
|
568
597
|
|
|
569
598
|
`children` array: `[firstValue, secondValue]` (same as `values`)
|
|
570
599
|
|
|
571
|
-
|
|
600
|
+
---
|
|
601
|
+
|
|
572
602
|
### LESS_THAN
|
|
573
603
|
|
|
574
|
-
|
|
604
|
+
_Less than (or equal to)_
|
|
575
605
|
|
|
576
606
|
Aliases: `<`, `lessThan`, `lower`, `smaller`
|
|
577
607
|
|
|
@@ -581,6 +611,7 @@ Aliases: `<`, `lessThan`, `lower`, `smaller`
|
|
|
581
611
|
- `strict`: (boolean, default `false`) -- if `true`, value 1 must be strictly lower than value 2 (i.e. `<`). Otherwise it will be compared with "less than or equal to" (i.e. `<=`)
|
|
582
612
|
|
|
583
613
|
e.g.
|
|
614
|
+
|
|
584
615
|
```js
|
|
585
616
|
{
|
|
586
617
|
operator: '<',
|
|
@@ -604,10 +635,11 @@ e.g.
|
|
|
604
635
|
|
|
605
636
|
`children` array: `[firstValue, secondValue]` (same as `values`)
|
|
606
637
|
|
|
607
|
-
|
|
638
|
+
---
|
|
639
|
+
|
|
608
640
|
### COUNT
|
|
609
641
|
|
|
610
|
-
|
|
642
|
+
_Count elements in array_
|
|
611
643
|
|
|
612
644
|
Aliases: `count`, `length`
|
|
613
645
|
|
|
@@ -616,6 +648,7 @@ Aliases: `count`, `length`
|
|
|
616
648
|
- `values`<sup>*</sup>: (array) -- any number of elements. Returns `array.length`
|
|
617
649
|
|
|
618
650
|
e.g.
|
|
651
|
+
|
|
619
652
|
```js
|
|
620
653
|
{
|
|
621
654
|
operator: 'count',
|
|
@@ -626,10 +659,11 @@ e.g.
|
|
|
626
659
|
|
|
627
660
|
`children` array: `[...values]`
|
|
628
661
|
|
|
629
|
-
|
|
662
|
+
---
|
|
663
|
+
|
|
630
664
|
### CONDITIONAL
|
|
631
665
|
|
|
632
|
-
|
|
666
|
+
_Return different values depending on a condition expression_
|
|
633
667
|
|
|
634
668
|
Aliases: `?`, `conditional`, `ifThen`
|
|
635
669
|
|
|
@@ -640,6 +674,7 @@ Aliases: `?`, `conditional`, `ifThen`
|
|
|
640
674
|
- `valueIfFalse` (or `ifFalse`)<sup>*</sup>: the value returned if `condition` is `false`
|
|
641
675
|
|
|
642
676
|
e.g.
|
|
677
|
+
|
|
643
678
|
```js
|
|
644
679
|
{
|
|
645
680
|
operator: '?',
|
|
@@ -661,12 +696,13 @@ e.g.
|
|
|
661
696
|
|
|
662
697
|
`children` array: `[condition, valueIfTrue, valueIfFalse]`
|
|
663
698
|
|
|
664
|
-
**Note**:
|
|
699
|
+
**Note**: _For more complex branching logic, the ["match" operator](#match) can be used (it matches more than just a boolean condition)_
|
|
700
|
+
|
|
701
|
+
---
|
|
665
702
|
|
|
666
|
-
----
|
|
667
703
|
### REGEX
|
|
668
704
|
|
|
669
|
-
|
|
705
|
+
_Compares an input string against a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) pattern_
|
|
670
706
|
|
|
671
707
|
Aliases: `regex`, `patternMatch`, `regexp`, `matchPattern`
|
|
672
708
|
|
|
@@ -678,6 +714,7 @@ Aliases: `regex`, `patternMatch`, `regexp`, `matchPattern`
|
|
|
678
714
|
Returns `true` (match found) or `false` (no match)
|
|
679
715
|
|
|
680
716
|
e.g.
|
|
717
|
+
|
|
681
718
|
```js
|
|
682
719
|
{
|
|
683
720
|
operator: 'regex',
|
|
@@ -689,10 +726,11 @@ e.g.
|
|
|
689
726
|
|
|
690
727
|
`children` array: `[testString, pattern]`
|
|
691
728
|
|
|
692
|
-
|
|
729
|
+
---
|
|
730
|
+
|
|
693
731
|
### OBJECT_PROPERTIES
|
|
694
732
|
|
|
695
|
-
|
|
733
|
+
_Extracts values from data objects in your application_
|
|
696
734
|
|
|
697
735
|
Aliases: `objectProperties`, `dataProperties`,`data`, `getData`, `objProps`, `getProperty`, `getObjProp`
|
|
698
736
|
|
|
@@ -703,7 +741,7 @@ Aliases: `objectProperties`, `dataProperties`,`data`, `getData`, `objProps`, `ge
|
|
|
703
741
|
|
|
704
742
|
Data objects are normally expected to be passed in to the evaluator as part of the [options](#available-options), not as part of the expression itself. This is because the source objects are expected to be values internal to your application, whereas the evaluator provides an externally configurable mechanism to extract (and process) application data. (However, it is possible to pass data objects directly as part of the expression using the `additionalObjects` property, so (in theory) data objects could be dynamically generated from other expressions.)
|
|
705
743
|
|
|
706
|
-
For example, consider a `user` object and an fig-tree evaluator instance:
|
|
744
|
+
For example, consider a `user` object and an fig-tree evaluator instance:
|
|
707
745
|
|
|
708
746
|
```js
|
|
709
747
|
const user = {
|
|
@@ -745,18 +783,19 @@ Here is the result of various values of `expression:`
|
|
|
745
783
|
}
|
|
746
784
|
// => ["The Vulture", "Green Goblin"]
|
|
747
785
|
```
|
|
786
|
+
|
|
748
787
|
Notice the last example pulls multiple values out of an array of objects, in this case the "name". This is essentially a shorthand for:
|
|
749
788
|
|
|
750
789
|
```js
|
|
751
|
-
fig
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
).map((e) => e.name)
|
|
790
|
+
fig
|
|
791
|
+
.evaluate({ operator: 'getProperty', path: 'user.enemies' }, { data: { user } })
|
|
792
|
+
.map((e) => e.name)
|
|
755
793
|
```
|
|
756
794
|
|
|
757
795
|
The "objectProperties" operator uses [`object-property-extractor`](https://www.npmjs.com/package/object-property-extractor) internally, so please see the documentation of that package for more information.
|
|
758
796
|
|
|
759
797
|
The "objectProperties" operator will throw an error if an invalid path is provided, so it is recommended to provide a [`fallback`](#other-common-properties) value for the expression:
|
|
798
|
+
|
|
760
799
|
```js
|
|
761
800
|
{
|
|
762
801
|
operator: 'objectProperties',
|
|
@@ -768,7 +807,6 @@ The "objectProperties" operator will throw an error if an invalid path is provid
|
|
|
768
807
|
|
|
769
808
|
`children` array: `[property]`
|
|
770
809
|
|
|
771
|
-
|
|
772
810
|
Example using "data" passed in dynamically as part of expression:
|
|
773
811
|
|
|
774
812
|
```js
|
|
@@ -785,10 +823,11 @@ Example using "data" passed in dynamically as part of expression:
|
|
|
785
823
|
// => "Frodo"
|
|
786
824
|
```
|
|
787
825
|
|
|
788
|
-
|
|
826
|
+
---
|
|
827
|
+
|
|
789
828
|
### STRING_SUBSTITUTION
|
|
790
829
|
|
|
791
|
-
|
|
830
|
+
_Replace values in a string using simple parameter (positional or named properties) substitution_
|
|
792
831
|
|
|
793
832
|
Aliases: `stringSubstitution`, `substitute`, `stringSub`, `replace`
|
|
794
833
|
|
|
@@ -800,12 +839,6 @@ Aliases: `stringSubstitution`, `substitute`, `stringSub`, `replace`
|
|
|
800
839
|
- `substitutionCharacter` (or `subCharacter`, `subChar`): (`"%"` or `"$"`) -- by default, when using positional replacement, it looks for the `%` token (i.e `%1, %2, etc`), but this can be changed to `$` (i.e. `$1, $2, $3, etc`) by setting this property to `$`.
|
|
801
840
|
- `numberMapping` (or `numMap`, `numberMap`, `pluralisation`, `pluralization`, `plurals`): (object) -- when replacing with named properties and you have replacement values that are numbers, it's possible to map values or ranges to specific string outputs. This can be used to produce correct pluralisation, for example. [See below](#named-property-replacement) for more details.
|
|
802
841
|
|
|
803
|
-
#### Missing and `null` values
|
|
804
|
-
|
|
805
|
-
A substitution value of `null` or `undefined` is rendered as an empty string, as is a named parameter with no matching value in `substitutions` or the [`data` object](#available-options). So `"Hello, {{name}}!"` with `{ name: null }` gives `"Hello, !"` rather than `"Hello, null!"`. Note that `false` and `0` are values in their own right, so they're rendered as `"false"` and `"0"`.
|
|
806
|
-
|
|
807
|
-
If you need a placeholder other than an empty string, provide it with a [CONDITIONAL](#conditional) (or a [MATCH](#match)) in the substitution value itself.
|
|
808
|
-
|
|
809
842
|
Substitution can be done using either **positional** replacement, or with **named properties**:
|
|
810
843
|
|
|
811
844
|
#### Positional replacement
|
|
@@ -813,6 +846,7 @@ Substitution can be done using either **positional** replacement, or with **name
|
|
|
813
846
|
The values in the `substitutions` array are replaced in the original `string` by matching their order to the numerical order of the parameters.
|
|
814
847
|
|
|
815
848
|
e.g.
|
|
849
|
+
|
|
816
850
|
```js
|
|
817
851
|
{
|
|
818
852
|
operator: 'stringSubstitution',
|
|
@@ -872,6 +906,7 @@ e.g.
|
|
|
872
906
|
(`trimWhiteSpace` and `substitutionCharacter` not available, since `substitutions` can be an arbitrary number of items)
|
|
873
907
|
|
|
874
908
|
e.g.
|
|
909
|
+
|
|
875
910
|
```js
|
|
876
911
|
{
|
|
877
912
|
operator: 'replace',
|
|
@@ -896,6 +931,7 @@ Replacement tokens can be indicated in the main string with a named value, using
|
|
|
896
931
|
}
|
|
897
932
|
// => "Your name is Steve Rogers and your best friend is Bucky Barnes"
|
|
898
933
|
```
|
|
934
|
+
|
|
899
935
|
Note the use of `nested.properties` as per [objectProperties](#object_properties).
|
|
900
936
|
|
|
901
937
|
Additionally, the substitutions can actually be provided directly in the associated `data` object and the operator will search for them there if not found in the `substitutions` property. This could be achieved simply by nesting a [`getData` node](#object_properties) inside the `substitutions` property, but because this is a very common scenario (the values provided will normally be dynamic based on application state), this shorthand is provided as a convenience.
|
|
@@ -924,13 +960,12 @@ Additionally, the substitutions can actually be provided directly in the associa
|
|
|
924
960
|
// => "The rain in Spain falls mainly on the plain"
|
|
925
961
|
```
|
|
926
962
|
|
|
927
|
-
|
|
928
|
-
|
|
929
963
|
#### Number mapping
|
|
930
964
|
|
|
931
965
|
If the replacement values are numbers, we can extend this functionality with a special `numberMapping` object, which allows for different replacements depending on the value, which is handy for pluralisation, for example.
|
|
932
966
|
|
|
933
967
|
The syntax for the `numberMapping` property is:
|
|
968
|
+
|
|
934
969
|
```js
|
|
935
970
|
{
|
|
936
971
|
propertyName1: {
|
|
@@ -944,9 +979,11 @@ The syntax for the `numberMapping` property is:
|
|
|
944
979
|
propertyName2: { ...etc }
|
|
945
980
|
}
|
|
946
981
|
```
|
|
982
|
+
|
|
947
983
|
The number map can have as few or as many match options as desired -- if no match is found (or if no `numberMapping` property at all), the number will be returned as-is.
|
|
948
984
|
|
|
949
985
|
e.g.
|
|
986
|
+
|
|
950
987
|
```js
|
|
951
988
|
{
|
|
952
989
|
operator: 'stringSubstitution',
|
|
@@ -982,26 +1019,26 @@ e.g.
|
|
|
982
1019
|
|
|
983
1020
|
**Note**: `children` array not available for named properties
|
|
984
1021
|
|
|
985
|
-
|
|
986
|
-
----
|
|
1022
|
+
---
|
|
987
1023
|
|
|
988
1024
|
### SPLIT
|
|
989
1025
|
|
|
990
|
-
|
|
1026
|
+
_Split strings into arrays_
|
|
991
1027
|
|
|
992
1028
|
Aliases: `split`, `arraySplit`
|
|
993
1029
|
|
|
994
1030
|
#### Properties
|
|
995
1031
|
|
|
996
1032
|
- `value` (or `string`)<sup>*</sup>: (string) -- string to be split
|
|
997
|
-
- `delimiter` (or `separator`): (string) -- substring to split `value` on (Default: `" "` (space))
|
|
998
|
-
- `trimWhiteSpace` (or `trimWhitespace`, `trim`): (boolean, default `true`) -- strips whitespace from the beginning or end of resulting substrings
|
|
1033
|
+
- `delimiter` (or `separator`): (string) -- substring to split `value` on (Default: `" "` (space))
|
|
1034
|
+
- `trimWhiteSpace` (or `trimWhitespace`, `trim`): (boolean, default `true`) -- strips whitespace from the beginning or end of resulting substrings
|
|
999
1035
|
- `excludeTrailing` (or `removeTrailing`, `excludeTrailingDelimiter`): (boolean, default `true`) -- if `false`, if the input string ends with the delimiter, the last member of the output array will be an empty string.
|
|
1000
1036
|
i.e. `this, that, another,` (delimiter `","`) => `["this", "that", "another", ""]`
|
|
1001
1037
|
|
|
1002
|
-
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should
|
|
1038
|
+
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should _rarely_ be needed to be changed from their default values.
|
|
1003
1039
|
|
|
1004
1040
|
e.g.
|
|
1041
|
+
|
|
1005
1042
|
```js
|
|
1006
1043
|
{
|
|
1007
1044
|
operator: 'split',
|
|
@@ -1018,7 +1055,7 @@ e.g.
|
|
|
1018
1055
|
|
|
1019
1056
|
### HTTP requests
|
|
1020
1057
|
|
|
1021
|
-
The following three operators (`GET`, `POST`, `GraphQL`) make http requests, so require an http client. If using fig-tree in the browser, it will use the native `fetch()` method by default,
|
|
1058
|
+
The following three operators (`GET`, `POST`, `GraphQL`) make http requests, so require an http client. If using fig-tree in the browser, it will use the native `fetch()` method by default, _so no configuration is required_. However, if using in `node`, or you wish to use a different http client (if your project is already using [`axios`](https://www.npmjs.com/package/axios), say), you can specify it with the `httpClient` option.
|
|
1022
1059
|
|
|
1023
1060
|
The `httpClient` object is an abstraction around an http package in order to standardise the implementation for use in fig-tree. Two such "wrappers" are provided in the FigTree package, for:
|
|
1024
1061
|
|
|
@@ -1035,7 +1072,7 @@ import { FigTreeEvaluator, AxiosClient } from 'fig-tree-evaluator'
|
|
|
1035
1072
|
|
|
1036
1073
|
const fig = new FigTreeEvaluator({
|
|
1037
1074
|
httpClient: AxiosClient(axios),
|
|
1038
|
-
...otherOptions
|
|
1075
|
+
...otherOptions,
|
|
1039
1076
|
})
|
|
1040
1077
|
```
|
|
1041
1078
|
|
|
@@ -1047,7 +1084,7 @@ import { FigTreeEvaluator, FetchClient } from 'fig-tree-evaluator'
|
|
|
1047
1084
|
|
|
1048
1085
|
const fig = new FigTreeEvaluator({
|
|
1049
1086
|
httpClient: FetchClient(fetch),
|
|
1050
|
-
...otherOptions
|
|
1087
|
+
...otherOptions,
|
|
1051
1088
|
})
|
|
1052
1089
|
```
|
|
1053
1090
|
|
|
@@ -1078,21 +1115,19 @@ import { someClient } from 'some-library'
|
|
|
1078
1115
|
|
|
1079
1116
|
const fig = new FigTreeEvaluator({
|
|
1080
1117
|
httpClient: MyHttpWrapper(someClient),
|
|
1081
|
-
...otherOptions
|
|
1118
|
+
...otherOptions,
|
|
1082
1119
|
})
|
|
1083
|
-
|
|
1084
1120
|
```
|
|
1085
1121
|
|
|
1086
1122
|
See the implementation for `axios` and `node-fetch` [in the repo](https://github.com/CarlosNZ/fig-tree-evaluator/blob/main/src/httpClients.ts) for specific details.
|
|
1087
1123
|
|
|
1088
|
-
|
|
1089
1124
|
### GET
|
|
1090
1125
|
|
|
1091
|
-
|
|
1126
|
+
_Http GET request_
|
|
1092
1127
|
|
|
1093
1128
|
Aliases: `get`, `api`
|
|
1094
1129
|
|
|
1095
|
-
|
|
1130
|
+
_Note: if used in `node`, or you're using an http client other than `fetch`, you will need to explicitly provide an `httpClient` option. [See details](#http-requests)_
|
|
1096
1131
|
|
|
1097
1132
|
#### Properties
|
|
1098
1133
|
|
|
@@ -1104,6 +1139,7 @@ Aliases: `get`, `api`
|
|
|
1104
1139
|
As mentioned in the [options reference](#available-options) above, a `baseEndpoint` string and `headers` object can be provided in the constructor. These are applied to all subsequent requests to save having to specify them in every evaluation. (Additional/override `headers` can always be added to a specific evaluation, too.)
|
|
1105
1140
|
|
|
1106
1141
|
e.g.
|
|
1142
|
+
|
|
1107
1143
|
```js
|
|
1108
1144
|
{
|
|
1109
1145
|
operator: 'GET',
|
|
@@ -1134,6 +1170,7 @@ e.g.
|
|
|
1134
1170
|
- `returnProperty` (optional): as above
|
|
1135
1171
|
|
|
1136
1172
|
e.g.
|
|
1173
|
+
|
|
1137
1174
|
```js
|
|
1138
1175
|
{
|
|
1139
1176
|
operator: 'get',
|
|
@@ -1149,16 +1186,17 @@ e.g.
|
|
|
1149
1186
|
// => "🇨🇺"
|
|
1150
1187
|
```
|
|
1151
1188
|
|
|
1152
|
-
|
|
1189
|
+
---
|
|
1190
|
+
|
|
1153
1191
|
### POST
|
|
1154
1192
|
|
|
1155
|
-
|
|
1193
|
+
_Http POST request_
|
|
1156
1194
|
|
|
1157
1195
|
Aliases: `post`
|
|
1158
1196
|
|
|
1159
1197
|
The "POST" operator is basically structurally the same as [GET](#get).
|
|
1160
1198
|
|
|
1161
|
-
|
|
1199
|
+
_Note: if used in `node`, or you're using an http client other than `fetch`, you will need to explicitly provide an `httpClient` option. [See details](#http-requests)_
|
|
1162
1200
|
|
|
1163
1201
|
#### Properties
|
|
1164
1202
|
|
|
@@ -1166,6 +1204,7 @@ The "POST" operator is basically structurally the same as [GET](#get).
|
|
|
1166
1204
|
- `parameters` (or `bodyJson`, `data`) -- passed to the Post request as body JSON rather than url query parameters (hence the different aliases)
|
|
1167
1205
|
|
|
1168
1206
|
e.g.
|
|
1207
|
+
|
|
1169
1208
|
```js
|
|
1170
1209
|
{
|
|
1171
1210
|
operator: "post",
|
|
@@ -1183,17 +1222,17 @@ e.g.
|
|
|
1183
1222
|
|
|
1184
1223
|
`children` array: `[urlObject, parameterKeys, ...values, returnProperty]` (same as "GET")
|
|
1185
1224
|
|
|
1186
|
-
|
|
1225
|
+
---
|
|
1187
1226
|
|
|
1188
1227
|
### GRAPHQL
|
|
1189
1228
|
|
|
1190
|
-
|
|
1229
|
+
_Http GraphQL request (using POST)_
|
|
1191
1230
|
|
|
1192
1231
|
Aliases: `graphQL`, `graphQl`, `graphql`, `gql`
|
|
1193
1232
|
|
|
1194
1233
|
This operator is essentially a special case of the "POST" operator, but structured specifically for [GraphQL](https://graphql.org/) requests.
|
|
1195
1234
|
|
|
1196
|
-
|
|
1235
|
+
_Note: if used in `node`, or you're using an http client other than `fetch`, you will need to explicitly provide an `httpClient` option. [See details](#http-requests)_
|
|
1197
1236
|
|
|
1198
1237
|
#### Properties
|
|
1199
1238
|
|
|
@@ -1208,6 +1247,7 @@ As mentioned in the [options reference](#available-options) above, a `headers` o
|
|
|
1208
1247
|
Often, GraphQL queries will be to a single endpoint and only the query/variables will differ. In that case, it is recommended to pass a GraphQL connection object into the FigTreeEvaluator constructor [options](#available-options).
|
|
1209
1248
|
|
|
1210
1249
|
The required connection object is:
|
|
1250
|
+
|
|
1211
1251
|
```ts
|
|
1212
1252
|
{
|
|
1213
1253
|
endpoint: string // url
|
|
@@ -1216,6 +1256,7 @@ The required connection object is:
|
|
|
1216
1256
|
```
|
|
1217
1257
|
|
|
1218
1258
|
The following example expression uses the GraphQL connection (specified in constructor options): `{endpoint: 'https://countries.trevorblades.com/'}`
|
|
1259
|
+
|
|
1219
1260
|
```js
|
|
1220
1261
|
{
|
|
1221
1262
|
operator: 'graphQL',
|
|
@@ -1241,6 +1282,7 @@ The following example expression uses the GraphQL connection (specified in const
|
|
|
1241
1282
|
- `returnNode` (optional): the return property, as per "GET" and "POST" operators
|
|
1242
1283
|
|
|
1243
1284
|
e.g.
|
|
1285
|
+
|
|
1244
1286
|
```js
|
|
1245
1287
|
{
|
|
1246
1288
|
operator: 'GraphQL',
|
|
@@ -1261,10 +1303,11 @@ e.g.
|
|
|
1261
1303
|
// => "🇨🇺"
|
|
1262
1304
|
```
|
|
1263
1305
|
|
|
1264
|
-
|
|
1306
|
+
---
|
|
1307
|
+
|
|
1265
1308
|
### SQL
|
|
1266
1309
|
|
|
1267
|
-
|
|
1310
|
+
_Query an SQL database_
|
|
1268
1311
|
|
|
1269
1312
|
Aliases: `sql`, `pgSql`, `postgres`, `pg`, `sqlLite`, `sqlite`, `mySql`
|
|
1270
1313
|
|
|
@@ -1272,7 +1315,7 @@ Aliases: `sql`, `pgSql`, `postgres`, `pg`, `sqlLite`, `sqlite`, `mySql`
|
|
|
1272
1315
|
|
|
1273
1316
|
- `query`<sup>*</sup>: (string) -- SQL query string, with parameterised replacements (i.e. `$1`, `$2`, etc)
|
|
1274
1317
|
- `values` (or `replacements`): (array / object) -- replacements for the `query` parameters
|
|
1275
|
-
- `single` (or `singleRecord`): (boolean) -- by default, results are returned as an array of objects. However, if your query is expected to just return a single record, you can set `single: true` and just the record object will be returned (i.e. not in an array). Note that if the query
|
|
1318
|
+
- `single` (or `singleRecord`): (boolean) -- by default, results are returned as an array of objects. However, if your query is expected to just return a single record, you can set `single: true` and just the record object will be returned (i.e. not in an array). Note that if the query _does_ fetch multiple records, only the first will be returned.
|
|
1276
1319
|
- `flatten` (or `flat`): (boolean) -- Instead of returning an object, `flatten: true` will just return an array of values. e.g, instead of `{name: "Tom", age: 49}`, it will return `["Tom", 49]`. This would usually be used in conjunction with the `single` property -- if not, it will return an array of flattened arrays.
|
|
1277
1320
|
|
|
1278
1321
|
#### Examples
|
|
@@ -1333,7 +1376,7 @@ const pgConfig = {
|
|
|
1333
1376
|
host: 'localhost',
|
|
1334
1377
|
database: 'northwind',
|
|
1335
1378
|
port: 5432,
|
|
1336
|
-
...etc
|
|
1379
|
+
...etc,
|
|
1337
1380
|
}
|
|
1338
1381
|
|
|
1339
1382
|
const pgConnect = new Client(pgConfig)
|
|
@@ -1342,21 +1385,21 @@ pgConnect.connect()
|
|
|
1342
1385
|
|
|
1343
1386
|
const fig = new FigTreeEvaluator({
|
|
1344
1387
|
sqlConnection: SQLNodePostgres(pgConnect),
|
|
1345
|
-
...otherOptions
|
|
1388
|
+
...otherOptions,
|
|
1346
1389
|
})
|
|
1347
1390
|
|
|
1348
|
-
fig
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1391
|
+
fig
|
|
1392
|
+
.evaluate({
|
|
1393
|
+
operator: 'SQL',
|
|
1394
|
+
query: "SELECT contact_name FROM customers where customer_id = 'FAMIA';",
|
|
1395
|
+
single: true,
|
|
1396
|
+
flatten: true,
|
|
1397
|
+
})
|
|
1398
|
+
.then((result) => console.log(result)) // => "Aria Cruz"
|
|
1355
1399
|
```
|
|
1356
1400
|
|
|
1357
1401
|
##### SQLite
|
|
1358
1402
|
|
|
1359
|
-
|
|
1360
1403
|
```js
|
|
1361
1404
|
import sqlite3 from 'sqlite3'
|
|
1362
1405
|
import { open, Database } from 'sqlite'
|
|
@@ -1397,10 +1440,11 @@ You then implement in FigTree options the same way as the two described above.
|
|
|
1397
1440
|
|
|
1398
1441
|
Check out `SQLNodePostgres` and `SQLite` [in the repo](https://github.com/CarlosNZ/fig-tree-evaluator/blob/main/src/databaseConnections.ts) for specific details.
|
|
1399
1442
|
|
|
1400
|
-
|
|
1443
|
+
---
|
|
1444
|
+
|
|
1401
1445
|
### BUILD_OBJECT
|
|
1402
1446
|
|
|
1403
|
-
|
|
1447
|
+
_Return an object constructed by separate keys and values_
|
|
1404
1448
|
|
|
1405
1449
|
Aliases: `buildObject`, `build`, `object`
|
|
1406
1450
|
|
|
@@ -1409,18 +1453,20 @@ The "buildObject" operator would primarily be used to construct an object input
|
|
|
1409
1453
|
#### Properties
|
|
1410
1454
|
|
|
1411
1455
|
- `properties` (or `values`, `keyValPairs`, `keyValuePairs`)<sup>*</sup>: (array) -- array of either:
|
|
1412
|
-
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1456
|
+
- objects of the following shape:
|
|
1457
|
+
|
|
1458
|
+
```ts
|
|
1459
|
+
{
|
|
1460
|
+
key: string
|
|
1461
|
+
value: any
|
|
1462
|
+
}
|
|
1463
|
+
```
|
|
1419
1464
|
- key/value pairs in sequence, e.g. `[ "key1", "value1", "key2", "value2", ... ]`
|
|
1420
1465
|
|
|
1421
1466
|
Each object or pair of elements provides one key-value pair in the output object
|
|
1422
1467
|
|
|
1423
1468
|
e.g.
|
|
1469
|
+
|
|
1424
1470
|
```js
|
|
1425
1471
|
{
|
|
1426
1472
|
operator: 'buildObject',
|
|
@@ -1452,11 +1498,11 @@ e.g.
|
|
|
1452
1498
|
|
|
1453
1499
|
`children`: `[...properties]` (same as properties array above)
|
|
1454
1500
|
|
|
1455
|
-
|
|
1501
|
+
---
|
|
1456
1502
|
|
|
1457
1503
|
### MATCH
|
|
1458
1504
|
|
|
1459
|
-
|
|
1505
|
+
_Return different values depending on a matching expression_
|
|
1460
1506
|
|
|
1461
1507
|
Aliases: `match`, `switch`
|
|
1462
1508
|
|
|
@@ -1465,10 +1511,11 @@ The "match" operator is equivalent to a "switch"/"case" in Javascript. It is sim
|
|
|
1465
1511
|
#### Properties
|
|
1466
1512
|
|
|
1467
1513
|
- `matchExpression` (or `matchValue`)<sup>*</sup>: (string | number | boolean) -- a node that returns a value to be compared against possible cases.
|
|
1468
|
-
- `branches` (or `arms` or `cases`): (object) -- an object whose
|
|
1514
|
+
- `branches` (or `arms` or `cases`): (object) -- an object whose _keys_ are compared against the `matchExpression`. The _value_ of the matching key is returned.
|
|
1469
1515
|
- `...branches` -- as an alternative to the `branches` object, matching key/values can be placed at the root of the node (see example)
|
|
1470
1516
|
|
|
1471
1517
|
e.g.
|
|
1518
|
+
|
|
1472
1519
|
```js
|
|
1473
1520
|
// Simple decision tree
|
|
1474
1521
|
{
|
|
@@ -1504,6 +1551,7 @@ e.g.
|
|
|
1504
1551
|
```
|
|
1505
1552
|
|
|
1506
1553
|
This expression could also be written as (with branch/case keys at the root level)"
|
|
1554
|
+
|
|
1507
1555
|
```js
|
|
1508
1556
|
{
|
|
1509
1557
|
operator: 'match',
|
|
@@ -1539,10 +1587,11 @@ The pairs of `key`/`value`s are constructed into the `branches` object, the same
|
|
|
1539
1587
|
|
|
1540
1588
|
For an example of a complex decision tree implementation, which includes [aliases](#alias-nodes), [fallbacks](#other-common-properties) and a range of operators, see the "match" test case file (`20_match.test.ts`).
|
|
1541
1589
|
|
|
1542
|
-
|
|
1590
|
+
---
|
|
1591
|
+
|
|
1543
1592
|
### PASSTHRU
|
|
1544
1593
|
|
|
1545
|
-
|
|
1594
|
+
_Pass-thru (does nothing)_
|
|
1546
1595
|
|
|
1547
1596
|
Aliases: `passThru`, `_`, `pass`, `ignore`, `coerce`, `convert`
|
|
1548
1597
|
|
|
@@ -1553,6 +1602,7 @@ This operator simply returns its input. Its purpose is to allow an additional ty
|
|
|
1553
1602
|
- `value` (or `_`, `data`)<sup>*</sup>: (any) -- the value that is returned
|
|
1554
1603
|
|
|
1555
1604
|
e.g.
|
|
1605
|
+
|
|
1556
1606
|
```js
|
|
1557
1607
|
{
|
|
1558
1608
|
operator: 'pass',
|
|
@@ -1562,7 +1612,7 @@ e.g.
|
|
|
1562
1612
|
// => ["500"]
|
|
1563
1613
|
```
|
|
1564
1614
|
|
|
1565
|
-
|
|
1615
|
+
---
|
|
1566
1616
|
|
|
1567
1617
|
## Custom Functions/Operators
|
|
1568
1618
|
|
|
@@ -1575,7 +1625,7 @@ const fig = new FigTreeEvaluator({
|
|
|
1575
1625
|
functions: {
|
|
1576
1626
|
double: (x) => x * 2,
|
|
1577
1627
|
getCurrentYear: () => new Date().toLocaleString('en', { year: 'numeric' }),
|
|
1578
|
-
changeCase: ({string, toCase}) => toCase === "upper" ?
|
|
1628
|
+
changeCase: ({string, toCase}) => toCase === "upper" ?
|
|
1579
1629
|
string.toUpperCase() : string.toLowerCase()
|
|
1580
1630
|
average: (...numbers) => (numbers.reduce(
|
|
1581
1631
|
(a, n) => a + n, 0)) / numbers.length,
|
|
@@ -1583,7 +1633,7 @@ const fig = new FigTreeEvaluator({
|
|
|
1583
1633
|
})
|
|
1584
1634
|
```
|
|
1585
1635
|
|
|
1586
|
-
|
|
1636
|
+
_You can also define functions with extended metadata -- see [Metadata](#metadata) for more on that._
|
|
1587
1637
|
|
|
1588
1638
|
### The CUSTOM_FUNCTIONS operator
|
|
1589
1639
|
|
|
@@ -1591,11 +1641,12 @@ Aliases: `customFunctions`, `customFunction`, `functions`, `function`, `runFunct
|
|
|
1591
1641
|
|
|
1592
1642
|
#### Properties
|
|
1593
1643
|
|
|
1594
|
-
- `functionPath` (or `functionsPath`, `functionName`, `funcPath`<sup>*</sup>): (string) -- name of the function in the
|
|
1644
|
+
- `functionPath` (or `functionsPath`, `functionName`, `funcPath`<sup>*</sup>): (string) -- name of the function in the `options.functions` object
|
|
1595
1645
|
- `args` (or `arguments`, `variables`): (array | any) -- input arguments for the function. If an array, will be passed in as multiple arguments.
|
|
1596
1646
|
- `input`: Input argument if function only takes a single argument. Note that, if your function takes a single array as its argument, you'll need to pass it in the `input` property -- the `args` property will spread the array into multiple arguments.
|
|
1597
1647
|
|
|
1598
1648
|
Here is the result of various expressions:
|
|
1649
|
+
|
|
1599
1650
|
```js
|
|
1600
1651
|
{
|
|
1601
1652
|
operator: 'functions',
|
|
@@ -1679,12 +1730,12 @@ Converting the above examples to this format:
|
|
|
1679
1730
|
|
|
1680
1731
|
These custom operators even support the [shorthand syntax](#shorthand-syntax) -- they should behave just like standard operators.
|
|
1681
1732
|
|
|
1682
|
-
|
|
1683
1733
|
## Alias Nodes
|
|
1684
1734
|
|
|
1685
1735
|
If you have a node that is used more than once in a complex expression, it's possible to just evaluate the repeated node once, and refer to it throughout using an "alias" reference. This allows for a simpler expression (reduces code duplication) as well as a performance improvement, since the aliased node is only evaluated once, providing a simple [memoization](https://en.wikipedia.org/wiki/Memoization) mechanism. (See also [Caching/Memoization](#caching-memoization))
|
|
1686
1736
|
|
|
1687
1737
|
For example, if you have the expression:
|
|
1738
|
+
|
|
1688
1739
|
```js
|
|
1689
1740
|
{
|
|
1690
1741
|
operator: "?",
|
|
@@ -1719,6 +1770,7 @@ For example, if you have the expression:
|
|
|
1719
1770
|
The `GET` operation is used twice -- once to compare it for non-equality with `null`, and once again to return its value if `true`. This is particularly wasteful since it is a network request.
|
|
1720
1771
|
|
|
1721
1772
|
We can create an alias for this whole node, resulting in this equivalent expression:
|
|
1773
|
+
|
|
1722
1774
|
```js
|
|
1723
1775
|
{
|
|
1724
1776
|
$getCountry: {
|
|
@@ -1754,6 +1806,7 @@ Like all expression nodes, alias nodes can themselves contain complex expression
|
|
|
1754
1806
|
## Fragments
|
|
1755
1807
|
|
|
1756
1808
|
You may find that the expressions you are building for your configuration files often use very similar sub-expressions (but perhaps with only some input values that differ). For example, your expressions might be regularly looking up a "countries" database and fetching the capital city, such as:
|
|
1809
|
+
|
|
1757
1810
|
```js
|
|
1758
1811
|
{
|
|
1759
1812
|
operator: 'GET',
|
|
@@ -1782,21 +1835,22 @@ const fig = new FigTreeEvaluator({
|
|
|
1782
1835
|
url: {
|
|
1783
1836
|
operator: 'stringSubstitution',
|
|
1784
1837
|
string: 'https://restcountries.com/v3.1/name/%1',
|
|
1785
|
-
replacements: [
|
|
1838
|
+
replacements: ['$country'],
|
|
1786
1839
|
},
|
|
1787
1840
|
returnProperty: '[0].capital',
|
|
1788
1841
|
outputType: 'string',
|
|
1789
1842
|
metadata: {
|
|
1790
1843
|
// Not required, but useful for external consumers -- see Metadata below
|
|
1791
|
-
description:
|
|
1844
|
+
description: 'Fetches the capital city of a country',
|
|
1792
1845
|
parameters: { $country: { type: 'string', required: true } },
|
|
1793
|
-
}
|
|
1846
|
+
},
|
|
1794
1847
|
},
|
|
1795
1848
|
},
|
|
1796
1849
|
})
|
|
1797
1850
|
```
|
|
1798
1851
|
|
|
1799
1852
|
Then any subsequent expressions can use this fragment by specifying a special "Fragment Node", which contains the `fragment` and (optionally) `parameters` fields:
|
|
1853
|
+
|
|
1800
1854
|
```js
|
|
1801
1855
|
{
|
|
1802
1856
|
fragment: "getCapital",
|
|
@@ -1807,6 +1861,7 @@ Then any subsequent expressions can use this fragment by specifying a special "F
|
|
|
1807
1861
|
```
|
|
1808
1862
|
|
|
1809
1863
|
Like the `branches` field in the ["Match" operator](#match), the properties of the `parameters` field can be specified at the root level as well -- it just depends on whichever is most appropriate for your use case. So the following is equivalent to the previous fragment node:
|
|
1864
|
+
|
|
1810
1865
|
```js
|
|
1811
1866
|
{
|
|
1812
1867
|
fragment: "getCapital",
|
|
@@ -1816,21 +1871,24 @@ Like the `branches` field in the ["Match" operator](#match), the properties of t
|
|
|
1816
1871
|
|
|
1817
1872
|
See `22_fragments.test.ts` for more complex examples.
|
|
1818
1873
|
|
|
1819
|
-
Unlike Alias Nodes, which are evaluated
|
|
1874
|
+
Unlike Alias Nodes, which are evaluated _once_ and then the result re-used whenever the alias is referenced, Fragments are evaluated every time, as the input parameters may differ.
|
|
1820
1875
|
|
|
1821
1876
|
## Shorthand syntax
|
|
1822
1877
|
|
|
1823
1878
|
It's possible to express FigTree expressions in a more compact syntax, as follows:
|
|
1824
1879
|
|
|
1825
|
-
- Fragment and Operator nodes can be represented by putting the name of the fragment or operator as a property name (prefixed by `$`), then putting the parameters in an object as the property value. For example:
|
|
1880
|
+
- Fragment and Operator nodes can be represented by putting the name of the fragment or operator as a property name (prefixed by `$`), then putting the parameters in an object as the property value. For example:
|
|
1881
|
+
|
|
1826
1882
|
```js
|
|
1827
1883
|
{
|
|
1828
1884
|
operator: 'regex',
|
|
1829
1885
|
string: "home@myplace.com",
|
|
1830
|
-
pattern: '^[A-Za-z0-9.]+@[A-Za-z0-9]+\\.[A-Za-z0-9.]+$'
|
|
1886
|
+
pattern: '^[A-Za-z0-9.]+@[A-Za-z0-9]+\\.[A-Za-z0-9.]+$'
|
|
1831
1887
|
}
|
|
1832
1888
|
```
|
|
1889
|
+
|
|
1833
1890
|
can be written as:
|
|
1891
|
+
|
|
1834
1892
|
```js
|
|
1835
1893
|
{
|
|
1836
1894
|
$regex:
|
|
@@ -1841,14 +1899,15 @@ It's possible to express FigTree expressions in a more compact syntax, as follow
|
|
|
1841
1899
|
}
|
|
1842
1900
|
```
|
|
1843
1901
|
|
|
1844
|
-
- For operator nodes (not fragments, as they always require named parameters), parameters can be represented positionally (equivalent to the `children` property in normal operator nodes) in an array. The above example could also be expressed as:
|
|
1902
|
+
- For operator nodes (not fragments, as they always require named parameters), parameters can be represented positionally (equivalent to the `children` property in normal operator nodes) in an array. The above example could also be expressed as:
|
|
1903
|
+
|
|
1845
1904
|
```js
|
|
1846
1905
|
{
|
|
1847
|
-
$regex: [
|
|
1906
|
+
$regex: ['home@myplace.com', '^[A-Za-z0-9.]+@[A-Za-z0-9]+\\.[A-Za-z0-9.]+$']
|
|
1848
1907
|
}
|
|
1849
1908
|
```
|
|
1850
1909
|
|
|
1851
|
-
- Operator nodes with a single parameter can just be placed directly as the single property value. For example:
|
|
1910
|
+
- Operator nodes with a single parameter can just be placed directly as the single property value. For example:
|
|
1852
1911
|
```js
|
|
1853
1912
|
{
|
|
1854
1913
|
operator: "getData",
|
|
@@ -1857,12 +1916,13 @@ It's possible to express FigTree expressions in a more compact syntax, as follow
|
|
|
1857
1916
|
```
|
|
1858
1917
|
can become, simply:
|
|
1859
1918
|
```js
|
|
1860
|
-
{
|
|
1919
|
+
{
|
|
1920
|
+
$getData: 'user.firstName'
|
|
1921
|
+
}
|
|
1861
1922
|
```
|
|
1862
1923
|
|
|
1863
1924
|
For more examples, see `23_shorthand.test.ts`, or have a play with the [demo app](https://carlosnz.github.io/fig-tree-evaluator/) app.
|
|
1864
1925
|
|
|
1865
|
-
|
|
1866
1926
|
## Caching (Memoization)
|
|
1867
1927
|
|
|
1868
1928
|
FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoization) functionality for certain nodes to speed up re-evaluation when the input parameters haven't changed. There is a single cache store per FigTree instance which persists for the lifetime of the instance. By default, it remembers the last 50 results with each result being valid for half and hour, but these values can be modified using the `maxCacheSize` and `maxCacheTime` [options](#available-options).
|
|
@@ -1870,14 +1930,15 @@ FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoizat
|
|
|
1870
1930
|
Currently, caching is only implemented for the following operators, since they perform requests to external resources, which are inherently slow:
|
|
1871
1931
|
|
|
1872
1932
|
- GET (`useCache` default: `true`)
|
|
1873
|
-
- POST (`useCache` default: `false`)
|
|
1933
|
+
- POST (`useCache` default: `false`)
|
|
1874
1934
|
- PG_SQL (`useCache` default: `true`)
|
|
1875
1935
|
- GRAPH_QL (`useCache` default: `true`)
|
|
1876
1936
|
- CUSTOM_FUNCTIONS (`useCache` default: `false`)
|
|
1877
1937
|
|
|
1878
1938
|
This is different to the memoization provided by [Alias Nodes](#alias-nodes):
|
|
1879
|
-
|
|
1880
|
-
-
|
|
1939
|
+
|
|
1940
|
+
- Alias nodes are still evaluated once for every evaluation -- they're more for re-use _within_ a complex expression.
|
|
1941
|
+
- Cached nodes will persist _between_ different evaluations as long as the input values are the same as a previously evaluated node.
|
|
1881
1942
|
|
|
1882
1943
|
Caching is enabled by default for most of the above operators, but this can be overridden by setting `useCache: false` in [options](#available-options), either globally or per expression. If you're querying a database or API that is likely to have a different result for the same request (i.e. data has changed), then you probably want to turn the cache off.
|
|
1883
1944
|
|
|
@@ -1907,7 +1968,7 @@ interface FigTreeError extends Error {
|
|
|
1907
1968
|
There are two alternatives to throwing:
|
|
1908
1969
|
|
|
1909
1970
|
1. **Fallback**: If the `fallback` property is specified in the expression, this will be returned whenever an error occurs at that node (or below). See [Fallback option](#other-common-properties).
|
|
1910
|
-
2. **Formatted string**: By using the `returnErrorAsString: true` option, FigTree will return a nicely formatted string describing the error.
|
|
1971
|
+
2. **Formatted string**: By using the `returnErrorAsString: true` option, FigTree will return a nicely formatted string describing the error. _This is the same string returned in the `prettyPrint` property of the FigTreeError._ The formatted string will be structured like so:
|
|
1911
1972
|
|
|
1912
1973
|
```
|
|
1913
1974
|
Operator: <OPERATOR_NAME>: - <error.name (if specific)>
|
|
@@ -1916,9 +1977,11 @@ Operator: <OPERATOR_NAME>: - <error.name (if specific)>
|
|
|
1916
1977
|
...errorData
|
|
1917
1978
|
}
|
|
1918
1979
|
```
|
|
1980
|
+
|
|
1919
1981
|
`errorData` is specific data returned by the error thrown by an internal process (such as a network request using [fetch](#http-requests)).
|
|
1920
1982
|
|
|
1921
1983
|
For example, a 403 (forbidden) error thrown by the `GET` operator (with Axios HTTP client) would return a string like:
|
|
1984
|
+
|
|
1922
1985
|
```
|
|
1923
1986
|
Operator: GET - AxiosError
|
|
1924
1987
|
Request failed with status code 403
|
|
@@ -1934,6 +1997,7 @@ Request failed with status code 403
|
|
|
1934
1997
|
```
|
|
1935
1998
|
|
|
1936
1999
|
And, if thrown, the error object would contain:
|
|
2000
|
+
|
|
1937
2001
|
```js
|
|
1938
2002
|
{
|
|
1939
2003
|
name: "AxiosError",
|
|
@@ -2001,7 +2065,7 @@ const fig = new FigTreeEvaluator({
|
|
|
2001
2065
|
argsDefault: [1, 2, 3, 4]
|
|
2002
2066
|
},
|
|
2003
2067
|
changeCase: {
|
|
2004
|
-
function: ({string, toCase}) => toCase === "upper" ?
|
|
2068
|
+
function: ({string, toCase}) => toCase === "upper" ?
|
|
2005
2069
|
string.toUpperCase() : string.toLowerCase(),
|
|
2006
2070
|
description: "Convert a string to either upper or lower case",
|
|
2007
2071
|
inputDefault: {string: "New string", toCase: "upper"}
|
|
@@ -2075,6 +2139,7 @@ This will return something like:
|
|
|
2075
2139
|
#### Retrieve customFunction info
|
|
2076
2140
|
|
|
2077
2141
|
Similarly, we can fetch basic info about custom functions in the current FigTree instance, although with more limited detail:
|
|
2142
|
+
|
|
2078
2143
|
```js
|
|
2079
2144
|
fig.getCustomFunctions()
|
|
2080
2145
|
```
|
|
@@ -2082,19 +2147,19 @@ fig.getCustomFunctions()
|
|
|
2082
2147
|
Returns:
|
|
2083
2148
|
|
|
2084
2149
|
```js
|
|
2085
|
-
[
|
|
2150
|
+
;[
|
|
2086
2151
|
{
|
|
2087
2152
|
name: 'doubleArray',
|
|
2088
2153
|
numRequiredArgs: 1,
|
|
2089
2154
|
description: 'Double each item in an array',
|
|
2090
|
-
argsDefault: [
|
|
2155
|
+
argsDefault: [1, 2, 3, 4],
|
|
2091
2156
|
},
|
|
2092
2157
|
{
|
|
2093
2158
|
name: 'changeCase',
|
|
2094
2159
|
numRequiredArgs: 1,
|
|
2095
2160
|
description: 'Convert a string to either upper or lower case',
|
|
2096
|
-
inputDefault: { string: 'New string', toCase: 'upper' }
|
|
2097
|
-
}
|
|
2161
|
+
inputDefault: { string: 'New string', toCase: 'upper' },
|
|
2162
|
+
},
|
|
2098
2163
|
]
|
|
2099
2164
|
```
|
|
2100
2165
|
|
|
@@ -2104,14 +2169,14 @@ Returns:
|
|
|
2104
2169
|
fig.isFigTreeExpression(value)
|
|
2105
2170
|
```
|
|
2106
2171
|
|
|
2107
|
-
When building a UI, you often need to decide whether a given value should be treated as an evaluable FigTree expression or as plain data. This method returns `true` only for values that
|
|
2172
|
+
When building a UI, you often need to decide whether a given value should be treated as an evaluable FigTree expression or as plain data. This method returns `true` only for values that _this_ instance would actually process as an expression. It is **registry-aware** — `$`-prefixed [shorthand](#shorthand-syntax) and keys are validated against the instance's registered operators, [fragments](#fragments) and [custom functions](#custom_functions) — and it follows the instance's [`evaluateFullObject`](#available-options) and `noShorthand` settings.
|
|
2108
2173
|
|
|
2109
2174
|
```js
|
|
2110
2175
|
fig.isFigTreeExpression({ operator: '+', values: [1, 2] }) // true
|
|
2111
|
-
fig.isFigTreeExpression({ $getData: 'user.name' })
|
|
2112
|
-
fig.isFigTreeExpression({ name: 'Steve', age: 30 })
|
|
2113
|
-
fig.isFigTreeExpression({ $somethingUnknown: 1 })
|
|
2114
|
-
fig.isFigTreeExpression('$myAlias')
|
|
2176
|
+
fig.isFigTreeExpression({ $getData: 'user.name' }) // true (registered shorthand)
|
|
2177
|
+
fig.isFigTreeExpression({ name: 'Steve', age: 30 }) // false (plain data)
|
|
2178
|
+
fig.isFigTreeExpression({ $somethingUnknown: 1 }) // false (not a registered operator/fragment/function)
|
|
2179
|
+
fig.isFigTreeExpression('$myAlias') // false (alias reference with no definition in scope)
|
|
2115
2180
|
```
|
|
2116
2181
|
|
|
2117
2182
|
The last two cases are why this is preferable to a purely structural check: an object whose only `$`-prefixed key doesn't correspond to anything the evaluator recognises (e.g. `{ "$somethingUnknown": 1 }`) is plain data, not an expression, and won't be flagged here.
|
|
@@ -2153,4 +2218,5 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
2153
2218
|
See [here](https://github.com/CarlosNZ/fig-tree-evaluator/blob/main/CHANGELOG.md)
|
|
2154
2219
|
|
|
2155
2220
|
## Credit
|
|
2156
|
-
|
|
2221
|
+
|
|
2222
|
+
Icon: Tree by ka reemov from <a href="https://thenounproject.com/icon/tree-2665898/" target="_blank" title="Tree Icon">Noun Project</a>
|