@@ -182,60 +182,173 @@ export class SlsFramework implements IFramework {
182182 config ,
183183 ) ;
184184
185+ // Get functions from main configuration
185186 const lambdas = serverless . service . functions ;
186187
187188 Logger . verbose ( `[SLS] Found Lambdas:` , JSON . stringify ( lambdas , null , 2 ) ) ;
188189
190+ // Process main stack functions
189191 for ( const func in lambdas ) {
190- const lambda = lambdas [ func ] as Serverless . FunctionDefinitionHandler ;
191- const handlerFull = lambda . handler ;
192- const handlerParts = handlerFull . split ( '.' ) ;
193- const handler = handlerParts [ 1 ] ;
194-
195- const possibleCodePaths = [
196- `${ handlerParts [ 0 ] } .ts` ,
197- `${ handlerParts [ 0 ] } .js` ,
198- `${ handlerParts [ 0 ] } .cjs` ,
199- `${ handlerParts [ 0 ] } .mjs` ,
200- ] ;
201- let codePath : string | undefined ;
202- for ( const cp of possibleCodePaths ) {
203- try {
204- await fs . access ( cp , constants . F_OK ) ;
205- codePath = cp ;
206- break ;
207- } catch {
208- // ignore, file not found
209- }
210- }
192+ const lambdaResource = await this . processFunction (
193+ func ,
194+ lambdas [ func ] as Serverless . FunctionDefinitionHandler ,
195+ esBuildOptions ,
196+ ) ;
197+ lambdasDiscovered . push ( lambdaResource ) ;
198+ }
211199
212- if ( ! codePath ) {
213- throw new Error ( `Code path not found for handler: ${ handlerFull } ` ) ;
200+ // Check for nested stacks (serverless-nested-stack plugin)
201+ const nestedStacks = ( serverless . service as any ) . nestedStacks ;
202+ if ( nestedStacks ) {
203+ Logger . verbose (
204+ `[SLS] Found nested stacks configuration:` ,
205+ JSON . stringify ( nestedStacks , null , 2 ) ,
206+ ) ;
207+
208+ const nestedLambdas = await this . parseNestedStacks (
209+ nestedStacks ,
210+ esBuildOptions ,
211+ ) ;
212+ lambdasDiscovered . push ( ...nestedLambdas ) ;
213+ }
214+
215+ return lambdasDiscovered ;
216+ }
217+
218+ /**
219+ * Process a single Lambda function
220+ */
221+ private async processFunction (
222+ funcName : string ,
223+ lambda : Serverless . FunctionDefinitionHandler ,
224+ esBuildOptions : EsBuildOptions | undefined ,
225+ ) : Promise < LambdaResource > {
226+ const handlerFull = lambda . handler ;
227+ const handlerParts = handlerFull . split ( '.' ) ;
228+ const handler = handlerParts [ 1 ] ;
229+
230+ const possibleCodePaths = [
231+ `${ handlerParts [ 0 ] } .ts` ,
232+ `${ handlerParts [ 0 ] } .js` ,
233+ `${ handlerParts [ 0 ] } .cjs` ,
234+ `${ handlerParts [ 0 ] } .mjs` ,
235+ ] ;
236+ let codePath : string | undefined ;
237+ for ( const cp of possibleCodePaths ) {
238+ try {
239+ await fs . access ( cp , constants . F_OK ) ;
240+ codePath = cp ;
241+ break ;
242+ } catch {
243+ // ignore, file not found
214244 }
245+ }
215246
216- const functionName = lambda . name ;
217- if ( ! functionName ) {
218- throw new Error ( `Function name not found for handler: ${ handlerFull } ` ) ;
247+ if ( ! codePath ) {
248+ throw new Error ( `Code path not found for handler: ${ handlerFull } ` ) ;
249+ }
250+
251+ const functionName = lambda . name ;
252+ if ( ! functionName ) {
253+ throw new Error ( `Function name not found for handler: ${ handlerFull } ` ) ;
254+ }
255+
256+ const packageJsonPath = await findPackageJson ( codePath ) ;
257+ Logger . verbose ( `[SLS] package.json path: ${ packageJsonPath } ` ) ;
258+
259+ const lambdaResource : LambdaResource = {
260+ functionName,
261+ codePath,
262+ handler,
263+ packageJsonPath,
264+ esBuildOptions,
265+ metadata : {
266+ framework : 'sls' ,
267+ } ,
268+ } ;
269+
270+ return lambdaResource ;
271+ }
272+
273+ /**
274+ * Parse nested stacks recursively
275+ */
276+ private async parseNestedStacks (
277+ nestedStacks : any ,
278+ esBuildOptions : EsBuildOptions | undefined ,
279+ currentDir : string = process . cwd ( ) ,
280+ ) : Promise < LambdaResource [ ] > {
281+ const lambdas : LambdaResource [ ] = [ ] ;
282+
283+ for ( const stackName in nestedStacks ) {
284+ const stackConfig = nestedStacks [ stackName ] ;
285+ const templatePath = stackConfig . template ;
286+
287+ if ( ! templatePath ) {
288+ Logger . verbose (
289+ `[SLS] Nested stack ${ stackName } has no template property` ,
290+ ) ;
291+ continue ;
219292 }
220293
221- const packageJsonPath = await findPackageJson ( codePath ) ;
222- Logger . verbose ( `[SLS] package.json path: ${ packageJsonPath } ` ) ;
294+ const resolvedTemplatePath = path . resolve ( currentDir , templatePath ) ;
295+ Logger . verbose (
296+ `[SLS] Parsing nested stack ${ stackName } : ${ resolvedTemplatePath } ` ,
297+ ) ;
223298
224- const lambdaResource : LambdaResource = {
225- functionName,
226- codePath,
227- handler,
228- packageJsonPath,
229- esBuildOptions,
230- metadata : {
231- framework : 'sls' ,
232- } ,
233- } ;
299+ try {
300+ const templateContent = await fs . readFile (
301+ resolvedTemplatePath ,
302+ 'utf-8' ,
303+ ) ;
304+ const yaml = await import ( 'yaml' ) ;
305+ const nestedConfig = yaml . parse ( templateContent ) ;
306+
307+ // Process functions in nested stack
308+ if ( nestedConfig . functions ) {
309+ Logger . verbose (
310+ `[SLS] Found functions in nested stack ${ stackName } :` ,
311+ JSON . stringify ( nestedConfig . functions , null , 2 ) ,
312+ ) ;
313+
314+ for ( const funcName in nestedConfig . functions ) {
315+ const func = nestedConfig . functions [ funcName ] ;
316+ const lambdaResource = await this . processFunction (
317+ funcName ,
318+ func as Serverless . FunctionDefinitionHandler ,
319+ esBuildOptions ,
320+ ) ;
321+ lambdas . push ( lambdaResource ) ;
322+ }
323+ }
234324
235- lambdasDiscovered . push ( lambdaResource ) ;
325+ // Recursively process nested stacks within this stack
326+ if ( nestedConfig . nestedStacks ) {
327+ Logger . verbose (
328+ `[SLS] Found nested stacks within ${ stackName } :` ,
329+ JSON . stringify ( nestedConfig . nestedStacks , null , 2 ) ,
330+ ) ;
331+
332+ const templateDir = path . dirname ( resolvedTemplatePath ) ;
333+ const deeperNestedLambdas = await this . parseNestedStacks (
334+ nestedConfig . nestedStacks ,
335+ esBuildOptions ,
336+ templateDir ,
337+ ) ;
338+ lambdas . push ( ...deeperNestedLambdas ) ;
339+ }
340+ } catch ( err : any ) {
341+ Logger . warn (
342+ `[SLS] Could not parse nested stack at ${ resolvedTemplatePath } : ${ err . message } ` ,
343+ ) ;
344+ }
236345 }
237346
238- return lambdasDiscovered ;
347+ Logger . verbose (
348+ `[SLS] Finished parsing nested stacks, found ${ lambdas . length } Lambda function(s)${ lambdas . length > 0 ? `:\n${ lambdas . map ( ( l ) => ` - ${ l . functionName } ` ) . join ( '\n' ) } ` : '' } ` ,
349+ ) ;
350+
351+ return lambdas ;
239352 }
240353
241354 // eslint-disable-next-line @typescript-eslint/no-unused-vars
0 commit comments