@player-ui/player 0.3.1-next.1 → 0.3.1
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/dist/index.cjs.js +899 -336
- package/dist/index.d.ts +275 -93
- package/dist/index.esm.js +890 -334
- package/dist/player.dev.js +11429 -0
- package/dist/player.prod.js +2 -0
- package/package.json +16 -5
- package/src/binding/binding.ts +8 -0
- package/src/binding/index.ts +14 -4
- package/src/binding/resolver.ts +2 -4
- package/src/binding-grammar/custom/index.ts +17 -9
- package/src/controllers/constants/index.ts +9 -5
- package/src/controllers/{data.ts → data/controller.ts} +62 -61
- package/src/controllers/data/index.ts +1 -0
- package/src/controllers/data/utils.ts +42 -0
- package/src/controllers/flow/controller.ts +16 -12
- package/src/controllers/flow/flow.ts +6 -1
- package/src/controllers/index.ts +1 -1
- package/src/controllers/validation/binding-tracker.ts +42 -19
- package/src/controllers/validation/controller.ts +375 -148
- package/src/controllers/view/asset-transform.ts +4 -1
- package/src/controllers/view/controller.ts +20 -3
- package/src/data/dependency-tracker.ts +14 -0
- package/src/data/local-model.ts +25 -1
- package/src/data/model.ts +60 -8
- package/src/data/noop-model.ts +2 -0
- package/src/expressions/evaluator-functions.ts +24 -2
- package/src/expressions/evaluator.ts +38 -34
- package/src/expressions/index.ts +1 -0
- package/src/expressions/parser.ts +116 -44
- package/src/expressions/types.ts +50 -17
- package/src/expressions/utils.ts +143 -1
- package/src/player.ts +60 -46
- package/src/plugins/default-exp-plugin.ts +57 -0
- package/src/plugins/flow-exp-plugin.ts +2 -2
- package/src/schema/schema.ts +28 -9
- package/src/string-resolver/index.ts +26 -9
- package/src/types.ts +6 -3
- package/src/validator/binding-map-splice.ts +59 -0
- package/src/validator/index.ts +1 -0
- package/src/validator/types.ts +11 -3
- package/src/validator/validation-middleware.ts +58 -6
- package/src/view/parser/index.ts +51 -3
- package/src/view/plugins/applicability.ts +1 -1
- package/src/view/plugins/string-resolver.ts +35 -9
- package/src/view/plugins/template-plugin.ts +1 -6
- package/src/view/resolver/index.ts +119 -54
- package/src/view/resolver/types.ts +48 -7
|
@@ -92,7 +92,10 @@ export class AssetTransformCorePlugin {
|
|
|
92
92
|
const transform = this.registry.get(node.value);
|
|
93
93
|
|
|
94
94
|
if (transform?.beforeResolve) {
|
|
95
|
-
const store = getStore(
|
|
95
|
+
const store = getStore(
|
|
96
|
+
options.node ?? node,
|
|
97
|
+
this.beforeResolveSymbol
|
|
98
|
+
);
|
|
96
99
|
|
|
97
100
|
return transform.beforeResolve(node, options, store);
|
|
98
101
|
}
|
|
@@ -8,7 +8,7 @@ import type { Resolve } from '../../view';
|
|
|
8
8
|
import { ViewInstance } from '../../view';
|
|
9
9
|
import type { Logger } from '../../logger';
|
|
10
10
|
import type { FlowInstance, FlowController } from '../flow';
|
|
11
|
-
import type { DataController } from '../data';
|
|
11
|
+
import type { DataController } from '../data/controller';
|
|
12
12
|
import { AssetTransformCorePlugin } from './asset-transform';
|
|
13
13
|
import type { TransformRegistry } from './types';
|
|
14
14
|
import type { BindingInstance } from '../../binding';
|
|
@@ -75,14 +75,31 @@ export class ViewController {
|
|
|
75
75
|
}
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
/** Trigger a view update */
|
|
79
|
+
const update = (updates: Set<BindingInstance>) => {
|
|
79
80
|
if (this.currentView) {
|
|
80
81
|
if (this.optimizeUpdates) {
|
|
81
|
-
this.queueUpdate(
|
|
82
|
+
this.queueUpdate(updates);
|
|
82
83
|
} else {
|
|
83
84
|
this.currentView.update();
|
|
84
85
|
}
|
|
85
86
|
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
options.model.hooks.onUpdate.tap('viewController', (updates) => {
|
|
90
|
+
update(new Set(updates.map((t) => t.binding)));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
options.model.hooks.onDelete.tap('viewController', (binding) => {
|
|
94
|
+
const parentBinding = binding.parent();
|
|
95
|
+
const property = binding.key();
|
|
96
|
+
|
|
97
|
+
// Deleting an array item will trigger an update for the entire array
|
|
98
|
+
if (typeof property === 'number' && parentBinding) {
|
|
99
|
+
update(new Set([parentBinding]));
|
|
100
|
+
} else {
|
|
101
|
+
update(new Set([binding]));
|
|
102
|
+
}
|
|
86
103
|
});
|
|
87
104
|
}
|
|
88
105
|
|
|
@@ -157,6 +157,15 @@ export class DependencyMiddleware
|
|
|
157
157
|
|
|
158
158
|
return next?.get(binding, options);
|
|
159
159
|
}
|
|
160
|
+
|
|
161
|
+
public delete(
|
|
162
|
+
binding: BindingInstance,
|
|
163
|
+
options?: DataModelOptions,
|
|
164
|
+
next?: DataModelImpl | undefined
|
|
165
|
+
) {
|
|
166
|
+
this.addWriteDep(binding);
|
|
167
|
+
return next?.delete(binding, options);
|
|
168
|
+
}
|
|
160
169
|
}
|
|
161
170
|
|
|
162
171
|
/** A data-model that tracks dependencies of read/written data */
|
|
@@ -184,4 +193,9 @@ export class DependencyModel<Options = DataModelOptions>
|
|
|
184
193
|
|
|
185
194
|
return this.rootModel.get(binding, options);
|
|
186
195
|
}
|
|
196
|
+
|
|
197
|
+
public delete(binding: BindingInstance, options?: Options) {
|
|
198
|
+
this.addWriteDep(binding);
|
|
199
|
+
return this.rootModel.delete(binding, options);
|
|
200
|
+
}
|
|
187
201
|
}
|
package/src/data/local-model.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import get from 'dlv';
|
|
2
|
-
import { setIn } from 'timm';
|
|
2
|
+
import { setIn, omit, removeAt } from 'timm';
|
|
3
3
|
import type { BindingInstance } from '../binding';
|
|
4
4
|
import type { BatchSetTransaction, DataModelImpl, Updates } from './model';
|
|
5
5
|
|
|
@@ -38,4 +38,28 @@ export class LocalModel implements DataModelImpl {
|
|
|
38
38
|
});
|
|
39
39
|
return effectiveOperations;
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
public delete(binding: BindingInstance) {
|
|
43
|
+
const parentBinding = binding.parent();
|
|
44
|
+
|
|
45
|
+
if (parentBinding) {
|
|
46
|
+
const parentValue = this.get(parentBinding);
|
|
47
|
+
|
|
48
|
+
if (parentValue !== undefined) {
|
|
49
|
+
if (Array.isArray(parentValue)) {
|
|
50
|
+
this.model = setIn(
|
|
51
|
+
this.model,
|
|
52
|
+
parentBinding.asArray(),
|
|
53
|
+
removeAt(parentValue, binding.key() as number)
|
|
54
|
+
) as any;
|
|
55
|
+
} else {
|
|
56
|
+
this.model = setIn(
|
|
57
|
+
this.model,
|
|
58
|
+
parentBinding.asArray(),
|
|
59
|
+
omit(parentValue, binding.key() as string)
|
|
60
|
+
) as any;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
41
65
|
}
|
package/src/data/model.ts
CHANGED
|
@@ -41,6 +41,11 @@ export interface DataModelOptions {
|
|
|
41
41
|
*/
|
|
42
42
|
ignoreDefaultValue?: boolean;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* A flag to indicate that this update should happen silently
|
|
46
|
+
*/
|
|
47
|
+
silent?: boolean;
|
|
48
|
+
|
|
44
49
|
/** Other context associated with this request */
|
|
45
50
|
context?: {
|
|
46
51
|
/** The data model to use when getting other data from the context of this request */
|
|
@@ -51,11 +56,13 @@ export interface DataModelOptions {
|
|
|
51
56
|
export interface DataModelWithParser<Options = DataModelOptions> {
|
|
52
57
|
get(binding: BindingLike, options?: Options): any;
|
|
53
58
|
set(transaction: [BindingLike, any][], options?: Options): Updates;
|
|
59
|
+
delete(binding: BindingLike, options?: Options): void;
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
export interface DataModelImpl<Options = DataModelOptions> {
|
|
57
63
|
get(binding: BindingInstance, options?: Options): any;
|
|
58
64
|
set(transaction: BatchSetTransaction, options?: Options): Updates;
|
|
65
|
+
delete(binding: BindingInstance, options?: Options): void;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
export interface DataModelMiddleware {
|
|
@@ -67,11 +74,19 @@ export interface DataModelMiddleware {
|
|
|
67
74
|
options?: DataModelOptions,
|
|
68
75
|
next?: DataModelImpl
|
|
69
76
|
): Updates;
|
|
77
|
+
|
|
70
78
|
get(
|
|
71
79
|
binding: BindingInstance,
|
|
72
80
|
options?: DataModelOptions,
|
|
73
81
|
next?: DataModelImpl
|
|
74
82
|
): any;
|
|
83
|
+
|
|
84
|
+
delete?(
|
|
85
|
+
binding: BindingInstance,
|
|
86
|
+
options?: DataModelOptions,
|
|
87
|
+
next?: DataModelImpl
|
|
88
|
+
): void;
|
|
89
|
+
|
|
75
90
|
reset?(): void;
|
|
76
91
|
}
|
|
77
92
|
|
|
@@ -81,12 +96,16 @@ export function withParser<Options = unknown>(
|
|
|
81
96
|
parseBinding: BindingFactory
|
|
82
97
|
): DataModelWithParser<Options> {
|
|
83
98
|
/** Parse something into a binding if it requires it */
|
|
84
|
-
function maybeParse(
|
|
99
|
+
function maybeParse(
|
|
100
|
+
binding: BindingLike,
|
|
101
|
+
readOnly: boolean
|
|
102
|
+
): BindingInstance {
|
|
85
103
|
const parsed = isBinding(binding)
|
|
86
104
|
? binding
|
|
87
105
|
: parseBinding(binding, {
|
|
88
106
|
get: model.get,
|
|
89
107
|
set: model.set,
|
|
108
|
+
readOnly,
|
|
90
109
|
});
|
|
91
110
|
|
|
92
111
|
if (!parsed) {
|
|
@@ -98,14 +117,17 @@ export function withParser<Options = unknown>(
|
|
|
98
117
|
|
|
99
118
|
return {
|
|
100
119
|
get(binding, options?: Options) {
|
|
101
|
-
return model.get(maybeParse(binding), options);
|
|
120
|
+
return model.get(maybeParse(binding, true), options);
|
|
102
121
|
},
|
|
103
122
|
set(transaction, options?: Options) {
|
|
104
123
|
return model.set(
|
|
105
|
-
transaction.map(([key, val]) => [maybeParse(key), val]),
|
|
124
|
+
transaction.map(([key, val]) => [maybeParse(key, false), val]),
|
|
106
125
|
options
|
|
107
126
|
);
|
|
108
127
|
},
|
|
128
|
+
delete(binding, options?: Options) {
|
|
129
|
+
return model.delete(maybeParse(binding, false), options);
|
|
130
|
+
},
|
|
109
131
|
};
|
|
110
132
|
}
|
|
111
133
|
|
|
@@ -120,10 +142,33 @@ export function toModel(
|
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
return {
|
|
123
|
-
get: (binding: BindingInstance, options?: DataModelOptions) =>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
middleware.
|
|
145
|
+
get: (binding: BindingInstance, options?: DataModelOptions) => {
|
|
146
|
+
const resolvedOptions = options ?? defaultOptions;
|
|
147
|
+
|
|
148
|
+
if (middleware.get) {
|
|
149
|
+
return middleware.get(binding, resolvedOptions, next);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return next?.get(binding, resolvedOptions);
|
|
153
|
+
},
|
|
154
|
+
set: (transaction: BatchSetTransaction, options?: DataModelOptions) => {
|
|
155
|
+
const resolvedOptions = options ?? defaultOptions;
|
|
156
|
+
|
|
157
|
+
if (middleware.set) {
|
|
158
|
+
return middleware.set(transaction, resolvedOptions, next);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return next?.set(transaction, resolvedOptions);
|
|
162
|
+
},
|
|
163
|
+
delete: (binding: BindingInstance, options?: DataModelOptions) => {
|
|
164
|
+
const resolvedOptions = options ?? defaultOptions;
|
|
165
|
+
|
|
166
|
+
if (middleware.delete) {
|
|
167
|
+
return middleware.delete(binding, resolvedOptions, next);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return next?.delete(binding, resolvedOptions);
|
|
171
|
+
},
|
|
127
172
|
};
|
|
128
173
|
}
|
|
129
174
|
|
|
@@ -140,7 +185,7 @@ export function constructModelForPipeline(
|
|
|
140
185
|
}
|
|
141
186
|
|
|
142
187
|
if (pipeline.length === 1) {
|
|
143
|
-
return pipeline[0];
|
|
188
|
+
return toModel(pipeline[0]);
|
|
144
189
|
}
|
|
145
190
|
|
|
146
191
|
/** Default and propagate the options into the nested calls */
|
|
@@ -161,6 +206,9 @@ export function constructModelForPipeline(
|
|
|
161
206
|
set: (transaction, options) => {
|
|
162
207
|
return createModelWithOptions(options)?.set(transaction, options);
|
|
163
208
|
},
|
|
209
|
+
delete: (binding, options) => {
|
|
210
|
+
return createModelWithOptions(options)?.delete(binding, options);
|
|
211
|
+
},
|
|
164
212
|
};
|
|
165
213
|
}
|
|
166
214
|
|
|
@@ -213,4 +261,8 @@ export class PipelinedDataModel implements DataModelImpl {
|
|
|
213
261
|
public get(binding: BindingInstance, options?: DataModelOptions): any {
|
|
214
262
|
return this.effectiveDataModel.get(binding, options);
|
|
215
263
|
}
|
|
264
|
+
|
|
265
|
+
public delete(binding: BindingInstance, options?: DataModelOptions): void {
|
|
266
|
+
return this.effectiveDataModel.delete(binding, options);
|
|
267
|
+
}
|
|
216
268
|
}
|
package/src/data/noop-model.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { Binding } from '@player-ui/types';
|
|
2
2
|
|
|
3
3
|
import type { BindingLike } from '../binding';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
ExpressionHandler,
|
|
6
|
+
ExpressionContext,
|
|
7
|
+
ExpressionNode,
|
|
8
|
+
} from './types';
|
|
5
9
|
|
|
6
10
|
/** Sets a value to the data-model */
|
|
7
11
|
export const setDataVal: ExpressionHandler<[Binding, any], any> = (
|
|
@@ -25,5 +29,23 @@ export const deleteDataVal: ExpressionHandler<[Binding], void> = (
|
|
|
25
29
|
_context: ExpressionContext,
|
|
26
30
|
binding
|
|
27
31
|
) => {
|
|
28
|
-
return _context.model.
|
|
32
|
+
return _context.model.delete(binding);
|
|
29
33
|
};
|
|
34
|
+
|
|
35
|
+
/** Conditional expression handler */
|
|
36
|
+
export const conditional: ExpressionHandler<
|
|
37
|
+
[ExpressionNode, ExpressionNode, ExpressionNode?]
|
|
38
|
+
> = (ctx, condition, ifTrue, ifFalse) => {
|
|
39
|
+
const resolution = ctx.evaluate(condition);
|
|
40
|
+
if (resolution) {
|
|
41
|
+
return ctx.evaluate(ifTrue);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (ifFalse) {
|
|
45
|
+
return ctx.evaluate(ifFalse);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
conditional.resolveParams = false;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SyncWaterfallHook, SyncBailHook } from 'tapable-ts';
|
|
2
|
-
import
|
|
2
|
+
import { parseExpression } from './parser';
|
|
3
3
|
import * as DEFAULT_EXPRESSION_HANDLERS from './evaluator-functions';
|
|
4
|
+
import { isExpressionNode } from './types';
|
|
5
|
+
import { isObjectExpression } from './utils';
|
|
4
6
|
import type {
|
|
5
7
|
ExpressionNode,
|
|
6
8
|
BinaryOperator,
|
|
@@ -9,7 +11,6 @@ import type {
|
|
|
9
11
|
ExpressionContext,
|
|
10
12
|
ExpressionHandler,
|
|
11
13
|
} from './types';
|
|
12
|
-
import { isExpressionNode } from '.';
|
|
13
14
|
|
|
14
15
|
/** a && b -- but handles short cutting if the first value is false */
|
|
15
16
|
const andandOperator: BinaryOperator = (ctx, a, b) => {
|
|
@@ -71,6 +72,11 @@ const DEFAULT_UNARY_OPERATORS: Record<string, UnaryOperator> = {
|
|
|
71
72
|
export interface HookOptions extends ExpressionContext {
|
|
72
73
|
/** Given an expression node */
|
|
73
74
|
resolveNode: (node: ExpressionNode) => any;
|
|
75
|
+
|
|
76
|
+
/** Enabling this flag skips calling the onError hook, and just throws errors back to the caller.
|
|
77
|
+
* The caller is responsible for handling the error.
|
|
78
|
+
*/
|
|
79
|
+
throwErrors?: boolean;
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
export type ExpressionEvaluatorOptions = Omit<
|
|
@@ -92,6 +98,12 @@ export class ExpressionEvaluator {
|
|
|
92
98
|
/** Resolve an AST node for an expression to a value */
|
|
93
99
|
resolve: new SyncWaterfallHook<[any, ExpressionNode, HookOptions]>(),
|
|
94
100
|
|
|
101
|
+
/** Gets the options that will be passed in calls to the resolve hook */
|
|
102
|
+
resolveOptions: new SyncWaterfallHook<[HookOptions]>(),
|
|
103
|
+
|
|
104
|
+
/** Allows users to change the expression to be evaluated before processing */
|
|
105
|
+
beforeEvaluate: new SyncWaterfallHook<[ExpressionType, HookOptions]>(),
|
|
106
|
+
|
|
95
107
|
/**
|
|
96
108
|
* An optional means of handling an error in the expression execution
|
|
97
109
|
* Return true if handled, to stop propagation of the error
|
|
@@ -128,14 +140,22 @@ export class ExpressionEvaluator {
|
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
public evaluate(
|
|
131
|
-
|
|
143
|
+
expr: ExpressionType,
|
|
132
144
|
options?: ExpressionEvaluatorOptions
|
|
133
145
|
): any {
|
|
134
|
-
const
|
|
146
|
+
const resolvedOpts = this.hooks.resolveOptions.call({
|
|
135
147
|
...this.defaultHookOptions,
|
|
136
148
|
...options,
|
|
137
|
-
resolveNode: (node: ExpressionNode) => this._execAST(node,
|
|
138
|
-
};
|
|
149
|
+
resolveNode: (node: ExpressionNode) => this._execAST(node, resolvedOpts),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
let expression = this.hooks.beforeEvaluate.call(expr, resolvedOpts) ?? expr;
|
|
153
|
+
|
|
154
|
+
// Unwrap any returned expression type
|
|
155
|
+
// Since this could also be an object type, we need to recurse through it until we find the end
|
|
156
|
+
while (isObjectExpression(expression)) {
|
|
157
|
+
expression = expression.value;
|
|
158
|
+
}
|
|
139
159
|
|
|
140
160
|
// Check for literals
|
|
141
161
|
if (
|
|
@@ -149,21 +169,17 @@ export class ExpressionEvaluator {
|
|
|
149
169
|
|
|
150
170
|
// Skip doing anything with objects that are _actually_ just parsed expression nodes
|
|
151
171
|
if (isExpressionNode(expression)) {
|
|
152
|
-
return this._execAST(expression,
|
|
172
|
+
return this._execAST(expression, resolvedOpts);
|
|
153
173
|
}
|
|
154
174
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
? expression
|
|
158
|
-
: Object.values(expression);
|
|
159
|
-
|
|
160
|
-
return values.reduce(
|
|
175
|
+
if (Array.isArray(expression)) {
|
|
176
|
+
return expression.reduce(
|
|
161
177
|
(_nothing, exp) => this.evaluate(exp, options),
|
|
162
178
|
null
|
|
163
179
|
);
|
|
164
180
|
}
|
|
165
181
|
|
|
166
|
-
return this._execString(String(expression),
|
|
182
|
+
return this._execString(String(expression), resolvedOpts);
|
|
167
183
|
}
|
|
168
184
|
|
|
169
185
|
public addExpressionFunction<T extends readonly unknown[], R>(
|
|
@@ -212,13 +228,13 @@ export class ExpressionEvaluator {
|
|
|
212
228
|
return this._execAST(storedAST, options);
|
|
213
229
|
}
|
|
214
230
|
|
|
215
|
-
const expAST =
|
|
231
|
+
const expAST = parseExpression(matchedExp);
|
|
216
232
|
this.expressionsCache.set(matchedExp, expAST);
|
|
217
233
|
|
|
218
234
|
return this._execAST(expAST, options);
|
|
219
235
|
} catch (e: any) {
|
|
220
|
-
if (!this.hooks.onError.call(e)) {
|
|
221
|
-
// Only throw the error if it's not handled by the hook
|
|
236
|
+
if (options.throwErrors || !this.hooks.onError.call(e)) {
|
|
237
|
+
// Only throw the error if it's not handled by the hook, or throwErrors is true
|
|
222
238
|
throw e;
|
|
223
239
|
}
|
|
224
240
|
}
|
|
@@ -305,35 +321,23 @@ export class ExpressionEvaluator {
|
|
|
305
321
|
if (node.type === 'CallExpression') {
|
|
306
322
|
const expressionName = node.callTarget.name;
|
|
307
323
|
|
|
308
|
-
// Treat the conditional operator as special.
|
|
309
|
-
// Don't exec the arguments that don't apply
|
|
310
|
-
if (expressionName === 'conditional') {
|
|
311
|
-
const condition = resolveNode(node.args[0]);
|
|
312
|
-
|
|
313
|
-
if (condition) {
|
|
314
|
-
return resolveNode(node.args[1]);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (node.args[2]) {
|
|
318
|
-
return resolveNode(node.args[2]);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
324
|
const operator = this.operators.expressions.get(expressionName);
|
|
325
325
|
|
|
326
326
|
if (!operator) {
|
|
327
327
|
throw new Error(`Unknown expression function: ${expressionName}`);
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
+
if ('resolveParams' in operator && operator.resolveParams === false) {
|
|
331
|
+
return operator(expressionContext, ...node.args);
|
|
332
|
+
}
|
|
333
|
+
|
|
330
334
|
const args = node.args.map((n) => resolveNode(n));
|
|
331
335
|
|
|
332
336
|
return operator(expressionContext, ...args);
|
|
333
337
|
}
|
|
334
338
|
|
|
335
339
|
if (node.type === 'ModelRef') {
|
|
336
|
-
return model.get(node.ref);
|
|
340
|
+
return model.get(node.ref, { context: { model: options.model } });
|
|
337
341
|
}
|
|
338
342
|
|
|
339
343
|
if (node.type === 'MemberExpression') {
|
package/src/expressions/index.ts
CHANGED