@@ -22,6 +22,7 @@ import {
2222 isModel ,
2323 isReferenceExpr ,
2424 isStringLiteral ,
25+ isThisExpr ,
2526 isTypeDef ,
2627} from '../generated/ast' ;
2728import {
@@ -30,6 +31,7 @@ import {
3031 getContainingDataModel ,
3132 getDataSourceProvider ,
3233 getNumberLiteral ,
34+ getPrimitiveTypeDefThisField ,
3335 getStringLiteral ,
3436 hasAttribute ,
3537 isAuthOrAuthMemberAccess ,
@@ -40,6 +42,7 @@ import {
4042 isDelegateModel ,
4143 isManyToManyField ,
4244 isNativeTypeMappingAttribute ,
45+ isPrimitiveTypeDef ,
4346 isRelationshipField ,
4447 mapBuiltinTypeToExpressionType ,
4548 resolved ,
@@ -142,6 +145,14 @@ export default class AttributeApplicationValidator implements AstValidator<Attri
142145 }
143146
144147 const targetDecl = attr . $container ;
148+ if (
149+ ( isPrimitiveTypeDef ( targetDecl ) || isPrimitiveTypeDef ( targetDecl . $container ) ) &&
150+ ! hasAttribute ( attr . decl . ref ! , '@@@validation' )
151+ ) {
152+ accept ( 'error' , `attribute "${ decl . name } " cannot be used with primitive type defs` , { node : attr } ) ;
153+ return ;
154+ }
155+
145156 if ( decl . name === '@@@targetField' && ! isAttribute ( targetDecl ) ) {
146157 accept ( 'error' , `attribute "${ decl . name } " can only be used on attribute declarations` , { node : attr } ) ;
147158 return ;
@@ -381,13 +392,24 @@ export default class AttributeApplicationValidator implements AstValidator<Attri
381392 @check ( '@@validate' )
382393 private _checkValidate ( attr : AttributeApplication , accept : ValidationAcceptor ) {
383394 const condition = attr . args [ 0 ] ?. value ;
384- if (
385- condition &&
386- AstUtils . streamAst ( condition ) . some (
387- ( node ) => isDataFieldReference ( node ) && isDataModel ( node . $resolvedType ?. decl ) ,
388- )
389- ) {
390- accept ( 'error' , `\`@@validate\` condition cannot use relation fields` , { node : condition } ) ;
395+ if ( condition ) {
396+ if (
397+ AstUtils . streamAst ( condition ) . some (
398+ ( node ) => isDataFieldReference ( node ) && isDataModel ( node . $resolvedType ?. decl ) ,
399+ )
400+ ) {
401+ accept ( 'error' , `\`@@validate\` condition cannot use relation fields` , { node : condition } ) ;
402+ return ;
403+ }
404+
405+ if ( isPrimitiveTypeDef ( attr . $container ) && AstUtils . streamAst ( condition ) . some ( ( node ) => isThisExpr ( node ) ) ) {
406+ const thisField = getPrimitiveTypeDefThisField ( attr . $container ) ;
407+ if ( ! thisField ) {
408+ accept ( 'error' , 'primitive type def cannot reference `this` field without declaring it' , {
409+ node : condition ,
410+ } ) ;
411+ }
412+ }
391413 }
392414 }
393415
@@ -664,10 +686,16 @@ function assignableToAttributeParam(
664686 // attribute parameter type is ContextType, need to infer type from
665687 // the attribute's container
666688 if ( isDataField ( attr . $container ) ) {
667- if ( ! attr . $container ?. type ?. type ) {
668- return genericError ;
689+ if ( attr . $container . type . reference ?. ref && isPrimitiveTypeDef ( attr . $container . type . reference . ref ) ) {
690+ dstType = mapBuiltinTypeToExpressionType ( attr . $container . type . reference . ref . base ! ) ;
691+ } else {
692+ if ( ! attr . $container ?. type ?. type ) {
693+ return genericError ;
694+ }
695+
696+ dstType = mapBuiltinTypeToExpressionType ( attr . $container . type . type ) ;
669697 }
670- dstType = mapBuiltinTypeToExpressionType ( attr . $container . type . type ) ;
698+
671699 dstIsArray = attr . $container . type . array ;
672700 } else {
673701 dstType = 'Any' ;
@@ -708,34 +736,35 @@ function isValidAttributeTarget(attrDecl: Attribute, targetDecl: DataField) {
708736 . filter ( ( name ) : name is string => ! ! name ) ;
709737
710738 let allowed = false ;
739+ const targetDeclType = targetDecl . $resolvedType ?. decl ?? targetDecl . type . type ;
711740 for ( const allowedType of fieldTypes ) {
712741 switch ( allowedType ) {
713742 case 'StringField' :
714- allowed = allowed || targetDecl . type . type === 'String' ;
743+ allowed = allowed || targetDeclType === 'String' ;
715744 break ;
716745 case 'IntField' :
717- allowed = allowed || targetDecl . type . type === 'Int' ;
746+ allowed = allowed || targetDeclType === 'Int' ;
718747 break ;
719748 case 'BigIntField' :
720- allowed = allowed || targetDecl . type . type === 'BigInt' ;
749+ allowed = allowed || targetDeclType === 'BigInt' ;
721750 break ;
722751 case 'FloatField' :
723- allowed = allowed || targetDecl . type . type === 'Float' ;
752+ allowed = allowed || targetDeclType === 'Float' ;
724753 break ;
725754 case 'DecimalField' :
726- allowed = allowed || targetDecl . type . type === 'Decimal' ;
755+ allowed = allowed || targetDeclType === 'Decimal' ;
727756 break ;
728757 case 'BooleanField' :
729- allowed = allowed || targetDecl . type . type === 'Boolean' ;
758+ allowed = allowed || targetDeclType === 'Boolean' ;
730759 break ;
731760 case 'DateTimeField' :
732- allowed = allowed || targetDecl . type . type === 'DateTime' ;
761+ allowed = allowed || targetDeclType === 'DateTime' ;
733762 break ;
734763 case 'JsonField' :
735- allowed = allowed || targetDecl . type . type === 'Json' ;
764+ allowed = allowed || targetDeclType === 'Json' ;
736765 break ;
737766 case 'BytesField' :
738- allowed = allowed || targetDecl . type . type === 'Bytes' ;
767+ allowed = allowed || targetDeclType === 'Bytes' ;
739768 break ;
740769 case 'ModelField' :
741770 allowed = allowed || isDataModel ( targetDecl . type . reference ?. ref ) ;
0 commit comments