Skip to content

Commit 8038675

Browse files
committed
migrate generate-sam-template to typescript
1 parent c4c8db2 commit 8038675

File tree

6 files changed

+346
-108
lines changed

6 files changed

+346
-108
lines changed

packages/aws-durable-execution-sdk-js-examples/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"copy-examples": "cp -r dist/examples/*.js dist/examples/*.js.map build/aws-durable-execution-sdk-js-examples",
3737
"copy-source": "mkdir -p build/source && cp -r src/examples/*.ts build/source/",
3838
"copy-catalog": "cp examples-catalog.json build/aws-durable-execution-sdk-js-examples/",
39-
"generate-sam-template": "node scripts/generate-sam-template.js",
39+
"generate-sam-template": "tsx scripts/generate-sam-template.ts",
4040
"test": "npm run unit-test",
4141
"test:integration": "NODE_ENV=integration jest --config jest.config.integration.js",
4242
"pretest-with-sdk-coverage": "node scripts/copy-sdk-source.js",

packages/aws-durable-execution-sdk-js-examples/rollup.config.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import nodeResolve from "@rollup/plugin-node-resolve";
77
import json from "@rollup/plugin-json";
88
import commonJs from "@rollup/plugin-commonjs";
99
import path from "path";
10+
import { fileURLToPath } from "url";
1011

