@@ -3,6 +3,7 @@ import { TopLevelSection } from '../context/CloudFormationEnums';
33import { getEntityMap } from '../context/SectionContextBuilder' ;
44import { Resource } from '../context/semantic/Entity' ;
55import {
6+ AuthoredResource ,
67 GetRelatedResourceTypesParams ,
78 InsertRelatedResourcesParams ,
89 RelatedResourcesCodeAction ,
@@ -19,22 +20,25 @@ import {
1920
2021export function getAuthoredResourceTypesHandler (
2122 components : ServerComponents ,
22- ) : RequestHandler < TemplateUri , string [ ] , void > {
23+ ) : RequestHandler < TemplateUri , AuthoredResource [ ] , void > {
2324 return ( rawParams ) => {
2425 try {
2526 const templateUri = parseWithPrettyError ( parseTemplateUriParams , rawParams ) ;
2627 const syntaxTree = components . syntaxTreeManager . getSyntaxTree ( templateUri ) ;
2728 if ( syntaxTree ) {
2829 const resourcesMap = getEntityMap ( syntaxTree , TopLevelSection . Resources ) ;
2930 if ( resourcesMap ) {
30- const resourceTypes = [ ...resourcesMap . values ( ) ]
31- . map ( ( context ) => {
32- const resource = context . entity as Resource ;
33- return resource ?. Type ;
34- } )
35- . filter ( ( type ) : type is string => type !== undefined && type !== null ) ;
36-
37- return [ ...new Set ( resourceTypes ) ] ;
31+ const resources : AuthoredResource [ ] = [ ] ;
32+ for ( const [ logicalId , context ] of resourcesMap ) {
33+ const resource = context . entity as Resource ;
34+ if ( resource ?. Type ) {
35+ resources . push ( {
36+ logicalId,
37+ type : resource . Type ,
38+ } ) ;
39+ }
40+ }
41+ return resources ;
3842 }
3943 }
4044
@@ -52,26 +56,74 @@ export function getRelatedResourceTypesHandler(
5256 try {
5357 const { parentResourceType } = parseWithPrettyError ( parseGetRelatedResourceTypesParams , rawParams ) ;
5458 const relatedTypes = components . relationshipSchemaService . getAllRelatedResourceTypes ( parentResourceType ) ;
55- return [ ...relatedTypes ] ;
59+
60+ const filtered = [ ...relatedTypes ] . filter ( ( relatedType ) =>
61+ hasExactlyOnePopulatableRelationship ( relatedType , parentResourceType , components ) ,
62+ ) ;
63+
64+ return filtered ;
5665 } catch ( error ) {
5766 handleLspError ( error , 'Failed to get related resource types' ) ;
5867 }
5968 } ;
6069}
6170
71+ /**
72+ * Checks if a related resource type has exactly one top-level property
73+ * that references the parent resource type, and that property is not an array.
74+ */
75+ function hasExactlyOnePopulatableRelationship (
76+ relatedType : string ,
77+ parentResourceType : string ,
78+ components : ServerComponents ,
79+ ) : boolean {
80+ const relationships = components . relationshipSchemaService . getRelationshipsForResourceType ( relatedType ) ;
81+ if ( ! relationships ) {
82+ return false ;
83+ }
84+
85+ const schema = components . schemaRetriever . getDefault ( ) . schemas . get ( relatedType ) ;
86+
87+ const topLevelParentRefs : { property : string ; isArray : boolean } [ ] = [ ] ;
88+ for ( const rel of relationships . relationships ) {
89+ if ( rel . property . includes ( '/' ) ) {
90+ continue ;
91+ }
92+
93+ const referencesParent = rel . relatedResourceTypes . some ( ( rt ) => rt . typeName === parentResourceType ) ;
94+ if ( ! referencesParent ) {
95+ continue ;
96+ }
97+
98+ const isArray = schema ?. properties ?. [ rel . property ] ?. type === 'array' ;
99+ topLevelParentRefs . push ( { property : rel . property , isArray } ) ;
100+
101+ if ( topLevelParentRefs . length > 1 ) {
102+ break ;
103+ }
104+ }
105+
106+ if ( topLevelParentRefs . length !== 1 ) {
107+ return false ;
108+ }
109+
110+ return ! topLevelParentRefs [ 0 ] . isArray ;
111+ }
112+
62113export function insertRelatedResourcesHandler (
63114 components : ServerComponents ,
64115) : RequestHandler < InsertRelatedResourcesParams , RelatedResourcesCodeAction , void > {
65116 return ( rawParams ) => {
66117 try {
67- const { templateUri, relatedResourceTypes, parentResourceType } = parseWithPrettyError (
118+ const { templateUri, relatedResourceTypes, parentResourceType, parentLogicalId } = parseWithPrettyError (
68119 parseInsertRelatedResourcesParams ,
69120 rawParams ,
70121 ) ;
71122 return components . relatedResourcesSnippetProvider . insertRelatedResources (
72123 templateUri ,
73124 relatedResourceTypes ,
74125 parentResourceType ,
126+ parentLogicalId ,
75127 ) ;
76128 } catch ( error ) {
77129 handleLspError ( error , 'Failed to insert related resources' ) ;
0 commit comments