@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/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
+ ```