1112
const allExamplePaths = examplesCatalog.map((example) =>
1213
path.resolve(example.path),
@@ -43,6 +44,10 @@ export default defineConfig({
4344
typescript({
4445
// Disable incremental build to ensure examples catalog is parsed
4546
incremental: false,
47+
tsconfig: path.resolve(
48+
path.dirname(fileURLToPath(import.meta.url)),
49+
"./tsconfig.build.json",
50+
),
4651
}),
4752
nodeResolve({
4853
preferBuiltins: true,

packages/aws-durable-execution-sdk-js-examples/src/__tests__/generate-sam-template.test.ts renamed to packages/aws-durable-execution-sdk-js-examples/scripts/__tests__/generate-sam-template.test.ts

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,35 @@
1-
const {
1+
import {
22
toPascalCase,
3-
getExampleFiles,
43
createFunctionResource,
54
generateTemplate,
6-
} = require("../../scripts/generate-sam-template.js");
5+
getExamplesCatalogJson,
6+
} from "../generate-sam-template";
7+
8+
jest.mock("../generate-sam-template", () => ({
9+
...jest.requireActual("../generate-sam-template"),
10+
getExamplesCatalogJson: jest.fn(() => [
11+
{
12+
name: "hello-world",
13+
description: "A simple hello world example with no durable operations",
14+
path: "aws-durable-execution-sdk-js/packages/aws-durable-execution-sdk-js-examples/src/examples/hello-world/hello-world.ts",
15+
handler: "hello-world.handler",
16+
durableConfig: {
17+
ExecutionTimeout: 60,
18+
RetentionPeriodInDays: 7,
19+
},
20+
},
21+
{
22+
name: "steps-with-retry",
23+
description: "An example demonstrating retry functionality with steps",
24+
path: "aws-durable-execution-sdk-js/packages/aws-durable-execution-sdk-js-examples/src/examples/step/steps-with-retry/steps-with-retry.ts",
25+
handler: "steps-with-retry.handler",
26+
durableConfig: {
27+
ExecutionTimeout: 60,
28+
RetentionPeriodInDays: 7,
29+
},
30+
},
31+
]),
32+
}));
733

834
describe("generate-sam-template", () => {
935
describe("toPascalCase", () => {
@@ -17,16 +43,10 @@ describe("generate-sam-template", () => {
1743

1844
describe("createFunctionResource", () => {
1945
test("creates default function resource", () => {
20-
const resource = createFunctionResource("hello-world", {
21-
name: "Hello World",
22-
description: "A simple hello world example with no durable operations",
23-
path: "aws-durable-execution-sdk-js/packages/aws-durable-execution-sdk-js-examples/src/examples/hello-world/hello-world.ts",
24-
handler: "hello-world.handler",
25-
durableConfig: {
26-
ExecutionTimeout: 60,
27-
RetentionPeriodInDays: 7,
28-
},
29-
});
46+
const resource = createFunctionResource(
47+
"hello-world",
48+
getExamplesCatalogJson()[0],
49+
);
3050

3151
expect(resource.Type).toBe("AWS::Serverless::Function");
3252
expect(resource.Properties.FunctionName).toBe("hello-world");
@@ -38,16 +58,10 @@ describe("generate-sam-template", () => {
3858
});
3959

4060
test("creates function resource with custom config for steps-with-retry", () => {
41-
const resource = createFunctionResource("steps-with-retry", {
42-
name: "Steps With Retry",
43-
description: "An example demonstrating retry functionality with steps",
44-
path: "aws-durable-execution-sdk-js/packages/aws-durable-execution-sdk-js-examples/src/examples/step/steps-with-retry/steps-with-retry.ts",
45-
handler: "steps-with-retry.handler",
46-
durableConfig: {
47-
ExecutionTimeout: 60,
48-
RetentionPeriodInDays: 7,
49-
},
50-
});
61+
const resource = createFunctionResource(
62+
"steps-with-retry",
63+
getExamplesCatalogJson()[1],
64+
);
5165

5266
expect(resource.Properties.FunctionName).toBe("steps-with-retry");
5367
expect(resource.Properties.MemorySize).toBe(256);

packages/aws-durable-execution-sdk-js-examples/scripts/generate-sam-template.js renamed to packages/aws-durable-execution-sdk-js-examples/scripts/generate-sam-template.ts

Lines changed: 24 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env node
22

3-
const fs = require("fs");
4-
const path = require("path");
5-
const yaml = require("js-yaml");
3+
import fs from "fs";
4+
import path from "path";
5+
import yaml from "js-yaml";
66

77
// Configuration for different examples that need special settings
8-
const EXAMPLE_CONFIGS = {
8+
const EXAMPLE_CONFIGS: Record<string, any> = {
99
"steps-with-retry": {
1010
memorySize: 256,
1111
timeout: 300,
@@ -29,90 +29,24 @@ const DEFAULT_CONFIG = {
2929
/**
3030
* Convert kebab-case filename to PascalCase resource name
3131
*/
32-
function toPascalCase(filename) {
32+
function toPascalCase(filename: string) {
3333
return filename
3434
.split("-")
35-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
35+
.map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
3636
.join("");
3737
}
3838

39-
/**
40-
* Get TypeScript files from src/examples directory
41-
*/
42-
function getExampleFiles() {
43-
const catalogPath = path.join(
44-
__dirname,
45-
"../src/utils/examples-catalog.json",
46-
);
47-
48-
if (!fs.existsSync(catalogPath)) {
49-
throw new Error(`Examples directory not found: ${catalogPath}`);
50-
}
51-
52-
const catalog = JSON.parse(fs.readFileSync(catalogPath, "utf8"));
53-
54-
const exampleFiles = catalog.map((example) => example.name);
55-
56-
// Read all directories in examples
57-
const entries = fs.readdirSync(examplesDir, { withFileTypes: true });
58-
59-
for (const entry of entries) {
60-
// Skip non-directories and special directories
61-
if (!entry.isDirectory() || entry.name.startsWith(".")) {
62-
continue;
63-
}
64-
65-
const dirPath = path.join(examplesDir, entry.name);
66-
const subEntries = fs.readdirSync(dirPath, { withFileTypes: true });
67-
68-
// Check if this directory contains TypeScript files directly (standalone examples)
69-
const directTsFiles = subEntries.filter(
70-
(dirent) =>
71-
dirent.isFile() &&
72-
dirent.name.endsWith(".ts") &&
73-
!dirent.name.includes(".test"),
74-
);
75-
76-
if (directTsFiles.length > 0) {
77-
// Standalone example directory
78-
directTsFiles.forEach((file) => {
79-
exampleFiles.push(path.basename(file.name, ".ts"));
80-
});
81-
} else {
82-
// Nested structure - scan subdirectories
83-
const subDirs = subEntries.filter((dirent) => dirent.isDirectory());
84-
85-
for (const subDir of subDirs) {
86-
const subDirPath = path.join(dirPath, subDir.name);
87-
const filesInSubDir = fs.readdirSync(subDirPath);
88-
89-
// Find TypeScript files (excluding test files)
90-
const tsFiles = filesInSubDir.filter(
91-
(file) => file.endsWith(".ts") && !file.includes(".test."),
92-
);
93-
94-
// Add each example file (without .ts extension)
95-
tsFiles.forEach((file) => {
96-
exampleFiles.push(path.basename(file, ".ts"));
97-
});
98-
}
99-
}
100-
}
101-
102-
return exampleFiles.sort(); // Sort for consistent output
103-
}
104-
10539
/**
10640
* Create a Lambda function resource configuration
10741
*/
10842
function createFunctionResource(
109-
resourceName,
110-
catalog,
43+
resourceName: string,
44+
catalog: any,
11145
skipVerboseLogging = false,
11246
) {
11347
const config = EXAMPLE_CONFIGS[resourceName] || DEFAULT_CONFIG;
11448

115-
const functionResource = {
49+
const functionResource: Record<string, any> = {
11650
Type: "AWS::Serverless::Function",
11751
Properties: {
11852
FunctionName: resourceName,
@@ -145,10 +79,7 @@ function createFunctionResource(
14579
return functionResource;
14680
}
14781

148-
/**
149-
* Generate the complete CloudFormation template
150-
*/
151-
function generateTemplate(skipVerboseLogging = false) {
82+
function getExamplesCatalogJson() {
15283
const examplesCatalogPath = path.join(
15384
__dirname,
15485
"../src/utils/examples-catalog.json",
@@ -166,7 +97,16 @@ function generateTemplate(skipVerboseLogging = false) {
16697
throw new Error("No TypeScript example files found in src/examples");
16798
}
16899

169-
const template = {
100+
return examplesCatalog;
101+
}
102+
103+
/**
104+
* Generate the complete CloudFormation template
105+
*/
106+
function generateTemplate(skipVerboseLogging = false) {
107+
const examplesCatalog = getExamplesCatalogJson();
108+
109+
const template: Record<string, any> = {
170110
AWSTemplateFormatVersion: "2010-09-09",
171111
Description: "Durable Function examples written in TypeScript.",
172112
Transform: ["AWS::Serverless-2016-10-31"],
@@ -213,7 +153,7 @@ function generateTemplate(skipVerboseLogging = false) {
213153
};
214154

215155
// Generate resources for each example file
216-
examplesCatalog.forEach((catalog) => {
156+
examplesCatalog.forEach((catalog: { name: string; handler: string }) => {
217157
const resourceName = catalog.name.replace(/\s/g, "") + `-22x-NodeJS-Local`;
218158
template.Resources[
219159
toPascalCase(catalog.handler.slice(0, -".handler".length))
@@ -262,7 +202,7 @@ function main() {
262202
if (skipVerboseLogging) {
263203
console.log("🔇 Verbose logging disabled");
264204
}
265-
} catch (error) {
205+
} catch (error: any) {
266206
console.error("❌ Error generating template.yml:", error.message);
267207
process.exit(1);
268208
}
@@ -273,9 +213,9 @@ if (require.main === module) {
273213
main();
274214
}
275215

276-
module.exports = {
216+
export {
277217
generateTemplate,
278-
getExampleFiles,
279218
toPascalCase,
280219
createFunctionResource,
220+
getExamplesCatalogJson,
281221
};

0 commit comments

Comments
 (0)