├── .adr-dir ├── .github ├── pull_request_template.md └── workflows │ ├── auto-approve.yml │ └── pull-request-lint.yml ├── test ├── schema │ ├── fixture │ │ ├── README.md │ │ ├── .gitignore │ │ ├── index.d.ts.map │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── index.ts │ ├── fixtures.test.ts │ ├── self-test.test.ts │ └── failures.test.ts ├── fixtures │ ├── templates │ │ ├── cloudformation │ │ │ ├── only-empty-bucket.json │ │ │ ├── short-form-base64.yaml │ │ │ ├── short-form-import-value.yaml │ │ │ ├── non-existent-resource-attribute.json │ │ │ ├── custom-resource-with-bad-condition.json │ │ │ ├── boolean-for-string.json │ │ │ ├── fn-sub-map-empty.json │ │ │ ├── short-form-join.yaml │ │ │ ├── fn-sub-escaping.json │ │ │ ├── ssm-association.json │ │ │ ├── resource-attribute-depends-on.json │ │ │ ├── get-att-string-form.json │ │ │ ├── short-form-cidr.yaml │ │ │ ├── condition-using-mapping.json │ │ │ ├── fn-sub-parameters.json │ │ │ ├── short-form-split.yaml │ │ │ ├── resource-attribute-condition.json │ │ │ ├── fn-sub-override.json │ │ │ ├── number-for-string.json │ │ │ ├── resource-attribute-depends-on-array.json │ │ │ ├── short-form-fnsub-string.yaml │ │ │ ├── string-for-number.json │ │ │ ├── year-month-date-as-strings.yaml │ │ │ ├── fn-sub-string.json │ │ │ ├── fn-sub-shadow-attribute.json │ │ │ ├── fn-sub-shadow.json │ │ │ ├── short-form-find-in-map.yaml │ │ │ ├── short-form-sub-map.yaml │ │ │ ├── fn-sub-shadow-parameter.json │ │ │ ├── short-form-select.yaml │ │ │ ├── short-form-conditionals.yaml │ │ │ ├── only-mapping-and-bucket.json │ │ │ ├── only-bucket-complex-props.json │ │ │ ├── fn-select-with-novalue.json │ │ │ ├── if-simple-property.json │ │ │ ├── find-in-map-for-boolean-property.json │ │ │ ├── resource-attribute-creation-policy.json │ │ │ ├── find-in-map-with-dynamic-mapping.json │ │ │ ├── condition-same-name-as-resource.json │ │ │ ├── short-form-conditions.yaml │ │ │ ├── ref-array-property.json │ │ │ ├── short-form-get-att.yaml │ │ │ ├── json-in-fn-sub.yaml │ │ │ ├── only-parameters-and-rule.json │ │ │ ├── fn-sub-map-dotted-attributes.json │ │ │ ├── outputs-with-references.json │ │ │ ├── user-data.json │ │ │ ├── if-in-tags.json │ │ │ ├── only-empty-bucket-with-parameters.json │ │ │ ├── parameter-references.json │ │ │ ├── if-complex-property.json │ │ │ ├── long-form-subnet.yaml │ │ │ ├── custom-resource-with-attributes.json │ │ │ ├── bucket-with-parameters.json │ │ │ ├── long-form-vpc.yaml │ │ │ ├── properties-not-in-cfn-spec.json │ │ │ ├── fn-sub-brace-edges.json │ │ │ ├── resource-attribute-update-policy.json │ │ │ └── bucket-with-encryption-key.json │ │ ├── nested │ │ │ ├── custom-resource.json │ │ │ ├── only-nested-stack.json │ │ │ ├── child-with-number-parameter.yaml │ │ │ ├── parent-number-in-child-params.yaml │ │ │ ├── parent-bad-depends-on.json │ │ │ ├── parent-one-child.json │ │ │ ├── parent-two-parameters.json │ │ │ ├── parent-invalid-condition.json │ │ │ ├── parent-update-policy.json │ │ │ ├── parent-creation-policy.json │ │ │ ├── child-no-bucket.json │ │ │ ├── cross-stack-refs.json │ │ │ ├── grandchild-import-stack.json │ │ │ ├── parent-valid-condition.json │ │ │ ├── parent-two-children.json │ │ │ ├── child-import-stack.json │ │ │ ├── child-two-parameters.json │ │ │ ├── parent-with-attributes.json │ │ │ ├── child-import-stack.expected.json │ │ │ └── only-nested-stack.expected.json │ │ ├── cfn-transform.json │ │ ├── sam │ │ │ ├── api-endpoint-config-string.yaml │ │ │ ├── api-endpoint-config-string-empty.yaml │ │ │ ├── api-endpoint-config-object.yaml │ │ │ ├── only-minimal-sam-function-codeuri-as-param.yaml │ │ │ ├── only-minimal-sam-function-codeuri-bucket-as-param.yaml │ │ │ ├── only-sam-function-policies-array-ddb-crud.yaml │ │ │ ├── only-minimal-sam-function-codeuri-as-s3location.yaml │ │ │ └── only-sam-function-policies-array-ddb-crud-if.yaml │ │ ├── cfn-metadata.json │ │ ├── cfn-mappings.yaml │ │ ├── syntax-lambda-policy-from-constructor.yaml │ │ ├── overrides-delete-path.json │ │ ├── overrides-remove-resource.json │ │ ├── cfn-outputs-complex.json │ │ ├── cfn-conditions.yaml │ │ ├── cfn-parameters.json │ │ ├── cfn-outputs-simple.json │ │ ├── cfn-policies.yaml │ │ ├── overrides-update-path.json │ │ ├── syntax-short-intrinsics.yaml │ │ └── syntax-method-calls.json │ └── invalid-templates │ │ ├── output-referencing-non-existent-condition.json │ │ ├── non-existent-condition-in-conditions.json │ │ ├── non-existent-condition.json │ │ ├── short-form-import-sub.yaml │ │ ├── short-form-get-att-no-dot.yaml │ │ ├── fn-sub-${}-only.json │ │ ├── fn-sub-key-not-in-template-string.json │ │ ├── non-existent-depends-on.json │ │ ├── ref-ing-a-non-existent-element.json │ │ ├── bucket-with-cors-rules-not-an-array.json │ │ ├── non-existent-resource-attribute.json │ │ ├── bucket-with-cors-rules-null-element.json │ │ ├── getting-attribute-of-a-non-existent-resource.json │ │ ├── getatt-in-conditions.json │ │ ├── short-form-transform.yaml │ │ ├── non-existent-condition-in-if.json │ │ ├── bucket-with-invalid-cors-rule.json │ │ ├── cycle-in-resources.json │ │ ├── rule-referencing-a-non-existent-parameter.json │ │ ├── non-existent-mapping.json │ │ ├── only-codecommit-repo-using-cfn-functions.json │ │ ├── alphabetical-string-passed-to-number.json │ │ ├── multi-cycle-multi-dest-in-resources.json │ │ ├── multi-cycle-in-resources.json │ │ └── bucket-policy-without-bucket.json ├── setup.ts ├── parser │ ├── resource.test.ts │ ├── intrinsics.test.ts │ ├── yaml.test.ts │ └── errors.test.ts ├── evaluate │ ├── properties.test.ts │ ├── cdk-metadata.test.ts │ └── __snapshots__ │ │ └── references.test.ts.snap ├── sanity.test.ts ├── type-system │ └── interfaces.test.ts └── type-resolution │ ├── fixtures.test.ts │ ├── enums.test.ts │ ├── resource.test.ts │ ├── resolve.test.ts │ ├── references.test.ts │ └── collections.test.ts ├── src ├── specs │ └── specs.version.json ├── evaluate │ ├── index.ts │ ├── outputs.ts │ └── overrides.ts ├── schema │ ├── index.ts │ ├── cdk-intrinsics.ts │ └── expression.ts ├── parser │ ├── template │ │ ├── enums.ts │ │ ├── index.ts │ │ ├── transform.ts │ │ ├── hooks.ts │ │ ├── tags.ts │ │ ├── output.ts │ │ ├── rules.ts │ │ ├── mappings.ts │ │ ├── parameters.ts │ │ └── calls.ts │ ├── README.md │ └── private │ │ ├── cfn-yaml.ts │ │ └── sub.ts ├── error-handling │ ├── index.ts │ ├── unparse.ts │ ├── annotations.ts │ └── errors.ts ├── type-resolution │ ├── index.ts │ ├── literals.ts │ ├── types.ts │ ├── references.ts │ ├── union.ts │ ├── struct.ts │ ├── primitives.ts │ ├── collections.ts │ └── enums.ts ├── index.ts ├── type-system │ ├── index.ts │ ├── interfaces.ts │ ├── implements.ts │ ├── factories.ts │ └── enums.ts ├── scripts │ ├── bump-schema-version.sh │ └── bump-schema-version.ts ├── util.ts ├── decdk-specs.ts ├── decdk-schema.ts ├── decdk.ts └── declarative-stack.ts ├── bin ├── decdk ├── decdk-specs └── decdk-schema ├── .prettierrc.json ├── NOTICE ├── .prettierignore ├── examples ├── lambda-handler │ └── index.js ├── vpc.json ├── lambda-topic.json ├── fleet.json ├── lambda-layer.json ├── lambda-policy.yaml ├── apigw.json ├── http-proxy.yaml ├── ecs.json ├── application-load-balancer.yaml ├── lambda-events.json ├── integration.yaml └── lambda-dashboard.yaml ├── .mocharc.yaml ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── docs └── architecture │ └── decisions │ ├── 0001-record-architecture-decisions.md │ ├── 0003-types-and-properties-use-jsii-nomenclature.md │ ├── 0002-parse-typed-ast-before-evaluation.md │ ├── 0004-use-only-fully-qualified-names.md │ ├── 0005-custom-intrinsic-to-get-values-from-constructs.md │ ├── 0008-decdk-delegates-validation-to-downstream-services.md │ └── 0006-mocha-as-testing-framework.md ├── .npmignore ├── .mergify.yml ├── .projen └── files.json ├── tsconfig.json ├── tsconfig.dev.json ├── .gitignore └── .gitattributes /.adr-dir: -------------------------------------------------------------------------------- 1 | docs/architecture/decisions 2 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /test/schema/fixture/README.md: -------------------------------------------------------------------------------- 1 | # test 2 | -------------------------------------------------------------------------------- /src/specs/specs.version.json: -------------------------------------------------------------------------------- 1 | {"schemaVersion":"3.0.0"} -------------------------------------------------------------------------------- /test/schema/fixture/.gitignore: -------------------------------------------------------------------------------- 1 | *.d.ts 2 | *.js 3 | -------------------------------------------------------------------------------- /bin/decdk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../lib/decdk.js'); 3 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "overrides": [] 4 | } 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /bin/decdk-specs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../lib/decdk-specs.js'); 3 | -------------------------------------------------------------------------------- /bin/decdk-schema: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../lib/decdk-schema.js'); 3 | -------------------------------------------------------------------------------- /src/evaluate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './context'; 2 | export * from './evaluate'; 3 | -------------------------------------------------------------------------------- /src/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cdk-schema'; 2 | export * from './jsii2schema'; 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | -------------------------------------------------------------------------------- /src/parser/template/enums.ts: -------------------------------------------------------------------------------- 1 | export type RetentionPolicy = 'Retain' | 'Delete' | 'Snapshot'; 2 | -------------------------------------------------------------------------------- /examples/lambda-handler/index.js: -------------------------------------------------------------------------------- 1 | exports.handler = async function() { 2 | return 'SUCCESS'; 3 | } 4 | -------------------------------------------------------------------------------- /src/error-handling/index.ts: -------------------------------------------------------------------------------- 1 | export * from './annotations'; 2 | export * from './errors'; 3 | export * from './unparse'; 4 | -------------------------------------------------------------------------------- /src/type-resolution/index.ts: -------------------------------------------------------------------------------- 1 | export * from './resource-like'; 2 | export { resolveExpressionType } from './resolve'; 3 | export * from './template'; 4 | -------------------------------------------------------------------------------- /examples/vpc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../cdk.schema.json", 3 | "Resources": { 4 | "VPC": { 5 | "Type": "aws-cdk-lib.aws_ec2.Vpc" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/only-empty-bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/custom-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "CustomResource": { 4 | "Type": "AWS::CustomResource::Type" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './declarative-stack'; 2 | export * from './error-handling'; 3 | export * from './evaluate'; 4 | export * from './type-resolution'; 5 | export * from './util'; 6 | -------------------------------------------------------------------------------- /src/type-system/index.ts: -------------------------------------------------------------------------------- 1 | export * from './construct'; 2 | export * from './enums'; 3 | export * from './implements'; 4 | export * from './interfaces'; 5 | export * from './serializable'; 6 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/output-referencing-non-existent-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Outputs": { 3 | "SomeOutput": { 4 | "Condition": "NonexistantCondition" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-condition-in-conditions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "AlwaysTrue": { 4 | "Fn::Not": [{ "Condition": "AlwaysFalse" }] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Condition": "AlwaysFalseCond" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-base64.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Base64Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | !Base64 NonBase64BucketName 7 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-import-value.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | !ImportValue SomeSharedValue 7 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/short-form-import-sub.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | !ImportValue 7 | !Sub ${AWS::Region} 8 | -------------------------------------------------------------------------------- /src/parser/template/index.ts: -------------------------------------------------------------------------------- 1 | export * from './enums'; 2 | export * from './expression'; 3 | export * from './parameters'; 4 | export * from './resource'; 5 | export * from './template'; 6 | export * from './output'; 7 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/short-form-get-att-no-dot.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket1: 3 | Type: AWS::S3::Bucket 4 | Bucket2: 5 | Type: AWS::S3::Bucket 6 | Metadata: 7 | Bucket1Name: !GetAtt Bucket1Arn 8 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/non-existent-resource-attribute.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket2": { 4 | "Type": "AWS::S3::Bucket", 5 | "NonExistentResourceAttribute": "Bucket1" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/custom-resource-with-bad-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "CustomResource": { 4 | "Type": "AWS::MyService::Custom", 5 | "Condition": "AlwaysFalseCond" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/boolean-for-string.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "AccessControl": true 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/only-nested-stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "NestedStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "doesnt-matter" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /.mocharc.yaml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | ui: tdd 4 | spec: 5 | - test/**/*.test.ts 6 | require: 7 | - ts-node/register 8 | - mocha-expect-snapshot 9 | - test/setup.ts 10 | timeout: 10000 11 | slow: 500 12 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/fn-sub-${}-only.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::Sub": "${}" 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/fn-sub-key-not-in-template-string.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "AccessControl": { "Fn::Sub": "${AFakeResource}" } 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-depends-on.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket2": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": "bucket2" 7 | }, 8 | "DependsOn": "Bucket1" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/child-with-number-parameter.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Parameters: 3 | Number: 4 | Type: Number 5 | Resources: 6 | S3Bucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: 'testbucket1234unique' 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "recommendations": [ 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode", 6 | "hbenl.vscode-mocha-test-adapter", 7 | "redhat.vscode-yaml" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/ref-ing-a-non-existent-element.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Ref": "DoesNotExist" 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-map-empty.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::Sub": ["my-bucket", {}] 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-join.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: !Join [ 6 | ' ', 7 | [ 8 | "NamePart1 ", 9 | !ImportValue SomeSharedValue 10 | ] 11 | ] 12 | -------------------------------------------------------------------------------- /src/parser/template/transform.ts: -------------------------------------------------------------------------------- 1 | import { Token } from 'aws-cdk-lib'; 2 | 3 | export function parseTransform(xs: unknown): string[] { 4 | if (xs == null) return []; 5 | 6 | if (Array.isArray(xs)) { 7 | return xs.map((x) => Token.asString(x)); 8 | } 9 | 10 | return [Token.asString(xs)]; 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/bucket-with-cors-rules-not-an-array.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": "CorsRules!" 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-resource-attribute.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "NonExistentResourceAttribute": { 6 | "SomeProp": { 7 | "Ref": "NonExistentResource" 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-escaping.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { "Fn::Sub": "some-bucket${!AWS::AccountId}7896${ ! DoesNotExist}${!Immediate}234" } 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/templates/cfn-transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../../cdk.schema.json", 3 | "Transform": "AWS::LanguageExtensions", 4 | "Resources": { 5 | "MyQueue": { 6 | "Type": "aws-cdk-lib.aws_sqs.Queue", 7 | "Properties": { 8 | "encryption": "KMS" 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /src/scripts/bump-schema-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | scriptsdir=$(cd "$(dirname $0)" && pwd) 4 | packagedir=$(cd ${scriptsdir}/../.. && pwd) 5 | 6 | # Output 7 | OUTPUT_DIR="${packagedir}/schema" 8 | mkdir -p "${OUTPUT_DIR}" 9 | 10 | node -e "require('${packagedir}/lib/scripts/bump-schema-version.js').bump()" -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/bucket-with-cors-rules-null-element.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": [ 8 | null 9 | ] 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/getting-attribute-of-a-non-existent-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::GetAtt": ["DoesNotExist", "SomeAttribute"] 8 | } 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-number-in-child-params.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Resources: 3 | NestedStack: 4 | Type: AWS::CloudFormation::Stack 5 | Properties: 6 | TemplateURL: 'https://s3.amazonaws.com/masonme-cdk-test/templates/nested-bucket.yaml' 7 | Parameters: 8 | Number: 60 9 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/getatt-in-conditions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "MyCond": { 4 | "Fn::Equals": [ 5 | { "Fn::GetAtt": ["Bucket", "Arn"] }, 6 | "my-arn" 7 | ] 8 | } 9 | }, 10 | "Resources": { 11 | "Bucket": { 12 | "Type": "AWS::S3::Bucket" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/short-form-transform.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | !Transform { 7 | "Name": "SomeMacroName", 8 | "Parameters": { 9 | key1: value1, 10 | key2: value2, 11 | } 12 | } -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/ssm-association.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Association": { 4 | "Type": "AWS::SSM::Association", 5 | "Properties": { 6 | "Name": "association", 7 | "Parameters": { 8 | "P1": ["a", "b"], 9 | "p2": [] 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/api-endpoint-config-string.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | Api: 5 | Type: AWS::Serverless::Api 6 | Properties: 7 | StageName: prod 8 | DefinitionBody: 9 | Body: DefinitionBody 10 | EndpointConfiguration: GLOBAL 11 | -------------------------------------------------------------------------------- /src/type-resolution/literals.ts: -------------------------------------------------------------------------------- 1 | import { StringLiteral } from '../parser/template'; 2 | 3 | export interface DateLiteral { 4 | readonly type: 'date'; 5 | readonly date: Date; 6 | } 7 | 8 | export function resolveDateLiteral(x: StringLiteral): DateLiteral { 9 | return { 10 | type: 'date', 11 | date: new Date(x.value), 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/resource-attribute-depends-on.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket1": { 4 | "Type": "AWS::S3::Bucket" 5 | }, 6 | "Bucket2": { 7 | "Type": "AWS::S3::Bucket", 8 | "Properties": { 9 | "BucketName": "bucket2" 10 | }, 11 | "DependsOn": "Bucket1" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/get-att-string-form.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket1": { 4 | "Type": "AWS::S3::Bucket" 5 | }, 6 | "Bucket2": { 7 | "Type": "AWS::S3::Bucket", 8 | "Metadata": { 9 | "Bucket1Arn": { 10 | "Fn::GetAtt": "Bucket1.Arn" 11 | } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/api-endpoint-config-string-empty.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | Api: 5 | Type: AWS::Serverless::Api 6 | Properties: 7 | StageName: prod 8 | DefinitionBody: 9 | Body: DefinitionBody 10 | EndpointConfiguration: '' # empty string 11 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-condition-in-if.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::If": ["AlwaysFalse", 8 | "ThenName", 9 | "ElseName" 10 | ] 11 | } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/api-endpoint-config-object.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | Api: 5 | Type: AWS::Serverless::Api 6 | Properties: 7 | StageName: prod 8 | DefinitionBody: 9 | Body: DefinitionBody 10 | EndpointConfiguration: 11 | Type: GLOBAL 12 | -------------------------------------------------------------------------------- /src/parser/README.md: -------------------------------------------------------------------------------- 1 | # Template parser 2 | 3 | This folder contains the logic to parse declarative CDK templates. It transforms the input file into an abstract 4 | syntax tree, with all the necessary annotations, that can be used later for evaluation. 5 | 6 | This code was copied and adapted from [cfngine], by Rico Huijbers. 7 | 8 | 9 | [cfngine]: https://github.com/rix0rrr/cfngine -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-bad-depends-on.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/child-import-stack.json" 7 | }, 8 | "DependsOn": [ 9 | "AFakeResource" 10 | ] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-cidr.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | CidrVpc1: 3 | Type: AWS::EC2::VPC 4 | Properties: 5 | CidrBlock: 6 | !Cidr [ 192.168.1.1/24, 2, 5 ] 7 | CidrVpc2: 8 | Type: AWS::EC2::VPC 9 | Properties: 10 | CidrBlock: 11 | !Cidr 12 | - "192.168.1.1/24" 13 | - "2" 14 | - "5" 15 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/bucket-with-invalid-cors-rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": [ 8 | { 9 | "AllowedMethods": [] 10 | } 11 | ] 12 | } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/cycle-in-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket1": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Ref": "Bucket2" 8 | } 9 | } 10 | }, 11 | "Bucket2": { 12 | "Type": "AWS::S3::Bucket", 13 | "DependsOn": "Bucket1" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/schema/fixtures.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'expect'; 2 | import { readTemplate } from '../../src'; 3 | import { testTemplateFixtures } from '../util'; 4 | 5 | suite('Schema: Fixtures', () => { 6 | testTemplateFixtures(async (example) => { 7 | const template = await readTemplate(example.path); 8 | 9 | expect(template.template).toBeValidTemplate(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/rule-referencing-a-non-existent-parameter.json: -------------------------------------------------------------------------------- 1 | { 2 | "Rules": { 3 | "VpcRule": { 4 | "Assertions": [ 5 | { 6 | "Fn::EachMemberIn": [ 7 | { "Fn::ValueOfAll": ["AWS::EC2::Subnet::Id", "VpcId"] }, 8 | { "Fn::ValueOf": ["Subnets", "VpcId"] } 9 | ] 10 | } 11 | ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/non-existent-mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::FindInMap": [ 8 | "NonExistentMapping", 9 | { "Ref": "AWS::Region" }, 10 | "key1" 11 | ] 12 | } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/condition-using-mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "AlwaysTrue": { 4 | "Fn::Equals": [ 5 | { "Fn::FindInMap": ["Mapping01", "Key01", "Name"] }, 6 | "Value01" 7 | ] 8 | } 9 | }, 10 | "Mappings" : { 11 | "Mapping01" : { 12 | "Key01" : { 13 | "Name" : "Value01" 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "MyParam": { 4 | "Type": "String" 5 | } 6 | }, 7 | "Resources": { 8 | "Bucket": { 9 | "Type": "AWS::S3::Bucket", 10 | "Properties": { 11 | "BucketName": { 12 | "Fn::Sub": [ 13 | "${MyParam}" 14 | ] 15 | } 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-one-child.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 7 | "Parameters": { 8 | "MyBucketParameter": "some-magic-bucket-name" 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/only-codecommit-repo-using-cfn-functions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::CodeCommit::Repository", 5 | "Properties": { 6 | "RepositoryName": "my-repository", 7 | "RepositoryDescription": { 8 | "Fn::Select": [0, { "Fn::ValueOfAll": ["AWS::EC2::Subnet::Id", "VpcId"]}] 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-split.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: !Split [ 6 | ' ', 7 | !ImportValue SomeSharedBucketName 8 | ] 9 | Bucket2: 10 | Type: AWS::S3::Bucket 11 | Properties: 12 | BucketName: 13 | !Split 14 | - ' ' 15 | - !ImportValue SomeSharedBucketName 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/resource-attribute-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "AlwaysFalseCond": { 4 | "Fn::Equals": [ 5 | { 6 | "Ref": "AWS::Region" 7 | }, 8 | "completely-made-up-region" 9 | ] 10 | } 11 | }, 12 | "Resources": { 13 | "Bucket": { 14 | "Type": "AWS::S3::Bucket", 15 | "Condition": "AlwaysFalseCond" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/only-minimal-sam-function-codeuri-as-param.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Parameters: 4 | CodeLocation: 5 | Type: String 6 | Resources: 7 | MicroserviceHttpEndpoint: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | Handler: index.handler 11 | Runtime: nodejs12.x 12 | CodeUri: 13 | Ref: CodeLocation 14 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": "bucket" 7 | } 8 | }, 9 | "AnotherBucket": { 10 | "Type": "AWS::S3::Bucket", 11 | "Properties": { 12 | "BucketName": { "Fn::Sub": "${Bucket}-${!Bucket}-${Bucket.DomainName}" } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/number-for-string.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "WebsiteConfiguration": { 7 | "RoutingRules": [ 8 | { 9 | "RedirectRule": { 10 | "HttpRedirectCode": 403 11 | } 12 | } 13 | ] 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/resource-attribute-depends-on-array.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket0": { 4 | "Type": "AWS::S3::Bucket" 5 | }, 6 | "Bucket1": { 7 | "Type": "AWS::S3::Bucket" 8 | }, 9 | "Bucket2": { 10 | "Type": "AWS::S3::Bucket", 11 | "Properties": { 12 | "BucketName": "bucket2" 13 | }, 14 | "DependsOn": ["Bucket0", "Bucket1"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-fnsub-string.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | Fn::Sub: some-bucket${!AWS::AccountId}7896${ ! AWS::Region}1-1${!Immediate}234 7 | AnotherBucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: 11 | !Sub 1-${AWS::Region}-foo-${Bucket}-${!Literal}-${Bucket.DomainName}-${AWS::Region} 12 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-two-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 7 | "Parameters": { 8 | "FirstParameter": "first-value", 9 | "SecondParameter": "second-value" 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/string-for-number.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": [ 8 | { 9 | "AllowedMethods": ["GET"], 10 | "AllowedOrigins": ["*"], 11 | "MaxAge": "10" 12 | } 13 | ] 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/year-month-date-as-strings.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Resources: 3 | Role: 4 | Type: AWS::IAM::Role 5 | Properties: 6 | AssumeRolePolicyDocument: 7 | Version: 2012-10-17 8 | Statement: 9 | - Effect: Allow 10 | Principal: 11 | Service: 12 | - ec2.amazonaws.com 13 | Action: 14 | - sts:AssumeRole 15 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-invalid-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 7 | "Parameters": { 8 | "MyBucketParameter": "some-magic-bucket-name" 9 | } 10 | }, 11 | "Condition": "FakeCondition" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-update-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 7 | "Parameters": { 8 | "MyBucketParameter": "some-magic-bucket-name" 9 | } 10 | }, 11 | "UpdatePolicy": { 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-creation-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "ChildStack": { 4 | "Type": "AWS::CloudFormation::Stack", 5 | "Properties": { 6 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 7 | "Parameters": { 8 | "MyBucketParameter": "some-magic-bucket-name" 9 | } 10 | }, 11 | "CreationPolicy": { 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/alphabetical-string-passed-to-number.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": [ 8 | { 9 | "AllowedMethods": ["GET"], 10 | "AllowedOrigins": ["*"], 11 | "MaxAge": "abc" 12 | } 13 | ] 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-string.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": "bucket" 7 | } 8 | }, 9 | "AnotherBucket": { 10 | "Type": "AWS::S3::Bucket", 11 | "Properties": { 12 | "BucketName": { "Fn::Sub": "1-${AWS::Region}-foo-${Bucket}-${!Literal}-${Bucket.DomainName}-${AWS::Region}" } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/only-minimal-sam-function-codeuri-bucket-as-param.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Parameters: 4 | CodeLocation: 5 | Type: String 6 | Resources: 7 | MicroserviceHttpEndpoint: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | Handler: index.handler 11 | Runtime: nodejs12.x 12 | CodeUri: 13 | Bucket: 14 | Ref: CodeLocation 15 | Key: my-key 16 | -------------------------------------------------------------------------------- /src/type-system/interfaces.ts: -------------------------------------------------------------------------------- 1 | import * as reflect from 'jsii-reflect'; 2 | 3 | export function isBehavioralInterface( 4 | type: reflect.Type | undefined 5 | ): type is reflect.InterfaceType { 6 | if (!type || !type.isInterfaceType()) { 7 | return false; 8 | } 9 | 10 | return ( 11 | type.name.startsWith('I') && 12 | // Must check second char, otherwise names like `Integration` would match as well 13 | type.name[1] === type.name[1].toLocaleUpperCase() 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/cfn-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../../cdk.schema.json", 3 | "Metadata": { 4 | "Instances": { 5 | "Description": "Information about the instances" 6 | }, 7 | "Databases": { 8 | "Description": "Information about the databases" 9 | } 10 | }, 11 | "Resources": { 12 | "MyQueue": { 13 | "Type": "aws-cdk-lib.aws_sqs.Queue", 14 | "Properties": { 15 | "encryption": "KMS" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/schema/fixture/index.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAKnC,QAAQ,CAAC,YAAY,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CAClD;AAED,oBAAY,YAAY;IACtB,aAAa,IAAA;IACb,aAAa,IAAA;IACb,aAAa,IAAA;CACd"} -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-shadow-attribute.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::Sub": [ 8 | "${AnotherBucket.DomainName}", 9 | { 10 | "AnotherBucket": "whatever" 11 | } 12 | ] 13 | } 14 | } 15 | }, 16 | "AnotherBucket": { 17 | "Type": "AWS::S3::Bucket" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-shadow.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Fn::Sub": [ 8 | "${AnotherBucket}", 9 | { 10 | "AnotherBucket": { "Ref" : "AnotherBucket" } 11 | } 12 | ] 13 | } 14 | } 15 | }, 16 | "AnotherBucket": { 17 | "Type": "AWS::S3::Bucket" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-find-in-map.yaml: -------------------------------------------------------------------------------- 1 | Mappings: 2 | RegionMap: 3 | region-1: 4 | HVM64: name1 5 | HVMG2: name2 6 | Resources: 7 | Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: 11 | !FindInMap 12 | - RegionMap 13 | - region-1 14 | - HVM64 15 | Bucket2: 16 | Type: AWS::S3::Bucket 17 | Properties: 18 | BucketName: 19 | !FindInMap [ RegionMap, region-1, HVMG2 ] 20 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-sub-map.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | !Sub 7 | - "${Region}-foo-${!Immediate}-foo-${AnotherBucket}-${AnotherBucket.DomainName}-${Name}" 8 | - Name: 9 | Ref: AnotherBucket 10 | Region: 11 | Fn::Base64: AWS::Region 12 | AnotherBucket: 13 | Type: AWS::S3::Bucket 14 | Properties: 15 | BucketName: another-bucket 16 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/multi-cycle-multi-dest-in-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket1": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Ref": "Bucket2" 8 | } 9 | } 10 | }, 11 | "Bucket2": { 12 | "Type": "AWS::S3::Bucket", 13 | "DependsOn": ["Bucket3", "Bucket1"] 14 | }, 15 | "Bucket3": { 16 | "Type": "AWS::S3::Bucket", 17 | "DependsOn": ["Bucket1"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/templates/cfn-mappings.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../cdk.schema.json 2 | Mappings: 3 | RegionMap: 4 | us-west-1: 5 | HVM64: ami-0bdb828fd58c52235 6 | HVMG2: ami-066ee5fd4a9ef77f1 7 | eu-west-1: 8 | HVM64: ami-047bb4163c506cd98 9 | HVMG2: ami-0a7c483d527806435 10 | Resources: 11 | myEC2Instance: 12 | Type: 'AWS::EC2::Instance' 13 | Properties: 14 | ImageId: !FindInMap [RegionMap, !Ref 'AWS::Region', HVM64] 15 | InstanceType: m1.small 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-sub-shadow-parameter.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "MyParam": { 4 | "Type": "String" 5 | } 6 | }, 7 | "Resources": { 8 | "Bucket": { 9 | "Type": "AWS::S3::Bucket", 10 | "Properties": { 11 | "BucketName": { 12 | "Fn::Sub": [ 13 | "${MyParam}", 14 | { 15 | "MyParam": { "Ref" : "MyParam" } 16 | } 17 | ] 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/schema/fixture/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fixture", 3 | "version": "0.0.0", 4 | "description": "test fixtures for deCDK", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "jsii": { 8 | "tsc": { 9 | "types": [] 10 | } 11 | }, 12 | "repository": { 13 | "url": "https://github.com/aws/aws-cdk", 14 | "type": "git" 15 | }, 16 | "author": { 17 | "name": "Amazon Web Services", 18 | "url": "https://aws.amazon.com" 19 | }, 20 | "license": "Apache-2.0" 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-select.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Subnet1: 3 | Type: AWS::EC2::Subnet 4 | Properties: 5 | VpcId: 6 | !Select [ 0, !GetAZs "" ] 7 | CidrBlock: 10.0.0.0/24 8 | AvailabilityZone: 9 | !Select [ '0', !GetAZs eu-west-2 ] 10 | Subnet2: 11 | Type: AWS::EC2::Subnet 12 | Properties: 13 | VpcId: 14 | !Ref Subnet1 15 | CidrBlock: 10.0.0.0/24 16 | AvailabilityZone: 17 | !Select [ 0, !GetAZs eu-west-2 ] 18 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-conditionals.yaml: -------------------------------------------------------------------------------- 1 | Conditions: 2 | AlwaysTrueCond: 3 | !And 4 | - !Not [ !Equals [ !Ref "AWS::Region", completely-made-up-region ] ] 5 | - !Or [ !Equals [ !Ref "AWS::Region", completely-made-up-region ], !Equals [ !Ref "AWS::Region", completely-made-up-region] ] 6 | Resources: 7 | Bucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: 11 | !If 12 | - AlwaysTrueCond 13 | - MyBucketName 14 | - !Ref AWS::NoValue -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "eslint.format.enable": true, 4 | "[javascript]": { 5 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 6 | }, 7 | "[typescript]": { 8 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 9 | }, 10 | "mochaExplorer.env": { 11 | "TS_NODE_PROJECT": "tsconfig.dev.json" 12 | }, 13 | "testExplorer.useNativeTesting": true, 14 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/only-mapping-and-bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "Mappings": { 3 | "SomeMapping": { 4 | "region": { 5 | "key1": "value1" 6 | } 7 | } 8 | }, 9 | "Resources": { 10 | "Bucket": { 11 | "Type": "AWS::S3::Bucket", 12 | "Properties": { 13 | "BucketName": { 14 | "Fn::FindInMap": [ 15 | "SomeMapping", 16 | { "Ref": "AWS::Region" }, 17 | "key1" 18 | ] 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/only-sam-function-policies-array-ddb-crud.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Parameters: 4 | TableNameParameter: 5 | Type: String 6 | Resources: 7 | MicroserviceHttpEndpoint: 8 | Type: AWS::Serverless::Function 9 | Properties: 10 | Handler: index.handler 11 | Runtime: nodejs12.x 12 | CodeUri: my-code-uri 13 | Policies: 14 | - DynamoDBCrudPolicy: 15 | TableName: 16 | Ref: TableNameParameter 17 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/only-bucket-complex-props.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "CorsConfiguration": { 7 | "CorsRules": [ 8 | { 9 | "AllowedMethods": [ 10 | "GET" 11 | ], 12 | "AllowedOrigins": [ 13 | "*" 14 | ], 15 | "MaxAge": 10 16 | } 17 | ] 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | declare module 'mocha-expect-snapshot' { 2 | export function setSnapshotStateOptions(snapshotStateOptions: any): void; 3 | } 4 | 5 | import { setSnapshotStateOptions } from 'mocha-expect-snapshot'; 6 | import { Testing } from './util'; 7 | 8 | setSnapshotStateOptions({ 9 | snapshotFormat: { 10 | printBasicPrototype: true, 11 | }, 12 | }); 13 | 14 | export async function mochaGlobalSetup() { 15 | await Promise.all([ 16 | Testing.typeSystem, 17 | Testing.schema, 18 | Testing.templateFixtures, 19 | ]); 20 | } 21 | -------------------------------------------------------------------------------- /src/parser/template/hooks.ts: -------------------------------------------------------------------------------- 1 | import { ifField, parseObject, TemplateExpression } from './expression'; 2 | import { assertField, assertObject, assertString } from '../private/types'; 3 | 4 | export interface TemplateHook { 5 | readonly type: string; 6 | readonly properties?: Record; 7 | } 8 | 9 | export function parseHook(x: unknown): TemplateHook { 10 | const hook = assertObject(x); 11 | 12 | return { 13 | type: assertString(assertField(hook, 'Type')), 14 | properties: ifField(hook, 'Properties', parseObject), 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/child-no-bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "MyBucketParameter": { 4 | "Type": "String", 5 | "Default": "default-bucket-param-name" 6 | } 7 | }, 8 | "Resources": { 9 | "GrandChildStack": { 10 | "Type": "AWS::CloudFormation::Stack", 11 | "Properties": { 12 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 13 | "Parameters": { 14 | "MyBucketParameter": "some-other-bucket-name" 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/templates/sam/only-minimal-sam-function-codeuri-as-s3location.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Resources: 4 | MicroserviceHttpEndpoint: 5 | Type: AWS::Serverless::Function 6 | Properties: 7 | Handler: index.handler 8 | Runtime: nodejs12.x 9 | CodeUri: 10 | Bucket: awsserverlessrepo-changesets-1f9ifp952i9h0 11 | Key: 123456789012/arn:aws:serverlessrepo:us-east-1:077246666028:applications-microservice-http-endpoint-versions-1.0.4/dc38a8c1-d27f-44f3-b545-4cfff4f8b865 12 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/fn-select-with-novalue.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "DoIt": { 4 | "Type": "String" 5 | } 6 | }, 7 | "Conditions": { 8 | "MyCondition": { 9 | "Fn::Equals": [{ "Ref": "DoIt" }, "Yes"] 10 | } 11 | }, 12 | "Resources": { 13 | "Bucket": { 14 | "Type": "AWS::S3::Bucket", 15 | "Properties": { 16 | "BucketName": { "Fn::Select": [0, [ 17 | { "Fn::If": ["MyCondition", "doing-it", { "Ref": "AWS::NoValue" }] }, 18 | "not-doingit" 19 | ]]} 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/if-simple-property.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "AlwaysFalseCond": { 4 | "Fn::Equals": [ 5 | { 6 | "Ref": "AWS::Region" 7 | }, 8 | "completely-made-up-region" 9 | ] 10 | } 11 | }, 12 | "Resources": { 13 | "Bucket": { 14 | "Type": "AWS::S3::Bucket", 15 | "Properties": { 16 | "BucketName": { 17 | "Fn::If": [ 18 | "AlwaysFalseCond", 19 | "Name1", 20 | "Name2" 21 | ] 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/invalid-templates/multi-cycle-in-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Bucket1": { 4 | "Type": "AWS::S3::Bucket", 5 | "Properties": { 6 | "BucketName": { 7 | "Ref": "Bucket2" 8 | } 9 | } 10 | }, 11 | "Bucket2": { 12 | "Type": "AWS::S3::Bucket", 13 | "DependsOn": "Bucket3" 14 | }, 15 | "Bucket3": { 16 | "Type": "AWS::S3::Bucket", 17 | "DependsOn": ["Bucket4", "Bucket1"] 18 | }, 19 | "Bucket4": { 20 | "Type": "AWS::S3::Bucket", 21 | "DependsOn": "Bucket2" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/cross-stack-refs.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "Param": { 4 | "Type": "String" 5 | } 6 | }, 7 | "Resources": { 8 | "Bucket": { 9 | "Type": "AWS::S3::Bucket" 10 | }, 11 | "ChildStack": { 12 | "Type": "AWS::CloudFormation::Stack", 13 | "Properties": { 14 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/child-import-stack.json", 15 | "Parameters": { 16 | "Param1": { "Ref": "Param" }, 17 | "Param2": { "Fn::GetAtt": ["Bucket", "Arn"] } 18 | } 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/parser/template/tags.ts: -------------------------------------------------------------------------------- 1 | import { 2 | assertField, 3 | assertListOfForm, 4 | assertObject, 5 | assertString, 6 | } from '../private/types'; 7 | 8 | export interface ResourceTag { 9 | key: string; 10 | value: string; 11 | } 12 | 13 | export function parseTags(x: unknown): ResourceTag[] { 14 | return assertListOfForm(x ?? [], parseTag, '{Key: string, Value: string}'); 15 | } 16 | 17 | function parseTag(x: unknown): ResourceTag { 18 | const t = assertObject(x); 19 | 20 | return { 21 | key: assertString(assertField(t, 'Key')), 22 | value: assertString(assertField(t, 'Value')), 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/find-in-map-for-boolean-property.json: -------------------------------------------------------------------------------- 1 | { 2 | "Mappings": { 3 | "SomeMapping": { 4 | "region": { 5 | "key1": true 6 | } 7 | } 8 | }, 9 | "Resources": { 10 | "Bucket": { 11 | "Type": "AWS::S3::Bucket", 12 | "Properties": { 13 | "PublicAccessBlockConfiguration": { 14 | "BlockPublicAcls": { 15 | "Fn::FindInMap": [ 16 | "SomeMapping", 17 | { "Ref": "AWS::Region" }, 18 | "key1" 19 | ] 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/parser/resource.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'expect'; 2 | import { Template } from '../../src/parser/template'; 3 | 4 | suite('Parse Resources', () => { 5 | test('Resource properties must be object', async () => { 6 | // GIVEN 7 | const template = { 8 | Resources: { 9 | CdkTopic: { 10 | Type: 'aws-cdk-lib.aws_sns.Topic', 11 | Properties: [1, 2, 3], 12 | }, 13 | }, 14 | }; 15 | 16 | // THEN 17 | await expect(async () => Template.fromObject(template)).rejects.toThrow( 18 | 'Expected object, got: [1,2,3]' 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/resource-attribute-creation-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "CountParameter": { 4 | "Type": "Number", 5 | "Default": 3 6 | } 7 | }, 8 | "Resources": { 9 | "Bucket": { 10 | "Type": "AWS::S3::Bucket", 11 | "CreationPolicy": { 12 | "AutoScalingCreationPolicy": { 13 | "MinSuccessfulInstancesPercent": 50 14 | }, 15 | "ResourceSignal": { 16 | "Count": { 17 | "Ref": "CountParameter" 18 | }, 19 | "Timeout":"PT5H4M3S" 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/architecture/decisions/0001-record-architecture-decisions.md: -------------------------------------------------------------------------------- 1 | # 1. Record architecture decisions 2 | 3 | Date: 2022-09-02 4 | 5 | ## Status 6 | 7 | Accepted 8 | 9 | ## Context 10 | 11 | We need to record the architectural decisions made on this project. 12 | 13 | ## Decision 14 | 15 | We will use Architecture Decision Records, as [described by Michael 16 | Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). 17 | 18 | ## Consequences 19 | 20 | See Michael Nygard's article, linked above. For a lightweight ADR toolset, see 21 | Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools). 22 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/grandchild-import-stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "MyBucketParameter": { 4 | "Type": "String", 5 | "Default": "default-bucket-param-name" 6 | } 7 | }, 8 | "Resources": { 9 | "BucketImport": { 10 | "Type": "AWS::S3::Bucket", 11 | "Properties": { 12 | "BucketName": { 13 | "Fn::Join": [ 14 | "-", 15 | [ 16 | "bucket-name-prefix", 17 | { 18 | "Ref": "MyBucketParameter" 19 | } 20 | ] 21 | ] 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | /.projen/ 3 | permissions-backup.acl 4 | /dist/changelog.md 5 | /dist/version.txt 6 | /.mergify.yml 7 | /.prettierignore 8 | /.prettierrc.json 9 | /test/ 10 | /tsconfig.dev.json 11 | /src/ 12 | !/lib/ 13 | !/lib/**/*.js 14 | !/lib/**/*.d.ts 15 | dist 16 | /tsconfig.json 17 | /.github/ 18 | /.vscode/ 19 | /.idea/ 20 | /.projenrc.js 21 | tsconfig.tsbuildinfo 22 | /.eslintrc.json 23 | /cdk.out/ 24 | /docs/ 25 | /examples/ 26 | /*.schema.json 27 | /*.specs.json 28 | .mocharc.yaml 29 | /coverage/ 30 | /.nyc_output/ 31 | /.gitattributes 32 | /.projenrc.ts 33 | /projenrc 34 | -------------------------------------------------------------------------------- /test/fixtures/templates/nested/parent-valid-condition.json: -------------------------------------------------------------------------------- 1 | { 2 | "Conditions": { 3 | "AlwaysFalseCond": { 4 | "Fn::Equals": [ 5 | { 6 | "Ref": "AWS::Region" 7 | }, 8 | "completely-made-up-region" 9 | ] 10 | } 11 | }, 12 | "Resources": { 13 | "ChildStack": { 14 | "Type": "AWS::CloudFormation::Stack", 15 | "Properties": { 16 | "TemplateURL": "https://cfn-templates-set.s3.amazonaws.com/grandchild-import-stack.json", 17 | "Parameters": { 18 | "MyBucketParameter": "some-magic-bucket-name" 19 | } 20 | }, 21 | "Condition": "AlwaysFalseCond" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/find-in-map-with-dynamic-mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "Stage": { 4 | "Type": "String", 5 | "AllowedValues": ["beta"], 6 | "Default": "beta" 7 | } 8 | }, 9 | "Mappings": { 10 | "beta": { 11 | "region": { 12 | "key1": "name" 13 | } 14 | } 15 | }, 16 | "Resources": { 17 | "Bucket": { 18 | "Type": "AWS::S3::Bucket", 19 | "Properties": { 20 | "BucketName": { 21 | "Fn::FindInMap": [ 22 | { "Ref": "Stage" }, 23 | "region", 24 | "key1" 25 | ] 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/lambda-topic.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../cdk.schema.json", 3 | "Resources": { 4 | "Topic": { 5 | "Type": "aws-cdk-lib.aws_sns.Topic" 6 | }, 7 | "Lambda": { 8 | "Type": "aws-cdk-lib.aws_lambda.Function", 9 | "Properties": { 10 | "code": { 11 | "aws-cdk-lib.aws_lambda.Code.fromAsset": "examples/lambda-handler" 12 | }, 13 | "runtime": "NODEJS", 14 | "handler": "index.handler", 15 | "events": [ 16 | { 17 | "aws-cdk-lib.aws_lambda_event_sources.SnsEventSource": { 18 | "Ref": "Topic" 19 | } 20 | } 21 | ] 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/condition-same-name-as-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "Parameters": { 3 | "Param": { 4 | "Type": "String" 5 | } 6 | }, 7 | "Conditions": { 8 | "AlwaysTrue": { 9 | "Fn::Not": [{ "Condition": "AlwaysFalse" }] 10 | }, 11 | "AlwaysFalse": { 12 | "Fn::Equals": [{ "Ref": "Param" }, 2] 13 | } 14 | }, 15 | "Resources": { 16 | "AlwaysTrue": { 17 | "Type": "AWS::S3::Bucket", 18 | "Properties": { 19 | "BucketName": { 20 | "Fn::If": ["AlwaysFalse", 21 | { "Ref": "Param" }, 22 | { "Ref": "AWS::NoValue" } 23 | ] 24 | } 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/fixtures/templates/cloudformation/short-form-conditions.yaml: -------------------------------------------------------------------------------- 1 | Conditions: 2 | AlwaysTrueCond: 3 | !Not [ !Equals [ !Ref "AWS::Region", completely-made-up-region1 ] ] 4 | AnotherAlwaysTrueCond: 5 | !Not [ !Equals [ !Ref "AWS::Region", completely-made-up-region2 ] ] 6 | ThirdAlwaysTrueCond: 7 | !Not [ !Equals [ !Ref "AWS::Region", completely-made-up-region3 ] ] 8 | CombinedCond: 9 | !Or [!Condition AlwaysTrueCond, !Condition AnotherAlwaysTrueCond, !Condition ThirdAlwaysTrueCond] 10 | Resources: 11 | Bucket: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: 15 | !If 16 | - CombinedCond 17 | - MyBucketName 18 | - !Ref AWS::NoValue 19 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as reflect from 'jsii-reflect'; 3 | import { Template } from './parser/template'; 4 | 5 | /** 6 | * Reads a YAML/JSON template file. 7 | */ 8 | export async function readTemplate(templateFile: string): Promise