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 ,
@@ -17,11 +17,6 @@ const EXAMPLE_CONFIGS = {
1717 } ,
1818 ] ,
1919 } ,
20- "wait-for-callback-submitter-retry-success" : {
21- memorySize : 128 ,
22- timeout : 120 ,
23- policies : [ ] ,
24- } ,
2520} ;
2621
2722// Default configuration for Lambda functions
@@ -34,96 +29,35 @@ const DEFAULT_CONFIG = {
3429/**
3530 * Convert kebab-case filename to PascalCase resource name
3631 */
37- function toPascalCase ( filename ) {
32+ function toPascalCase ( filename : string ) {
3833 return filename
3934 . split ( "-" )
40- . map ( ( word ) => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) )
35+ . map ( ( word : string ) => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) )
4136 . join ( "" ) ;
4237}
4338
44- /**
45- * Get TypeScript files from src/examples directory
46- */
47- function getExampleFiles ( ) {
48- const examplesDir = path . join ( __dirname , "../src/examples" ) ;
49-
50- if ( ! fs . existsSync ( examplesDir ) ) {
51- throw new Error ( `Examples directory not found: ${ examplesDir } ` ) ;
52- }
53-
54- const exampleFiles = [ ] ;
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 */
108- function createFunctionResource ( filename , skipVerboseLogging = false ) {
109- const resourceName = toPascalCase ( filename ) ;
110- const config = EXAMPLE_CONFIGS [ filename ] || DEFAULT_CONFIG ;
111-
112- const functionResource = {
42+ function createFunctionResource (
43+ resourceName : string ,
44+ catalog : any ,
45+ skipVerboseLogging = false ,
46+ ) {
47+ const config = EXAMPLE_CONFIGS [ resourceName ] || DEFAULT_CONFIG ;
48+
49+ const functionResource : Record < string , any > = {
11350 Type : "AWS::Serverless::Function" ,
11451 Properties : {
115- FunctionName : ` ${ resourceName } -TypeScript` ,
52+ FunctionName : resourceName ,
11653 CodeUri : "./dist" ,
117- Handler : ` ${ filename } .handler` ,
54+ Handler : catalog . handler ,
11855 Runtime : "nodejs22.x" ,
11956 Architectures : [ "x86_64" ] ,
12057 MemorySize : config . memorySize ,
12158 Timeout : config . timeout ,
12259 Role : { "Fn::GetAtt" : [ "DurableFunctionRole" , "Arn" ] } ,
123- DurableConfig : {
124- ExecutionTimeout : 3600 ,
125- RetentionPeriodInDays : 7 ,
126- } ,
60+ DurableConfig : catalog . durableConfig ,
12761 Environment : {
12862 Variables : {
12963 AWS_ENDPOINT_URL_LAMBDA : "http://host.docker.internal:5000" ,
@@ -145,17 +79,34 @@ function createFunctionResource(filename, skipVerboseLogging = false) {
14579 return functionResource ;
14680}
14781
82+ function getExamplesCatalogJson ( ) {
83+ const examplesCatalogPath = path . join (
84+ __dirname ,
85+ "../src/utils/examples-catalog.json" ,
86+ ) ;
87+
88+ if ( ! fs . existsSync ( examplesCatalogPath ) ) {
89+ throw new Error ( `Examples directory not found: ${ examplesCatalogPath } ` ) ;
90+ }
91+
92+ const examplesCatalog = JSON . parse (
93+ fs . readFileSync ( examplesCatalogPath , "utf8" ) ,
94+ ) ;
95+
96+ if ( examplesCatalog . length === 0 ) {
97+ throw new Error ( "No TypeScript example files found in src/examples" ) ;
98+ }
99+
100+ return examplesCatalog ;
101+ }
102+
148103/**
149104 * Generate the complete CloudFormation template
150105 */
151106function generateTemplate ( skipVerboseLogging = false ) {
152- const exampleFiles = getExampleFiles ( ) ;
107+ const examplesCatalog = getExamplesCatalogJson ( ) ;
153108
154- if ( exampleFiles . length === 0 ) {
155- throw new Error ( "No TypeScript example files found in src/examples" ) ;
156- }
157-
158- const template = {
109+ const template : Record < string , any > = {
159110 AWSTemplateFormatVersion : "2010-09-09" ,
160111 Description : "Durable Function examples written in TypeScript." ,
161112 Transform : [ "AWS::Serverless-2016-10-31" ] ,
@@ -202,12 +153,11 @@ function generateTemplate(skipVerboseLogging = false) {
202153 } ;
203154
204155 // Generate resources for each example file
205- exampleFiles . forEach ( ( filename ) => {
206- const resourceName = toPascalCase ( filename ) ;
207- template . Resources [ resourceName ] = createFunctionResource (
208- filename ,
209- skipVerboseLogging ,
210- ) ;
156+ examplesCatalog . forEach ( ( catalog : { name : string ; handler : string } ) => {
157+ const resourceName = catalog . name . replace ( / \s / g, "" ) + `-22x-NodeJS-Local` ;
158+ template . Resources [
159+ toPascalCase ( catalog . handler . slice ( 0 , - ".handler" . length ) )
160+ ] = createFunctionResource ( resourceName , catalog , skipVerboseLogging ) ;
211161 } ) ;
212162
213163 return template ;
@@ -252,7 +202,7 @@ function main() {
252202 if ( skipVerboseLogging ) {
253203 console . log ( "🔇 Verbose logging disabled" ) ;
254204 }
255- } catch ( error ) {
205+ } catch ( error : any ) {
256206 console . error ( "❌ Error generating template.yml:" , error . message ) ;
257207 process . exit ( 1 ) ;
258208 }
@@ -263,9 +213,9 @@ if (require.main === module) {
263213 main ( ) ;
264214}
265215
266- module . exports = {
216+ export {
267217 generateTemplate ,
268- getExampleFiles,
269218 toPascalCase ,
270219 createFunctionResource ,
220+ getExamplesCatalogJson ,
271221} ;
0 commit comments