@@ -10,6 +10,7 @@ import { CloudFormation } from '../cloudFormation.js';
1010import { AwsConfiguration } from '../types/awsConfiguration.js' ;
1111import { LldConfigBase } from '../types/lldConfig.js' ;
1212import { Logger } from '../logger.js' ;
13+ import type { Format } from 'esbuild' ;
1314
1415/**
1516 * Support for AWS SAM framework
@@ -102,19 +103,10 @@ export class SamFramework implements IFramework {
102103 throw new Error ( `Stack name not found in ${ samConfigFile } ` ) ;
103104 }
104105
105- const samTemplateContent = await fs . readFile (
106- path . resolve ( samTemplateFile ) ,
107- 'utf-8' ,
108- ) ;
109- const template = yaml . parse ( samTemplateContent ) ;
110-
111- const lambdas : any [ ] = [ ] ;
112-
113106 // Recursively parse templates to find all Lambda functions, including those in nested stacks
114- await this . parseLambdasFromTemplate (
115- template ,
116- path . dirname ( path . resolve ( samTemplateFile ) ) ,
117- lambdas ,
107+ const lambdas = await this . parseLambdasFromTemplate (
108+ samTemplateFile ,
109+ stackName ,
118110 ) ;
119111
120112 const lambdasDiscovered : LambdaResource [ ] = [ ] ;
@@ -141,37 +133,32 @@ export class SamFramework implements IFramework {
141133
142134 // get tags for each Lambda
143135 for ( const func of lambdas ) {
144- const handlerFull = path . join (
145- func . Properties . CodeUri ?? '' ,
146- func . Properties . Handler ,
147- ) ;
136+ const handlerFull = path . join ( func . codeUri ?? '' , func . handler ) ;
148137 const handlerParts = handlerFull . split ( '.' ) ;
149138 const handler = handlerParts [ 1 ] ;
150139
151140 const functionName = lambdasInStack . find (
152- ( lambda ) => lambda . logicalId === func . Name ,
141+ ( lambda ) =>
142+ lambda . logicalId === func . name && lambda . stackName === func . stackName ,
153143 ) ?. lambdaName ;
154144
155145 if ( ! functionName ) {
156- throw new Error ( `Function name not found for function: ${ func . Name } ` ) ;
146+ throw new Error ( `Function name not found for function: ${ func . name } ` ) ;
157147 }
158148
159149 let esBuildOptions : EsBuildOptions | undefined = undefined ;
160150
161151 let codePath : string | undefined ;
162- if ( func . Metadata ?. BuildMethod ?. toLowerCase ( ) === 'esbuild' ) {
163- if ( func . Metadata ?. BuildProperties ?. EntryPoints ?. length > 0 ) {
164- codePath = path . join (
165- func . Properties . CodeUri ?? '' ,
166- func . Metadata ?. BuildProperties ?. EntryPoints [ 0 ] ,
167- ) ;
152+ if ( func . buildMethod ?. toLowerCase ( ) === 'esbuild' ) {
153+ if ( func . entryPoints && func . entryPoints . length > 0 ) {
154+ codePath = path . join ( func . codeUri ?? '' , func . entryPoints [ 0 ] ) ;
168155 }
169156
170157 esBuildOptions = {
171- external : func . Metadata ?. BuildProperties ?. External ,
172- minify : func . Metadata ?. BuildProperties ?. Minify ,
173- format : func . Metadata ?. BuildProperties ?. Format ,
174- target : func . Metadata ?. BuildProperties ?. Target ,
158+ external : func . external ,
159+ minify : func . minify ,
160+ format : func . format ,
161+ target : func . target ,
175162 } ;
176163 }
177164
@@ -228,62 +215,95 @@ export class SamFramework implements IFramework {
228215
229216 /**
230217 * Recursively parse templates to find all Lambda functions, including nested stacks
231- * @param template The parsed CloudFormation/SAM template
232- * @param templateDir The directory containing the template file
233- * @param lambdas The array to collect Lambda functions into
218+ * @param templatePath The path to the CloudFormation/SAM template file
219+ * @param stackName The name of the stack this template belongs to (for nested stacks)
234220 */
235221 private async parseLambdasFromTemplate (
236- template : any ,
237- templateDir : string ,
238- lambdas : any [ ] ,
239- ) : Promise < void > {
222+ templatePath : string ,
223+ stackName : string ,
224+ ) : Promise < ParsedLambda [ ] > {
225+ const resolvedTemplatePath = path . resolve ( templatePath ) ;
226+ const templateDir = path . dirname ( resolvedTemplatePath ) ;
227+
228+ let template : any ;
229+ try {
230+ const templateContent = await fs . readFile ( resolvedTemplatePath , 'utf-8' ) ;
231+ template = yaml . parse ( templateContent ) ;
232+ } catch ( err : any ) {
233+ Logger . warn (
234+ `[SAM] Could not read or parse template at ${ templatePath } : ${ err . message } ` ,
235+ ) ;
236+ return [ ] ;
237+ }
238+
240239 if ( ! template . Resources ) {
241- return ;
240+ return [ ] ;
242241 }
243242
243+ const lambdas : ParsedLambda [ ] = [ ] ;
244+
244245 for ( const resourceName in template . Resources ) {
245246 const resource = template . Resources [ resourceName ] ;
246247
247248 // Check if it's a Lambda function
248249 if ( resource . Type === 'AWS::Serverless::Function' ) {
249250 lambdas . push ( {
250- Name : resourceName ,
251- ...resource ,
251+ templatePath,
252+ name : resourceName ,
253+ codeUri : resource . Properties ?. CodeUri ,
254+ handler : resource . Properties ?. Handler ,
255+ buildMethod : resource . Metadata ?. BuildMethod ,
256+ entryPoints : resource . Metadata ?. BuildProperties ?. EntryPoints ,
257+ external : resource . Metadata ?. BuildProperties ?. External ,
258+ minify : resource . Metadata ?. BuildProperties ?. Minify ,
259+ format : resource . Metadata ?. BuildProperties ?. Format as
260+ | Format
261+ | undefined ,
262+ target : resource . Metadata ?. BuildProperties ?. Target ,
263+ stackName,
252264 } ) ;
253265 }
254266 // Check if it's a nested stack
255267 else if (
256268 resource . Type === 'AWS::Serverless::Application' ||
257269 resource . Type === 'AWS::CloudFormation::Stack'
258270 ) {
259- const nestedTemplateLocation = resource . Properties ?. Location ;
271+ const nestedTemplateLocation =
272+ resource . Properties ?. Location ?? resource . Properties ?. TemplateURL ;
260273 if ( nestedTemplateLocation ) {
261- try {
262- const nestedTemplatePath = path . resolve (
263- templateDir ,
264- nestedTemplateLocation ,
265- ) ;
266- const nestedTemplateContent = await fs . readFile (
267- nestedTemplatePath ,
268- 'utf-8' ,
269- ) ;
270- const nestedTemplate = yaml . parse ( nestedTemplateContent ) ;
271-
272- // Recursively parse the nested template
273- await this . parseLambdasFromTemplate (
274- nestedTemplate ,
275- path . dirname ( nestedTemplatePath ) ,
276- lambdas ,
277- ) ;
278- } catch ( err : any ) {
279- Logger . warn (
280- `[SAM] Could not parse nested template at ${ nestedTemplateLocation } : ${ err . message } ` ,
281- ) ;
282- }
274+ const nestedTemplatePath = path . resolve (
275+ templateDir ,
276+ nestedTemplateLocation ,
277+ ) ;
278+
279+ // Recursively parse the nested template
280+ const nestedLambdas = await this . parseLambdasFromTemplate (
281+ nestedTemplatePath ,
282+ resourceName ,
283+ ) ;
284+ lambdas . push ( ...nestedLambdas ) ;
283285 }
284286 }
285287 }
288+
289+ Logger . verbose ( JSON . stringify ( lambdas , null , 2 ) ) ;
290+
291+ return lambdas ;
286292 }
287293}
288294
289295export const samFramework = new SamFramework ( ) ;
296+
297+ type ParsedLambda = {
298+ templatePath : string ;
299+ name : string ;
300+ codeUri ?: string ;
301+ handler : string ;
302+ buildMethod ?: string ;
303+ entryPoints ?: string [ ] ;
304+ external ?: string [ ] ;
305+ minify ?: boolean ;
306+ format ?: Format ;
307+ target ?: string ;
308+ stackName : string ;
309+ } ;
0 commit comments