Composite Rules
Composite rules enforce best practices in Composite() factory definitions. They ensure composites stay clean, consistent, and use lexicon types wherever possible.
EVL009: No Extractable Constants
Section titled “EVL009: No Extractable Constants”Object literals and arrays-of-objects inside a Composite factory that don’t reference props or sibling members are extractable constants. Move them to a separate file (e.g. defaults.ts) and import directly.
| Severity | Warning |
| Category | Style |
// ❌ Triggers EVL009const LambdaApi = Composite<Props>((props) => { const role = new _.Role({ assumeRolePolicyDocument: { Version: "2012-10-17", Statement: [{ Effect: "Allow", Principal: { Service: "lambda.amazonaws.com" }, Action: "sts:AssumeRole" }], }, }); return { role };}, "LambdaApi");// ✅ Fixed — extract to defaults.ts, import directlyconst LambdaApi = Composite<Props>((props) => { const role = new Role({ assumeRolePolicyDocument: lambdaTrustPolicy, }); return { role };}, "LambdaApi");Simple string, number, and boolean literals are allowed inline — only object literals and arrays containing objects are flagged.
EVL010: No Data Transformation
Section titled “EVL010: No Data Transformation”Composite factories should only compose resources from props, not transform data. Array methods like .map(), .filter(), .reduce(), and .flatMap() should be called before passing props to the composite.
| Severity | Warning |
| Category | Style |
// ❌ Triggers EVL010const LambdaApi = Composite<Props>((props) => { const role = new _.Role({ policies: props.policyStatements.map(s => new _.Role_Policy({ policyDocument: s }) ), }); return { role };}, "LambdaApi");// ✅ Fixed — caller constructs Role_Policy[] before passingconst LambdaApi = Composite<Props>((props) => { const role = new _.Role({ policies: props.policies, }); return { role };}, "LambdaApi");COR017: Composite Name Must Match Variable
Section titled “COR017: Composite Name Must Match Variable”The second argument to Composite() must be a string literal that matches the const variable name. This name is used in resource expansion (e.g. healthApiRole, healthApiFunc) and error messages.
| Severity | Error |
| Category | Correctness |
| Auto-fix | Yes |
// ❌ Triggers COR017 — name mismatchconst LambdaApi = Composite<Props>((props) => { return { role: new _.Role({}) };}, "MyFunction");
// ❌ Triggers COR017 — missing nameconst LambdaApi = Composite<Props>((props) => { return { role: new _.Role({}) };});// ✅ Fixedconst LambdaApi = Composite<Props>((props) => { return { role: new _.Role({}) };}, "LambdaApi");COR018: Prefer Lexicon Property Types
Section titled “COR018: Prefer Lexicon Property Types”Composite prop interfaces should use lexicon property types instead of locally-declared interfaces. If the lexicon already provides a matching type (e.g. Role_Policy), use InstanceType<typeof _.Role_Policy> instead of defining a custom interface.
| Severity | Info |
| Category | Style |
// ❌ Triggers COR018 — local interface duplicates lexicon typeinterface PolicyStatement { effect: string; action: string[]; resource: string[];}
interface LambdaApiProps { policies?: PolicyStatement[];}
const LambdaApi = Composite<LambdaApiProps>((props) => { // ...}, "LambdaApi");// ✅ Fixed — use lexicon property typeinterface LambdaApiProps { policies?: InstanceType<typeof _.Role_Policy>[];}
const LambdaApi = Composite<LambdaApiProps>((props) => { // ...}, "LambdaApi");