From f69c94ad779bbc14ec1837b2dbd095b46acc7398 Mon Sep 17 00:00:00 2001 From: Oskari Okko Ojala Date: Mon, 29 Aug 2022 15:22:14 +0300 Subject: [PATCH 1/3] Fix default entry finding when Node returns paths starting with file:// --- packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index ea3b1f9b6f005..1dc06221c43df 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -171,17 +171,17 @@ function findEntry(id: string, entry?: string): string { const definingFile = findDefiningFile(); const extname = path.extname(definingFile); - const tsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.ts`); + const tsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.ts`).replace('file://', ''); if (fs.existsSync(tsHandlerFile)) { return tsHandlerFile; } - const jsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.js`); + const jsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.js`).replace('file://', ''); if (fs.existsSync(jsHandlerFile)) { return jsHandlerFile; } - const mjsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.mjs`); + const mjsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.mjs`).replace('file://', ''); if (fs.existsSync(mjsHandlerFile)) { return mjsHandlerFile; } From 47da4cef780c70712f5cc31c332719a567a7d89f Mon Sep 17 00:00:00 2001 From: Oskari Okko Ojala Date: Tue, 30 Aug 2022 17:18:01 +0300 Subject: [PATCH 2/3] Extract findDefiningFile so that it can be mocked in tests --- .../aws-lambda-nodejs/lib/function.ts | 25 ++----------------- .../@aws-cdk/aws-lambda-nodejs/lib/util.ts | 21 ++++++++++++++++ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index 1dc06221c43df..f2f3a50196641 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -6,7 +6,7 @@ import { Construct } from 'constructs'; import { Bundling } from './bundling'; import { LockFile } from './package-manager'; import { BundlingOptions } from './types'; -import { callsites, findUpMultiple } from './util'; +import { callsites, findDefiningFile, findUpMultiple } from './util'; /** * Properties for a NodejsFunction @@ -168,7 +168,7 @@ function findEntry(id: string, entry?: string): string { return entry; } - const definingFile = findDefiningFile(); + const definingFile = findDefiningFile(callsites()); const extname = path.extname(definingFile); const tsHandlerFile = definingFile.replace(new RegExp(`${extname}$`), `.${id}.ts`).replace('file://', ''); @@ -188,24 +188,3 @@ function findEntry(id: string, entry?: string): string { throw new Error(`Cannot find handler file ${tsHandlerFile}, ${jsHandlerFile} or ${mjsHandlerFile}`); } - -/** - * Finds the name of the file where the `NodejsFunction` is defined - */ -function findDefiningFile(): string { - let definingIndex; - const sites = callsites(); - for (const [index, site] of sites.entries()) { - if (site.getFunctionName() === 'NodejsFunction') { - // The next site is the site where the NodejsFunction was created - definingIndex = index + 1; - break; - } - } - - if (!definingIndex || !sites[definingIndex]) { - throw new Error('Cannot find defining file.'); - } - - return sites[definingIndex].getFileName(); -} diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts index eb2f59db03e09..b85280cc56eae 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/util.ts @@ -208,3 +208,24 @@ function extractTsConfig(tsconfigPath: string, previousCompilerOptions?: Record< } return updatedCompilerOptions; } + + +/** + * Finds the name of the file where the `NodejsFunction` is defined + */ +export function findDefiningFile(sites: CallSite[]): string { + let definingIndex; + for (const [index, site] of sites.entries()) { + if (site.getFunctionName() === 'NodejsFunction') { + // The next site is the site where the NodejsFunction was created + definingIndex = index + 1; + break; + } + } + + if (!definingIndex || !sites[definingIndex]) { + throw new Error('Cannot find defining file.'); + } + + return sites[definingIndex].getFileName(); +} From 6f983e2674b310231305299593760820aaa3646e Mon Sep 17 00:00:00 2001 From: Oskari Okko Ojala Date: Tue, 30 Aug 2022 17:19:58 +0300 Subject: [PATCH 3/3] Add test for NodejsFunction when NodeJS returns a call stack with file paths starting with file:// prefix --- .../test/function_esmPaths.test.handler1.ts | 1 + .../test/function_esmPaths.test.ts | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.handler1.ts create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.ts diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.handler1.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.handler1.ts new file mode 100644 index 0000000000000..33af638be9b99 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.handler1.ts @@ -0,0 +1 @@ +// Dummy for test purposes diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.ts new file mode 100644 index 0000000000000..5b9969f21169c --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/function_esmPaths.test.ts @@ -0,0 +1,51 @@ +import { Template } from '@aws-cdk/assertions'; +import { CodeConfig } from '@aws-cdk/aws-lambda'; +import { Stack } from '@aws-cdk/core'; +import { NodejsFunction } from '../lib'; +import { Bundling } from '../lib/bundling'; +import { CallSite } from '../lib/util'; +import * as util from '../lib/util'; + +jest.mock('../lib/bundling', () => { + return { + Bundling: { + bundle: jest.fn().mockReturnValue({ + bind: (): CodeConfig => { + return { + s3Location: { + bucketName: 'my-bucket', + objectKey: 'my-key', + }, + }; + }, + bindToResource: () => { return; }, + }), + }, + }; +}); + +const actualFindDefiningFile = util.findDefiningFile; + +jest.spyOn(util, 'findDefiningFile').mockImplementation((sites: CallSite[]): string => { + return 'file://' + actualFindDefiningFile(sites); +}); + +let stack: Stack; +beforeEach(() => { + stack = new Stack(); + jest.clearAllMocks(); +}); + +test('NodejsFunction with .ts handler, with ESM file:// paths', () => { + // WHEN + new NodejsFunction(stack, 'handler1'); + + expect(Bundling.bundle).toHaveBeenCalledWith(expect.objectContaining({ + entry: expect.stringContaining('function_esmPaths.test.handler1.ts'), // Automatically finds .ts handler file + })); + + Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', { + Handler: 'index.handler', + Runtime: 'nodejs14.x', + }); +});