diff --git a/src/__tests__/__snapshots__/integration.test.ts.snap b/src/__tests__/__snapshots__/integration.test.ts.snap index 5d2e907..810bbf0 100644 --- a/src/__tests__/__snapshots__/integration.test.ts.snap +++ b/src/__tests__/__snapshots__/integration.test.ts.snap @@ -43,6 +43,7 @@ Resources: ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"MyLambda\\", \\"type\\": \\"node\\", @@ -62,6 +63,7 @@ Resources: \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", }, @@ -89,6 +91,7 @@ Resources: ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"MyLambda\\", \\"type\\": \\"node\\", @@ -108,6 +111,7 @@ Resources: \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", }, @@ -135,6 +139,7 @@ Resources: ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"MyLambda\\", \\"type\\": \\"node\\", @@ -154,6 +159,7 @@ Resources: \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", }, @@ -181,6 +187,7 @@ Resources: ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"MyLambda\\", \\"type\\": \\"node\\", @@ -200,6 +207,7 @@ Resources: \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", }, @@ -216,6 +224,7 @@ Object { ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"a:MyLambda\\", \\"type\\": \\"node\\", @@ -254,6 +263,7 @@ Object { \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", "project-a/.aws-sam/build/template.yaml": "AWSTemplateFormatVersion: 2010-09-09 @@ -294,6 +304,7 @@ Object { ".vscode/launch.json": "{ \\"version\\": \\"0.2.0\\", \\"configurations\\": [ + // BEGIN AwsSamPlugin { \\"name\\": \\"a:MyLambda\\", \\"type\\": \\"node\\", @@ -332,6 +343,7 @@ Object { \\"/**/*.js\\" ] } + // END AwsSamPlugin ] }", "project-a/.aws-sam/build/template.yaml": "AWSTemplateFormatVersion: 2010-09-09 diff --git a/src/__tests__/integration.test.ts b/src/__tests__/integration.test.ts index 8f83cff..4995eb5 100644 --- a/src/__tests__/integration.test.ts +++ b/src/__tests__/integration.test.ts @@ -189,6 +189,165 @@ test("Happy path with VS Code debugging disabled", () => { expect({ entryPoints, files: fs.__getMockWrittenFiles() }).toMatchSnapshot(); }); +const vscodeLaunchJson1 = `{ + "version": "0.2.0", + "configurations": [ + { + "name": "CustomLambda", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 5858, + "localRoot": "\${workspaceFolder}/.aws-sam/build/CustomLambda", + "remoteRoot": "/var/task", + "protocol": "inspector", + "stopOnEntry": false, + "outFiles": [ + "\${workspaceFolder}/.aws-sam/build/CustomLambda/**/*.js" + ], + "sourceMaps": true, + "skipFiles": [ + "/var/runtime/**/*.js", + "/**/*.js" + ] + } + ] +}`; +const vscodeLaunchJson2 = `{ + "version": "0.2.0", + "configurations": [ + { + "name": "CustomLambda", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 5858, + "localRoot": "\${workspaceFolder}/.aws-sam/build/CustomLambda", + "remoteRoot": "/var/task", + "protocol": "inspector", + "stopOnEntry": false, + "outFiles": [ + "\${workspaceFolder}/.aws-sam/build/CustomLambda/**/*.js" + ], + "sourceMaps": true, + "skipFiles": [ + "/var/runtime/**/*.js", + "/**/*.js" + ] + }, + // BEGIN AwsSamPlugin + { + "name": "OldLambda", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 5858, + "localRoot": "\${workspaceFolder}/.aws-sam/build/OldLambda", + "remoteRoot": "/var/task", + "protocol": "inspector", + "stopOnEntry": false, + "outFiles": [ + "\${workspaceFolder}/.aws-sam/build/OldLambda/**/*.js" + ], + "sourceMaps": true, + "skipFiles": [ + "/var/runtime/**/*.js", + "/**/*.js" + ] + } + // END AwsSamPlugin + ] +}`; +const vscodeLaunchJsonTest = `{ + "version": "0.2.0", + "configurations": [ + { + "name": "CustomLambda", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 5858, + "localRoot": "\${workspaceFolder}/.aws-sam/build/CustomLambda", + "remoteRoot": "/var/task", + "protocol": "inspector", + "stopOnEntry": false, + "outFiles": [ + "\${workspaceFolder}/.aws-sam/build/CustomLambda/**/*.js" + ], + "sourceMaps": true, + "skipFiles": [ + "/var/runtime/**/*.js", + "/**/*.js" + ] + }, + // BEGIN AwsSamPlugin + { + "name": "MyLambda", + "type": "node", + "request": "attach", + "address": "localhost", + "port": 5858, + "localRoot": "\${workspaceFolder}/.aws-sam/build/MyLambda", + "remoteRoot": "/var/task", + "protocol": "inspector", + "stopOnEntry": false, + "outFiles": [ + "\${workspaceFolder}/.aws-sam/build/MyLambda/**/*.js" + ], + "sourceMaps": true, + "skipFiles": [ + "/var/runtime/**/*.js", + "/**/*.js" + ] + } + // END AwsSamPlugin + ] +}`; + +test.each([ + [vscodeLaunchJson1, vscodeLaunchJsonTest], + [vscodeLaunchJson2, vscodeLaunchJsonTest], +])("Happy build launch.json with replace old content", (srcData, testData) => { + const plugin = new SamPlugin({ vscodeDebug: true }); + + // @ts-ignore + fs.__clearMocks(); + // @ts-ignore + fs.__setMockDirs(["."]); + // @ts-ignore + fs.__setMockFiles({ "./template.yaml": samTemplate, ".vscode/launch.json": srcData }); + + // @ts-ignore + path.__clearMocks(); + // @ts-ignore + path.__setMockBasenames({ "./template.yaml": "template.yaml" }); + // @ts-ignore + path.__setMockDirnames({ "./template.yaml": "." }); + // @ts-ignore + path.__setMockRelatives({ ".#.": "" }); + + const entryPoints = plugin.entry(); + + let afterEmit: (_compilation: any) => void; + + plugin.apply({ + hooks: { + afterEmit: { + tap: (n: string, f: (_compilation: any) => void) => { + afterEmit = f; + }, + }, + }, + }); + // @ts-ignore + afterEmit(null); + + // @ts-ignore + const vscodeLaunchJsonContent = fs.__getMockWrittenFiles()[".vscode/launch.json"]; + + expect(vscodeLaunchJsonContent).toEqual(testData); +}); + test("Happy path with multiple projects works", () => { const plugin = new SamPlugin({ projects: { a: "project-a", b: "project-b" } }); diff --git a/src/index.ts b/src/index.ts index 15cff38..ad846f0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -335,7 +335,35 @@ class AwsSamPlugin { if (!fs.existsSync(".vscode")) { fs.mkdirSync(".vscode"); } - fs.writeFileSync(".vscode/launch.json", JSON.stringify(this.launchConfig, null, 2)); + + const launchPath = ".vscode/launch.json"; + + const launchContent = JSON.stringify(this.launchConfig, null, 2) + .replace(/^(.*"configurations": \[\s*)$/m, "$1\n // BEGIN AwsSamPlugin") + .replace(/(\n \s*\][\r\n]+\})$/m, "\n // END AwsSamPlugin$1"); + const regexBlock = /\s+\/\/ BEGIN AwsSamPlugin(\r|\n|.)+\/\/ END AwsSamPlugin/m; + + // get new "configurations" content + const matches = launchContent.match(regexBlock); + if (!matches) { + throw new Error(launchPath + " new content does not match"); + } + const launchConfigurations = matches[0]; + + if (fs.existsSync(launchPath)) { + const launchContentOld = fs.readFileSync(launchPath).toString("utf8"); + if (launchContentOld.match(regexBlock)) { + // partial rewrite contents + const newContent = launchContentOld.replace(regexBlock, () => launchConfigurations); + fs.writeFileSync(launchPath, newContent); + } else { + // add configurations + const newContent = launchContentOld.replace(/(\n \]\n\})$/m, (p0, p1) => `,${launchConfigurations}${p1}`); + fs.writeFileSync(launchPath, newContent); + } + } else { + fs.writeFileSync(launchPath, launchContent); + } } }); }