Skip to content

Instantly share code, notes, and snippets.

@Dasc3er
Created May 25, 2025 17:56
Show Gist options
  • Save Dasc3er/feb81a7049f083bbe92742dc4769cff8 to your computer and use it in GitHub Desktop.
Save Dasc3er/feb81a7049f083bbe92742dc4769cff8 to your computer and use it in GitHub Desktop.
Simple TS script to generate enums of available AWS Lambda entrypoints for CDK from Java code
import * as fs from 'fs';
import * as path from 'path';
// Ensure the generated folder exists
const GENERATED_FOLDER = path.resolve('./generated');
if (!fs.existsSync(GENERATED_FOLDER)) {
fs.mkdirSync(GENERATED_FOLDER);
}
// Function to recursively find Java files in a directory
function findJavaFiles(dir: string): string[] {
let results: string[] = [];
const list = fs.readdirSync(dir);
list.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat && stat.isDirectory()) {
results = results.concat(findJavaFiles(filePath));
} else if (file.endsWith('.java')) {
results.push(filePath);
}
});
return results;
}
// Function to extract package name and Lambda class implementations from Java files
function extractLambdaFunctions(filePath: string): { packageName: string, functions: {[key:string]: string} } {
const content = fs.readFileSync(filePath, 'utf-8');
const lambdaFunctions: {[key:string]: string}= {};
// Extract package name
const packageMatch = content.match(/package\s+([\w.]+);/);
const packageName = packageMatch ? packageMatch[1] : 'default';
// Identify classes implementing Lambda interfaces
const classRegex = /class\s+(\w+)\s+.*implements\s+([\w.,\s]+)/g;
let match;
while ((match = classRegex.exec(content)) !== null) {
const className = match[1];
const implementedInterfaces = match[2];
if (implementedInterfaces.includes('RequestHandler') || implementedInterfaces.includes('RequestStreamHandler')) {
lambdaFunctions[className] = `${packageName}.${className}::handleRequest`;
}
}
return { packageName, functions: lambdaFunctions };
}
// Function to determine Java version from multiple sources
function getJavaVersion(javaPath: string): string | null {
// 1. Check the standard Java 'release' file
const releaseFile = path.join(javaPath, 'release');
if (fs.existsSync(releaseFile)) {
const content = fs.readFileSync(releaseFile, 'utf-8');
const match = content.match(/JAVA_VERSION="([\d.]+)"/);
if (match) return match[1];
}
// 2. Check Maven `pom.xml`
const pomFile = path.join(javaPath, 'pom.xml');
if (fs.existsSync(pomFile)) {
const content = fs.readFileSync(pomFile, 'utf-8');
const match = content.match(/<java.version>([\d.]+)<\/java.version>/) ||
content.match(/<maven.compiler.source>([\d.]+)<\/maven.compiler.source>/);
if (match) return match[1];
}
// 3. Check Ant `build.xml`
const buildFile = path.join(javaPath, 'build.xml');
if (fs.existsSync(buildFile)) {
const content = fs.readFileSync(buildFile, 'utf-8');
const match = content.match(/<javac[^>]+target="([\d.]+)"/);
if (match) return match[1];
}
// 4. Check Java environment variable `JAVA_HOME`
const javaHome = process.env.JAVA_HOME;
if (javaHome) {
const javaVersionMatch = javaHome.match(/\d+/);
if (javaVersionMatch) return javaVersionMatch[0];
}
return null;
}
// Generate TypeScript interface for each package
function generateCdkInterfaces(javaPaths: string[]) {
const packageMap: Record<string, {[key:string]: string}> = {};
let javaVersion: string | null = null;
javaPaths.forEach(javaPath => {
console.log(`Processing Java path: ${javaPath}`);
const packageName = path.resolve(javaPath).split(path.sep).pop() || 'default';
const version = getJavaVersion(javaPath);
if (!javaVersion && version) {
javaVersion = version;
}
console.log(`${javaPath}/src`)
const javaFiles = findJavaFiles(`${javaPath}/src`);
javaFiles.forEach(file => {
const { functions } = extractLambdaFunctions(file);
// Generate TypeScript interfaces for each package
if (Object.keys(functions).length > 0) {
let output = `// Auto-generated Lambda function interface\n`;
output += `// Java Version: ${javaVersion || 'Unknown'}\n\n`;
output += `export enum ${packageName.replace(/\./g, '_')} {\n`;
Object.entries(functions).forEach(([name, func]) => {
output += ` ${name} = '${func}',\n`;
});
output += `}\n`;
fs.writeFileSync(`${GENERATED_FOLDER}/${packageName.replace(/\./g, '_')}.ts`, output);
console.log(`Generated: ${GENERATED_FOLDER}/${packageName.replace(/\./g, '_')}.ts`);
}
});
});
const INDEX_FILE_PATH = path.join(GENERATED_FOLDER, 'index.ts');
// Read all TypeScript files in the generated folder
const files = fs.readdirSync(GENERATED_FOLDER)
.filter(file => file.endsWith('.ts') && file !== 'index.ts');
// Generate the index.ts content
let indexContent = `// Auto-generated index file for Lambda functions\n\n`;
files.forEach(file => {
const moduleName = file.replace('.ts', '');
indexContent += `export * from './${moduleName}';\n`;
});
// Write the index.ts file
fs.writeFileSync(INDEX_FILE_PATH, indexContent);
console.log(`Generated: ${INDEX_FILE_PATH}`);
}
// Example usage
generateCdkInterfaces(['./TestPackage']);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment