@@ -11,6 +11,7 @@ import {
11
11
isDataModel ,
12
12
isDataModelAttribute ,
13
13
isDataModelFieldAttribute ,
14
+ isInvocationExpr ,
14
15
isLiteralExpr ,
15
16
} from '@zenstackhq/language/ast' ;
16
17
import {
@@ -21,6 +22,7 @@ import {
21
22
isDataModelFieldReference ,
22
23
isEnumFieldReference ,
23
24
isFromStdlib ,
25
+ isValidationAttribute ,
24
26
} from '@zenstackhq/sdk' ;
25
27
import { AstNode , streamAst , ValidationAcceptor } from 'langium' ;
26
28
import { match , P } from 'ts-pattern' ;
@@ -70,20 +72,21 @@ export default class FunctionInvocationValidator implements AstValidator<Express
70
72
}
71
73
72
74
// validate the context allowed for the function
73
- const exprContext = match ( containerAttribute ?. decl . $refText )
74
- . with ( '@default' , ( ) => ExpressionContext . DefaultValue )
75
- . with ( P . union ( '@@allow' , '@@deny' , '@allow' , '@deny' ) , ( ) => ExpressionContext . AccessPolicy )
76
- . with ( '@@validate' , ( ) => ExpressionContext . ValidationRule )
77
- . with ( '@@index' , ( ) => ExpressionContext . Index )
78
- . otherwise ( ( ) => undefined ) ;
75
+ const exprContext = this . getExpressionContext ( containerAttribute ) ;
79
76
80
77
// get the context allowed for the function
81
78
const funcAllowedContext = getFunctionExpressionContext ( funcDecl ) ;
82
79
83
- if ( exprContext && ! funcAllowedContext . includes ( exprContext ) ) {
84
- accept ( 'error' , `function "${ funcDecl . name } " is not allowed in the current context: ${ exprContext } ` , {
85
- node : expr ,
86
- } ) ;
80
+ if ( funcAllowedContext . length > 0 && ( ! exprContext || ! funcAllowedContext . includes ( exprContext ) ) ) {
81
+ accept (
82
+ 'error' ,
83
+ `function "${ funcDecl . name } " is not allowed in the current context${
84
+ exprContext ? ': ' + exprContext : ''
85
+ } `,
86
+ {
87
+ node : expr ,
88
+ }
89
+ ) ;
87
90
return ;
88
91
}
89
92
@@ -121,6 +124,8 @@ export default class FunctionInvocationValidator implements AstValidator<Express
121
124
! isEnumFieldReference ( secondArg ) &&
122
125
// `auth()...` expression
123
126
! isAuthOrAuthMemberAccess ( secondArg ) &&
127
+ // static function calls that are runtime constants: `currentModel`, `currentOperation`
128
+ ! this . isStaticFunctionCall ( secondArg ) &&
124
129
// array of literal/enum
125
130
! (
126
131
isArrayExpr ( secondArg ) &&
@@ -148,6 +153,24 @@ export default class FunctionInvocationValidator implements AstValidator<Express
148
153
}
149
154
}
150
155
156
+ private getExpressionContext ( containerAttribute : DataModelAttribute | DataModelFieldAttribute | undefined ) {
157
+ if ( ! containerAttribute ) {
158
+ return undefined ;
159
+ }
160
+ if ( isValidationAttribute ( containerAttribute ) ) {
161
+ return ExpressionContext . ValidationRule ;
162
+ }
163
+ return match ( containerAttribute ?. decl . $refText )
164
+ . with ( '@default' , ( ) => ExpressionContext . DefaultValue )
165
+ . with ( P . union ( '@@allow' , '@@deny' , '@allow' , '@deny' ) , ( ) => ExpressionContext . AccessPolicy )
166
+ . with ( '@@index' , ( ) => ExpressionContext . Index )
167
+ . otherwise ( ( ) => undefined ) ;
168
+ }
169
+
170
+ private isStaticFunctionCall ( expr : Expression ) {
171
+ return isInvocationExpr ( expr ) && [ 'currentModel' , 'currentOperation' ] . includes ( expr . function . $refText ) ;
172
+ }
173
+
151
174
private validateArgs ( funcDecl : FunctionDecl , args : Argument [ ] , accept : ValidationAcceptor ) {
152
175
let success = true ;
153
176
for ( let i = 0 ; i < funcDecl . params . length ; i ++ ) {
0 commit comments