Skip to content

Commit 5337f9d

Browse files
committed
feat(mixins-preview): developer preview of CDK Mixins
1 parent 0312e24 commit 5337f9d

File tree

12 files changed

+597
-343
lines changed

12 files changed

+597
-343
lines changed

packages/@aws-cdk/mixins-preview/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ The `.with()` method is available after importing `@aws-cdk/mixins-preview/with`
5555
5656
## Creating Custom Mixins
5757

58-
Mixins are simple classes that implement the `IMixin` interface:
58+
Mixins are simple classes that implement the `IMixin` interface (usually by extending the abstract `Mixin` class:
5959

6060
```typescript
6161
// Simple mixin that enables versioning
62-
class CustomVersioningMixin implements IMixin {
62+
class CustomVersioningMixin extends Mixin implements IMixin {
6363
supports(construct: any): boolean {
6464
return construct instanceof s3.CfnBucket;
6565
}
@@ -131,7 +131,7 @@ For every CloudFormation resource, CDK Mixins automatically generates type-safe
131131

132132
```typescript
133133
import '@aws-cdk/mixins-preview/with';
134-
import { CfnBucketPropsMixin } from '@aws-cdk/mixins-preview/aws-s3/mixins';
134+
135135

136136
const bucket = new s3.Bucket(scope, "Bucket")
137137
.with(new CfnBucketPropsMixin({
@@ -146,6 +146,8 @@ const bucket = new s3.Bucket(scope, "Bucket")
146146
Property mixins support two merge strategies:
147147

148148
```typescript
149+
declare const bucket: s3.CfnBucket;
150+
149151
// MERGE (default): Deep merges properties with existing values
150152
Mixins.of(bucket).apply(new CfnBucketPropsMixin(
151153
{ versioningConfiguration: { status: "Enabled" } },
@@ -155,16 +157,16 @@ Mixins.of(bucket).apply(new CfnBucketPropsMixin(
155157
// OVERWRITE: Replaces existing property values
156158
Mixins.of(bucket).apply(new CfnBucketPropsMixin(
157159
{ versioningConfiguration: { status: "Enabled" } },
158-
{ strategy: PropertyMergeStrategy.OVERWRITE }
160+
{ strategy: PropertyMergeStrategy.OVERRIDE }
159161
));
160162
```
161163

162164
Property mixins are available for all AWS services:
163165

164166
```typescript
165-
import { CfnLogGroupMixin } from '@aws-cdk/mixins-preview/aws-logs/mixins';
166-
import { CfnFunctionMixin } from '@aws-cdk/mixins-preview/aws-lambda/mixins';
167-
import { CfnTableMixin } from '@aws-cdk/mixins-preview/aws-dynamodb/mixins';
167+
import { CfnLogGroupPropsMixin } from '@aws-cdk/mixins-preview/aws_logs/mixins';
168+
import { CfnFunctionPropsMixin } from '@aws-cdk/mixins-preview/aws_lambda/mixins';
169+
import { CfnTablePropsMixin } from '@aws-cdk/mixins-preview/aws_dynamodb/mixins';
168170
```
169171

170172
## Error Handling

packages/@aws-cdk/mixins-preview/jest.config.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ const baseConfig = require('@aws-cdk/cdk-build-tools/config/jest.config');
33
/** @type {import('ts-jest').JestConfigWithTsJest} */
44
module.exports = {
55
...baseConfig,
6-
transform: {
7-
'^.+\\.tsx?$': ['ts-jest'],
8-
},
6+
coveragePathIgnorePatterns: [
7+
'scripts',
8+
'\\.generated\\.[jt]s$',
9+
'.warnings.jsii.js$'
10+
],
911
};

packages/@aws-cdk/mixins-preview/lib/core/applicator.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,31 @@ export class MixinApplicator {
2121
/**
2222
* Applies a mixin to selected constructs.
2323
*/
24-
apply(mixin: IMixin): this {
24+
apply(...mixins: IMixin[]): this {
2525
const constructs = this.selector.select(this.scope);
2626
for (const construct of constructs) {
27-
if (mixin.supports(construct)) {
28-
const errors = mixin.validate?.(construct) ?? [];
29-
if (errors.length > 0) {
30-
throw new ValidationError(`Mixin validation failed: ${errors.join(', ')}`, this.scope);
27+
for (const mixin of mixins) {
28+
if (mixin.supports(construct)) {
29+
mixin.applyTo(construct);
3130
}
32-
mixin.applyTo(construct);
3331
}
3432
}
3533
return this;
3634
}
3735

3836
/**
39-
* Applies a mixin and requires that it be applied to at least one construct.
37+
* Applies a mixin and requires that it be applied to all constructs.
4038
*/
41-
mustApply(mixin: IMixin): this {
39+
mustApply(...mixins: IMixin[]): this {
4240
const constructs = this.selector.select(this.scope);
43-
let applied = false;
4441
for (const construct of constructs) {
45-
if (mixin.supports(construct)) {
46-
const errors = mixin.validate?.(construct) ?? [];
47-
if (errors.length > 0) {
48-
throw new ValidationError(`Mixin validation failed: ${errors.join(', ')}`, construct);
42+
for (const mixin of mixins) {
43+
if (!mixin.supports(construct)) {
44+
throw new ValidationError(`Mixin ${mixin.constructor.name} could not be applied to ${construct.constructor.name} but was requested to.`, this.scope);
4945
}
5046
mixin.applyTo(construct);
51-
applied = true;
5247
}
5348
}
54-
if (!applied) {
55-
throw new ValidationError(`Mixin ${mixin.constructor.name} could not be applied to any constructs`, this.scope);
56-
}
5749
return this;
5850
}
5951
}

packages/@aws-cdk/mixins-preview/lib/core/mixins.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@ export interface IMixin {
2727
*/
2828
supports(construct: IConstruct): boolean;
2929

30-
/**
31-
* Validates the construct before applying the mixin.
32-
*/
33-
validate?(construct: IConstruct): string[];
34-
3530
/**
3631
* Applies the mixin functionality to the target construct.
3732
*/
@@ -60,9 +55,5 @@ export abstract class Mixin implements IMixin {
6055
return true;
6156
}
6257

63-
public validate(_construct: IConstruct): string[] {
64-
return [];
65-
}
66-
6758
abstract applyTo(construct: IConstruct): IConstruct;
6859
}

packages/@aws-cdk/mixins-preview/lib/with.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ import { Mixins, ConstructSelector } from './core';
55

66
declare module 'constructs' {
77
interface IConstruct {
8-
with(mixin: IMixin): this;
8+
with(...mixin: IMixin[]): this;
99
}
1010

1111
interface Construct {
12-
with(mixin: IMixin): this;
12+
with(...mixin: IMixin[]): this;
1313
}
1414
}
1515

1616
// Hack the prototype to add .with() method
17-
(Construct.prototype as any).with = function(this: IConstruct, mixin: IMixin): IConstruct {
18-
Mixins.of(this, ConstructSelector.cfnResource()).mustApply(mixin);
17+
(Construct.prototype as any).with = function(this: IConstruct, ...mixin: IMixin[]): IConstruct {
18+
Mixins.of(this, ConstructSelector.cfnResource()).mustApply(...mixin);
1919
return this;
2020
};

0 commit comments

Comments
 (0)