Code Generation (cfn2ts)
Relevant source files
The following files were used as context for generating this wiki page:The cfn2ts module is a critical tool within the AWS CDK's build system responsible for generating TypeScript code from the AWS CloudFormation Resource Specification. Its primary function is to create the low-level (L1) constructs for each AWS resource, which serve as the foundation for the higher-level (L2) constructs in the AWS Construct Library. This automated process ensures that the CDK can provide comprehensive and up-to-date coverage of AWS services as they are released and updated in CloudFormation.
The system works by first processing and unifying various CloudFormation specification files into a single, coherent model. Then, cfn2ts consumes this model to generate TypeScript classes (Cfn...), property interfaces (...Props), validators, and mapping functions for every resource and property type. This generated code forms the core of the individual @aws-cdk/aws-* service modules.
Overall Architecture
The code generation pipeline involves several distinct stages, starting from raw specification files and ending with published TypeScript packages.
The following diagram illustrates the high-level flow of the cfn2ts code generation process.
Specification Processing
Before code generation can occur, the raw CloudFormation specification fragments must be consolidated into a single, unified JSON file. This task is handled by the build tools within the @aws-cdk/cfnspec package.
Sources: packages/@aws-cdk/cfnspec/build-tools/build.ts
build.ts
The build.ts script is the entry point for this stage. It performs two main functions:
-
Generate Resource Specification: It reads all
.jsonfiles from thespec-sourcedirectory.- Files are merged together to form the base specification.
- Files containing
patchin their name are applied as patches to the merged specification, allowing for corrections or enrichments. - The final, unified model is written to
spec/specification.json.
-
Merge Cfn-Lint Specification: It processes cfn-lint annotations from
spec-source/cfn-lintand merges them intospec/cfn-lint.json.
The generateResourceSpecification function is key to this process.
// packages/@aws-cdk/cfnspec/build-tools/build.ts:24-39
async function generateResourceSpecification(inputDir: string, outFile: string) {
const spec: schema.Specification = { PropertyTypes: {}, ResourceTypes: {}, Fingerprint: '' };
const files = await fs.readdir(inputDir);
for (const file of files.filter(n => n.endsWith('.json')).sort()) {
const data = await fs.readJson(path.join(inputDir, file));
if (file.indexOf('patch') === -1) {
decorateResourceTypes(data);
forEachSection(spec, data, merge);
} else {
forEachSection(spec, data, patch);
}
}
massageSpec(spec);
spec.Fingerprint = md5(JSON.stringify(normalize(spec)));
await fs.mkdirp(path.dirname(outFile));
await fs.writeJson(outFile, spec, { spaces: 2 });
}
Sources: packages/@aws-cdk/cfnspec/build-tools/build.ts:24-39
Core Code Generation (codegen.ts)
The codegen.ts file is the heart of cfn2ts. It contains the CodeGenerator class, which iterates through the ResourceTypes and PropertyTypes in the specification.json file and emits corresponding TypeScript code.
Sources: tools/cfn2ts/lib/codegen.ts
Key Generated Components
For each CloudFormation resource (e.g., AWS::S3::Bucket), the generator produces several artifacts:
| Component | Description | Example |
|---|---|---|
| L1 Construct Class | The main class representing the resource, extending cdk.CfnResource. It includes properties for each CloudFormation attribute. | class CfnBucket extends cdk.CfnResource { ... } |
| Props Interface | A TypeScript interface defining the properties required to create the resource. | interface CfnBucketProps { ... } |
| Validator Function | A function that validates a properties object against the required schema. | function cfnBucketPropsValidator(properties: any): cdk.ValidationResult |
| Mapper Function | A function that transforms the TypeScript props object into the JSON format expected by CloudFormation. | function cfnBucketPropsToCloudFormation(properties: any): any |
_fromCloudFormation Factory | A static method to create a construct instance from parsed CloudFormation template properties. Used by @aws-cdk/cloudformation-include. | public static _fromCloudFormation(...) |
Sources: tools/cfn2ts/lib/codegen.ts:130-132, 172-174, 440-442, 609-611
Class and Interface Generation
The CodeGenerator class structure and its relationship with generated artifacts can be visualized as follows.
This diagram shows how the CodeGenerator produces a CfnBucket class and its corresponding CfnBucketProps interface.
Sources: tools/cfn2ts/lib/codegen.ts:25-41, 172-438
_fromCloudFormation Factory Method
A crucial feature for interoperability is the _fromCloudFormation static method generated on each L1 construct. This allows the @aws-cdk/cloudformation-include module to parse an existing CloudFormation template and instantiate the corresponding CDK L1 constructs.
The following sequence diagram shows how CfnInclude might use this factory.
This process enables developers to import and manage existing CloudFormation templates within a CDK application.
Sources: tools/cfn2ts/lib/codegen.ts:200-226, packages/@aws-cdk/cloudformation-include/build.js:46-56
Tree Inspector Integration
Generated constructs also implement the IInspectable interface by providing an inspect method. This method adds CloudFormation-specific metadata to the construct tree, which can be used by tools for analysis and visualization. The attributes aws:cdk:cloudformation:type and aws:cdk:cloudformation:props are added to the node.
// tools/cfn2ts/lib/codegen.ts:440-450
public inspect(inspector: ${CORE}.TreeInspector) {
inspector.addAttribute("${TreeAttributes.CFN_TYPE}", ${resource.className}.CFN_RESOURCE_TYPE_NAME);
inspector.addAttribute("${TreeAttributes.CFN_PROPS}", this.cfnProperties);
}
Sources: tools/cfn2ts/lib/codegen.ts:440-450, design/construct-tree.md
Augmentation Generation
In addition to the base L1 constructs, cfn2ts can generate "augmentations" that add extra methods to the constructs. This is handled by AugmentationGenerator. A primary use case is adding metric methods (e.g., metricBuilds()) to resources that emit CloudWatch metrics.
This is achieved through TypeScript's declaration merging (declare module). The generator adds method signatures to the L2 interface (e.g., IProject) and the L2 base class (e.g., ProjectBase), and then attaches the implementation to the base class's prototype.
Sources: tools/cfn2ts/lib/augmentation-generator.ts
Automatic Module Scaffolding
To ensure that new AWS services are quickly available in the CDK, the create-missing-libraries.ts script automates the creation of new @aws-cdk/aws-* packages.
The script iterates through all CloudFormation namespaces (e.g., AWS::NewService) and checks if a corresponding CDK package exists. If not, it generates a complete package structure, including:
package.jsonwith correct dependencies and JSII targets.lib/index.tsto export the generated L1 constructs..gitignore,.npmignore, and other standard configuration files.- A placeholder
README.mdand test file.
This dramatically reduces the manual effort required to add support for a new AWS service.
Sources: packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts:15-70
Summary
The cfn2ts code generation system is a cornerstone of the AWS CDK's development process. By automating the creation of L1 constructs from the official CloudFormation specification, it provides a scalable and maintainable way to keep the CDK in sync with the ever-expanding AWS ecosystem. The pipeline, from specification processing to code generation, augmentation, and automatic module scaffolding, enables the CDK team to deliver comprehensive AWS service coverage to developers with high velocity and accuracy.