diff --git a/package.json b/package.json index f295b20..2895037 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "samp-cli", - "version": "1.0.60", + "version": "1.0.61", "description": "CLI tool for extended productivity with AWS Serverless Application Model (SAM)", "main": "index.js", "scripts": { diff --git a/src/commands/local/runtime-support/nodejs/cdk/cdk-wrapper.js b/src/commands/local/runtime-support/nodejs/cdk/cdk-wrapper.js index c726013..d328ab5 100644 --- a/src/commands/local/runtime-support/nodejs/cdk/cdk-wrapper.js +++ b/src/commands/local/runtime-support/nodejs/cdk/cdk-wrapper.js @@ -1,127 +1,45 @@ -const cdk = require('aws-cdk-lib'); const fs = require('fs'); const { yamlDump } = require('yaml-cfn'); -const path = require('path'); -const jsonpath = require('jsonpath'); -const baseDir = `${process.cwd()}/.samp-out`; +const cdkDir = `${process.cwd()}/cdk.out`; +const inputUtil = require('../../../../../shared/inputUtil'); -for (const file of getAllJsFiles(baseDir)) { - if (file.endsWith('.js')) { - let fileContents = fs.readFileSync(file, 'utf8'); - if (fileContents.includes('aws-cdk-lib')) { - fileContents = fileContents.replace(/\.ts"/g, '.js"').replace(/\.ts'/g, ".js'").replace(/\.ts`/g, ".js`"); - fs.writeFileSync(file, fileContents); - } - } -} - -const TargetStack = require(`${process.cwd()}/${process.argv[2]}`); -const className = Object.keys(TargetStack)[0]; - -const templatePath = `${process.cwd()}/cdk.out/${process.env.SAMP_STACKNAME}.template.json`; +const templatePath = `${cdkDir}/${process.env.SAMP_STACKNAME}.template.json`; const synthedTemplate = JSON.parse(fs.readFileSync(templatePath, 'utf8')); -const stack = new TargetStack[className](null, process.env.SAMP_STACKNAME, {}); -const resources = stack.node._children; const mockTemplate = { AWSTemplateFormatVersion: "2010-09-09", Transform: ['AWS::Serverless-2016-10-31'], Resources: {} }; -for (const key of Object.keys(resources)) { - const resource = JSON.parse(JSON.stringify(resources[key], getCircularReplacer())); - delete resource.node?._children?._children?._children?.stack; - const fingerprintOptions = findShallowestOccurrence(resource, 'fingerprintOptions').occurrence; - - const entry = fingerprintOptions?.bundling?.relativeEntryPath || (fingerprintOptions?.path ? `${fingerprintOptions?.path}/` : null); +for (const fn of Object.keys(synthedTemplate.Resources)) { + const resource = synthedTemplate.Resources[fn]; + if (resource.Type === "AWS::Lambda::Function") { + if (!resource.Properties?.Code?.S3Bucket) continue; + if (!resource.Properties?.Runtime.startsWith("node")) continue; + if (resource.Metadata?.["aws:asset:is-bundled"] === false) continue; + if (resource.Metadata?.['aws:cdk:path'].includes('/Resource')) { + const asset = `${resource.Metadata?.['aws:asset:path']}/index.js`; + const assetFile = fs.readFileSync(`${cdkDir}/${asset}`, 'utf8'); + const fileNames = assetFile.match(/\n\/\/.+?\.ts\n/g); + let fileName = null; + if (fileNames && fileNames.length === 1) { + fileName = fileNames[0].replace('// ', '').replace('.ts', '').replace(/\n/g, ''); + } else { + const handler = await inputUtil.file("Select handler file", "*.ts"); + } - let logicalId = null; - let handler - if (entry) { - for (const fn of Object.keys(synthedTemplate.Resources)) { - const resource = synthedTemplate.Resources[fn]; - if (resource.Type === "AWS::Lambda::Function") { - if (!resource.Properties?.Code?.S3Bucket) continue; - if (!resource.Properties?.Runtime.startsWith("node")) continue; - if (resource.Metadata?.["aws:asset:is-bundled"] === false) continue; - if (resource.Metadata?.['aws:cdk:path'].includes(`/${key}/`) && resource.Metadata?.['aws:cdk:path'].includes('/Resource')) { - //get filename from entry + logicalId = fn; + const handler = `${fileName}.${resource.Properties.Handler.split(".")[1]}`; + if (logicalId === null) continue; - const entryFile = entry.substring(entry.lastIndexOf("/") + 1).split(".")[0]; - logicalId = fn; - handler = `${entryFile}.${resource.Properties.Handler.split(".")[1]}`; - break; + mockTemplate.Resources[logicalId] = { + Type: "AWS::Serverless::Function", + Properties: { + CodeUri: ".", + Handler: handler } } } - if (logicalId === null) continue; - - mockTemplate.Resources[logicalId] = { - Type: "AWS::Serverless::Function", - Properties: { - CodeUri: ".", - Handler: `${entry.substring(0, entry.lastIndexOf("/"))}/${handler}`, - } - } } } fs.writeFileSync(".samp-out/mock-template.yaml", yamlDump(mockTemplate)); -fs.writeFileSync(".samp-out/stack-dump.json", JSON.stringify(stack.node._children, getCircularReplacer(), 2)); -function getCircularReplacer() { - const seen = new WeakSet(); - return (key, value) => { - if (typeof value === "object" && value !== null) { - if (seen.has(value)) { - return "[Circular Reference]"; - } - seen.add(value); - } - return value; - }; -} - -function getAllJsFiles(directory) { - let fileArray = []; - - const files = fs.readdirSync(directory); - - for (const file of files) { - const filePath = path.join(directory, file); - const fileStats = fs.statSync(filePath); - - if (fileStats.isDirectory()) { - const nestedFiles = getAllJsFiles(filePath); // Recursively get files in subdirectory - fileArray = fileArray.concat(nestedFiles); - } else { - if (filePath.endsWith('.js')) - fileArray.push(filePath); - } - } - - return fileArray; -} - - -function findShallowestOccurrence(obj, key, depth = 0) { - let shallowestDepth = Infinity; - let shallowestOccurrence = null; - - for (const prop in obj) { - if (obj.hasOwnProperty(prop)) { - if (prop === key) { - if (depth < shallowestDepth) { - shallowestDepth = depth; - shallowestOccurrence = obj[prop]; - } - } else if (typeof obj[prop] === 'object') { - const occurrence = findShallowestOccurrence(obj[prop], key, depth + 1); - if (occurrence && occurrence.depth < shallowestDepth) { - shallowestDepth = occurrence.depth; - shallowestOccurrence = occurrence.occurrence; - } - } - } - } - - return { occurrence: shallowestOccurrence, depth: shallowestDepth }; -} \ No newline at end of file