@bifravst/aws-cdk-lambda-helpers 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/findDependencies.d.ts +11 -3
- package/dist/src/findDependencies.js +59 -25
- package/dist/src/findDependencies.spec.js +12 -1
- package/dist/src/packLambda.js +2 -1
- package/dist/src/packLambdaFromPath.d.ts +17 -1
- package/dist/src/packLambdaFromPath.js +5 -9
- package/dist/src/test-data/resolve-paths/foo/1.d.ts +1 -0
- package/dist/src/test-data/resolve-paths/foo/1.js +1 -0
- package/dist/src/test-data/resolve-paths/foo/2.d.ts +1 -0
- package/dist/src/test-data/resolve-paths/foo/2.js +1 -0
- package/dist/src/test-data/resolve-paths/foo/index.d.ts +1 -0
- package/dist/src/test-data/resolve-paths/foo/index.js +1 -0
- package/package.json +2 -2
@@ -1,9 +1,17 @@
|
|
1
1
|
/**
|
2
2
|
* Resolve project-level dependencies for the given file using TypeScript compiler API
|
3
3
|
*/
|
4
|
-
export declare const findDependencies: (
|
4
|
+
export declare const findDependencies: (args: {
|
5
5
|
sourceFilePath: string;
|
6
|
-
tsConfigFilePath?: string;
|
7
6
|
imports?: string[];
|
8
7
|
visited?: string[];
|
9
|
-
|
8
|
+
tsConfigFilePath?: string;
|
9
|
+
importsSubpathPatterns?: Record<string, string>;
|
10
|
+
}) => {
|
11
|
+
dependencies: string[];
|
12
|
+
/**
|
13
|
+
* A map of import subpath patterns to their resolved paths
|
14
|
+
* @see https://nodejs.org/api/packages.html#subpath-patterns
|
15
|
+
*/
|
16
|
+
importsSubpathPatterns: Record<string, string>;
|
17
|
+
};
|
@@ -4,30 +4,36 @@ import ts, {} from 'typescript';
|
|
4
4
|
/**
|
5
5
|
* Resolve project-level dependencies for the given file using TypeScript compiler API
|
6
6
|
*/
|
7
|
-
export const findDependencies = (
|
8
|
-
const
|
9
|
-
const
|
7
|
+
export const findDependencies = (args) => {
|
8
|
+
const sourceFilePath = args.sourceFilePath;
|
9
|
+
const visited = args.visited ?? [];
|
10
|
+
const dependencies = args.imports ?? [];
|
11
|
+
let importsSubpathPatterns = args.importsSubpathPatterns ?? {};
|
10
12
|
if (visited.includes(sourceFilePath))
|
11
|
-
return
|
13
|
+
return { dependencies, importsSubpathPatterns };
|
14
|
+
const tsConfigFilePath = args.tsConfigFilePath;
|
12
15
|
const tsConfig = tsConfigFilePath !== undefined
|
13
16
|
? JSON.parse(readFileSync(tsConfigFilePath, 'utf-8').toString())
|
14
17
|
: undefined;
|
15
18
|
const fileNode = ts.createSourceFile(sourceFilePath, readFileSync(sourceFilePath, 'utf-8').toString(), ts.ScriptTarget.ES2022,
|
16
19
|
/*setParentNodes */ true);
|
17
20
|
const parseChild = (node) => {
|
18
|
-
if (node.kind !== ts.SyntaxKind.ImportDeclaration
|
21
|
+
if (node.kind !== ts.SyntaxKind.ImportDeclaration &&
|
22
|
+
node.kind !== ts.SyntaxKind.ExportDeclaration)
|
19
23
|
return;
|
20
24
|
const moduleSpecifier = node.moduleSpecifier.text;
|
21
|
-
const file = resolve({
|
25
|
+
const { resolvedPath: file, importsSubpathPatterns: updatedImportsSubpathPatterns, } = resolve({
|
22
26
|
moduleSpecifier,
|
23
27
|
sourceFilePath,
|
24
28
|
tsConfigFilePath,
|
25
29
|
tsConfig,
|
30
|
+
importsSubpathPatterns,
|
26
31
|
});
|
32
|
+
importsSubpathPatterns = updatedImportsSubpathPatterns;
|
27
33
|
try {
|
28
34
|
const s = statSync(file);
|
29
35
|
if (!s.isDirectory())
|
30
|
-
|
36
|
+
dependencies.push(file);
|
31
37
|
}
|
32
38
|
catch {
|
33
39
|
// Module or file not found
|
@@ -36,26 +42,30 @@ export const findDependencies = ({ sourceFilePath, tsConfigFilePath, imports: im
|
|
36
42
|
};
|
37
43
|
ts.forEachChild(fileNode, parseChild);
|
38
44
|
visited.push(sourceFilePath);
|
39
|
-
for (const file of
|
45
|
+
for (const file of dependencies) {
|
40
46
|
findDependencies({
|
41
47
|
sourceFilePath: file,
|
42
|
-
imports,
|
48
|
+
imports: dependencies,
|
43
49
|
visited,
|
44
50
|
tsConfigFilePath,
|
51
|
+
importsSubpathPatterns,
|
45
52
|
});
|
46
53
|
}
|
47
|
-
return
|
54
|
+
return { dependencies, importsSubpathPatterns };
|
48
55
|
};
|
49
|
-
const resolve = ({ moduleSpecifier, sourceFilePath, tsConfigFilePath, tsConfig, }) => {
|
56
|
+
const resolve = ({ moduleSpecifier, sourceFilePath, tsConfigFilePath, tsConfig, importsSubpathPatterns, }) => {
|
50
57
|
if (moduleSpecifier.startsWith('.'))
|
51
|
-
return
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
return {
|
59
|
+
resolvedPath: path
|
60
|
+
.resolve(path.parse(sourceFilePath).dir, moduleSpecifier)
|
61
|
+
// In ECMA Script modules, all imports from local files must have an extension.
|
62
|
+
// See https://nodejs.org/api/esm.html#mandatory-file-extensions
|
63
|
+
// So we need to replace the `.js` in the import specification to find the TypeScript source for the file.
|
64
|
+
// Example: import { Network, notifyClients } from './notifyClients.js'
|
65
|
+
// The source file for that is actually in './notifyClients.ts'
|
66
|
+
.replace(/\.js$/, '.ts'),
|
67
|
+
importsSubpathPatterns,
|
68
|
+
};
|
59
69
|
if (tsConfigFilePath !== undefined &&
|
60
70
|
tsConfig?.compilerOptions?.paths !== undefined) {
|
61
71
|
for (const [key, value] of Object.entries(tsConfig.compilerOptions.paths)) {
|
@@ -64,7 +74,18 @@ const resolve = ({ moduleSpecifier, sourceFilePath, tsConfigFilePath, tsConfig,
|
|
64
74
|
continue;
|
65
75
|
// Exact match
|
66
76
|
if (moduleSpecifier === key) {
|
67
|
-
|
77
|
+
const fullResolvedPath = path.join(path.parse(tsConfigFilePath).dir, tsConfig.compilerOptions.baseUrl, resolvedPath);
|
78
|
+
return {
|
79
|
+
resolvedPath: fullResolvedPath,
|
80
|
+
importsSubpathPatterns: {
|
81
|
+
...importsSubpathPatterns,
|
82
|
+
[key]: [
|
83
|
+
tsConfig.compilerOptions.baseUrl,
|
84
|
+
path.sep,
|
85
|
+
resolvedPath.replace(/\.ts$/, '.js'),
|
86
|
+
].join(''),
|
87
|
+
},
|
88
|
+
};
|
68
89
|
}
|
69
90
|
// Wildcard match
|
70
91
|
if (!key.includes('*'))
|
@@ -73,11 +94,24 @@ const resolve = ({ moduleSpecifier, sourceFilePath, tsConfigFilePath, tsConfig,
|
|
73
94
|
const maybeMatch = rx.exec(moduleSpecifier);
|
74
95
|
if (maybeMatch?.groups?.wildcard === undefined)
|
75
96
|
continue;
|
76
|
-
return
|
77
|
-
|
78
|
-
|
79
|
-
|
97
|
+
return {
|
98
|
+
resolvedPath: path
|
99
|
+
.resolve(path.parse(tsConfigFilePath).dir, tsConfig.compilerOptions.baseUrl, resolvedPath.replace('*', maybeMatch.groups.wildcard))
|
100
|
+
// Same as above, replace `.js` with `.ts`
|
101
|
+
.replace(/\.js$/, '.ts'),
|
102
|
+
importsSubpathPatterns: {
|
103
|
+
...importsSubpathPatterns,
|
104
|
+
[key]: [
|
105
|
+
tsConfig.compilerOptions.baseUrl,
|
106
|
+
path.sep,
|
107
|
+
resolvedPath.replace(/\.ts$/, '.js'),
|
108
|
+
].join(''),
|
109
|
+
},
|
110
|
+
};
|
80
111
|
}
|
81
112
|
}
|
82
|
-
return
|
113
|
+
return {
|
114
|
+
resolvedPath: moduleSpecifier,
|
115
|
+
importsSubpathPatterns,
|
116
|
+
};
|
83
117
|
};
|
@@ -6,11 +6,22 @@ import { findDependencies } from './findDependencies.js';
|
|
6
6
|
const __dirname = new URL('.', import.meta.url).pathname;
|
7
7
|
void describe('findDependencies()', () => {
|
8
8
|
void it('should honor tsconfig.json paths', () => {
|
9
|
-
const dependencies = findDependencies({
|
9
|
+
const { dependencies } = findDependencies({
|
10
10
|
sourceFilePath: path.join(__dirname, 'test-data', 'resolve-paths', 'lambda.ts'),
|
11
11
|
tsConfigFilePath: path.join(__dirname, 'test-data', 'resolve-paths', 'tsconfig.json'),
|
12
12
|
});
|
13
13
|
assert.equal(dependencies.includes(path.join(__dirname, 'test-data', 'resolve-paths', 'foo', 'index.ts')), true, 'Should include the index.ts file');
|
14
|
+
assert.equal(dependencies.includes(path.join(__dirname, 'test-data', 'resolve-paths', 'foo', '1.ts')), true, 'Should include the module referenced in the index.ts file');
|
14
15
|
assert.equal(dependencies.includes(path.join(__dirname, 'test-data', 'resolve-paths', 'foo', '2.ts')), true, 'Should include the module file');
|
15
16
|
});
|
17
|
+
void it('should return an import map', () => {
|
18
|
+
const { importsSubpathPatterns } = findDependencies({
|
19
|
+
sourceFilePath: path.join(__dirname, 'test-data', 'resolve-paths', 'lambda.ts'),
|
20
|
+
tsConfigFilePath: path.join(__dirname, 'test-data', 'resolve-paths', 'tsconfig.json'),
|
21
|
+
});
|
22
|
+
assert.deepEqual(importsSubpathPatterns, {
|
23
|
+
'#foo': './foo/index.js',
|
24
|
+
'#foo/*': './foo/*',
|
25
|
+
});
|
26
|
+
});
|
16
27
|
});
|
package/dist/src/packLambda.js
CHANGED
@@ -22,7 +22,7 @@ const removeCommonAncestor = (parentDir) => (filePath) => {
|
|
22
22
|
* In the bundle we only include code that's not in the layer.
|
23
23
|
*/
|
24
24
|
export const packLambda = async ({ sourceFilePath, zipFilePath, tsConfigFilePath, debug, progress, }) => {
|
25
|
-
const deps = findDependencies({
|
25
|
+
const { dependencies: deps, importsSubpathPatterns } = findDependencies({
|
26
26
|
sourceFilePath,
|
27
27
|
tsConfigFilePath,
|
28
28
|
});
|
@@ -61,6 +61,7 @@ export const packLambda = async ({ sourceFilePath, zipFilePath, tsConfigFilePath
|
|
61
61
|
// Mark it as ES module
|
62
62
|
zipfile.addBuffer(Buffer.from(JSON.stringify({
|
63
63
|
type: 'module',
|
64
|
+
imports: importsSubpathPatterns,
|
64
65
|
}), 'utf-8'), 'package.json');
|
65
66
|
progress?.(`added`, 'package.json');
|
66
67
|
await new Promise((resolve) => {
|
@@ -1,2 +1,18 @@
|
|
1
1
|
import { type PackedLambda } from './packLambda.js';
|
2
|
-
export declare const packLambdaFromPath: (id
|
2
|
+
export declare const packLambdaFromPath: ({ id, sourceFilePath, handlerFunction: handlerFunctionArg, baseDir: baseDirArg, distDir: distDirArg, tsConfigFilePath, }: {
|
3
|
+
id: string;
|
4
|
+
sourceFilePath: string;
|
5
|
+
handlerFunction?: string;
|
6
|
+
/**
|
7
|
+
* @default process.cwd()
|
8
|
+
*/
|
9
|
+
baseDir?: string;
|
10
|
+
/**
|
11
|
+
* @default ${baseDir}/dist/lambdas
|
12
|
+
*/
|
13
|
+
distDir?: string;
|
14
|
+
/**
|
15
|
+
* Pass the path to the tsconfig.json file if you want to use paths from the tsconfig.json file.
|
16
|
+
*/
|
17
|
+
tsConfigFilePath?: string;
|
18
|
+
}) => Promise<PackedLambda>;
|
@@ -1,15 +1,10 @@
|
|
1
1
|
import { mkdir } from 'node:fs/promises';
|
2
2
|
import path from 'node:path';
|
3
3
|
import { packLambda } from './packLambda.js';
|
4
|
-
export const packLambdaFromPath = async (id, sourceFilePath, handlerFunction
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
baseDir = process.cwd(),
|
9
|
-
/**
|
10
|
-
* @default ${baseDir}/dist/lambdas
|
11
|
-
*/
|
12
|
-
distDir = path.join(process.cwd(), 'dist', 'lambdas')) => {
|
4
|
+
export const packLambdaFromPath = async ({ id, sourceFilePath, handlerFunction: handlerFunctionArg, baseDir: baseDirArg, distDir: distDirArg, tsConfigFilePath, }) => {
|
5
|
+
const distDir = distDirArg ?? path.join(process.cwd(), 'dist', 'lambdas');
|
6
|
+
const baseDir = baseDirArg ?? process.cwd();
|
7
|
+
const handlerFunction = handlerFunctionArg ?? 'handler';
|
13
8
|
try {
|
14
9
|
await mkdir(distDir, {
|
15
10
|
recursive: true,
|
@@ -22,6 +17,7 @@ distDir = path.join(process.cwd(), 'dist', 'lambdas')) => {
|
|
22
17
|
const { handler, hash } = await packLambda({
|
23
18
|
sourceFilePath: path.join(baseDir, sourceFilePath),
|
24
19
|
zipFilePath: zipFile,
|
20
|
+
tsConfigFilePath,
|
25
21
|
});
|
26
22
|
return {
|
27
23
|
id,
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const foo: () => number;
|
@@ -0,0 +1 @@
|
|
1
|
+
export const foo = () => 42;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const foo2: () => number;
|
@@ -0,0 +1 @@
|
|
1
|
+
export const foo2 = () => 17;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { foo } from './1.js';
|
@@ -0,0 +1 @@
|
|
1
|
+
export { foo } from './1.js';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@bifravst/aws-cdk-lambda-helpers",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.1.0",
|
4
4
|
"description": "Helper functions which simplify working with TypeScript lambdas for AWS CDK.",
|
5
5
|
"exports": {
|
6
6
|
".": {
|
@@ -51,7 +51,7 @@
|
|
51
51
|
"author": "Nordic Semiconductor ASA | nordicsemi.no",
|
52
52
|
"license": "BSD-3-Clause",
|
53
53
|
"devDependencies": {
|
54
|
-
"@aws-sdk/client-cloudformation": "3.
|
54
|
+
"@aws-sdk/client-cloudformation": "3.692.0",
|
55
55
|
"@bifravst/cloudformation-helpers": "9.1.1",
|
56
56
|
"@bifravst/eslint-config-typescript": "6.1.18",
|
57
57
|
"@bifravst/from-env": "3.0.2",
|