@rs-x/expression-parser 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +701 -0
- package/dist/index.js +17075 -0
- package/package.json +64 -0
- package/readme.md +2793 -0
package/readme.md
ADDED
|
@@ -0,0 +1,2793 @@
|
|
|
1
|
+
# Expression parser
|
|
2
|
+
|
|
3
|
+
The **JavaScript Expression Parser** translates a JavaScript expression string into an **observable expression tree**. Expressions are not only reactive, but also **composable**, allowing complex logic to be built from smaller, reusable expression units. In addition, you no longer need to worry about asynchronous data: it can be used as if it were **synchronous**. The RS-X framework automatically takes care of resolving and tracking async values.
|
|
4
|
+
|
|
5
|
+
Besides this, expressions can also invoke **methods**. The only assumption made is that these methods are **pure**—meaning that if the input arguments change, the return value will also change, and no hidden side effects are introduced. This guarantees predictable reactivity and correct change propagation.
|
|
6
|
+
|
|
7
|
+
Each identifier used inside an expression is automatically registered with the **State Manager**, enabling fine-grained change detection and highly efficient updates. Identifiers are resolved via an **Identifier Owner Resolver** service, which can be replaced with a custom implementation to adapt resolution behavior to different architectures or domains.
|
|
8
|
+
|
|
9
|
+
Because expressions themselves can be referenced by other expressions, the parser supports **true modularity**. Simple expressions can be combined, nested, and reused to form larger expression graphs, with changes propagating automatically across expression boundaries.
|
|
10
|
+
|
|
11
|
+
This parser forms the core of the **data-binding implementation** for the SPA framework and allows **synchronous and asynchronous data** (such as observables) to be mixed transparently, while ensuring that only the affected parts of the expression tree—and ultimately the UI—are updated.
|
|
12
|
+
|
|
13
|
+
### Examples
|
|
14
|
+
|
|
15
|
+
- **Expression with a promise** — ``promise + 2`` (where `promise` resolves to a number)
|
|
16
|
+
- **Expression with an observable** - ``observable + 2`` (where `observable` emits a number)
|
|
17
|
+
- **Expression referencing nested async data**
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
21
|
+
import {
|
|
22
|
+
IExpressionFactory,
|
|
23
|
+
RsXExpressionParserInjectionTokens,
|
|
24
|
+
RsXExpressionParserModule
|
|
25
|
+
} from '@rs-x/expression-parser';
|
|
26
|
+
|
|
27
|
+
// Load the expression parser module into the injection container
|
|
28
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
29
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
30
|
+
|
|
31
|
+
export const run = (async () => {
|
|
32
|
+
const expressionContext = {
|
|
33
|
+
a: {
|
|
34
|
+
b: Promise.resolve({
|
|
35
|
+
c: Promise.resolve({
|
|
36
|
+
d: 20
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const expression = expressionFactory.create(expressionContext, `a.b.c.d`);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Wait until the expression has been resolved (has a value)
|
|
46
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
47
|
+
|
|
48
|
+
console.log(`Initial value of 'a.b.c.d':`);
|
|
49
|
+
expression.changed.subscribe((change) => {
|
|
50
|
+
printValue(change.value);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log(`Value of 'a.b.c.d' after changing 'a' to '{ b: Promise.resolve({ c: Promise.resolve({ d: 200 }) }) }':`);
|
|
54
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
55
|
+
expressionContext.a = { b: Promise.resolve({ c: Promise.resolve({ d: 200 }) }) };
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
console.log(`Final value of 'a.b.c.d':`)
|
|
59
|
+
printValue(expression.value);
|
|
60
|
+
} finally {
|
|
61
|
+
// Always dispose of expressions after use.
|
|
62
|
+
expression.dispose();
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **Modular expressions** — expressions can reference other expressions:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const model = {
|
|
71
|
+
a: 10,
|
|
72
|
+
b: 20
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const expr1 = expressionFactory.create(model, '(a + 1)');
|
|
76
|
+
const expr2 = expressionFactory.create(model, '(b + 2)');
|
|
77
|
+
|
|
78
|
+
const modularModel = {
|
|
79
|
+
expr1,
|
|
80
|
+
expr2
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const expr3 = expressionFactory.create(modularModel, 'expr1 * expr2');
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Use cases
|
|
87
|
+
|
|
88
|
+
**Data binding for SPA frameworks and change detection** is the primary reason the expression parser was developed. However, it is a generic solution and can be used in any scenario where actions need to be triggered when data or an expression changes. Below are a few example use cases:
|
|
89
|
+
|
|
90
|
+
- **Logging and alert conditions**
|
|
91
|
+
Trigger alerts based on runtime conditions:
|
|
92
|
+
- Monitoring systems
|
|
93
|
+
- Health checks
|
|
94
|
+
- Observability tools
|
|
95
|
+
|
|
96
|
+
- **UI logic outside data binding**
|
|
97
|
+
Declarative UI behavior without relying on a full framework.
|
|
98
|
+
|
|
99
|
+
- **Workflow and automation engines**
|
|
100
|
+
- CI/CD pipelines
|
|
101
|
+
- Job schedulers
|
|
102
|
+
- Business process automation
|
|
103
|
+
|
|
104
|
+
- **Game logic and simulation**
|
|
105
|
+
- AI decision trees
|
|
106
|
+
- Ability unlock rules
|
|
107
|
+
- Physics toggles
|
|
108
|
+
|
|
109
|
+
- **Spreadsheet-like calculations**
|
|
110
|
+
- Financial dashboards
|
|
111
|
+
- Pricing calculators
|
|
112
|
+
- Quotation systems
|
|
113
|
+
-
|
|
114
|
+
- **Validation engines**
|
|
115
|
+
Field validation based on the values of other fields.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## Modular Expressions
|
|
119
|
+
|
|
120
|
+
RS-X supports **modular expressions**, allowing expressions to reference **other expressions** as first-class values.
|
|
121
|
+
|
|
122
|
+
This enables you to:
|
|
123
|
+
- Compose complex calculations from smaller, reusable parts
|
|
124
|
+
- Share intermediate results across multiple expressions
|
|
125
|
+
- Improve readability, maintainability, and testability
|
|
126
|
+
- Improve performance by ensuring shared expressions are **evaluated only once**
|
|
127
|
+
|
|
128
|
+
Modular expressions are a core feature of the **JavaScript Expression Parser** and play an important role in scalable data-binding scenarios.
|
|
129
|
+
|
|
130
|
+
## Overview
|
|
131
|
+
|
|
132
|
+
Instead of defining one large expression, you can split logic into smaller expressions and combine them:
|
|
133
|
+
|
|
134
|
+
- Define **base expressions** for reusable logic
|
|
135
|
+
- Reference those expressions in **higher-level expressions**
|
|
136
|
+
- React automatically to changes anywhere in the dependency graph
|
|
137
|
+
|
|
138
|
+
Each expression remains **observable**, and changes propagate efficiently through the expression tree.
|
|
139
|
+
|
|
140
|
+
## Basic Example
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const model = {
|
|
144
|
+
a: 10,
|
|
145
|
+
b: 20
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const expr1 = expressionFactory.create(model, '(a + 1)');
|
|
149
|
+
const expr2 = expressionFactory.create(model, '(b + 2)');
|
|
150
|
+
|
|
151
|
+
const modularModel = {
|
|
152
|
+
expr1,
|
|
153
|
+
expr2
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const expr3 = expressionFactory.create(modularModel, 'expr1 * expr2');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Result
|
|
160
|
+
|
|
161
|
+
- `expr1` evaluates to `11`
|
|
162
|
+
- `expr2` evaluates to `22`
|
|
163
|
+
- `expr3` evaluates to `242`
|
|
164
|
+
|
|
165
|
+
When `a` or `b` changes:
|
|
166
|
+
- Only the affected expressions are recalculated
|
|
167
|
+
- Dependent expressions update automatically
|
|
168
|
+
|
|
169
|
+
## Reactive Behavior
|
|
170
|
+
|
|
171
|
+
Each expression exposes a `changed` event:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
expr3.changed.subscribe(() => {
|
|
175
|
+
console.log('New value:', expr3.value);
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Changes to:
|
|
180
|
+
- `a`
|
|
181
|
+
- `b`
|
|
182
|
+
- `expr1`
|
|
183
|
+
- `expr2`
|
|
184
|
+
|
|
185
|
+
automatically propagate to `expr3`.
|
|
186
|
+
|
|
187
|
+
## Performance Benefits
|
|
188
|
+
|
|
189
|
+
Modular expressions are not only about structure — they also **improve performance**.
|
|
190
|
+
|
|
191
|
+
### Why?
|
|
192
|
+
|
|
193
|
+
- Each expression is evaluated **once**
|
|
194
|
+
- Dependent expressions reuse the cached result
|
|
195
|
+
- No duplicated computation for shared logic
|
|
196
|
+
|
|
197
|
+
This is especially important when:
|
|
198
|
+
- Expressions are computationally expensive
|
|
199
|
+
- Expressions depend on asynchronous or reactive data
|
|
200
|
+
- The same calculation is reused in multiple places (e.g. UI bindings)
|
|
201
|
+
|
|
202
|
+
## What Expressions Can Reference
|
|
203
|
+
|
|
204
|
+
Modular expression support is enabled by adding a **custom index accessor** and a **custom observer factory**, allowing expressions to treat **other expressions as first-class reactive values**.
|
|
205
|
+
|
|
206
|
+
This clearly illustrates the power of the expression parser: **new data types and reactive models can be seamlessly integrated** by extending the **State Manager** via plugins.
|
|
207
|
+
|
|
208
|
+
## Complex modular expression example
|
|
209
|
+
|
|
210
|
+
To get a sense of how powerful **modular expressions** are, we will look at a more realistic example.
|
|
211
|
+
We are going to create an expression that calculates **credit risk**.
|
|
212
|
+
|
|
213
|
+
First, we will show an implementation **without modular expressions**, followed by an implementation **using modular expressions**.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### Non-Modular example
|
|
218
|
+
```ts
|
|
219
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
220
|
+
import {
|
|
221
|
+
IExpressionFactory,
|
|
222
|
+
RsXExpressionParserInjectionTokens,
|
|
223
|
+
RsXExpressionParserModule
|
|
224
|
+
} from '@rs-x/expression-parser';
|
|
225
|
+
import { BehaviorSubject } from 'rxjs';
|
|
226
|
+
|
|
227
|
+
// Load the expression parser module into the injection container
|
|
228
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
229
|
+
const expressionFactory: IExpressionFactory =
|
|
230
|
+
InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
231
|
+
|
|
232
|
+
export const run = (async () => {
|
|
233
|
+
interface IRisk {
|
|
234
|
+
volatilityIndex: number;
|
|
235
|
+
recessionProbability: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const riskModel = {
|
|
239
|
+
customer: {
|
|
240
|
+
age: 42,
|
|
241
|
+
income: 72000,
|
|
242
|
+
employmentYears: 6
|
|
243
|
+
},
|
|
244
|
+
credit: {
|
|
245
|
+
score: 680,
|
|
246
|
+
outstandingDebt: 18000
|
|
247
|
+
},
|
|
248
|
+
market: {
|
|
249
|
+
baseInterestRate: 0.035
|
|
250
|
+
},
|
|
251
|
+
risk: new BehaviorSubject<IRisk>({
|
|
252
|
+
volatilityIndex: 0.28,
|
|
253
|
+
recessionProbability: 0.12
|
|
254
|
+
}),
|
|
255
|
+
thresholds: {
|
|
256
|
+
highRisk: 0.75,
|
|
257
|
+
mediumRisk: 0.45
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const expressionString = `(
|
|
262
|
+
(
|
|
263
|
+
// =========================
|
|
264
|
+
// Numeric risk score
|
|
265
|
+
// =========================
|
|
266
|
+
(
|
|
267
|
+
// Base personal risk
|
|
268
|
+
(
|
|
269
|
+
(credit.score < 600 ? 0.4 : 0.1) +
|
|
270
|
+
(credit.outstandingDebt / customer.income) * 0.6 -
|
|
271
|
+
(customer.employmentYears * 0.03)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
// Age-based risk adjustment
|
|
275
|
+
+
|
|
276
|
+
(
|
|
277
|
+
customer.age < 25 ? 0.15 :
|
|
278
|
+
customer.age < 35 ? 0.05 :
|
|
279
|
+
customer.age < 55 ? 0.00 :
|
|
280
|
+
0.08
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
// Market risk (async observable)
|
|
284
|
+
+
|
|
285
|
+
(
|
|
286
|
+
(risk.volatilityIndex * 0.5) +
|
|
287
|
+
(risk.recessionProbability * 0.5)
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
// Interest rate impact
|
|
291
|
+
+
|
|
292
|
+
(market.baseInterestRate * 2)
|
|
293
|
+
)
|
|
294
|
+
// =========================
|
|
295
|
+
// Risk classification
|
|
296
|
+
// =========================
|
|
297
|
+
>= thresholds.highRisk
|
|
298
|
+
? 'HIGH'
|
|
299
|
+
: (
|
|
300
|
+
(
|
|
301
|
+
(
|
|
302
|
+
(credit.score < 600 ? 0.4 : 0.1) +
|
|
303
|
+
(credit.outstandingDebt / customer.income) * 0.6 -
|
|
304
|
+
(customer.employmentYears * 0.03)
|
|
305
|
+
)
|
|
306
|
+
+
|
|
307
|
+
(
|
|
308
|
+
customer.age < 25 ? 0.15 :
|
|
309
|
+
customer.age < 35 ? 0.05 :
|
|
310
|
+
customer.age < 55 ? 0.00 :
|
|
311
|
+
0.08
|
|
312
|
+
)
|
|
313
|
+
+
|
|
314
|
+
(
|
|
315
|
+
(risk.volatilityIndex * 0.5) +
|
|
316
|
+
(risk.recessionProbability * 0.5)
|
|
317
|
+
)
|
|
318
|
+
+
|
|
319
|
+
(market.baseInterestRate * 2)
|
|
320
|
+
) >= thresholds.mediumRisk
|
|
321
|
+
? 'MEDIUM'
|
|
322
|
+
: 'LOW'
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
)`;
|
|
326
|
+
|
|
327
|
+
const expression = expressionFactory.create(riskModel, expressionString);
|
|
328
|
+
|
|
329
|
+
console.log('Initial risk: ')
|
|
330
|
+
const changeSubscription = expression.changed.subscribe(() => {
|
|
331
|
+
console.log(expression.value);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
// Wait until the expression has been resolved (has a value)
|
|
336
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
337
|
+
|
|
338
|
+
console.log('Risk after changing risk parameters from { volatilityIndex: 0.28, recessionProbability: 0.12 } to { volatilityIndex: 0.41, recessionProbability: 0.35 } :')
|
|
339
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
340
|
+
riskModel.risk.next({
|
|
341
|
+
volatilityIndex: 0.45,
|
|
342
|
+
recessionProbability: 0.35
|
|
343
|
+
})
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
console.log('Risk after change age = 63 and employmentYears = 1 ');
|
|
347
|
+
|
|
348
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
349
|
+
riskModel.customer.age = 63;
|
|
350
|
+
riskModel.customer.employmentYears = 1;
|
|
351
|
+
});
|
|
352
|
+
} finally {
|
|
353
|
+
changeSubscription.unsubscribe();
|
|
354
|
+
// Always dispose of expressions after use.
|
|
355
|
+
expression.dispose();
|
|
356
|
+
}
|
|
357
|
+
})();
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Modular example
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
366
|
+
import {
|
|
367
|
+
IExpressionFactory,
|
|
368
|
+
RsXExpressionParserInjectionTokens,
|
|
369
|
+
RsXExpressionParserModule
|
|
370
|
+
} from '@rs-x/expression-parser';
|
|
371
|
+
import { BehaviorSubject } from 'rxjs';
|
|
372
|
+
|
|
373
|
+
// Load the expression parser module into the injection container
|
|
374
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
375
|
+
const expressionFactory: IExpressionFactory =
|
|
376
|
+
InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
export const run = (async () => {
|
|
380
|
+
interface IRisk {
|
|
381
|
+
volatilityIndex: number;
|
|
382
|
+
recessionProbability: number;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const riskModel = {
|
|
386
|
+
customer: {
|
|
387
|
+
age: 42,
|
|
388
|
+
income: 72000,
|
|
389
|
+
employmentYears: 6
|
|
390
|
+
},
|
|
391
|
+
credit: {
|
|
392
|
+
score: 680,
|
|
393
|
+
outstandingDebt: 18000
|
|
394
|
+
},
|
|
395
|
+
market: {
|
|
396
|
+
baseInterestRate: 0.035
|
|
397
|
+
},
|
|
398
|
+
risk: new BehaviorSubject<IRisk>({
|
|
399
|
+
volatilityIndex: 0.28,
|
|
400
|
+
recessionProbability: 0.12
|
|
401
|
+
}),
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const basePersonalRisk = expressionFactory.create(riskModel, `
|
|
405
|
+
(credit.score < 600 ? 0.4 : 0.1) +
|
|
406
|
+
(credit.outstandingDebt / customer.income) * 0.6 -
|
|
407
|
+
(customer.employmentYears * 0.03)
|
|
408
|
+
`);
|
|
409
|
+
|
|
410
|
+
const ageBasedRiskAdjustment = expressionFactory.create(riskModel, `
|
|
411
|
+
customer.age < 25 ? 0.15 :
|
|
412
|
+
customer.age < 35 ? 0.05 :
|
|
413
|
+
customer.age < 55 ? 0.00 :
|
|
414
|
+
0.08
|
|
415
|
+
`);
|
|
416
|
+
|
|
417
|
+
const marketRisk = expressionFactory.create(riskModel, `
|
|
418
|
+
(risk.volatilityIndex * 0.5) +
|
|
419
|
+
(risk.recessionProbability * 0.5)
|
|
420
|
+
`);
|
|
421
|
+
|
|
422
|
+
const interestRateImpact = expressionFactory.create(riskModel, 'market.baseInterestRate * 2');
|
|
423
|
+
|
|
424
|
+
const riskScoreModel = {
|
|
425
|
+
basePersonalRisk,
|
|
426
|
+
ageBasedRiskAdjustment,
|
|
427
|
+
marketRisk,
|
|
428
|
+
interestRateImpact
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const riskScore = expressionFactory.create(riskScoreModel, `
|
|
432
|
+
basePersonalRisk +
|
|
433
|
+
ageBasedRiskAdjustment +
|
|
434
|
+
marketRisk +
|
|
435
|
+
interestRateImpact
|
|
436
|
+
`);
|
|
437
|
+
|
|
438
|
+
const riskClassificationModel = {
|
|
439
|
+
riskScore,
|
|
440
|
+
thresholds: {
|
|
441
|
+
highRisk: 0.75,
|
|
442
|
+
mediumRisk: 0.45
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const riskClassification = expressionFactory.create(riskClassificationModel, `
|
|
447
|
+
riskScore >= thresholds.highRisk
|
|
448
|
+
? 'HIGH'
|
|
449
|
+
: riskScore >= thresholds.mediumRisk
|
|
450
|
+
? 'MEDIUM'
|
|
451
|
+
: 'LOW'
|
|
452
|
+
`);
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
console.log('Initial risk: ')
|
|
456
|
+
const changeSubscription = riskClassification.changed.subscribe(() => {
|
|
457
|
+
console.log(riskClassification.value);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
// Wait until the expression has been resolved (has a value)
|
|
462
|
+
await new WaitForEvent(riskClassification, 'changed').wait(emptyFunction);
|
|
463
|
+
|
|
464
|
+
console.log('Risk after changing risk parameters from { volatilityIndex: 0.28, recessionProbability: 0.12 } to { volatilityIndex: 0.41, recessionProbability: 0.35 } :')
|
|
465
|
+
await new WaitForEvent(riskClassification, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
466
|
+
riskModel.risk.next({
|
|
467
|
+
volatilityIndex: 0.45,
|
|
468
|
+
recessionProbability: 0.35
|
|
469
|
+
})
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
console.log('Risk after change age = 63 and employmentYears = 1 ');
|
|
473
|
+
|
|
474
|
+
await new WaitForEvent(riskClassification, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
475
|
+
riskModel.customer.age = 63;
|
|
476
|
+
riskModel.customer.employmentYears = 1;
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
} finally {
|
|
480
|
+
changeSubscription.unsubscribe();
|
|
481
|
+
// Always dispose of expressions after use.
|
|
482
|
+
riskClassification.dispose();
|
|
483
|
+
riskScore.dispose();
|
|
484
|
+
interestRateImpact.dispose();
|
|
485
|
+
marketRisk.dispose();
|
|
486
|
+
ageBasedRiskAdjustment.dispose();
|
|
487
|
+
basePersonalRisk.dispose();
|
|
488
|
+
}
|
|
489
|
+
})();
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Limitations of the Non-Modular Implementation
|
|
495
|
+
|
|
496
|
+
We can observe the following issues in the non-modular implementation:
|
|
497
|
+
|
|
498
|
+
- The expression is quite long and difficult to read.
|
|
499
|
+
- Debugging is hard because the entire expression must be inspected as a single unit.
|
|
500
|
+
- The risk score calculation is duplicated, meaning it is evaluated **twice**, which makes the implementation less efficient.
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
### Improvements with Modular Expressions
|
|
505
|
+
|
|
506
|
+
With the modular implementation, we notice the following improvements:
|
|
507
|
+
|
|
508
|
+
- The expression is split into multiple smaller expressions, making it much more readable.
|
|
509
|
+
- Debugging becomes easier because each sub-expression can be tested and debugged independently.
|
|
510
|
+
- Code duplication is eliminated by reusing the risk score expression. This also means the risk score is calculated **only once**, improving performance.
|
|
511
|
+
|
|
512
|
+
## Summary
|
|
513
|
+
|
|
514
|
+
- Expressions can reference **other expressions**
|
|
515
|
+
- Modular expressions improve **clarity**, **reuse**, and **performance**
|
|
516
|
+
- Shared expressions are evaluated **once**
|
|
517
|
+
- Changes propagate efficiently through the expression tree
|
|
518
|
+
- Works seamlessly with synchronous and asynchronous data
|
|
519
|
+
|
|
520
|
+
Modular expressions form a powerful foundation for advanced data binding and reactive logic in RS-X.
|
|
521
|
+
|
|
522
|
+
## Get an instance of the Expression Parser Factory
|
|
523
|
+
|
|
524
|
+
The expression parser factory is registered as a **singleton service**.
|
|
525
|
+
You must load the module into the injection container if you went
|
|
526
|
+
to use it.
|
|
527
|
+
|
|
528
|
+
```ts
|
|
529
|
+
import { InjectionContainer } from '@rs-x/core';
|
|
530
|
+
import {
|
|
531
|
+
RsXExpressionParserInjectionTokens,
|
|
532
|
+
RsXExpressionParserModule
|
|
533
|
+
} from '@rs-x/expression-parser';
|
|
534
|
+
|
|
535
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
There are two ways to get an instance:
|
|
539
|
+
|
|
540
|
+
1. Using the injection container
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
import { InjectionContainer } from '@rs-x/core';
|
|
544
|
+
import {
|
|
545
|
+
IExpressionFactory,
|
|
546
|
+
RsXExpressionParserInjectionTokens,
|
|
547
|
+
RsXExpressionParserModule
|
|
548
|
+
} from '@rs-x/expression-parser';
|
|
549
|
+
|
|
550
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(
|
|
551
|
+
RsXExpressionParserInjectionTokens.IExpressionFactory
|
|
552
|
+
);
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
2. Using the `@Inject` decorator
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
import { Inject } from '@rs-x/core';
|
|
559
|
+
import {
|
|
560
|
+
RsXExpressionParserInjectionTokens,
|
|
561
|
+
RsXExpressionParserModule
|
|
562
|
+
} from '@rs-x/expression-parser';
|
|
563
|
+
|
|
564
|
+
export class MyClass {
|
|
565
|
+
|
|
566
|
+
constructor(
|
|
567
|
+
@Inject(RsXExpressionParserInjectionTokens.IExpressionFactory)
|
|
568
|
+
private readonly _expressionFactory: IExpressionFactory
|
|
569
|
+
) {}
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Resolving Identifier Owner
|
|
574
|
+
|
|
575
|
+
Expressions resolve to data values for there leaves. These values may be constants (such as numbers or strings), but more commonly they are stored as **indexes** within a given **context**. For example, when the context is an object instance, indexes refer to properties or fields; when the context is a `Map`, indexes refer to map keys.
|
|
576
|
+
|
|
577
|
+
The interface responsible for resolving the owner of an identifier is defined as follows:
|
|
578
|
+
```ts
|
|
579
|
+
export interface IIdentifierOwnerResolver {
|
|
580
|
+
resolve(index: unknown, context: unknown): object | null;
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
The default resolution mechanism uses a list of identifier owner resolvers. Each resolver is evaluated in order until one returns a non-`null` context, which is then considered the owner of the identifier.
|
|
585
|
+
|
|
586
|
+
In `rs-x-expression-parser.module.ts`, the default resolver list is configured as shown below:
|
|
587
|
+
|
|
588
|
+
```ts
|
|
589
|
+
registerMultiInjectServices(
|
|
590
|
+
options,
|
|
591
|
+
RsXExpressionParserInjectionTokens.IIdentifierOwnerResolverList,
|
|
592
|
+
[
|
|
593
|
+
{ target: PropertyOwnerResolver, token: RsXExpressionParserInjectionTokens.PropertyOwnerResolver },
|
|
594
|
+
{ target: ArrayIndexOwnerResolver, token: RsXExpressionParserInjectionTokens.ArrayIndexOwnerResolver },
|
|
595
|
+
{ target: MapKeyOwnerResolver, token: RsXExpressionParserInjectionTokens.MapKeyOwnerResolver },
|
|
596
|
+
]
|
|
597
|
+
);
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
The default configuration includes the following resolvers:
|
|
601
|
+
|
|
602
|
+
- **PropertyOwnerResolver**
|
|
603
|
+
Resolves the identifier if the specified index corresponds to a property or field on the provided context. Returns the context if resolved; otherwise, returns `null`.
|
|
604
|
+
|
|
605
|
+
- **ArrayIndexOwnerResolver**
|
|
606
|
+
Resolves the identifier if the context is an array and the specified index is a valid array index. Returns the context if resolved; otherwise, returns `null`.
|
|
607
|
+
|
|
608
|
+
- **MapKeyOwnerResolver**
|
|
609
|
+
Resolves the identifier if the context is a `Map` and the specified index exists as a key in that map. Returns the context if resolved; otherwise, returns `null`.
|
|
610
|
+
|
|
611
|
+
The default resolver list may be overridden by registering a custom list in a consuming module:
|
|
612
|
+
```ts
|
|
613
|
+
overrideMultiInjectServices(
|
|
614
|
+
options,
|
|
615
|
+
RsXExpressionParserInjectionTokens.IIdentifierOwnerResolverList,
|
|
616
|
+
CUSTOM_LIST
|
|
617
|
+
);
|
|
618
|
+
```
|
|
619
|
+
A common use case for a custom resolver occurs during data binding. In such scenarios, the initial context is the HTML element on which the data-binding expression is declared, while the identifier may be defined on an ancestor element (for example, a custom element). In this case, the resolver must traverse the parent chain until an element defining the identifier is found. The resolved context is then that element.
|
|
620
|
+
|
|
621
|
+
This behavior can be implemented by providing a custom `IIdentifierOwnerResolver` that encapsulates the required traversal logic.
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
## Supported Expresssion types
|
|
625
|
+
|
|
626
|
+
All non-assignment JavaScript expressions are supported. These expressions can be combined to form more complex expressions. The following expressions are the basic supported expressions:
|
|
627
|
+
|
|
628
|
+
### Addition expression
|
|
629
|
+
|
|
630
|
+
```ts
|
|
631
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
632
|
+
import {
|
|
633
|
+
IExpressionFactory,
|
|
634
|
+
RsXExpressionParserInjectionTokens,
|
|
635
|
+
RsXExpressionParserModule
|
|
636
|
+
} from '@rs-x/expression-parser';
|
|
637
|
+
|
|
638
|
+
// Load the expression parser module into the injection container
|
|
639
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
640
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
641
|
+
|
|
642
|
+
export const run = (async () => {
|
|
643
|
+
const expressionContext = {
|
|
644
|
+
a: 1,
|
|
645
|
+
b: 3
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
const expression = expressionFactory.create(expressionContext, 'a + b');
|
|
649
|
+
|
|
650
|
+
try {
|
|
651
|
+
// Wait until the expression has been resolved (has a value)
|
|
652
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
653
|
+
|
|
654
|
+
console.log(`Initial value of 'a + b':`);
|
|
655
|
+
expression.changed.subscribe((change) => {
|
|
656
|
+
console.log(change.value);
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
console.log(`Value of 'a + b' after changing 'a' to '6':`);
|
|
660
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 6; })
|
|
661
|
+
|
|
662
|
+
console.log(`Value of 'a + b' after changing 'b' to '4':`)
|
|
663
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; })
|
|
664
|
+
|
|
665
|
+
console.log(`Final value of 'a + b':`)
|
|
666
|
+
console.log(expression.value);
|
|
667
|
+
} finally {
|
|
668
|
+
// Always dispose of expressions after use.
|
|
669
|
+
expression.dispose();
|
|
670
|
+
}
|
|
671
|
+
})();
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Array expression
|
|
677
|
+
|
|
678
|
+
```ts
|
|
679
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
680
|
+
import {
|
|
681
|
+
IExpressionFactory,
|
|
682
|
+
RsXExpressionParserInjectionTokens,
|
|
683
|
+
RsXExpressionParserModule
|
|
684
|
+
} from '@rs-x/expression-parser';
|
|
685
|
+
|
|
686
|
+
// Load the expression parser module into the injection container
|
|
687
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
688
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
689
|
+
|
|
690
|
+
export const run = (async () => {
|
|
691
|
+
const expressionContext = {
|
|
692
|
+
a: 3,
|
|
693
|
+
array: [1, 2]
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const expression = expressionFactory.create(expressionContext, '[a, ...array, 100]');
|
|
697
|
+
|
|
698
|
+
try {
|
|
699
|
+
// Wait until the expression has been resolved (has a value)
|
|
700
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
701
|
+
|
|
702
|
+
console.log(`Initial value of '[a, ...array, 100]':`)
|
|
703
|
+
expression.changed.subscribe((change) => {
|
|
704
|
+
printValue(change.value);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
console.log(`Value of [a, ...array, 100]' after changing 'a' to '6':`);
|
|
708
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 6; });
|
|
709
|
+
|
|
710
|
+
console.log(`Value of '[a, ...array, 100]' after changing 'array' to '[1, 2, 3]':`)
|
|
711
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.array.push(3); });
|
|
712
|
+
|
|
713
|
+
console.log(`Value of '[a, ...array, 100]' after setting 'array' to '[100, 200]':`)
|
|
714
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.array = [100, 200]; });
|
|
715
|
+
|
|
716
|
+
console.log(`Final value of '[a, ...array, 100]':`)
|
|
717
|
+
printValue(expression.value);
|
|
718
|
+
} finally {
|
|
719
|
+
// Always dispose of expressions after use.
|
|
720
|
+
expression.dispose();
|
|
721
|
+
}
|
|
722
|
+
})();
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Bitwise and expression
|
|
726
|
+
|
|
727
|
+
```ts
|
|
728
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
729
|
+
import {
|
|
730
|
+
IExpressionFactory,
|
|
731
|
+
RsXExpressionParserInjectionTokens,
|
|
732
|
+
RsXExpressionParserModule
|
|
733
|
+
} from '@rs-x/expression-parser';
|
|
734
|
+
|
|
735
|
+
// Load the expression parser module into the injection container
|
|
736
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
737
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
738
|
+
|
|
739
|
+
export const run = (async () => {
|
|
740
|
+
const expressionContext = {
|
|
741
|
+
a: 5,
|
|
742
|
+
b: 3
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
const expression = expressionFactory.create(expressionContext, 'a & b');
|
|
746
|
+
|
|
747
|
+
try {
|
|
748
|
+
// Wait until the expression has been resolved (has a value)
|
|
749
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
750
|
+
|
|
751
|
+
console.log(`Initial value of 'a & b':`)
|
|
752
|
+
expression.changed.subscribe((change) => {
|
|
753
|
+
console.log(change.value);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
console.log(`Value of 'a & b' after changing 'a' to '2':`);
|
|
757
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 2; });
|
|
758
|
+
|
|
759
|
+
console.log(`Value of 'a & b' after changing 'b' to '8':`)
|
|
760
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 8; });
|
|
761
|
+
|
|
762
|
+
console.log(`Final value of 'a & b':`)
|
|
763
|
+
console.log(expression.value);
|
|
764
|
+
} finally {
|
|
765
|
+
// Always dispose of expressions after use.
|
|
766
|
+
expression.dispose();
|
|
767
|
+
}
|
|
768
|
+
})();
|
|
769
|
+
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
### Bitwise left shift expression
|
|
773
|
+
|
|
774
|
+
```ts
|
|
775
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
776
|
+
import {
|
|
777
|
+
IExpressionFactory,
|
|
778
|
+
RsXExpressionParserInjectionTokens,
|
|
779
|
+
RsXExpressionParserModule
|
|
780
|
+
} from '@rs-x/expression-parser';
|
|
781
|
+
|
|
782
|
+
// Load the expression parser module into the injection container
|
|
783
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
784
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
785
|
+
|
|
786
|
+
export const run = (async () => {
|
|
787
|
+
const expressionContext = {
|
|
788
|
+
a: 5,
|
|
789
|
+
b: 2
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
const expression = expressionFactory.create(expressionContext, 'a << b');
|
|
793
|
+
|
|
794
|
+
try {
|
|
795
|
+
// Wait until the expression has been resolved (has a value)
|
|
796
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
797
|
+
|
|
798
|
+
console.log(`Initial value of 'a << b':`)
|
|
799
|
+
expression.changed.subscribe((change) => {
|
|
800
|
+
console.log(change.value);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
console.log(`Value of 'a << b' after changing 'a' to '4':`);
|
|
804
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 4; });
|
|
805
|
+
|
|
806
|
+
console.log(`Value of 'a << b' after changing 'b' to '3':`)
|
|
807
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 3; });
|
|
808
|
+
|
|
809
|
+
console.log(`Final value of 'a << b':`)
|
|
810
|
+
console.log(expression.value);
|
|
811
|
+
} finally {
|
|
812
|
+
// Always dispose of expressions after use.
|
|
813
|
+
expression.dispose();
|
|
814
|
+
}
|
|
815
|
+
})();
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Bitwise not expression
|
|
822
|
+
|
|
823
|
+
```ts
|
|
824
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
825
|
+
import {
|
|
826
|
+
IExpressionFactory,
|
|
827
|
+
RsXExpressionParserInjectionTokens,
|
|
828
|
+
RsXExpressionParserModule
|
|
829
|
+
} from '@rs-x/expression-parser';
|
|
830
|
+
|
|
831
|
+
// Load the expression parser module into the injection container
|
|
832
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
833
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
export const run = (async () => {
|
|
837
|
+
const expressionContext = {
|
|
838
|
+
a: 5,
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
const expression = expressionFactory.create(expressionContext, '~a');
|
|
842
|
+
|
|
843
|
+
try {
|
|
844
|
+
// Wait until the expression has been resolved (has a value)
|
|
845
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
846
|
+
|
|
847
|
+
console.log(`Initial value of '~a':`)
|
|
848
|
+
expression.changed.subscribe((change) => {
|
|
849
|
+
console.log(change.value);
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
console.log(`Value of ~a' after changing 'a' to '3':`);
|
|
853
|
+
await new WaitForEvent(expression, 'changed', {ignoreInitialValue: true}).wait(() => {expressionContext.a = 3;});
|
|
854
|
+
|
|
855
|
+
console.log(`Final value of '~a':`)
|
|
856
|
+
console.log(expression.value);
|
|
857
|
+
} finally {
|
|
858
|
+
// Always dispose of expressions after use.
|
|
859
|
+
expression.dispose();
|
|
860
|
+
}
|
|
861
|
+
})();
|
|
862
|
+
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
### Bitwise or expression
|
|
866
|
+
|
|
867
|
+
```ts
|
|
868
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
869
|
+
import {
|
|
870
|
+
IExpressionFactory,
|
|
871
|
+
RsXExpressionParserInjectionTokens,
|
|
872
|
+
RsXExpressionParserModule
|
|
873
|
+
} from '@rs-x/expression-parser';
|
|
874
|
+
|
|
875
|
+
// Load the expression parser module into the injection container
|
|
876
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
877
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
878
|
+
|
|
879
|
+
export const run = (async () => {
|
|
880
|
+
const expressionContext = {
|
|
881
|
+
a: 5,
|
|
882
|
+
b: 2
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
const expression = expressionFactory.create(expressionContext, 'a | b');
|
|
886
|
+
|
|
887
|
+
try {
|
|
888
|
+
// Wait until the expression has been resolved (has a value)
|
|
889
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
890
|
+
|
|
891
|
+
console.log(`Initial value of 'a | b':`)
|
|
892
|
+
expression.changed.subscribe((change) => {
|
|
893
|
+
console.log(change.value);
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
console.log(`Value of 'a | b' after changing 'a' to '10':`);
|
|
897
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 10; });
|
|
898
|
+
|
|
899
|
+
console.log(`Value of 'a | b' after changing 'b' to '3':`)
|
|
900
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 3; });
|
|
901
|
+
|
|
902
|
+
console.log(`Final value of 'a | b':`)
|
|
903
|
+
console.log(expression.value);
|
|
904
|
+
} finally {
|
|
905
|
+
// Always dispose of expressions after use.
|
|
906
|
+
expression.dispose();
|
|
907
|
+
}
|
|
908
|
+
})();
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
### Bitwise right shift expression
|
|
914
|
+
|
|
915
|
+
```ts
|
|
916
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
917
|
+
import {
|
|
918
|
+
IExpressionFactory,
|
|
919
|
+
RsXExpressionParserInjectionTokens,
|
|
920
|
+
RsXExpressionParserModule
|
|
921
|
+
} from '@rs-x/expression-parser';
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
// Load the expression parser module into the injection container
|
|
925
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
926
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
927
|
+
|
|
928
|
+
export const run = (async () => {
|
|
929
|
+
const expressionContext = {
|
|
930
|
+
a: 5,
|
|
931
|
+
b: 2
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
const expression = expressionFactory.create(expressionContext, 'a >> b');
|
|
935
|
+
|
|
936
|
+
try {
|
|
937
|
+
// Wait until the expression has been resolved (has a value)
|
|
938
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
939
|
+
|
|
940
|
+
console.log(`Initial value of 'a >> b':`)
|
|
941
|
+
expression.changed.subscribe((change) => {
|
|
942
|
+
console.log(change.value);
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
console.log(`Value of 'a >> b' after changing 'a' to '10':`);
|
|
946
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 10; });
|
|
947
|
+
|
|
948
|
+
console.log(`Value of 'a >> b' after changing 'b' to '3':`)
|
|
949
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 3; });
|
|
950
|
+
|
|
951
|
+
console.log(`Final value of 'a >> b':`)
|
|
952
|
+
console.log(expression.value);
|
|
953
|
+
} finally {
|
|
954
|
+
// Always dispose of expressions after use.
|
|
955
|
+
expression.dispose();
|
|
956
|
+
}
|
|
957
|
+
})();
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Bitwise unsigned right shift expression
|
|
963
|
+
|
|
964
|
+
```ts
|
|
965
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
966
|
+
import {
|
|
967
|
+
IExpressionFactory,
|
|
968
|
+
RsXExpressionParserInjectionTokens,
|
|
969
|
+
RsXExpressionParserModule
|
|
970
|
+
} from '@rs-x/expression-parser';
|
|
971
|
+
|
|
972
|
+
// Load the expression parser module into the injection container
|
|
973
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
974
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
975
|
+
|
|
976
|
+
export const run = (async () => {
|
|
977
|
+
const expressionContext = {
|
|
978
|
+
a: 5,
|
|
979
|
+
b: 2
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
const expression = expressionFactory.create(expressionContext, 'a >>> b');
|
|
983
|
+
|
|
984
|
+
try {
|
|
985
|
+
// Wait until the expression has been resolved (has a value)
|
|
986
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
987
|
+
|
|
988
|
+
console.log(`Initial value of 'a >>> b':`)
|
|
989
|
+
expression.changed.subscribe((change) => {
|
|
990
|
+
console.log(change.value);
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
console.log(`Value of 'a >>> b' after changing 'a' to '-5':`);
|
|
994
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = -5; });
|
|
995
|
+
|
|
996
|
+
console.log(`Value of 'a >>> b' after changing 'b' to '3':`)
|
|
997
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 3; });
|
|
998
|
+
|
|
999
|
+
console.log(`Final value of 'a >>> b':`)
|
|
1000
|
+
console.log(expression.value);
|
|
1001
|
+
} finally {
|
|
1002
|
+
// Always dispose of expressions after use.
|
|
1003
|
+
expression.dispose();
|
|
1004
|
+
}
|
|
1005
|
+
})();
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### Bitwise xor expression
|
|
1011
|
+
|
|
1012
|
+
```ts
|
|
1013
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1014
|
+
import {
|
|
1015
|
+
IExpressionFactory,
|
|
1016
|
+
RsXExpressionParserInjectionTokens,
|
|
1017
|
+
RsXExpressionParserModule
|
|
1018
|
+
} from '@rs-x/expression-parser';
|
|
1019
|
+
|
|
1020
|
+
// Load the expression parser module into the injection container
|
|
1021
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1022
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1023
|
+
|
|
1024
|
+
export const run = (async () => {
|
|
1025
|
+
const expressionContext = {
|
|
1026
|
+
a: 5,
|
|
1027
|
+
b: 3
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
const expression = expressionFactory.create(expressionContext, 'a ^ b');
|
|
1031
|
+
|
|
1032
|
+
try {
|
|
1033
|
+
// Wait until the expression has been resolved (has a value)
|
|
1034
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1035
|
+
|
|
1036
|
+
console.log(`Initial value of 'a ^ b':`)
|
|
1037
|
+
expression.changed.subscribe((change) => {
|
|
1038
|
+
console.log(change.value);
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
console.log(`Value of 'a ^ b' after changing 'a' to '10':`);
|
|
1042
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 10; });
|
|
1043
|
+
|
|
1044
|
+
console.log(`Value of 'a ^ b' after changing 'b' to '8':`)
|
|
1045
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 8; });
|
|
1046
|
+
|
|
1047
|
+
console.log(`Final value of 'a ^ b':`)
|
|
1048
|
+
console.log(expression.value);
|
|
1049
|
+
} finally {
|
|
1050
|
+
// Always dispose of expressions after use.
|
|
1051
|
+
expression.dispose();
|
|
1052
|
+
}
|
|
1053
|
+
})();
|
|
1054
|
+
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
### Conditional expression
|
|
1058
|
+
|
|
1059
|
+
```ts
|
|
1060
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1061
|
+
import {
|
|
1062
|
+
IExpressionFactory,
|
|
1063
|
+
RsXExpressionParserInjectionTokens,
|
|
1064
|
+
RsXExpressionParserModule
|
|
1065
|
+
} from '@rs-x/expression-parser';
|
|
1066
|
+
|
|
1067
|
+
// Load the expression parser module into the injection container
|
|
1068
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1069
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1070
|
+
|
|
1071
|
+
export const run = (async () => {
|
|
1072
|
+
const expressionContext = {
|
|
1073
|
+
a: 1,
|
|
1074
|
+
b: 2,
|
|
1075
|
+
c: 100,
|
|
1076
|
+
d: 200
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
const expression = expressionFactory.create(expressionContext, 'a > b ? c : d');
|
|
1080
|
+
|
|
1081
|
+
try {
|
|
1082
|
+
// Wait until the expression has been resolved (has a value)
|
|
1083
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1084
|
+
|
|
1085
|
+
console.log(`Initial value of 'a > b ? c : d':`)
|
|
1086
|
+
expression.changed.subscribe((change) => {
|
|
1087
|
+
console.log(change.value);
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
console.log(`Value of 'a > b ? c : d' after changing d to '300':`);
|
|
1091
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.d = 300; });
|
|
1092
|
+
|
|
1093
|
+
console.log(`Value of 'a > b ? c : d' after changing 'a' to '3':`)
|
|
1094
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 3; });
|
|
1095
|
+
|
|
1096
|
+
console.log(`Value of 'a > b ? c : d' after changing c to '2000':`)
|
|
1097
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.c = 2000; });
|
|
1098
|
+
|
|
1099
|
+
console.log(`Value of 'a > b ? c : d' after changing 'b' to '4':`)
|
|
1100
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; });
|
|
1101
|
+
|
|
1102
|
+
console.log(`Final value of 'a > b ? c : d':`)
|
|
1103
|
+
console.log(expression.value);
|
|
1104
|
+
} finally {
|
|
1105
|
+
// Always dispose of expressions after use.
|
|
1106
|
+
expression.dispose();
|
|
1107
|
+
}
|
|
1108
|
+
})();
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
### Division expression
|
|
1114
|
+
|
|
1115
|
+
```ts
|
|
1116
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1117
|
+
import {
|
|
1118
|
+
IExpressionFactory,
|
|
1119
|
+
RsXExpressionParserInjectionTokens,
|
|
1120
|
+
RsXExpressionParserModule
|
|
1121
|
+
} from '@rs-x/expression-parser';
|
|
1122
|
+
|
|
1123
|
+
// Load the expression parser module into the injection container
|
|
1124
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1125
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1126
|
+
|
|
1127
|
+
export const run = (async () => {
|
|
1128
|
+
const expressionContext = {
|
|
1129
|
+
a: 20,
|
|
1130
|
+
b: 2
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
const expression = expressionFactory.create(expressionContext, 'a / b');
|
|
1134
|
+
|
|
1135
|
+
try {
|
|
1136
|
+
// Wait until the expression has been resolved (has a value)
|
|
1137
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1138
|
+
|
|
1139
|
+
console.log(`Initial value of 'a / b':`)
|
|
1140
|
+
expression.changed.subscribe((change) => {
|
|
1141
|
+
console.log(change.value);
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
console.log(`Value of 'a / b' after changing 'a' to '10':`);
|
|
1145
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 10; });
|
|
1146
|
+
|
|
1147
|
+
console.log(`Value of 'a /b b' after changing 'b' to '2':`)
|
|
1148
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 2; });
|
|
1149
|
+
|
|
1150
|
+
console.log(`Final value of 'a / b':`)
|
|
1151
|
+
console.log(expression.value);
|
|
1152
|
+
} finally {
|
|
1153
|
+
// Always dispose of expressions after use.
|
|
1154
|
+
expression.dispose();
|
|
1155
|
+
}
|
|
1156
|
+
})();
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
### Equality expression
|
|
1162
|
+
|
|
1163
|
+
```ts
|
|
1164
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1165
|
+
import {
|
|
1166
|
+
IExpressionFactory,
|
|
1167
|
+
RsXExpressionParserInjectionTokens,
|
|
1168
|
+
RsXExpressionParserModule
|
|
1169
|
+
} from '@rs-x/expression-parser';
|
|
1170
|
+
|
|
1171
|
+
// Load the expression parser module into the injection container
|
|
1172
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1173
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1174
|
+
|
|
1175
|
+
export const run = (async () => {
|
|
1176
|
+
const expressionContext = {
|
|
1177
|
+
a: 3,
|
|
1178
|
+
b: 2
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
const expression = expressionFactory.create(expressionContext, 'a == b');
|
|
1182
|
+
|
|
1183
|
+
try {
|
|
1184
|
+
// Wait until the expression has been resolved (has a value)
|
|
1185
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1186
|
+
|
|
1187
|
+
console.log(`Initial value of 'a == b':`)
|
|
1188
|
+
expression.changed.subscribe((change) => {
|
|
1189
|
+
console.log(change.value);
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
console.log(`Value of 'a == b' after changing 'a' to '2':`);
|
|
1193
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 2; });
|
|
1194
|
+
|
|
1195
|
+
console.log(`Value of 'a == b' after changing 'b' to '4':`)
|
|
1196
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; });
|
|
1197
|
+
|
|
1198
|
+
console.log(`Final value of 'a == b':`)
|
|
1199
|
+
console.log(expression.value);
|
|
1200
|
+
} finally {
|
|
1201
|
+
// Always dispose of expressions after use.
|
|
1202
|
+
expression.dispose();
|
|
1203
|
+
}
|
|
1204
|
+
})();
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
### Exponentiation expression
|
|
1210
|
+
|
|
1211
|
+
```ts
|
|
1212
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1213
|
+
import {
|
|
1214
|
+
IExpressionFactory,
|
|
1215
|
+
RsXExpressionParserInjectionTokens,
|
|
1216
|
+
RsXExpressionParserModule
|
|
1217
|
+
} from '@rs-x/expression-parser';
|
|
1218
|
+
|
|
1219
|
+
// Load the expression parser module into the injection container
|
|
1220
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1221
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1222
|
+
|
|
1223
|
+
export const run = (async () => {
|
|
1224
|
+
const expressionContext = {
|
|
1225
|
+
a: 2,
|
|
1226
|
+
b: 3
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
const expression = expressionFactory.create(expressionContext, 'a ** b');
|
|
1230
|
+
|
|
1231
|
+
try {
|
|
1232
|
+
// Wait until the expression has been resolved (has a value)
|
|
1233
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1234
|
+
|
|
1235
|
+
console.log(`Initial value of 'a ** b':`)
|
|
1236
|
+
expression.changed.subscribe((change) => {
|
|
1237
|
+
console.log(change.value);
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
console.log(`Value of 'a ** b' after changing 'a' to '4':`);
|
|
1241
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 4; });
|
|
1242
|
+
|
|
1243
|
+
console.log(`Value of 'a ** b' after changing 'b' to '5':`)
|
|
1244
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 5; });
|
|
1245
|
+
|
|
1246
|
+
console.log(`Final value of 'a ** b':`)
|
|
1247
|
+
console.log(expression.value);
|
|
1248
|
+
} finally {
|
|
1249
|
+
// Always dispose of expressions after use.
|
|
1250
|
+
expression.dispose();
|
|
1251
|
+
}
|
|
1252
|
+
})();
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
### Function expression
|
|
1258
|
+
|
|
1259
|
+
```ts
|
|
1260
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1261
|
+
import {
|
|
1262
|
+
IExpressionFactory,
|
|
1263
|
+
RsXExpressionParserInjectionTokens,
|
|
1264
|
+
RsXExpressionParserModule
|
|
1265
|
+
} from '@rs-x/expression-parser';
|
|
1266
|
+
|
|
1267
|
+
// Load the expression parser module into the injection container
|
|
1268
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1269
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1270
|
+
|
|
1271
|
+
export const run = (async () => {
|
|
1272
|
+
const expressionContext = {
|
|
1273
|
+
a: 2,
|
|
1274
|
+
b: 3,
|
|
1275
|
+
multiply(a: number, b: number) {
|
|
1276
|
+
return a * b;
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
const expression = expressionFactory.create(expressionContext, 'multiply(a, b)');
|
|
1281
|
+
|
|
1282
|
+
try {
|
|
1283
|
+
// Wait until the expression has been resolved (has a value)
|
|
1284
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1285
|
+
|
|
1286
|
+
console.log(`Initial value of 'multiply(a, b)'`)
|
|
1287
|
+
expression.changed.subscribe((change) => {
|
|
1288
|
+
console.log(change.value);
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
console.log(`Value of 'multiply(a, b)' after changing 'a' to '4':`);
|
|
1292
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 4; });
|
|
1293
|
+
|
|
1294
|
+
console.log(`Value of 'mutiply(a, b)' after changing 'b' to '5':`)
|
|
1295
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 5; });
|
|
1296
|
+
|
|
1297
|
+
console.log(`Final value of 'multiply(a, b)':`)
|
|
1298
|
+
console.log(expression.value);
|
|
1299
|
+
} finally {
|
|
1300
|
+
// Always dispose of expressions after use.
|
|
1301
|
+
expression.dispose();
|
|
1302
|
+
}
|
|
1303
|
+
})();
|
|
1304
|
+
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
### Greater than expression
|
|
1308
|
+
|
|
1309
|
+
```ts
|
|
1310
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1311
|
+
import {
|
|
1312
|
+
IExpressionFactory,
|
|
1313
|
+
RsXExpressionParserInjectionTokens,
|
|
1314
|
+
RsXExpressionParserModule
|
|
1315
|
+
} from '@rs-x/expression-parser';
|
|
1316
|
+
|
|
1317
|
+
// Load the expression parser module into the injection container
|
|
1318
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1319
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1320
|
+
|
|
1321
|
+
export const run = (async () => {
|
|
1322
|
+
const expressionContext = {
|
|
1323
|
+
a: 3,
|
|
1324
|
+
b: 2
|
|
1325
|
+
};
|
|
1326
|
+
|
|
1327
|
+
const expression = expressionFactory.create(expressionContext, 'a > b');
|
|
1328
|
+
|
|
1329
|
+
try {
|
|
1330
|
+
// Wait until the expression has been resolved (has a value)
|
|
1331
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1332
|
+
|
|
1333
|
+
console.log(`Initial value of 'a > b':`)
|
|
1334
|
+
expression.changed.subscribe((change) => {
|
|
1335
|
+
console.log(change.value);
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
console.log(`Value of 'a > b' after changing 'a' to '2':`);
|
|
1339
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 2; });
|
|
1340
|
+
|
|
1341
|
+
console.log(`Value of 'a > b' after changing 'b' to '1':`)
|
|
1342
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 1; });
|
|
1343
|
+
|
|
1344
|
+
console.log(`Final value of 'a > b':`)
|
|
1345
|
+
console.log(expression.value);
|
|
1346
|
+
} finally {
|
|
1347
|
+
// Always dispose of expressions after use.
|
|
1348
|
+
expression.dispose();
|
|
1349
|
+
}
|
|
1350
|
+
})();
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
### Greater than or equal expression
|
|
1356
|
+
|
|
1357
|
+
```ts
|
|
1358
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1359
|
+
import {
|
|
1360
|
+
IExpressionFactory,
|
|
1361
|
+
RsXExpressionParserInjectionTokens,
|
|
1362
|
+
RsXExpressionParserModule
|
|
1363
|
+
} from '@rs-x/expression-parser';
|
|
1364
|
+
|
|
1365
|
+
// Load the expression parser module into the injection container
|
|
1366
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1367
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1368
|
+
|
|
1369
|
+
export const run = (async () => {
|
|
1370
|
+
const expressionContext = {
|
|
1371
|
+
a: 3,
|
|
1372
|
+
b: 2
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
const expression = expressionFactory.create(expressionContext, 'a >= b');
|
|
1376
|
+
|
|
1377
|
+
try {
|
|
1378
|
+
// Wait until the expression has been resolved (has a value)
|
|
1379
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1380
|
+
|
|
1381
|
+
console.log(`Initial value of 'a >= b':`)
|
|
1382
|
+
expression.changed.subscribe((change) => {
|
|
1383
|
+
console.log(change.value);
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
console.log(`Value of 'a >= b' after changing 'a' to '1':`);
|
|
1387
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 1; });
|
|
1388
|
+
|
|
1389
|
+
console.log(`Value of 'a >= b' after changing 'b' to '0':`)
|
|
1390
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 0; });
|
|
1391
|
+
|
|
1392
|
+
console.log(`Final value of 'a >= b':`)
|
|
1393
|
+
console.log(expression.value);
|
|
1394
|
+
} finally {
|
|
1395
|
+
// Always dispose of expressions after use.
|
|
1396
|
+
expression.dispose();
|
|
1397
|
+
}
|
|
1398
|
+
})();
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
```
|
|
1402
|
+
|
|
1403
|
+
### In expression
|
|
1404
|
+
|
|
1405
|
+
```ts
|
|
1406
|
+
import { emptyFunction, InjectionContainer, Type, WaitForEvent } from '@rs-x/core';
|
|
1407
|
+
import {
|
|
1408
|
+
IExpressionFactory,
|
|
1409
|
+
RsXExpressionParserInjectionTokens,
|
|
1410
|
+
RsXExpressionParserModule
|
|
1411
|
+
} from '@rs-x/expression-parser';
|
|
1412
|
+
|
|
1413
|
+
// Load the expression parser module into the injection container
|
|
1414
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1415
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1416
|
+
|
|
1417
|
+
export const run = (async () => {
|
|
1418
|
+
const expressionContext = {
|
|
1419
|
+
propertyName: 'hello',
|
|
1420
|
+
b: {
|
|
1421
|
+
hello: 'hi',
|
|
1422
|
+
},
|
|
1423
|
+
};
|
|
1424
|
+
|
|
1425
|
+
const expression = expressionFactory.create(expressionContext, 'propertyName in b');
|
|
1426
|
+
|
|
1427
|
+
try {
|
|
1428
|
+
// Wait until the expression has been resolved (has a value)
|
|
1429
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1430
|
+
|
|
1431
|
+
console.log(`Initial value of 'propertyName in b':`)
|
|
1432
|
+
expression.changed.subscribe((change) => {
|
|
1433
|
+
console.log(change.value);
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
console.log(`Value of 'propertyName in b' after changing 'a' to 'x':`);
|
|
1437
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.propertyName = 'x'; });
|
|
1438
|
+
|
|
1439
|
+
console.log(`Value of 'propertyName in b' after changing 'b' to '{x: 1}':`)
|
|
1440
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = Type.cast({ x: 1 }); });
|
|
1441
|
+
|
|
1442
|
+
console.log(`Final value of 'propertyName in b':`)
|
|
1443
|
+
console.log(expression.value);
|
|
1444
|
+
} finally {
|
|
1445
|
+
// Always dispose of expressions after use.
|
|
1446
|
+
expression.dispose();
|
|
1447
|
+
}
|
|
1448
|
+
})();
|
|
1449
|
+
|
|
1450
|
+
|
|
1451
|
+
```
|
|
1452
|
+
|
|
1453
|
+
### Inequality expression
|
|
1454
|
+
|
|
1455
|
+
```ts
|
|
1456
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1457
|
+
import {
|
|
1458
|
+
IExpressionFactory,
|
|
1459
|
+
RsXExpressionParserInjectionTokens,
|
|
1460
|
+
RsXExpressionParserModule
|
|
1461
|
+
} from '@rs-x/expression-parser';
|
|
1462
|
+
|
|
1463
|
+
// Load the expression parser module into the injection container
|
|
1464
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1465
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1466
|
+
|
|
1467
|
+
export const run = (async () => {
|
|
1468
|
+
const expressionContext = {
|
|
1469
|
+
a: 1,
|
|
1470
|
+
b: 2
|
|
1471
|
+
};
|
|
1472
|
+
|
|
1473
|
+
const expression = expressionFactory.create(expressionContext, 'a != b');
|
|
1474
|
+
|
|
1475
|
+
try {
|
|
1476
|
+
// Wait until the expression has been resolved (has a value)
|
|
1477
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1478
|
+
|
|
1479
|
+
console.log(`Initial value of 'a != b':`)
|
|
1480
|
+
expression.changed.subscribe((change) => {
|
|
1481
|
+
console.log(change.value);
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
console.log(`Value of 'a != b' after changing 'a' to '2':`);
|
|
1485
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 2; });
|
|
1486
|
+
|
|
1487
|
+
console.log(`Value of 'a != b' after changing 'b' to '2':`)
|
|
1488
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 2; });
|
|
1489
|
+
|
|
1490
|
+
console.log(`Final value of 'a != b':`)
|
|
1491
|
+
console.log(expression.value);
|
|
1492
|
+
} finally {
|
|
1493
|
+
// Always dispose of expressions after use.
|
|
1494
|
+
expression.dispose();
|
|
1495
|
+
}
|
|
1496
|
+
})();
|
|
1497
|
+
|
|
1498
|
+
|
|
1499
|
+
```
|
|
1500
|
+
|
|
1501
|
+
### Instanceof expression
|
|
1502
|
+
|
|
1503
|
+
```ts
|
|
1504
|
+
import { emptyFunction, InjectionContainer, Type, WaitForEvent } from '@rs-x/core';
|
|
1505
|
+
import {
|
|
1506
|
+
IExpressionFactory,
|
|
1507
|
+
RsXExpressionParserInjectionTokens,
|
|
1508
|
+
RsXExpressionParserModule
|
|
1509
|
+
} from '@rs-x/expression-parser';
|
|
1510
|
+
|
|
1511
|
+
// Load the expression parser module into the injection container
|
|
1512
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1513
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1514
|
+
|
|
1515
|
+
export const run = (async () => {
|
|
1516
|
+
const expressionContext = {
|
|
1517
|
+
type: Date,
|
|
1518
|
+
a: new Date(),
|
|
1519
|
+
};
|
|
1520
|
+
|
|
1521
|
+
const expression = expressionFactory.create(expressionContext, 'a instanceof type');
|
|
1522
|
+
|
|
1523
|
+
try {
|
|
1524
|
+
// Wait until the expression has been resolved (has a value)
|
|
1525
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1526
|
+
|
|
1527
|
+
console.log(`Initial value of 'a instanceof type':`)
|
|
1528
|
+
expression.changed.subscribe((change) => {
|
|
1529
|
+
console.log(change.value);
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
console.log(`Value of 'a instanceof type' after changing 'a' to 'new Number(2)':`);
|
|
1533
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = Type.cast(new Number(2)); });
|
|
1534
|
+
|
|
1535
|
+
console.log(`Value of 'a instanceof type' after changing 'type' to 'Number':`)
|
|
1536
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.type = Type.cast(Number); });
|
|
1537
|
+
|
|
1538
|
+
console.log(`Final value of 'a instanceof type':`)
|
|
1539
|
+
console.log(expression.value);
|
|
1540
|
+
} finally {
|
|
1541
|
+
// Always dispose of expressions after use.
|
|
1542
|
+
expression.dispose();
|
|
1543
|
+
}
|
|
1544
|
+
})();
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
```
|
|
1548
|
+
|
|
1549
|
+
### Less than expression
|
|
1550
|
+
|
|
1551
|
+
```ts
|
|
1552
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1553
|
+
import {
|
|
1554
|
+
IExpressionFactory,
|
|
1555
|
+
RsXExpressionParserInjectionTokens,
|
|
1556
|
+
RsXExpressionParserModule
|
|
1557
|
+
} from '@rs-x/expression-parser';
|
|
1558
|
+
|
|
1559
|
+
// Load the expression parser module into the injection container
|
|
1560
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1561
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1562
|
+
|
|
1563
|
+
export const run = (async () => {
|
|
1564
|
+
const expressionContext = {
|
|
1565
|
+
a: 2,
|
|
1566
|
+
b: 3
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
const expression = expressionFactory.create(expressionContext, 'a < b');
|
|
1570
|
+
|
|
1571
|
+
try {
|
|
1572
|
+
// Wait until the expression has been resolved (has a value)
|
|
1573
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1574
|
+
|
|
1575
|
+
console.log(`Initial value of 'a < b':`)
|
|
1576
|
+
expression.changed.subscribe((change) => {
|
|
1577
|
+
console.log(change.value);
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
console.log(`Value of 'a < b' after changing 'a' to '3':`);
|
|
1581
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 3; });
|
|
1582
|
+
|
|
1583
|
+
console.log(`Value of 'a < b' after changing 'b' to '4':`)
|
|
1584
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; });
|
|
1585
|
+
|
|
1586
|
+
console.log(`Final value of 'a < b':`)
|
|
1587
|
+
console.log(expression.value);
|
|
1588
|
+
} finally {
|
|
1589
|
+
// Always dispose of expressions after use.
|
|
1590
|
+
expression.dispose();
|
|
1591
|
+
}
|
|
1592
|
+
})();
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1597
|
+
### Less than or equal expression
|
|
1598
|
+
|
|
1599
|
+
```ts
|
|
1600
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1601
|
+
import {
|
|
1602
|
+
IExpressionFactory,
|
|
1603
|
+
RsXExpressionParserInjectionTokens,
|
|
1604
|
+
RsXExpressionParserModule
|
|
1605
|
+
} from '@rs-x/expression-parser';
|
|
1606
|
+
|
|
1607
|
+
// Load the expression parser module into the injection container
|
|
1608
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1609
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1610
|
+
|
|
1611
|
+
export const run = (async () => {
|
|
1612
|
+
const expressionContext = {
|
|
1613
|
+
a: 2,
|
|
1614
|
+
b: 3
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
const expression = expressionFactory.create(expressionContext, 'a <= b');
|
|
1618
|
+
|
|
1619
|
+
try {
|
|
1620
|
+
// Wait until the expression has been resolved (has a value)
|
|
1621
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1622
|
+
|
|
1623
|
+
console.log(`Initial value of 'a <= b':`)
|
|
1624
|
+
expression.changed.subscribe((change) => {
|
|
1625
|
+
console.log(change.value);
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
console.log(`Value of 'a <= b' after changing 'a' to '4':`);
|
|
1629
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 4; });
|
|
1630
|
+
|
|
1631
|
+
console.log(`Value of 'a < b' after changing 'b' to '4':`)
|
|
1632
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; });
|
|
1633
|
+
|
|
1634
|
+
console.log(`Final value of 'a <= b':`)
|
|
1635
|
+
console.log(expression.value);
|
|
1636
|
+
} finally {
|
|
1637
|
+
// Always dispose of expressions after use.
|
|
1638
|
+
expression.dispose();
|
|
1639
|
+
}
|
|
1640
|
+
})();
|
|
1641
|
+
|
|
1642
|
+
|
|
1643
|
+
```
|
|
1644
|
+
|
|
1645
|
+
### Logical and expression
|
|
1646
|
+
|
|
1647
|
+
```ts
|
|
1648
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1649
|
+
import {
|
|
1650
|
+
IExpressionFactory,
|
|
1651
|
+
RsXExpressionParserInjectionTokens,
|
|
1652
|
+
RsXExpressionParserModule
|
|
1653
|
+
} from '@rs-x/expression-parser';
|
|
1654
|
+
|
|
1655
|
+
// Load the expression parser module into the injection container
|
|
1656
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1657
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1658
|
+
|
|
1659
|
+
export const run = (async () => {
|
|
1660
|
+
const expressionContext = {
|
|
1661
|
+
a: false,
|
|
1662
|
+
b: true
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
const expression = expressionFactory.create(expressionContext, 'a && b');
|
|
1666
|
+
|
|
1667
|
+
try {
|
|
1668
|
+
// Wait until the expression has been resolved (has a value)
|
|
1669
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1670
|
+
|
|
1671
|
+
console.log(`Initial value of 'a && b':`)
|
|
1672
|
+
expression.changed.subscribe((change) => {
|
|
1673
|
+
console.log(change.value);
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
console.log(`Value of 'a && b' after changing 'a' to 'true':`);
|
|
1677
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = true; });
|
|
1678
|
+
|
|
1679
|
+
console.log(`Value of 'a && b' after changing 'b' to 'false':`)
|
|
1680
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = false; });
|
|
1681
|
+
|
|
1682
|
+
console.log(`Final value of 'a && b':`)
|
|
1683
|
+
console.log(expression.value);
|
|
1684
|
+
} finally {
|
|
1685
|
+
// Always dispose of expressions after use.
|
|
1686
|
+
expression.dispose();
|
|
1687
|
+
}
|
|
1688
|
+
})();
|
|
1689
|
+
|
|
1690
|
+
```
|
|
1691
|
+
|
|
1692
|
+
### Logical not expression
|
|
1693
|
+
|
|
1694
|
+
```ts
|
|
1695
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1696
|
+
import {
|
|
1697
|
+
IExpressionFactory,
|
|
1698
|
+
RsXExpressionParserInjectionTokens,
|
|
1699
|
+
RsXExpressionParserModule
|
|
1700
|
+
} from '@rs-x/expression-parser';
|
|
1701
|
+
|
|
1702
|
+
// Load the expression parser module into the injection container
|
|
1703
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1704
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1705
|
+
|
|
1706
|
+
export const run = (async () => {
|
|
1707
|
+
const expressionContext = {
|
|
1708
|
+
a: false
|
|
1709
|
+
};
|
|
1710
|
+
|
|
1711
|
+
const expression = expressionFactory.create(expressionContext, '!a');
|
|
1712
|
+
|
|
1713
|
+
try {
|
|
1714
|
+
// Wait until the expression has been resolved (has a value)
|
|
1715
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1716
|
+
|
|
1717
|
+
console.log(`Initial value of '!a':`)
|
|
1718
|
+
expression.changed.subscribe((change) => {
|
|
1719
|
+
console.log(change.value);
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1722
|
+
console.log(`Value of !a' after changing 'a' to 'true':`);
|
|
1723
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = true; });
|
|
1724
|
+
|
|
1725
|
+
console.log(`Final value of '!a':`)
|
|
1726
|
+
console.log(expression.value);
|
|
1727
|
+
} finally {
|
|
1728
|
+
// Always dispose of expressions after use.
|
|
1729
|
+
expression.dispose();
|
|
1730
|
+
}
|
|
1731
|
+
})();
|
|
1732
|
+
```
|
|
1733
|
+
|
|
1734
|
+
### Logical or expression
|
|
1735
|
+
|
|
1736
|
+
```ts
|
|
1737
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
1738
|
+
import {
|
|
1739
|
+
IExpressionFactory,
|
|
1740
|
+
RsXExpressionParserInjectionTokens,
|
|
1741
|
+
RsXExpressionParserModule
|
|
1742
|
+
} from '@rs-x/expression-parser';
|
|
1743
|
+
|
|
1744
|
+
// Load the expression parser module into the injection container
|
|
1745
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1746
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1747
|
+
|
|
1748
|
+
export const run = (async () => {
|
|
1749
|
+
const expressionContext = {
|
|
1750
|
+
a: true,
|
|
1751
|
+
b: false
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
const expression = expressionFactory.create(expressionContext, 'a || b');
|
|
1755
|
+
|
|
1756
|
+
try {
|
|
1757
|
+
// Wait until the expression has been resolved (has a value)
|
|
1758
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1759
|
+
|
|
1760
|
+
console.log(`Initial value of 'a || b':`)
|
|
1761
|
+
expression.changed.subscribe((change) => {
|
|
1762
|
+
console.log(change.value);
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
console.log(`Value of 'a || b' after changing 'a' to 'false':`);
|
|
1766
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = false; });
|
|
1767
|
+
|
|
1768
|
+
console.log(`Value of 'a || b' after changing 'b' to 'true':`)
|
|
1769
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = true; });
|
|
1770
|
+
|
|
1771
|
+
console.log(`Final value of 'a || b':`)
|
|
1772
|
+
console.log(expression.value);
|
|
1773
|
+
} finally {
|
|
1774
|
+
// Always dispose of expressions after use.
|
|
1775
|
+
expression.dispose();
|
|
1776
|
+
}
|
|
1777
|
+
})();
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
```
|
|
1781
|
+
|
|
1782
|
+
### Member expression
|
|
1783
|
+
|
|
1784
|
+
* Member expression
|
|
1785
|
+
```ts
|
|
1786
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
1787
|
+
import {
|
|
1788
|
+
IExpressionFactory,
|
|
1789
|
+
RsXExpressionParserInjectionTokens,
|
|
1790
|
+
RsXExpressionParserModule
|
|
1791
|
+
} from '@rs-x/expression-parser';
|
|
1792
|
+
|
|
1793
|
+
// Load the expression parser module into the injection container
|
|
1794
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1795
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1796
|
+
|
|
1797
|
+
export const run = (async () => {
|
|
1798
|
+
const expressionContext = {
|
|
1799
|
+
a: {
|
|
1800
|
+
b: {
|
|
1801
|
+
c: 10
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
const expression = expressionFactory.create(expressionContext, 'a.b.c');
|
|
1807
|
+
|
|
1808
|
+
try {
|
|
1809
|
+
// Wait until the expression has been resolved (has a value)
|
|
1810
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1811
|
+
|
|
1812
|
+
console.log(`Initial value of 'a.b.c':`)
|
|
1813
|
+
expression.changed.subscribe((change) => {
|
|
1814
|
+
printValue(change.value);
|
|
1815
|
+
});
|
|
1816
|
+
|
|
1817
|
+
console.log(`Value of 'a.b.c' after changing 'a' to '{b : {c: 20}}':`);
|
|
1818
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = { b: { c: 20 } }; });
|
|
1819
|
+
|
|
1820
|
+
console.log(`Value of 'a.b.c' after changing 'b' to '{c: 30}':`);
|
|
1821
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a.b = { c: 30 }; });
|
|
1822
|
+
|
|
1823
|
+
console.log(`Value of 'a.b.c' after changing c to '40':`);
|
|
1824
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a.b.c = 40; });
|
|
1825
|
+
|
|
1826
|
+
console.log(`Final value of 'a.b.c':`)
|
|
1827
|
+
printValue(expression.value);
|
|
1828
|
+
} finally {
|
|
1829
|
+
// Always dispose of expressions after use.
|
|
1830
|
+
expression.dispose();
|
|
1831
|
+
}
|
|
1832
|
+
})();
|
|
1833
|
+
|
|
1834
|
+
|
|
1835
|
+
```
|
|
1836
|
+
* Member expression with array
|
|
1837
|
+
```ts
|
|
1838
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
1839
|
+
import {
|
|
1840
|
+
IExpressionFactory,
|
|
1841
|
+
RsXExpressionParserInjectionTokens,
|
|
1842
|
+
RsXExpressionParserModule
|
|
1843
|
+
} from '@rs-x/expression-parser';
|
|
1844
|
+
|
|
1845
|
+
|
|
1846
|
+
// Load the expression parser module into the injection container
|
|
1847
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1848
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1849
|
+
|
|
1850
|
+
export const run = (async () => {
|
|
1851
|
+
const expressionContext = {
|
|
1852
|
+
a: {
|
|
1853
|
+
b: [
|
|
1854
|
+
{
|
|
1855
|
+
c: {
|
|
1856
|
+
d: 10
|
|
1857
|
+
}
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
c: {
|
|
1861
|
+
d: 11
|
|
1862
|
+
}
|
|
1863
|
+
},
|
|
1864
|
+
]
|
|
1865
|
+
},
|
|
1866
|
+
x: { y: 1 }
|
|
1867
|
+
};
|
|
1868
|
+
|
|
1869
|
+
const expression = expressionFactory.create(expressionContext, 'a.b[1].c.d');
|
|
1870
|
+
|
|
1871
|
+
try {
|
|
1872
|
+
// Wait until the expression has been resolved (has a value)
|
|
1873
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1874
|
+
|
|
1875
|
+
console.log(`Initial value of 'a.b[1].c.d':`);
|
|
1876
|
+
expression.changed.subscribe((change) => {
|
|
1877
|
+
printValue(change.value);
|
|
1878
|
+
});
|
|
1879
|
+
|
|
1880
|
+
console.log(`Value of 'a.b.c' after changing 'a' to '{b: [{ c: { d: 100}},{ c: { d: 110}}}':`);
|
|
1881
|
+
await new WaitForEvent(expression, 'changed', {ignoreInitialValue: true}).wait(() => {
|
|
1882
|
+
expressionContext.a = {
|
|
1883
|
+
b: [
|
|
1884
|
+
{
|
|
1885
|
+
c: {
|
|
1886
|
+
d: 100
|
|
1887
|
+
}
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
c: {
|
|
1891
|
+
d: 110
|
|
1892
|
+
}
|
|
1893
|
+
},
|
|
1894
|
+
]
|
|
1895
|
+
};
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
console.log(`Value of 'a.b[1].c.d' after changing b[1] to '{ c: { d: 120}}':`);
|
|
1899
|
+
await new WaitForEvent(expression, 'changed', {ignoreInitialValue: true}).wait(() => {
|
|
1900
|
+
expressionContext.a.b[1] = {
|
|
1901
|
+
c: {
|
|
1902
|
+
d: 120
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
});
|
|
1906
|
+
|
|
1907
|
+
console.log(`Value of 'a.b[1].c.d' after changing b[1].c to '{d: 220}':`);
|
|
1908
|
+
await new WaitForEvent(expression, 'changed', {ignoreInitialValue: true}).wait(() => { expressionContext.a.b[1].c = { d: 220 }; });
|
|
1909
|
+
|
|
1910
|
+
console.log(`Value of 'a.b[1].c.d' after changing b[1].c.d to '330':`);
|
|
1911
|
+
await new WaitForEvent(expression, 'changed', {ignoreInitialValue: true}).wait(() => { expressionContext.a.b[1].c.d = 330; });
|
|
1912
|
+
|
|
1913
|
+
console.log(`Final value of 'a.b[1].c.d':`)
|
|
1914
|
+
printValue(expression.value);
|
|
1915
|
+
} finally {
|
|
1916
|
+
// Always dispose of expressions after use.
|
|
1917
|
+
expression.dispose();
|
|
1918
|
+
}
|
|
1919
|
+
})();
|
|
1920
|
+
```
|
|
1921
|
+
* Member expression with map
|
|
1922
|
+
```ts
|
|
1923
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
1924
|
+
import {
|
|
1925
|
+
IExpressionFactory,
|
|
1926
|
+
RsXExpressionParserInjectionTokens,
|
|
1927
|
+
RsXExpressionParserModule
|
|
1928
|
+
} from '@rs-x/expression-parser';
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
// Load the expression parser module into the injection container
|
|
1932
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
1933
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
1934
|
+
|
|
1935
|
+
export const run = (async () => {
|
|
1936
|
+
const expressionContext = {
|
|
1937
|
+
a: {
|
|
1938
|
+
b: new Map([
|
|
1939
|
+
['a', { c: { d: 1 } }],
|
|
1940
|
+
['b', { c: { d: 2 } }]
|
|
1941
|
+
])
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1944
|
+
|
|
1945
|
+
const expression = expressionFactory.create(expressionContext, `a.b['b'].c.d`);
|
|
1946
|
+
|
|
1947
|
+
try {
|
|
1948
|
+
// Wait until the expression has been resolved (has a value)
|
|
1949
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
1950
|
+
|
|
1951
|
+
console.log(`Initial value of 'a.b['b'].c.d':`);
|
|
1952
|
+
expression.changed.subscribe((change) => {
|
|
1953
|
+
printValue(change.value);
|
|
1954
|
+
});
|
|
1955
|
+
|
|
1956
|
+
console.log(`Value of 'a.b['b'].c.d' after changing 'a' to '{ b: new Map([['a', { c: { d: 11 } }], ['b', { c: { d: 21 } }]]) }':`);
|
|
1957
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
1958
|
+
expressionContext.a = {
|
|
1959
|
+
b: new Map([
|
|
1960
|
+
['a', { c: { d: 11 } }],
|
|
1961
|
+
['b', { c: { d: 21 } }]
|
|
1962
|
+
])
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
|
|
1966
|
+
console.log(`Value of 'a.b['b'].c.d' after changing b['b'] to '{ c: { d: 120 } }':`);
|
|
1967
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
1968
|
+
expressionContext.a.b.set('b', { c: { d: 120 } });
|
|
1969
|
+
});
|
|
1970
|
+
|
|
1971
|
+
console.log(`Value of 'a.b['b'].c.d' after changing b['b'].c to '{ d: 220 }':`);
|
|
1972
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
1973
|
+
expressionContext.a.b.get('b').c = { d: 220 };
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
console.log(`Value of 'a.b['b'].c.d' after changing b[1].c.d to '330':`);
|
|
1977
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
1978
|
+
expressionContext.a.b.get('b').c.d = 330;
|
|
1979
|
+
});
|
|
1980
|
+
|
|
1981
|
+
console.log(`Final value of 'a.b['b'].c.d':`)
|
|
1982
|
+
printValue(expression.value);
|
|
1983
|
+
} finally {
|
|
1984
|
+
// Always dispose of expressions after use.
|
|
1985
|
+
expression.dispose();
|
|
1986
|
+
}
|
|
1987
|
+
})();
|
|
1988
|
+
```
|
|
1989
|
+
* Member expression with method
|
|
1990
|
+
```ts
|
|
1991
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
1992
|
+
import {
|
|
1993
|
+
IExpressionFactory,
|
|
1994
|
+
RsXExpressionParserInjectionTokens,
|
|
1995
|
+
RsXExpressionParserModule
|
|
1996
|
+
} from '@rs-x/expression-parser';
|
|
1997
|
+
|
|
1998
|
+
// Load the expression parser module into the injection container
|
|
1999
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2000
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2001
|
+
|
|
2002
|
+
export const run = (async () => {
|
|
2003
|
+
const expressionContext = {
|
|
2004
|
+
message: 'Hello',
|
|
2005
|
+
subject: 'Message',
|
|
2006
|
+
a: {
|
|
2007
|
+
b: {
|
|
2008
|
+
mail: (message: string, subject: string) => {
|
|
2009
|
+
return {
|
|
2010
|
+
messageWithSubject: `message: ${message}, subject: ${subject}`
|
|
2011
|
+
};
|
|
2012
|
+
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
};
|
|
2017
|
+
|
|
2018
|
+
const expression = expressionFactory.create(expressionContext, 'a.b.mail(message, subject).messageWithSubject');
|
|
2019
|
+
|
|
2020
|
+
try {
|
|
2021
|
+
// Wait until the expression has been resolved (has a value)
|
|
2022
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2023
|
+
|
|
2024
|
+
console.log(`Initial value of 'a.b.mail(message, subject).messageWithSubject':`);
|
|
2025
|
+
expression.changed.subscribe((change) => {
|
|
2026
|
+
printValue(change.value);
|
|
2027
|
+
});
|
|
2028
|
+
|
|
2029
|
+
console.log(`Value of 'a.b.mail(message, subject).messageWithSubject' after changing 'message' to 'hi'`);
|
|
2030
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2031
|
+
expressionContext.message = 'hi';
|
|
2032
|
+
});
|
|
2033
|
+
|
|
2034
|
+
console.log(`Value of 'a.b.mail(message, subject).messageWithSubject' after changing 'subject' to 'urgent message'`);
|
|
2035
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2036
|
+
expressionContext.subject = 'urgent message';
|
|
2037
|
+
});
|
|
2038
|
+
|
|
2039
|
+
console.log(`Final value of 'a.b.mail(message, subject).messageWithSubject':`)
|
|
2040
|
+
printValue(expression.value);
|
|
2041
|
+
} finally {
|
|
2042
|
+
// Always dispose of expressions after use.
|
|
2043
|
+
expression.dispose();
|
|
2044
|
+
}
|
|
2045
|
+
})();
|
|
2046
|
+
```
|
|
2047
|
+
* Member expression with observable
|
|
2048
|
+
```ts
|
|
2049
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
2050
|
+
import {
|
|
2051
|
+
IExpressionFactory,
|
|
2052
|
+
RsXExpressionParserInjectionTokens,
|
|
2053
|
+
RsXExpressionParserModule
|
|
2054
|
+
} from '@rs-x/expression-parser';
|
|
2055
|
+
import { BehaviorSubject } from 'rxjs';
|
|
2056
|
+
|
|
2057
|
+
// Load the expression parser module into the injection container
|
|
2058
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2059
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2060
|
+
|
|
2061
|
+
export const run = (async () => {
|
|
2062
|
+
const nestedObservable = new BehaviorSubject({ d: 200 });
|
|
2063
|
+
const rootObservable = new BehaviorSubject({ c: nestedObservable });
|
|
2064
|
+
const expressionContext = {
|
|
2065
|
+
a: {
|
|
2066
|
+
b: new BehaviorSubject(
|
|
2067
|
+
{
|
|
2068
|
+
c: new BehaviorSubject({ d: 20 })
|
|
2069
|
+
}
|
|
2070
|
+
)
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
const expression = expressionFactory.create(expressionContext, `a.b.c.d`);
|
|
2074
|
+
|
|
2075
|
+
try {
|
|
2076
|
+
// Wait until the expression has been resolved (has a value)
|
|
2077
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2078
|
+
|
|
2079
|
+
console.log(`Initial value of 'a.b.c.d':`);
|
|
2080
|
+
expression.changed.subscribe((change) => {
|
|
2081
|
+
printValue(change.value);
|
|
2082
|
+
});
|
|
2083
|
+
|
|
2084
|
+
|
|
2085
|
+
console.log(`Value of 'a.b.c.d' after changing 'a' to '{ b: BehaviorSubject({ c: BehaviorSubject({ d: 200 }) }) }':`);
|
|
2086
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2087
|
+
expressionContext.a = { b: rootObservable }
|
|
2088
|
+
|
|
2089
|
+
});
|
|
2090
|
+
|
|
2091
|
+
console.log(`Value of 'a.b.c.d' after emitting a new value '{ d: 300 }' for c':`);
|
|
2092
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2093
|
+
nestedObservable.next({ d: 300 });
|
|
2094
|
+
});
|
|
2095
|
+
|
|
2096
|
+
console.log(`Value of 'a.b.c.d' after emitting a new value '{ c: new BehaviorSubject({ d: 400 }) }' for b':`);
|
|
2097
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2098
|
+
rootObservable.next({
|
|
2099
|
+
c: new BehaviorSubject({ d: 400 })
|
|
2100
|
+
})
|
|
2101
|
+
});
|
|
2102
|
+
|
|
2103
|
+
console.log(`Final value of 'a.b.c.d':`)
|
|
2104
|
+
printValue(expression.value);
|
|
2105
|
+
} finally {
|
|
2106
|
+
// Always dispose of expressions after use.
|
|
2107
|
+
expression.dispose();
|
|
2108
|
+
}
|
|
2109
|
+
})();
|
|
2110
|
+
```
|
|
2111
|
+
* Member expression with promise
|
|
2112
|
+
```ts
|
|
2113
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
2114
|
+
import {
|
|
2115
|
+
IExpressionFactory,
|
|
2116
|
+
RsXExpressionParserInjectionTokens,
|
|
2117
|
+
RsXExpressionParserModule
|
|
2118
|
+
} from '@rs-x/expression-parser';
|
|
2119
|
+
|
|
2120
|
+
// Load the expression parser module into the injection container
|
|
2121
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2122
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2123
|
+
|
|
2124
|
+
export const run = (async () => {
|
|
2125
|
+
const expressionContext = {
|
|
2126
|
+
a: {
|
|
2127
|
+
b: Promise.resolve({
|
|
2128
|
+
c: Promise.resolve({
|
|
2129
|
+
d: 20
|
|
2130
|
+
})
|
|
2131
|
+
})
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
|
|
2135
|
+
const expression = expressionFactory.create(expressionContext, `a.b.c.d`);
|
|
2136
|
+
|
|
2137
|
+
try {
|
|
2138
|
+
// Wait until the expression has been resolved (has a value)
|
|
2139
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2140
|
+
|
|
2141
|
+
console.log(`Initial value of 'a.b.c.d':`);
|
|
2142
|
+
expression.changed.subscribe((change) => {
|
|
2143
|
+
printValue(change.value);
|
|
2144
|
+
});
|
|
2145
|
+
|
|
2146
|
+
console.log(`Value of 'a.b.c.d' after changing 'a' to '{ b: Promise.resolve({ c: Promise.resolve({ d: 200 }) }) }':`);
|
|
2147
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => {
|
|
2148
|
+
expressionContext.a = { b: Promise.resolve({ c: Promise.resolve({ d: 200 }) }) };
|
|
2149
|
+
});
|
|
2150
|
+
|
|
2151
|
+
console.log(`Final value of 'a.b.c.d':`)
|
|
2152
|
+
printValue(expression.value);
|
|
2153
|
+
} finally {
|
|
2154
|
+
// Always dispose of expressions after use.
|
|
2155
|
+
expression.dispose();
|
|
2156
|
+
}
|
|
2157
|
+
})();
|
|
2158
|
+
```
|
|
2159
|
+
|
|
2160
|
+
### Multiplication expression
|
|
2161
|
+
|
|
2162
|
+
```ts
|
|
2163
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2164
|
+
import {
|
|
2165
|
+
IExpressionFactory,
|
|
2166
|
+
RsXExpressionParserInjectionTokens,
|
|
2167
|
+
RsXExpressionParserModule
|
|
2168
|
+
} from '@rs-x/expression-parser';
|
|
2169
|
+
|
|
2170
|
+
// Load the expression parser module into the injection container
|
|
2171
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2172
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2173
|
+
|
|
2174
|
+
export const run = (async () => {
|
|
2175
|
+
const expressionContext = {
|
|
2176
|
+
a: 1,
|
|
2177
|
+
b: 3
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
const expression = expressionFactory.create(expressionContext, 'a * b');
|
|
2181
|
+
|
|
2182
|
+
try {
|
|
2183
|
+
// Wait until the expression has been resolved (has a value)
|
|
2184
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2185
|
+
|
|
2186
|
+
console.log(`Initial value of 'a * b':`);
|
|
2187
|
+
expression.changed.subscribe((change) => {
|
|
2188
|
+
console.log(change.value);
|
|
2189
|
+
});
|
|
2190
|
+
|
|
2191
|
+
console.log(`Value of 'a * b' after changing 'a' to '6':`);
|
|
2192
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 6; })
|
|
2193
|
+
|
|
2194
|
+
console.log(`Value of 'a * b' after changing 'b' to '4':`)
|
|
2195
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; })
|
|
2196
|
+
|
|
2197
|
+
console.log(`Final value of 'a * b':`)
|
|
2198
|
+
console.log(expression.value);
|
|
2199
|
+
} finally {
|
|
2200
|
+
// Always dispose of expressions after use.
|
|
2201
|
+
expression.dispose();
|
|
2202
|
+
}
|
|
2203
|
+
})();
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
```
|
|
2207
|
+
|
|
2208
|
+
### New expression
|
|
2209
|
+
|
|
2210
|
+
```ts
|
|
2211
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
2212
|
+
import {
|
|
2213
|
+
IExpressionFactory,
|
|
2214
|
+
RsXExpressionParserInjectionTokens,
|
|
2215
|
+
RsXExpressionParserModule
|
|
2216
|
+
} from '@rs-x/expression-parser';
|
|
2217
|
+
|
|
2218
|
+
// Load the expression parser module into the injection container
|
|
2219
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2220
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2221
|
+
|
|
2222
|
+
export const run = (async () => {
|
|
2223
|
+
class Value {
|
|
2224
|
+
constructor(public readonly value: number) { }
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
class Add10 {
|
|
2228
|
+
constructor(public readonly value: number) {
|
|
2229
|
+
this.value += 10;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
const expressionContext = {
|
|
2234
|
+
type: Value,
|
|
2235
|
+
value: 10,
|
|
2236
|
+
};
|
|
2237
|
+
|
|
2238
|
+
const expression = expressionFactory.create(expressionContext, 'new type(value)');
|
|
2239
|
+
|
|
2240
|
+
function print(instance: unknown): void {
|
|
2241
|
+
console.log(instance.constructor.name);
|
|
2242
|
+
printValue(instance);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
try {
|
|
2246
|
+
// Wait until the expression has been resolved (has a value)
|
|
2247
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2248
|
+
|
|
2249
|
+
console.log(`Initial value of 'new type(value)':`);
|
|
2250
|
+
expression.changed.subscribe((change) => {
|
|
2251
|
+
print(change.value)
|
|
2252
|
+
});
|
|
2253
|
+
|
|
2254
|
+
console.log(`Value of 'new type(value)' after changing 'value' to '20':`);
|
|
2255
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.value = 20; })
|
|
2256
|
+
|
|
2257
|
+
console.log(`Value of 'new type(value)' after changing 'type' to 'Add10':`)
|
|
2258
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.type = Add10; })
|
|
2259
|
+
|
|
2260
|
+
console.log(`Final value of 'new type(value)':`)
|
|
2261
|
+
print(expression.value);
|
|
2262
|
+
|
|
2263
|
+
} finally {
|
|
2264
|
+
// Always dispose of expressions after use.
|
|
2265
|
+
expression.dispose();
|
|
2266
|
+
}
|
|
2267
|
+
})();
|
|
2268
|
+
|
|
2269
|
+
|
|
2270
|
+
```
|
|
2271
|
+
|
|
2272
|
+
### Nullish coalescing expression
|
|
2273
|
+
|
|
2274
|
+
```ts
|
|
2275
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2276
|
+
import {
|
|
2277
|
+
IExpressionFactory,
|
|
2278
|
+
RsXExpressionParserInjectionTokens,
|
|
2279
|
+
RsXExpressionParserModule
|
|
2280
|
+
} from '@rs-x/expression-parser';
|
|
2281
|
+
|
|
2282
|
+
// Load the expression parser module into the injection container
|
|
2283
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2284
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2285
|
+
|
|
2286
|
+
export const run = (async () => {
|
|
2287
|
+
const expressionContext = {
|
|
2288
|
+
a: null,
|
|
2289
|
+
b: 10,
|
|
2290
|
+
};
|
|
2291
|
+
|
|
2292
|
+
const expression = expressionFactory.create(expressionContext, 'a ?? b');
|
|
2293
|
+
|
|
2294
|
+
try {
|
|
2295
|
+
// Wait until the expression has been resolved (has a value)
|
|
2296
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2297
|
+
|
|
2298
|
+
console.log(`Initial value of 'a ?? b':`);
|
|
2299
|
+
expression.changed.subscribe((change) => {
|
|
2300
|
+
console.log(change.value);
|
|
2301
|
+
});
|
|
2302
|
+
|
|
2303
|
+
console.log(`Value of 'a ?? b' after changing 'b' to '6':`);
|
|
2304
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 6; })
|
|
2305
|
+
|
|
2306
|
+
console.log(`Value of 'a ?? b' after changing 'a' to '10':`)
|
|
2307
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 10; })
|
|
2308
|
+
|
|
2309
|
+
console.log(`Value of 'a ?? b' after changing 'a' to 'null':`)
|
|
2310
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = null; })
|
|
2311
|
+
|
|
2312
|
+
|
|
2313
|
+
console.log(`Final value of 'a ?? b'':`)
|
|
2314
|
+
console.log(expression.value);
|
|
2315
|
+
} finally {
|
|
2316
|
+
// Always dispose of expressions after use.
|
|
2317
|
+
expression.dispose();
|
|
2318
|
+
}
|
|
2319
|
+
})();
|
|
2320
|
+
|
|
2321
|
+
|
|
2322
|
+
```
|
|
2323
|
+
|
|
2324
|
+
### Object expression
|
|
2325
|
+
|
|
2326
|
+
```ts
|
|
2327
|
+
import { emptyFunction, InjectionContainer, printValue, WaitForEvent } from '@rs-x/core';
|
|
2328
|
+
import {
|
|
2329
|
+
IExpressionFactory,
|
|
2330
|
+
RsXExpressionParserInjectionTokens,
|
|
2331
|
+
RsXExpressionParserModule
|
|
2332
|
+
} from '@rs-x/expression-parser';
|
|
2333
|
+
|
|
2334
|
+
// Load the expression parser module into the injection container
|
|
2335
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2336
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2337
|
+
|
|
2338
|
+
export const run = (async () => {
|
|
2339
|
+
const expressionContext = {
|
|
2340
|
+
x: 10,
|
|
2341
|
+
y: 20,
|
|
2342
|
+
};
|
|
2343
|
+
|
|
2344
|
+
const expression = expressionFactory.create(expressionContext, '({ a: x, b: y })');
|
|
2345
|
+
|
|
2346
|
+
try {
|
|
2347
|
+
// Wait until the expression has been resolved (has a value)
|
|
2348
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2349
|
+
|
|
2350
|
+
console.log(`Initial value of '({ a: x, b: y })':`);
|
|
2351
|
+
expression.changed.subscribe((change) => {
|
|
2352
|
+
printValue(change.value)
|
|
2353
|
+
});
|
|
2354
|
+
|
|
2355
|
+
console.log(`Value of '({ a: x, b: y })' after changing 'x' to '100':`);
|
|
2356
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.x = 100; })
|
|
2357
|
+
|
|
2358
|
+
console.log(`Value of '({ a: x, b: y })' after changing 'y' to '200':`);
|
|
2359
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.y = 200; })
|
|
2360
|
+
|
|
2361
|
+
console.log(`Final value of '({ a: x, b: y })':`)
|
|
2362
|
+
printValue(expression.value);
|
|
2363
|
+
|
|
2364
|
+
} finally {
|
|
2365
|
+
// Always dispose of expressions after use.
|
|
2366
|
+
expression.dispose();
|
|
2367
|
+
}
|
|
2368
|
+
})();
|
|
2369
|
+
|
|
2370
|
+
|
|
2371
|
+
```
|
|
2372
|
+
|
|
2373
|
+
### Remainder expression
|
|
2374
|
+
|
|
2375
|
+
```ts
|
|
2376
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2377
|
+
import {
|
|
2378
|
+
IExpressionFactory,
|
|
2379
|
+
RsXExpressionParserInjectionTokens,
|
|
2380
|
+
RsXExpressionParserModule
|
|
2381
|
+
} from '@rs-x/expression-parser';
|
|
2382
|
+
|
|
2383
|
+
// Load the expression parser module into the injection container
|
|
2384
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2385
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2386
|
+
|
|
2387
|
+
export const run = (async () => {
|
|
2388
|
+
const expressionContext = {
|
|
2389
|
+
a: 5,
|
|
2390
|
+
b: 2
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
const expression = expressionFactory.create(expressionContext, 'a % b');
|
|
2394
|
+
|
|
2395
|
+
try {
|
|
2396
|
+
// Wait until the expression has been resolved (has a value)
|
|
2397
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2398
|
+
|
|
2399
|
+
console.log(`Initial value of a % b':`);
|
|
2400
|
+
expression.changed.subscribe((change) => {
|
|
2401
|
+
console.log(change.value);
|
|
2402
|
+
});
|
|
2403
|
+
|
|
2404
|
+
console.log(`Value of 'a % b' after changing 'a' to '6':`);
|
|
2405
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 6; })
|
|
2406
|
+
|
|
2407
|
+
console.log(`Value of 'a % b after changing 'b' to '4':`)
|
|
2408
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; })
|
|
2409
|
+
|
|
2410
|
+
console.log(`Final value of 'a % b':`)
|
|
2411
|
+
console.log(expression.value);
|
|
2412
|
+
} finally {
|
|
2413
|
+
// Always dispose of expressions after use.
|
|
2414
|
+
expression.dispose();
|
|
2415
|
+
}
|
|
2416
|
+
})();
|
|
2417
|
+
|
|
2418
|
+
|
|
2419
|
+
```
|
|
2420
|
+
|
|
2421
|
+
### Sequence expression
|
|
2422
|
+
|
|
2423
|
+
```ts
|
|
2424
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2425
|
+
import {
|
|
2426
|
+
IExpressionFactory,
|
|
2427
|
+
RsXExpressionParserInjectionTokens,
|
|
2428
|
+
RsXExpressionParserModule
|
|
2429
|
+
} from '@rs-x/expression-parser';
|
|
2430
|
+
|
|
2431
|
+
// Load the expression parser module into the injection container
|
|
2432
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2433
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2434
|
+
|
|
2435
|
+
export const run = (async () => {
|
|
2436
|
+
const expressionContext = {
|
|
2437
|
+
b: 2,
|
|
2438
|
+
value: 100,
|
|
2439
|
+
setB(v: number) {
|
|
2440
|
+
this.b = v;
|
|
2441
|
+
},
|
|
2442
|
+
};
|
|
2443
|
+
|
|
2444
|
+
const expression = expressionFactory.create(expressionContext, '(setB(value), b)');
|
|
2445
|
+
|
|
2446
|
+
try {
|
|
2447
|
+
// Wait until the expression has been resolved (has a value)
|
|
2448
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2449
|
+
|
|
2450
|
+
console.log(`Initial value of (setB(value), b)':`);
|
|
2451
|
+
expression.changed.subscribe((change) => {
|
|
2452
|
+
console.log(change.value);
|
|
2453
|
+
});
|
|
2454
|
+
|
|
2455
|
+
console.log(`Value of '(setB(value)', b)' after changing 'value' to '200':`);
|
|
2456
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.value = 200; })
|
|
2457
|
+
|
|
2458
|
+
|
|
2459
|
+
console.log(`Value of '(setB(value)', b)' after changing 'b' to '300':`);
|
|
2460
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 300; })
|
|
2461
|
+
|
|
2462
|
+
|
|
2463
|
+
console.log(`Final value of '(setB(value), b)':`)
|
|
2464
|
+
console.log(expression.value);
|
|
2465
|
+
} finally {
|
|
2466
|
+
// Always dispose of expressions after use.
|
|
2467
|
+
expression.dispose();
|
|
2468
|
+
}
|
|
2469
|
+
})();
|
|
2470
|
+
|
|
2471
|
+
|
|
2472
|
+
```
|
|
2473
|
+
|
|
2474
|
+
### Strict equality expression
|
|
2475
|
+
|
|
2476
|
+
```ts
|
|
2477
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2478
|
+
import {
|
|
2479
|
+
IExpressionFactory,
|
|
2480
|
+
RsXExpressionParserInjectionTokens,
|
|
2481
|
+
RsXExpressionParserModule
|
|
2482
|
+
} from '@rs-x/expression-parser';
|
|
2483
|
+
|
|
2484
|
+
// Load the expression parser module into the injection container
|
|
2485
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2486
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2487
|
+
|
|
2488
|
+
export const run = (async () => {
|
|
2489
|
+
const expressionContext = {
|
|
2490
|
+
a: 3,
|
|
2491
|
+
b: 2 as string| number
|
|
2492
|
+
};
|
|
2493
|
+
|
|
2494
|
+
const expression = expressionFactory.create(expressionContext, 'a === b');
|
|
2495
|
+
|
|
2496
|
+
try {
|
|
2497
|
+
// Wait until the expression has been resolved (has a value)
|
|
2498
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2499
|
+
|
|
2500
|
+
console.log(`Initial value of 'a === b':`)
|
|
2501
|
+
expression.changed.subscribe((change) => {
|
|
2502
|
+
console.log(change.value);
|
|
2503
|
+
});
|
|
2504
|
+
|
|
2505
|
+
console.log(`Value of 'a === b' after changing 'a' to '2':`);
|
|
2506
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 2; });
|
|
2507
|
+
|
|
2508
|
+
console.log(`Value of 'a === b' after changing 'b' to '"2"':`)
|
|
2509
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = '2'; });
|
|
2510
|
+
|
|
2511
|
+
console.log(`Final value of 'a === b':`)
|
|
2512
|
+
console.log(expression.value);
|
|
2513
|
+
} finally {
|
|
2514
|
+
// Always dispose of expressions after use.
|
|
2515
|
+
expression.dispose();
|
|
2516
|
+
}
|
|
2517
|
+
})();
|
|
2518
|
+
|
|
2519
|
+
|
|
2520
|
+
```
|
|
2521
|
+
|
|
2522
|
+
### Strict inequality expression
|
|
2523
|
+
|
|
2524
|
+
```ts
|
|
2525
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2526
|
+
import {
|
|
2527
|
+
IExpressionFactory,
|
|
2528
|
+
RsXExpressionParserInjectionTokens,
|
|
2529
|
+
RsXExpressionParserModule
|
|
2530
|
+
} from '@rs-x/expression-parser';
|
|
2531
|
+
|
|
2532
|
+
// Load the expression parser module into the injection container
|
|
2533
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2534
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2535
|
+
|
|
2536
|
+
export const run = (async () => {
|
|
2537
|
+
const expressionContext = {
|
|
2538
|
+
a: 2 as string | number,
|
|
2539
|
+
b: 2 as string | number
|
|
2540
|
+
};
|
|
2541
|
+
|
|
2542
|
+
const expression = expressionFactory.create(expressionContext, 'a !== b');
|
|
2543
|
+
|
|
2544
|
+
try {
|
|
2545
|
+
// Wait until the expression has been resolved (has a value)
|
|
2546
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2547
|
+
|
|
2548
|
+
console.log(`Initial value of 'a !== b':`)
|
|
2549
|
+
expression.changed.subscribe((change) => {
|
|
2550
|
+
console.log(change.value);
|
|
2551
|
+
});
|
|
2552
|
+
|
|
2553
|
+
console.log(`Value of 'a !== b' after changing 'a' to '"2"':`);
|
|
2554
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = '2'; });
|
|
2555
|
+
|
|
2556
|
+
console.log(`Value of 'a !== b' after changing 'b' to '"2"':`)
|
|
2557
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = '2'; });
|
|
2558
|
+
|
|
2559
|
+
console.log(`Final value of 'a !== b':`)
|
|
2560
|
+
console.log(expression.value);
|
|
2561
|
+
} finally {
|
|
2562
|
+
// Always dispose of expressions after use.
|
|
2563
|
+
expression.dispose();
|
|
2564
|
+
}
|
|
2565
|
+
})();
|
|
2566
|
+
|
|
2567
|
+
|
|
2568
|
+
```
|
|
2569
|
+
|
|
2570
|
+
### Substraction expression
|
|
2571
|
+
|
|
2572
|
+
```ts
|
|
2573
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2574
|
+
import {
|
|
2575
|
+
IExpressionFactory,
|
|
2576
|
+
RsXExpressionParserInjectionTokens,
|
|
2577
|
+
RsXExpressionParserModule
|
|
2578
|
+
} from '@rs-x/expression-parser';
|
|
2579
|
+
|
|
2580
|
+
// Load the expression parser module into the injection container
|
|
2581
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2582
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2583
|
+
|
|
2584
|
+
export const run = (async () => {
|
|
2585
|
+
const expressionContext = {
|
|
2586
|
+
a: 1,
|
|
2587
|
+
b: 3
|
|
2588
|
+
};
|
|
2589
|
+
|
|
2590
|
+
const expression = expressionFactory.create(expressionContext, 'a - b');
|
|
2591
|
+
|
|
2592
|
+
try {
|
|
2593
|
+
// Wait until the expression has been resolved (has a value)
|
|
2594
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2595
|
+
|
|
2596
|
+
console.log(`Initial value of 'a - b':`);
|
|
2597
|
+
expression.changed.subscribe((change) => {
|
|
2598
|
+
console.log(change.value);
|
|
2599
|
+
});
|
|
2600
|
+
|
|
2601
|
+
console.log(`Value of 'a - b' after changing 'a' to '6':`);
|
|
2602
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.a = 6; })
|
|
2603
|
+
|
|
2604
|
+
console.log(`Value of 'a - b' after changing 'b' to '4':`)
|
|
2605
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.b = 4; })
|
|
2606
|
+
|
|
2607
|
+
console.log(`Final value of 'a - b':`)
|
|
2608
|
+
console.log(expression.value);
|
|
2609
|
+
} finally {
|
|
2610
|
+
// Always dispose of expressions after use.
|
|
2611
|
+
expression.dispose();
|
|
2612
|
+
}
|
|
2613
|
+
})();
|
|
2614
|
+
|
|
2615
|
+
|
|
2616
|
+
```
|
|
2617
|
+
|
|
2618
|
+
### Template string expression
|
|
2619
|
+
|
|
2620
|
+
```ts
|
|
2621
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2622
|
+
import {
|
|
2623
|
+
IExpressionFactory,
|
|
2624
|
+
RsXExpressionParserInjectionTokens,
|
|
2625
|
+
RsXExpressionParserModule
|
|
2626
|
+
} from '@rs-x/expression-parser';
|
|
2627
|
+
|
|
2628
|
+
// Load the expression parser module into the injection container
|
|
2629
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2630
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2631
|
+
|
|
2632
|
+
export const run = (async () => {
|
|
2633
|
+
const expressionContext = {
|
|
2634
|
+
message: 'hi',
|
|
2635
|
+
};
|
|
2636
|
+
|
|
2637
|
+
const expression = expressionFactory.create(expressionContext, '`Say ${message}`');
|
|
2638
|
+
|
|
2639
|
+
try {
|
|
2640
|
+
// Wait until the expression has been resolved (has a value)
|
|
2641
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2642
|
+
|
|
2643
|
+
console.log("Initial value of '`Say ${message}`':");
|
|
2644
|
+
expression.changed.subscribe((change) => {
|
|
2645
|
+
console.log(change.value);
|
|
2646
|
+
});
|
|
2647
|
+
|
|
2648
|
+
console.log("Value of '`Say ${message}`' after changing message a to 'hello':");
|
|
2649
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.message = 'hello'; })
|
|
2650
|
+
|
|
2651
|
+
console.log("Final value of '`Say ${message}`':")
|
|
2652
|
+
console.log(expression.value);
|
|
2653
|
+
} finally {
|
|
2654
|
+
// Always dispose of expressions after use.
|
|
2655
|
+
expression.dispose();
|
|
2656
|
+
}
|
|
2657
|
+
})();
|
|
2658
|
+
|
|
2659
|
+
|
|
2660
|
+
```
|
|
2661
|
+
|
|
2662
|
+
### Typeof expression
|
|
2663
|
+
|
|
2664
|
+
```ts
|
|
2665
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2666
|
+
import {
|
|
2667
|
+
IExpressionFactory,
|
|
2668
|
+
RsXExpressionParserInjectionTokens,
|
|
2669
|
+
RsXExpressionParserModule
|
|
2670
|
+
} from '@rs-x/expression-parser';
|
|
2671
|
+
|
|
2672
|
+
// Load the expression parser module into the injection container
|
|
2673
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2674
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2675
|
+
|
|
2676
|
+
export const run = (async () => {
|
|
2677
|
+
const expressionContext = {
|
|
2678
|
+
index: 0,
|
|
2679
|
+
a: ['1', 1],
|
|
2680
|
+
};
|
|
2681
|
+
|
|
2682
|
+
const expression = expressionFactory.create(expressionContext, 'typeof a[index]');
|
|
2683
|
+
|
|
2684
|
+
try {
|
|
2685
|
+
// Wait until the expression has been resolved (has a value)
|
|
2686
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2687
|
+
|
|
2688
|
+
console.log(`Initial value of 'typeof a[index]':`);
|
|
2689
|
+
expression.changed.subscribe((change) => {
|
|
2690
|
+
console.log(change.value);
|
|
2691
|
+
});
|
|
2692
|
+
|
|
2693
|
+
console.log(`Value of 'typeof a[index]' after changing 'index' to '1':`);
|
|
2694
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.index = 1; })
|
|
2695
|
+
|
|
2696
|
+
console.log(`Final value of 'typeof a[index]':`)
|
|
2697
|
+
console.log(expression.value);
|
|
2698
|
+
} finally {
|
|
2699
|
+
// Always dispose of expressions after use.
|
|
2700
|
+
expression.dispose();
|
|
2701
|
+
}
|
|
2702
|
+
})();
|
|
2703
|
+
|
|
2704
|
+
|
|
2705
|
+
```
|
|
2706
|
+
|
|
2707
|
+
### Unary negation expression
|
|
2708
|
+
|
|
2709
|
+
```ts
|
|
2710
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2711
|
+
import {
|
|
2712
|
+
IExpressionFactory,
|
|
2713
|
+
RsXExpressionParserInjectionTokens,
|
|
2714
|
+
RsXExpressionParserModule
|
|
2715
|
+
} from '@rs-x/expression-parser';
|
|
2716
|
+
|
|
2717
|
+
// Load the expression parser module into the injection container
|
|
2718
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2719
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2720
|
+
|
|
2721
|
+
export const run = (async () => {
|
|
2722
|
+
const expressionContext = {
|
|
2723
|
+
value: 1
|
|
2724
|
+
};
|
|
2725
|
+
|
|
2726
|
+
const expression = expressionFactory.create(expressionContext, '-value');
|
|
2727
|
+
|
|
2728
|
+
try {
|
|
2729
|
+
// Wait until the expression has been resolved (has a value)
|
|
2730
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2731
|
+
|
|
2732
|
+
console.log(`Initial value of '-value':`);
|
|
2733
|
+
expression.changed.subscribe((change) => {
|
|
2734
|
+
console.log(change.value);
|
|
2735
|
+
});
|
|
2736
|
+
|
|
2737
|
+
console.log(`Value of '-value' after changing 'value' to '-5':`);
|
|
2738
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.value = -5; })
|
|
2739
|
+
|
|
2740
|
+
console.log(`Final value of '-value':`)
|
|
2741
|
+
console.log(expression.value);
|
|
2742
|
+
} finally {
|
|
2743
|
+
// Always dispose of expressions after use.
|
|
2744
|
+
expression.dispose();
|
|
2745
|
+
}
|
|
2746
|
+
})();
|
|
2747
|
+
|
|
2748
|
+
|
|
2749
|
+
```
|
|
2750
|
+
|
|
2751
|
+
### Unary plus expression
|
|
2752
|
+
|
|
2753
|
+
```ts
|
|
2754
|
+
import { emptyFunction, InjectionContainer, WaitForEvent } from '@rs-x/core';
|
|
2755
|
+
import {
|
|
2756
|
+
IExpressionFactory,
|
|
2757
|
+
RsXExpressionParserInjectionTokens,
|
|
2758
|
+
RsXExpressionParserModule
|
|
2759
|
+
} from '@rs-x/expression-parser';
|
|
2760
|
+
|
|
2761
|
+
// Load the expression parser module into the injection container
|
|
2762
|
+
InjectionContainer.load(RsXExpressionParserModule);
|
|
2763
|
+
const expressionFactory: IExpressionFactory = InjectionContainer.get(RsXExpressionParserInjectionTokens.IExpressionFactory);
|
|
2764
|
+
|
|
2765
|
+
export const run = (async () => {
|
|
2766
|
+
const expressionContext = {
|
|
2767
|
+
value: '2'
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
const expression = expressionFactory.create(expressionContext, '+value');
|
|
2771
|
+
|
|
2772
|
+
try {
|
|
2773
|
+
// Wait until the expression has been resolved (has a value)
|
|
2774
|
+
await new WaitForEvent(expression, 'changed').wait(emptyFunction);
|
|
2775
|
+
|
|
2776
|
+
console.log(`Initial value of '+value':`);
|
|
2777
|
+
expression.changed.subscribe((change) => {
|
|
2778
|
+
console.log(change.value);
|
|
2779
|
+
});
|
|
2780
|
+
|
|
2781
|
+
console.log(`Value of '+value' after changing 'value' to '"6"':`);
|
|
2782
|
+
await new WaitForEvent(expression, 'changed', { ignoreInitialValue: true }).wait(() => { expressionContext.value = '6'; })
|
|
2783
|
+
|
|
2784
|
+
console.log(`Final value of '+value':`)
|
|
2785
|
+
console.log(expression.value);
|
|
2786
|
+
} finally {
|
|
2787
|
+
// Always dispose of expressions after use.
|
|
2788
|
+
expression.dispose();
|
|
2789
|
+
}
|
|
2790
|
+
})();
|
|
2791
|
+
|
|
2792
|
+
|
|
2793
|
+
```
|