77 DataModelAttribute ,
88 DataModelField ,
99 DataModelFieldAttribute ,
10+ Expression ,
1011 ExpressionType ,
1112 isArrayExpr ,
1213 isAttribute ,
@@ -54,10 +55,21 @@ export function getStringLiteral(node: AstNode | undefined): string | undefined
5455 }
5556}
5657
58+ const isoDateTimeRegex = / ^ \d { 4 } ( - \d \d ( - \d \d ( T \d \d : \d \d ( : \d \d ) ? ( \. \d + ) ? ( ( [ + - ] \d \d : \d \d ) | Z ) ? ) ? ) ? ) ? $ / i;
59+
5760/**
5861 * Determines if the given sourceType is assignable to a destination of destType
5962 */
60- export function typeAssignable ( destType : ExpressionType , sourceType : ExpressionType ) : boolean {
63+ export function typeAssignable ( destType : ExpressionType , sourceType : ExpressionType , sourceExpr ?: Expression ) : boolean {
64+ // implicit conversion from ISO datetime string to datetime
65+ if ( destType === 'DateTime' && sourceType === 'String' && sourceExpr && isLiteralExpr ( sourceExpr ) ) {
66+ const literal = getStringLiteral ( sourceExpr ) ;
67+ if ( literal && isoDateTimeRegex . test ( literal ) ) {
68+ // implicitly convert to DateTime
69+ sourceType = 'DateTime' ;
70+ }
71+ }
72+
6173 switch ( destType ) {
6274 case 'Any' :
6375 return true ;
@@ -108,6 +120,19 @@ export function assignableToAttributeParam(
108120 let dstIsArray = param . type . array ;
109121 const dstRef = param . type . reference ;
110122
123+ // destination is field reference or transitive field reference, check if
124+ // argument is reference or array or reference
125+ if ( dstType === 'FieldReference' || dstType === 'TransitiveFieldReference' ) {
126+ if ( dstIsArray ) {
127+ return (
128+ isArrayExpr ( arg . value ) &&
129+ ! arg . value . items . find ( ( item ) => ! isReferenceExpr ( item ) || ! isDataModelField ( item . target . ref ) )
130+ ) ;
131+ } else {
132+ return isReferenceExpr ( arg . value ) && isDataModelField ( arg . value . target . ref ) ;
133+ }
134+ }
135+
111136 if ( isEnum ( argResolvedType . decl ) ) {
112137 // enum type
113138
@@ -127,16 +152,7 @@ export function assignableToAttributeParam(
127152 return false ;
128153 }
129154
130- if ( dstType === 'FieldReference' || dstType === 'TransitiveFieldReference' ) {
131- if ( dstIsArray ) {
132- return (
133- isArrayExpr ( arg . value ) &&
134- ! arg . value . items . find ( ( item ) => ! isReferenceExpr ( item ) || ! isDataModelField ( item . target . ref ) )
135- ) ;
136- } else {
137- return isReferenceExpr ( arg . value ) && isDataModelField ( arg . value . target . ref ) ;
138- }
139- } else if ( dstType === 'ContextType' ) {
155+ if ( dstType === 'ContextType' ) {
140156 // attribute parameter type is ContextType, need to infer type from
141157 // the attribute's container
142158 if ( isDataModelField ( attr . $container ) ) {
@@ -151,7 +167,8 @@ export function assignableToAttributeParam(
151167 }
152168
153169 return (
154- typeAssignable ( dstType , argResolvedType . decl ) && ( dstType === 'Any' || dstIsArray === argResolvedType . array )
170+ typeAssignable ( dstType , argResolvedType . decl , arg . value ) &&
171+ ( dstType === 'Any' || dstIsArray === argResolvedType . array )
155172 ) ;
156173 } else {
157174 // reference type
0 commit comments