@@ -50,9 +50,10 @@ export const SamSchemaTransformer = {
5050 string ,
5151 unknown
5252 > ;
53+ let propertiesRefKey : string | undefined ;
5354 if ( propertiesSchema ?. $ref ) {
54- const refKey = ( propertiesSchema . $ref as string ) . replace ( '#/definitions/' , '' ) ;
55- propertiesSchema = samSchema . definitions [ refKey ] as Record < string , unknown > ;
55+ propertiesRefKey = ( propertiesSchema . $ref as string ) . replace ( '#/definitions/' , '' ) ;
56+ propertiesSchema = samSchema . definitions [ propertiesRefKey ] as Record < string , unknown > ;
5657 }
5758
5859 const cfnSchema : CloudFormationResourceSchema = {
@@ -63,7 +64,7 @@ export const SamSchemaTransformer = {
6364 ( propertiesSchema ?. properties as Record < string , unknown > ) ?? { } ,
6465 samSchema . definitions ,
6566 ) ,
66- definitions : samSchema . definitions ,
67+ definitions : this . extractReferencedDefinitions ( definition , samSchema . definitions , defKey ) ,
6768 additionalProperties : false ,
6869 required : ( propertiesSchema ?. required as string [ ] ) ?? [ ] ,
6970 attributes : { } , // Empty to avoid GetAtt issues
@@ -79,6 +80,47 @@ export const SamSchemaTransformer = {
7980 return resourceSchemas ;
8081 } ,
8182
83+ extractReferencedDefinitions (
84+ schema : Record < string , unknown > | undefined ,
85+ allDefinitions : Record < string , unknown > ,
86+ rootDefinitionKey ?: string ,
87+ ) : Record < string , unknown > {
88+ const referenced = new Set < string > ( ) ;
89+ const result : Record < string , unknown > = { } ;
90+
91+ // Include the root definition if provided
92+ if ( rootDefinitionKey && allDefinitions [ rootDefinitionKey ] ) {
93+ referenced . add ( rootDefinitionKey ) ;
94+ result [ rootDefinitionKey ] = allDefinitions [ rootDefinitionKey ] ;
95+ }
96+
97+ const collectRefs = ( obj : unknown ) : void => {
98+ if ( typeof obj === 'object' && obj !== null ) {
99+ if ( Array . isArray ( obj ) ) {
100+ for ( const item of obj ) {
101+ collectRefs ( item ) ;
102+ }
103+ } else {
104+ const record = obj as Record < string , unknown > ;
105+ if ( record . $ref && typeof record . $ref === 'string' ) {
106+ const refKey = record . $ref . replace ( '#/definitions/' , '' ) ;
107+ if ( ! referenced . has ( refKey ) && allDefinitions [ refKey ] ) {
108+ referenced . add ( refKey ) ;
109+ result [ refKey ] = allDefinitions [ refKey ] ;
110+ collectRefs ( allDefinitions [ refKey ] ) ;
111+ }
112+ }
113+ for ( const value of Object . values ( record ) ) {
114+ collectRefs ( value ) ;
115+ }
116+ }
117+ }
118+ } ;
119+
120+ collectRefs ( schema ) ;
121+ return result ;
122+ } ,
123+
82124 resolvePropertyTypes (
83125 properties : Record < string , unknown > ,
84126 definitions : Record < string , unknown > ,
@@ -98,6 +140,18 @@ export const SamSchemaTransformer = {
98140 property = { ...property , description : property . markdownDescription } ;
99141 }
100142
143+ // Convert SAM's non-standard additionalProperties usage to CloudFormation-compliant patternProperties
144+ if ( property . additionalProperties && typeof property . additionalProperties === 'object' ) {
145+ const additionalProps = property . additionalProperties as Record < string , unknown > ;
146+ property = {
147+ ...property ,
148+ additionalProperties : false ,
149+ patternProperties : {
150+ '.*' : additionalProps ,
151+ } ,
152+ } ;
153+ }
154+
101155 // If property already has a type, keep it
102156 if ( property . type ) {
103157 return property ;
0 commit comments