@@ -20,6 +20,8 @@ import { Commands } from '../../shared/vscode/commands2'
2020import { getLambdaSnapshot , persistLambdaSnapshot , type LambdaDebugger , type DebugConfig } from './lambdaDebugger'
2121import { RemoteLambdaDebugger } from './remoteLambdaDebugger'
2222import { LocalStackLambdaDebugger } from './localStackLambdaDebugger'
23+ import { fs } from '../../shared/fs/fs'
24+ import { detectCdkProjects } from '../../awsService/cdk/explorer/detectCdkProjects'
2325
2426const localize = nls . loadMessageBundle ( )
2527const logger = getLogger ( )
@@ -165,6 +167,108 @@ export async function activateRemoteDebugging(): Promise<void> {
165167 }
166168}
167169
170+ /**
171+ * Try to auto-detect outFile for TypeScript debugging (SAM or CDK)
172+ * @param debugConfig Debug configuration
173+ * @param functionConfig Lambda function configuration
174+ * @returns The auto-detected outFile path or undefined
175+ */
176+ export async function tryAutoDetectOutFile (
177+ debugConfig : DebugConfig ,
178+ functionConfig : Lambda . FunctionConfiguration
179+ ) : Promise < string | undefined > {
180+ // Only works for TypeScript files
181+ if (
182+ ! debugConfig . handlerFile ||
183+ ( ! debugConfig . handlerFile . endsWith ( '.ts' ) && ! debugConfig . handlerFile . endsWith ( '.tsx' ) )
184+ ) {
185+ return undefined
186+ }
187+
188+ // Try SAM detection first using the provided parameters
189+ if ( debugConfig . samProjectLogicalId && debugConfig . samProjectRoot ) {
190+ // if proj root is ..../sam-proj/
191+ // build dir will be ..../sam-proj/.aws-sam/build/{LogicalID}/
192+ const samBuildPath = vscode . Uri . joinPath (
193+ debugConfig . samProjectRoot ,
194+ '.aws-sam' ,
195+ 'build' ,
196+ debugConfig . samProjectLogicalId
197+ )
198+
199+ if ( await fs . exists ( samBuildPath ) ) {
200+ getLogger ( ) . info ( `SAM outFile auto-detected: ${ samBuildPath . fsPath } ` )
201+ return samBuildPath . fsPath
202+ }
203+ }
204+
205+ // If SAM detection didn't work, try CDK detection using the function name
206+ if ( ! functionConfig . FunctionName ) {
207+ return undefined
208+ }
209+
210+ try {
211+ // Find which workspace contains the handler file
212+ const workspaceFolder = vscode . workspace . getWorkspaceFolder ( vscode . Uri . file ( debugConfig . handlerFile ) )
213+ if ( ! workspaceFolder ) {
214+ return undefined
215+ }
216+
217+ // Detect CDK projects in the workspace
218+ const cdkProjects = await detectCdkProjects ( [ workspaceFolder ] )
219+
220+ for ( const project of cdkProjects ) {
221+ // Check if CDK project contains the handler file
222+ const cdkProjectDir = vscode . Uri . joinPath ( project . cdkJsonUri , '..' )
223+ if ( ! debugConfig . handlerFile . startsWith ( cdkProjectDir . fsPath ) ) {
224+ continue
225+ }
226+
227+ // Get the cdk.out directory
228+ const cdkOutDir = vscode . Uri . joinPath ( project . treeUri , '..' )
229+
230+ // Look for template.json files in cdk.out directory
231+ const pattern = new vscode . RelativePattern ( cdkOutDir . fsPath , '*.template.json' )
232+ const templateFiles = await vscode . workspace . findFiles ( pattern )
233+
234+ for ( const templateFile of templateFiles ) {
235+ try {
236+ // Read and parse the template.json file
237+ const templateContent = await fs . readFileText ( templateFile )
238+ const template = JSON . parse ( templateContent )
239+
240+ // Search through resources for a Lambda function with matching FunctionName
241+ for ( const [ _ , resource ] of Object . entries ( template . Resources || { } ) ) {
242+ const res = resource as any
243+ if (
244+ res . Type === 'AWS::Lambda::Function' &&
245+ res . Properties ?. FunctionName === functionConfig . FunctionName
246+ ) {
247+ // Found the matching function, extract the asset path from metadata
248+ const assetPath = res . Metadata ?. [ 'aws:asset:path' ]
249+ if ( assetPath ) {
250+ const assetDir = vscode . Uri . joinPath ( cdkOutDir , assetPath )
251+
252+ // Check if the asset directory exists
253+ if ( await fs . exists ( assetDir ) ) {
254+ getLogger ( ) . info ( `CDK outFile auto-detected from template.json: ${ assetDir . fsPath } ` )
255+ return assetDir . fsPath
256+ }
257+ }
258+ }
259+ }
260+ } catch ( error ) {
261+ getLogger ( ) . debug ( `Failed to parse template file ${ templateFile . fsPath } : ${ error } ` )
262+ }
263+ }
264+ }
265+ } catch ( error ) {
266+ getLogger ( ) . warn ( `Failed to auto-detect CDK outFile: ${ error } ` )
267+ }
268+
269+ return undefined
270+ }
271+
168272/**
169273 * Helper function to check if a string is a valid VSCode glob pattern
170274 */
@@ -287,6 +391,15 @@ async function getVscodeDebugConfig(
287391 let vsCodeDebugConfig : vscode . DebugConfiguration
288392 switch ( debugType ) {
289393 case 'node' :
394+ // Try to auto-detect outFiles for TypeScript if not provided
395+ if ( debugConfig . sourceMap && ! debugConfig . outFiles && debugConfig . handlerFile ) {
396+ const autoDetectedOutFile = await tryAutoDetectOutFile ( debugConfig , functionConfig )
397+ if ( autoDetectedOutFile ) {
398+ debugConfig . outFiles = [ autoDetectedOutFile ]
399+ getLogger ( ) . info ( `outFile auto-detected: ${ autoDetectedOutFile } ` )
400+ }
401+ }
402+
290403 // source map support
291404 if ( debugConfig . sourceMap && debugConfig . outFiles ) {
292405 // process outFiles first, if they are relative path (not starting with /),
0 commit comments