Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ee13236
feat: new resource reference interfaces
otaviomacedo Jul 22, 2025
9dd8eba
Oops
otaviomacedo Jul 22, 2025
bef585b
Updated snapshot
otaviomacedo Jul 23, 2025
d680262
Merge branch 'main' into otaviom/resource-ref-interface
otaviomacedo Jul 23, 2025
3713f10
itemId
otaviomacedo Jul 23, 2025
1dcfbd8
feat: add ARN attribute to common resource interface
otaviomacedo Jul 23, 2025
b00f7bc
Removed debug code
otaviomacedo Jul 23, 2025
accce40
Skip composite primary identifiers
otaviomacedo Aug 7, 2025
f896e87
Merge branch 'main' into otaviom/resource-ref-interface
otaviomacedo Aug 8, 2025
f750c46
Merge branch 'main' into otaviom/resource-ref-interface
otaviomacedo Aug 11, 2025
9f96725
Revert scripts/prioritization/assign-r5-priority.js
otaviomacedo Aug 11, 2025
62bdc76
Remove `Construct` from the parents of the generated interfaces
otaviomacedo Aug 11, 2025
40fb819
Exclude the 'construct-interface-extends-iconstruct' rule for the ICf…
otaviomacedo Aug 12, 2025
9a79ff7
Add "@aws-cdk/aws-pipes-sources-alpha" to example dependencies
otaviomacedo Aug 12, 2025
d8da50c
Addressed comments
otaviomacedo Aug 12, 2025
a60fbf9
Updated interface names
otaviomacedo Aug 12, 2025
8099618
Removed awslint exclusions
otaviomacedo Aug 12, 2025
f0d857b
Removed unused code
otaviomacedo Aug 12, 2025
27d75ee
Rewrite to an indirecting interface
rix0rrr Aug 19, 2025
e2fde34
Naming fixes
rix0rrr Aug 19, 2025
585defe
Final touches
rix0rrr Aug 19, 2025
b3dd9f4
Merge remote-tracking branch 'origin/main' into otaviom/resource-ref-…
rix0rrr Aug 19, 2025
e9df322
Update tests
rix0rrr Aug 19, 2025
d8825af
Updates
rix0rrr Aug 20, 2025
0e51961
Add IConstruct
rix0rrr Aug 25, 2025
6b1941e
NameRef -> NameReference in ResourceClass
otaviomacedo Aug 29, 2025
892c88f
Merge branch 'main' into otaviom/resource-ref-interface
otaviomacedo Sep 1, 2025
601b8d5
Experimental
otaviomacedo Sep 1, 2025
345907c
Update snapshots
otaviomacedo Sep 1, 2025
9e82000
feat: implement new shared interfaces for L2 resources (ref-interface…
rix0rrr Sep 2, 2025
5f9fb8c
feat: update references to use new shared resource interface (ref-int…
otaviomacedo Sep 2, 2025
73d1b33
Merge branch 'main' into otaviom/resource-ref-interface
rix0rrr Sep 3, 2025
dc8c47b
Merge branch 'main' into otaviom/resource-ref-interface
mergify[bot] Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions packages/awslint/lib/rules/core-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ export class CoreTypes {
return false;
}

if (!c.name.startsWith('Cfn')) {
return false;
}

return true;
return c.name.startsWith('Cfn');
}

/**
Expand Down Expand Up @@ -86,10 +82,11 @@ export class CoreTypes {
}

/**
* Return true if the given interface type is a CFN class or prop type
* Return true if the given interface type is a CFN class, prop type or interface
*/
public static isCfnType(interfaceType: reflect.Type) {
return interfaceType.name.startsWith('Cfn')
|| interfaceType.name.startsWith('ICfn')
|| (interfaceType.namespace && interfaceType.namespace.startsWith('Cfn'))
// aws_service.CfnTheResource.SubType
|| (interfaceType.namespace && interfaceType.namespace.split('.', 2).at(1)?.startsWith('Cfn'));
Expand Down
24 changes: 23 additions & 1 deletion tools/@aws-cdk/spec2cdk/lib/cdk/resource-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
Stability,
ObjectLiteral,
Module,
InterfaceType,
} from '@cdklabs/typewriter';
import { CDK_CORE, CONSTRUCTS } from './cdk';
import { CloudFormationMapping } from './cloudformation-mapping';
Expand All @@ -33,6 +34,7 @@ import {
cfnProducerNameFromType,
propStructNameFromResource,
staticRequiredTransform,
interfaceNameFromResource,
} from '../naming';
import { splitDocumentation } from '../util';

Expand All @@ -45,6 +47,7 @@ const $this = $E(expr.this_());

export class ResourceClass extends ClassType {
private readonly propsType: StructType;
private readonly resourceInterface: InterfaceType;
private readonly decider: ResourceDecider;
private readonly converter: TypeConverter;
private readonly module: Module;
Expand All @@ -55,6 +58,16 @@ export class ResourceClass extends ClassType {
private readonly resource: Resource,
private readonly suffix?: string,
) {
const resourceInterface = new InterfaceType(scope, {
export: true,
name: interfaceNameFromResource(resource, suffix),
docs: {
summary: `Attributes to reference a \`${classNameFromResource(resource)}\`.`,
stability: Stability.External,
},
extends: [CONSTRUCTS.IConstruct],
});

super(scope, {
export: true,
name: classNameFromResource(resource, suffix),
Expand All @@ -67,9 +80,10 @@ export class ResourceClass extends ClassType {
}),
},
extends: CDK_CORE.CfnResource,
implements: [CDK_CORE.IInspectable, ...ResourceDecider.taggabilityInterfaces(resource)],
implements: [CDK_CORE.IInspectable, resourceInterface.type, ...ResourceDecider.taggabilityInterfaces(resource)],
});

this.resourceInterface = resourceInterface;
this.module = Module.of(this);

this.propsType = new StructType(this.scope, {
Expand Down Expand Up @@ -105,6 +119,14 @@ export class ResourceClass extends ClassType {
cfnMapping.add(prop.cfnMapping);
}

// Build the shared interface
for (const identifier of this.decider.primaryIdentifier ?? []) {
this.resourceInterface.addProperty({
...identifier,
immutable: true,
});
}

// Build the members of this class
this.addProperty({
name: staticResourceTypeName(),
Expand Down
73 changes: 73 additions & 0 deletions tools/@aws-cdk/spec2cdk/lib/cdk/resource-decider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { splitDocumentation } from '../util';
// This convenience typewriter builder is used all over the place
const $this = $E(expr.this_());

// This convenience typewriter builder is used for cloudformation intrinsics
const $Fn = $E(expr.directCode('cdk.Fn'));

/**
* Decide how properties get mapped between model types, Typescript types, and CloudFormation
*/
Expand All @@ -25,6 +28,7 @@ export class ResourceDecider {

private readonly taggability?: TaggabilityStyle;

public readonly primaryIdentifier = new Array<PropertySpec>();
public readonly propsProperties = new Array<PropsProperty>();
public readonly classProperties = new Array<ClassProperty>();
public readonly classAttributeProperties = new Array<ClassAttributeProperty>();
Expand All @@ -35,6 +39,8 @@ export class ResourceDecider {
this.convertProperties();
this.convertAttributes();

this.convertPrimaryIdentifier();

this.propsProperties.sort((p1, p2) => p1.propertySpec.name.localeCompare(p2.propertySpec.name));
this.classProperties.sort((p1, p2) => p1.propertySpec.name.localeCompare(p2.propertySpec.name));
this.classAttributeProperties.sort((p1, p2) => p1.propertySpec.name.localeCompare(p2.propertySpec.name));
Expand All @@ -59,6 +65,73 @@ export class ResourceDecider {
}
}

private convertPrimaryIdentifier() {
if (this.resource.primaryIdentifier === undefined) { return; }
for (let i = 0; i < (this.resource.primaryIdentifier).length; i++) {
const cfnName = this.resource.primaryIdentifier[i];
const att = this.findAttributeByName(attributePropertyName(cfnName));
const prop = this.findPropertyByName(propertyNameFromCloudFormation(cfnName));
if (att) {
this.primaryIdentifier.push(att);
} else if (prop) {
const propSpec = prop.propertySpec;

// Build an attribute out of the property we're getting
// Create initializer for new attribute, if possible
let initializer: Expression | undefined = undefined;
if (propSpec.type === Type.STRING) { // handling only this case for now
if (this.resource.primaryIdentifier!.length === 1) {
initializer = CDK_CORE.tokenAsString($this.ref);
} else {
initializer = CDK_CORE.tokenAsString($Fn.select(expr.lit(i), $Fn.split(expr.lit('|'), $this.ref)));
}
}

// If we cannot come up with an initializer, we're dropping this property on the floor
if (!initializer) { continue; }

// Build an attribute spec out of the property spec
const attrPropertySpec = this.convertPropertySpecToRefAttribute(propSpec);

// Add the new attribute to the relevant places
this.classAttributeProperties.push({
propertySpec: attrPropertySpec,
initializer,
});

this.primaryIdentifier.push(attrPropertySpec);
}
}
}

private convertPropertySpecToRefAttribute(propSpec: PropertySpec): PropertySpec {
return {
...propSpec,
name: attributePropertyName(propSpec.name[0].toUpperCase() + propSpec.name.slice(1)),
docs: {
...propSpec.docs,
summary: (propSpec.docs?.summary ?? '').concat('\nThis property gets determined after the resource is created.'),
remarks: (propSpec.docs?.remarks ?? '').concat('@cloudformationAttribute Ref'),
},
immutable: true,
optional: false,
};
}

private findPropertyByName(name: string): ClassProperty | undefined {
const props = this.classProperties.filter((prop) => prop.propertySpec.name === name);
// there's no way we have multiple properties with the same name
if (props.length > 0) { return props[0]; }
return;
}

private findAttributeByName(name: string): PropertySpec | undefined {
const atts = this.classAttributeProperties.filter((att) => att.propertySpec.name === name);
// there's no way we have multiple attributes with the same name
if (atts.length > 0) { return atts[0].propertySpec; }
return;
}

/**
* Default mapping for a property
*/
Expand Down
4 changes: 4 additions & 0 deletions tools/@aws-cdk/spec2cdk/lib/naming/conventions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export function propStructNameFromResource(res: Resource, suffix?: string) {
return `${classNameFromResource(res, suffix)}Props`;
}

export function interfaceNameFromResource(res: Resource, suffix?: string) {
return `I${classNameFromResource(res, suffix)}`;
}

export function cfnProducerNameFromType(struct: TypeDeclaration) {
return `convert${qualifiedName(struct)}ToCloudFormation`;
}
Expand Down
Loading
Loading