@@ -11,6 +11,7 @@ import {
1111 isDataModel ,
1212 isDataModelAttribute ,
1313 isDataModelFieldAttribute ,
14+ isInvocationExpr ,
1415 isLiteralExpr ,
1516} from '@zenstackhq/language/ast' ;
1617import {
@@ -21,6 +22,7 @@ import {
2122 isDataModelFieldReference ,
2223 isEnumFieldReference ,
2324 isFromStdlib ,
25+ isValidationAttribute ,
2426} from '@zenstackhq/sdk' ;
2527import { AstNode , streamAst , ValidationAcceptor } from 'langium' ;
2628import { match , P } from 'ts-pattern' ;
@@ -70,20 +72,21 @@ export default class FunctionInvocationValidator implements AstValidator<Express
7072 }
7173
7274 // 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 ) ;
7976
8077 // get the context allowed for the function
8178 const funcAllowedContext = getFunctionExpressionContext ( funcDecl ) ;
8279
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+ ) ;
8790 return ;
8891 }
8992
@@ -121,6 +124,8 @@ export default class FunctionInvocationValidator implements AstValidator<Express
121124 ! isEnumFieldReference ( secondArg ) &&
122125 // `auth()...` expression
123126 ! isAuthOrAuthMemberAccess ( secondArg ) &&
127+ // static function calls that are runtime constants: `currentModel`, `currentOperation`
128+ ! this . isStaticFunctionCall ( secondArg ) &&
124129 // array of literal/enum
125130 ! (
126131 isArrayExpr ( secondArg ) &&
@@ -148,6 +153,24 @@ export default class FunctionInvocationValidator implements AstValidator<Express
148153 }
149154 }
150155
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+
151174 private validateArgs ( funcDecl : FunctionDecl , args : Argument [ ] , accept : ValidationAcceptor ) {
152175 let success = true ;
153176 for ( let i = 0 ; i < funcDecl . params . length ; i ++ ) {
0 commit comments