{"id":17109577,"url":"https://github.com/monken/cfn-include","last_synced_at":"2025-10-09T15:35:54.622Z","repository":{"id":46063373,"uuid":"46093384","full_name":"monken/cfn-include","owner":"monken","description":"Preprocessor for CloudFormation templates with support for loops and flexible include statements","archived":false,"fork":false,"pushed_at":"2024-11-04T17:28:29.000Z","size":314,"stargazers_count":85,"open_issues_count":8,"forks_count":10,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-09-21T12:37:03.086Z","etag":null,"topics":["aws","cloudformation","json","yaml"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/monken.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"monken"}},"created_at":"2015-11-13T02:01:03.000Z","updated_at":"2025-08-25T18:37:18.000Z","dependencies_parsed_at":"2024-06-20T23:24:57.848Z","dependency_job_id":"774a08f0-ae12-4df5-b2f0-371f24343d6a","html_url":"https://github.com/monken/cfn-include","commit_stats":{"total_commits":199,"total_committers":7,"mean_commits":"28.428571428571427","dds":"0.11055276381909551","last_synced_commit":"f7a3bc76024273f348253cf20d50dab5120d32b2"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/monken/cfn-include","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monken%2Fcfn-include","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monken%2Fcfn-include/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monken%2Fcfn-include/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monken%2Fcfn-include/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monken","download_url":"https://codeload.github.com/monken/cfn-include/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monken%2Fcfn-include/sbom","scorecard":{"id":658599,"data":{"date":"2025-08-11","repo":{"name":"github.com/monken/cfn-include","commit":"f7a3bc76024273f348253cf20d50dab5120d32b2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":3,"reason":"Found 6/18 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/commitlint.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Info: Possibly incomplete results: error parsing shell code: reached EOF without closing quote \": examples/userdata.txt:0","Info: Possibly incomplete results: error parsing shell code: reached EOF without closing quote \": t/includes/userdata.sh:0","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/commitlint.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/monken/cfn-include/commitlint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/commitlint.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/monken/cfn-include/commitlint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/monken/cfn-include/tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/monken/cfn-include/tests.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/commitlint.yml:27","Warn: npmCommand not pinned by hash: .github/workflows/tests.yml:23","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T15:24:30.593Z","repository_id":46063373,"created_at":"2025-08-21T15:24:30.593Z","updated_at":"2025-08-21T15:24:30.593Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001646,"owners_count":26083147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cloudformation","json","yaml"],"created_at":"2024-10-14T16:23:39.432Z","updated_at":"2025-10-09T15:35:54.585Z","avatar_url":"https://github.com/monken.png","language":"JavaScript","funding_links":["https://github.com/sponsors/monken"],"categories":["Open Source Repos"],"sub_categories":["CloudFormation"],"readme":"# cfn-include\n\n`cfn-include` is a preprocessor for CloudFormation templates which extends CloudFormation's [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html).\nFor example, [`Fn::Include`](#fninclude) provides a convenient way to include files, which can be local, a URL or on an S3 bucket (with proper IAM authentication if necessary). It supports both JSON and YAML as input and output format. CloudFormation's tag syntax for YAML (e.g. `!GetAtt`) is supported as well.\n\n`cfn-include` tries to be minimally invasive, meaning that the template will still look and feel like an ordinary CloudFormation template. This is what sets `cfn-include` apart from other CloudFormation preprocessors such as [CFNDSL](https://github.com/stevenjack/cfndsl), [StackFormation](https://github.com/AOEpeople/StackFormation) and [AWSBoxen](https://github.com/mozilla/awsboxen). There is no need to use a scripting language or adjust to new syntax. Check them out though, they might be a better fit for you.\n\n**Functions**\n- [cfn-include](#cfn-include)\n  - [Installation](#installation)\n  - [Synopsis](#synopsis)\n    - [CLI](#cli)\n    - [Example](#example)\n  - [Fn::Include](#fninclude)\n    - [Examples](#examples)\n      - [Include a file from a URL](#include-a-file-from-a-url)\n      - [Include a file in the same folder](#include-a-file-in-the-same-folder)\n      - [Include an AWS API response](#include-an-aws-api-response)\n      - [Include Globs](#include-globs)\n      - [Include Inject State](#include-inject-state)\n  - [Fn::Map](#fnmap)\n  - [Fn::Flatten](#fnflatten)\n  - [Fn::FlattenDeep](#fnflattendeep)\n  - [Fn::GetEnv](#fngetenv)\n  - [Fn::Length](#fnlength)\n  - [Fn::Merge](#fnmerge)\n  - [Fn::DeepMerge](#fndeepmerge)\n  - [Fn::Sequence](#fnsequence)\n  - [Fn::Stringify](#fnstringify)\n  - [Fn::Uniq](#fnuniq)\n  - [Fn::Compact](#fncompact)\n  - [Fn::Concat](#fnconcat)\n  - [Fn::Sort](#fnsort)\n  - [Fn::SortedUniq](#fnsorteduniq)\n  - [Fn::SortBy](#fnsortby)\n  - [Fn::SortObject](#fnsortobject)\n  - [Fn::ObjectKeys](#fnobjectkeys)\n  - [Fn::ObjectValues](#fnobjectvalues)\n  - [Fn::Filenames](#fnfilenames)\n  - [Fn::StringSplit](#fnstringsplit)\n  - [Fn::Without](#fnwithout)\n  - [Fn::Omit](#fnomit)\n  - [Fn::OmitEmpty](#fnomitempty)\n  - [Fn::Eval](#fneval)\n  - [Fn::IfEval](#fnifeval)\n  - [Fn::JoinNow](#fnjoinnow)\n  - [Fn::ApplyTags](#fnapplytags)\n  - [Fn::Outputs](#fnoutputs)\n  - [More Examples](#more-examples)\n  - [Proxy Support](#proxy-support)\n  - [Compatibility](#compatibility)\n  - [Web Service](#web-service)\n\nTag-based syntax is available in YAML templates. For example,`Fn::Include` becomes `!Include`.\n\n## Installation\n\nYou can either install `cfn-include` or use a web service to compile templates.\n\n```\nnpm install --global cfn-include\n```\n\nThe web service can be called with your favorite CLI tool such as `curl`.\n\n```\ncurl https://api.netcubed.de/latest/template -XPOST -d @template.json\n```\n\n## Synopsis\n\n### CLI\n\n    cfn-include \u003cpath\u003e [options]\n\n- `path`\n\n  location of template. Either path to a local file, URL or file on an S3 bucket (e.g. `s3://bucket-name/example.template`)\n\nOptions:\n\n* `-m, --minimize`   minimize JSON output  [false]\n* `--metadata`       add build metadata to output  [false]\n* `-t, --validate`   validate compiled template  [false]\n* `-y, --yaml`       output yaml instead of json  [false]\n* `--bucket`         bucket name required for templates larger than 50k\n* `--prefix`         prefix for templates uploaded to the bucket ['cfn-include']\n* `--version`        print version and exit\n* `--context`        template full path. only utilized for stdin when the template is piped to this script\n  example:          `cat examples/base.template | ./bin/cli.js --context examples/base.template`\n* `--enable`         different options / toggles: ['env','eval']    [string] [choices: 'env','eval','env.eval' etc...]\n  * `env` pre-process env vars and inject into templates as they are processed looks for $KEY or ${KEY} matches\n* `-i, --inject`     JSON string payload to use for template injection. (Takes precedence over process.env (if enabled) injection and will be merged on top of process.env)\n* `--doLog`          console log out include options in recurse step.\n`cfn-include` also accepts a template passed from stdin\n\n```\ncat mytemplate.yml | cfn-include\n```\n\n### Example\n\n```yaml\nMappings:\n  Region2AMI: !Include https://api.netcubed.de/latest/ami/lookup?platform=amzn2\nResources:\n  Instance:\n    Type: AWS::EC2::Instance\n    Properties:\n      ImageId: !FindInMap [Region2AMI, !Ref AWS::Region, AMI]\n      UserData:\n        Fn::Base64:\n          Fn::Sub: !Include { type: string, location: userdata.sh }\n```\n\nThis is what the `userdata.sh` looks like:\n\n```bash\n#!/bin/bash\n/opt/aws/bin/cfn-init -s ${AWS::StackId} -r MyInstance --region ${AWS::Region}\n```\n\n```bash\ncfn-include synopsis.json \u003e output.template\n# you can also compile remote files\ncfn-include https://raw.githubusercontent.com/monken/cfn-include/master/examples/synopsis.json \u003e output.template\n```\n\nThe output will be something like this:\n\n```javascript\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Mappings\": {\n    \"Region2AMI\": {\n      \"Metadata\": {\n        \"Name\": \"amzn-ami-hvm-2016.09.0.20161028-x86_64-gp2\",\n        \"Owner\": \"amazon\",\n        \"CreationDate\": \"2016-10-29T00:49:47.000Z\"\n      },\n      \"us-east-2\": {\n        \"AMI\": \"ami-58277d3d\"\n      },\n      // ...\n  } },\n  \"Resources\": {\n    \"Instance\": {\n      \"Type\": \"AWS::EC2::Instance\",\n      \"Properties\": {\n        \"ImageId\": {\n          \"FindInMap\": [ \"Region2AMI\", { \"Ref\": \"AWS::Region\" }, \"AMI\" ]\n        },\n        \"UserData\": {\n          \"Fn::Base64\": {\n            \"Fn::Sub\": {\n              \"Fn::Join\": [\"\", [\n                  \"#!/bin/bash\\n\",\n                  \"\\\"/opt/aws/bin/cfn-init -s ${AWS::StackId} -r MyInstance --region ${AWS::Region}\\n\",\n                  \"\"\n] ] } } } } } } }\n```\n\n## Fn::Include\n\nPlace `Fn::Include` anywhere in the template and it will be replaced by the contents it is referring to. The function accepts an object. Parameters are:\n\n- **location**: The location to the file can be relative or absolute. A relative location is interpreted relative to the template. Included files can in turn include more files, i.e. recursion is supported.\n- **ignoreMissingVar**: If set to `true` the function will not throw an error if a variable is not found (unset). Instead, the variable will be replaced by an empty string. Defaults to `false`.\n- **ignoreMissingFile**: If set to `true` the function will not throw an error if the file is not found. Instead, the function will be replaced by an empty string. Defaults to `false`.\n- **type** (optional): either `json`, `string` or `api`. Defaults to `json`. `string` will include the file literally which is useful in combination with `Fn::Sub`. `api` will call any AWS API and return the response which can be included in the template. Choose `json` for both JSON and YAML files. The `literal` type is deprecated and uses the infamous `Fn::Join` syntax.\n- **context** (optional, deprecated): If `type` is `literal` a context object with variables can be provided. The object can contain plain values or references to parameters or resources in the CloudFormation template (e.g. `{ \"Ref\": \"StackId\" }`). Use Mustache like syntax in the file. This option is deprecated in favor of the `Fn::Sub` syntax (see examples below).\n- **parser** (optional):\n  - string: default is `\"jmespath\"`\n  - object `{location, query, parser}`: default is `\"jmespath\"`\n  - array: `[location, query, parser]`: default is `\"lodash\"`\n  - string (split |) `location|query|parser`: default is `\"lodash\"`\n- **query** (optional): If `type` is `json`, `array`, or `string split |`\n  - [JMESPath](http://jmespath.org/) query can be provided. The file to include is then queried using the value as a JMESPath expression.\n  - [Lodash _.get](https://lodash.com/docs/4.17.15#get) query\n\nOnly applicable if **type** is `api`:\n\n- **service**: Service to call (see [AWSJavaScriptSDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html), case sensitive, e.g. `EC2`, `CloudFormation`)\n- **action**: Action to call (case sensitive, e.g. `updateStack`, `describeRegions`)\n- **parameters** (optional): Parameters passed to **action** (e.g. `{ StackName: \"MyStack\" }`)\n- **region** (optional): Either `AWS_DEFAULT_REGION` or this parameter have to be set which specifies the region where the API call is made.\nYou can also use a plain string if you want the default behavior, which is simply including a JSON file.\n- **isGlob** (optional): Forces the usage of [glob](https://www.npmjs.com/package/glob) to spit out an array of includes\n- **inject** (optional): Pass in localized env / options to be injected into a template\n\n### Examples\n\n#### Include via Query\n\n```yaml\n# all equivalent\nFn::Include:\n  location: ./t/includes/complex.json\n  query: bulb[1].c\n\nFn::Include:\n  location: ./t/includes/complex.json\n  query: bulb.1.c\n  parser: lodash\n\n# Array parser is lodash\nFn::Include: [./t/includes/complex.json, bulb.1.c]\n\n# Array default parser is lodash\nFn::Include:\n  - ./t/includes/complex.json\n  - bulb.1.c\n\n# string split \"|\" default  parser is lodash\nFn::Include: ./t/includes/complex.json|bulb.1.c\n```\n\n#### Include a file from a URL\n\n```yaml\n!Include https://example.com/include.json\n\n// equivalent to\n\nFn::Include:\n  type: json\n  location: https://example.com/include.json\n```\n\nInclude a file from an S3 bucket. Authentication is handled by `aws-sdk`. See [Setting AWS Credentials](https://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html#Setting_AWS_Credentials) for details.\n\n```yaml\n!Include s3://bucket-name/include1.json\n```\n\n#### Include a file in the same folder\n\n```yaml\n!Include include.json\n```\n\nInclude a file literally and make use of `Fn::Sub`:\n\n```yaml\nFn::Sub:\n  Fn::Include:\n    type: string\n    location: https://example.com/userdata.txt\n```\n\n#### Include an AWS API response\n\nIE: loop through all regions and return the image id of a specific AMI:\n\n```yaml\nFn::Merge:\n  Fn::Map:\n    - Fn::Include:\n        action: describeRegions\n        query: \"Regions[*].RegionName[]\"\n        service: EC2\n        type: api\n    - _:\n        AMI:\n          Fn::Include:\n            action: describeImages\n            parameters:\n              Filters:\n                - Name: manifest-location\n                  Values:\n                    - amazon/amzn-ami-hvm-2016.03.3.x86_64-gp2\n            query: \"Images[*].ImageId | [0]\"\n            region: _\n            service: EC2\n            type: api\n```\n\nOutput as JSON:\n\n```json\n{ \"ap-south-1\": { \"AMI\": \"ami-ffbdd790\" },\n  \"eu-west-1\": {\"AMI\": \"ami-f9dd458a\" },\n  \"ap-southeast-1\": { \"AMI\": \"ami-a59b49c6\" },\n  ...\n}\n```\n\n#### Include Globs\n\nEssentially imagine if you had several yaml or json files you wanted to include.\n\n```\n./src/\n  files/\n    - one.yml\n    - two.yml\n    - three.yml\n    - four.yml\n  main.yml\n```\n\nBefore Glob you would have to do:\n\nmain.yml\n\n```yml\nFn::Map:\n  - [one, two, three]\n  - [FILE]\n  - Fn::Include: ./files/${FILE}.yml\n```\n\nWith Glob\n\nmain.yml\n\n```yml\nFn::Include: ./files/*.yml\n```\n\nor (say you need to ignore something)\n\n```yml\nFn::Include:\n  location: ./files/!(four).yml\n  isGlob: true\n```\n\n#### Include Inject State\n\nThis feature uses the exact same logic as doEnv in that all env variables are traversed and replaced however this is\nwith localized state for the included file.\n\nFile to inject to:\n\n`toInject.yml` - your include file\n\n```yml\nSomeResource:\n  Name: ${LOCALIZED_NAME}\n```\n\nConsume it and add some custom state\n\n```yml\nFn::Include:\n  location: ./toInject.yml\n  inject:\n    LOCALIZED_NAME: CustomName\n```\n\nyields\n\n```yml\nSomeResource:\n  Name: CustomName\n```\n\n## Fn::Map\n\n`Fn::Map` is the equivalent of the lodash [`map()`](https://lodash.com/docs/4.17.15#map) function allowing for the transformation of an input array or object to an output array.\nBy default the string `_` is used as the variable in the map function. A custom variable can be provided as a second parameter, see [`Fn::Flatten`](#fnflatten) for an example. If a custom variable is used, the variable will also be replaced if found in the object key, see [`Fn::Merge`](#fnmerge) for an example.\n\n```yaml\nFn::Map:\n  - [80, 443]\n  - CidrIp: 0.0.0.0/0\n    FromPort: _\n    ToPort: _\n    IpProtocol: tcp\n```\n\n```json\n[\n  {\n    \"CidrIp\": \"0.0.0.0/0\",\n    \"FromPort\": \"80\",\n    \"ToPort\": \"80\"\n  },\n  {\n    \"CidrIp\": \"0.0.0.0/0\",\n    \"FromPort\": \"443\",\n    \"ToPort\": \"443\"\n  }\n]\n```\n\nCustom variables can be specified as a single value, of as a list of up to three values. If a list is specified, the second variable is used as index and the third (if present) as size.\n\n```yaml\nFn::Map:\n  - !Sequence [A, C]\n  - [NET, INDEX, N]\n  - Subnet${NET}:\n      Type: 'AWS::EC2::Subnet'\n      Properties:\n        CidrBlock: !Select [INDEX, !Cidr [MyCIDR, N, 8]]\n```\n\n```json\n[{\n  \"SubnetA\": {\n    \"Type\": \"AWS::EC2::Subnet\",\n    \"Properties\": {\n      \"CidrBlock\": { \"Fn::Select\": [ 0, { \"Fn::Cidr\": [ \"MyCIDR\", 3, 8 ] } ] }\n    }\n  }\n}, {\n  \"SubnetB\": {\n    \"Type\": \"AWS::EC2::Subnet\",\n    \"Properties\": {\n      \"CidrBlock\": { \"Fn::Select\": [ 1, { \"Fn::Cidr\": [ \"MyCIDR\", 3, 8 ] } ] }\n    }\n  }\n}, {\n  \"SubnetC\": {\n    \"Type\": \"AWS::EC2::Subnet\",\n    \"Properties\": {\n      \"CidrBlock\": { \"Fn::Select\": [ 2, { \"Fn::Cidr\": [ \"MyCIDR\", 3, 8 ] } ] }\n    }\n  }\n}]\n```\n\n\n## Fn::Flatten\n\nThis function flattens an array a single level. This is useful for flattening out nested [`Fn::Map`](#fnmap) calls.\n\n```yaml\nSecurityGroupIngress:\n  Fn::Flatten:\n    Fn::Map:\n      - [80, 443]\n      - $\n      - Fn::Map:\n          - [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]\n          - CidrIp: _\n            FromPort: $\n            ToPort: $\n            IpProtocol: tcp\n```\n\nResults in:\n\n```json\n{\n  \"SecurityGroupIngress\": [\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    }\n  ]\n}\n```\n\n## Fn::FlattenDeep\n\nThis function flattens an array as many levels as possible. This is useful for flattening out nested [`Fn::Map`](#fnmap) calls.\n\n```yaml\nSecurityGroupIngress:\n  Fn::FlattenDeep:\n    Fn::Map:\n      - [80, 443]\n      - $\n      - Fn::Map:\n          - [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]\n          - Fn::Map:\n              - [tcp, udp]\n              - PROTOCOL\n              - CidrIp: _\n                FromPort: $\n                ToPort: $\n                IpProtocol: PROTOCOL\n```\n\nResults in:\n\n```json\n{\n  \"SecurityGroupIngress\": [\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"udp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"udp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"80\",\n      \"ToPort\": \"80\",\n      \"IpProtocol\": \"udp\"\n    },\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"10.0.0.0/8\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"udp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"172.16.0.0/12\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"udp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"tcp\"\n    },\n    {\n      \"CidrIp\": \"192.168.0.0/16\",\n      \"FromPort\": \"443\",\n      \"ToPort\": \"443\",\n      \"IpProtocol\": \"udp\"\n    }\n  ]\n}\n```\n\n## Fn::GetEnv\n\n```yaml\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !GetEnv [BUCKET_NAME, !Ref AWS::NoValue]\n```\n\nThe second argument is optional and provides the default value and will be used of the environmental variable is not defined. If the second argument is omitted `!GetEnv BUCKET_NAME` and the environmental variable is not defined then the compilation will fail.\n\n## Fn::Length\n\n`Fn::Length` returns the length of a list or expanded section.\n\n\n## Fn::Merge\n\n`Fn::Merge` will merge an array of objects into a single object. See [lodash / merge](https://devdocs.io/lodash~4/index#merge) for details on its behavior. This function is useful if you want to add functionality to an existing template if you want to merge objects of your template that have been created with [`Fn::Map`](#fnmap).\n\n`Fn::Merge` accepts a list of objects that will be merged together. You can use other `cfn-include` functions such as `Fn::Include` to pull in template from remote locations such as S3 buckets.\n\n```yaml\nFn::Merge:\n  - !Include s3://my-templates/my-template.json\n\n  - !Include s3://my-templates/my-other-template.json\n\n  - Parameters:\n      MyCustomParameter:\n        Type: String\n\n    Resources:\n      MyBucket:\n        Type: AWS::S3::Bucket\n```\n\n## Fn::DeepMerge\n\n`Fn::DeepMerge` will deeply merge an array of objects and arrays into a single object. See [deepmerge](https://www.npmjs.com/package/deepmerge) for details on its behavior. This function is useful if you want to add functionality to an existing template if you want to merge objects of your template that have been created with [`Fn::Map`](#fnmap).\n\n`Fn::DeepMerge` accepts a list of objects that will be merged together. You can use other `cfn-include` functions such as `Fn::Include` to pull in template from remote locations such as S3 buckets.\n\nTo understand it better besides the below example refer to this [test](t/tests/deepmerge.yml). Note that all arrays are concatenated.\n\nWhy does `Fn::Merge` still exist? Answer: Backwards compatibility for expected behavior.\n\n```yaml\nFn::DeepMerge:\n  - !Include s3://my-templates/my-template.json\n\n  - !Include s3://my-templates/my-other-template.json\n\n  - Parameters:\n      MyCustomParameter:\n        Type: String\n\n    Resources:\n      MyBucket:\n        Type: AWS::S3::Bucket\n```\n\nThis snippet shows how multiple subnets can be created for each AZ and then merged with the rest of the template.\n\n```yaml\nResources:\n  IAMUser:\n    Type: AWS::IAM::User\n  SecurityGroup:\n    Type: AWS::EC2::SecurityGroup\n  Fn::Merge:\n    Fn::Map:\n      - [A, B]\n      - AZ\n      - Subnet${AZ}:\n          Type: AWS::EC2::Subnet\n```\n\n```json\n{\n  \"Resources\": {\n    \"SubnetA\": {\n      \"Type\": \"AWS::EC2::Subnet\"\n    },\n    \"SubnetB\": {\n      \"Type\": \"AWS::EC2::Subnet\"\n    },\n    \"SG\": {\n      \"Type\": \"AWS::EC2::SecurityGroup\"\n    }\n  }\n}\n```\n\n## Fn::Sequence\n\n`Fn::Sequence` generates a sequence of numbers of characters. You can specify the start, end and step.\n\n```yaml\n!Sequence [1, 4]\n\n# generates\n[1, 2, 3 4]\n\n!Sequence [1, 10, 2]\n\n# generates\n[1, 3, 5, 7, 9]\n\n!Sequence [a, d]\n\n# generates\n[a, b, c, d]\n```\n\n`Fn::Sequence` can be used in combination with `Fn::Map` to generate complex objects:\n\n```\nFn::Map:\n  - !Sequence [a, c]\n  - AZ\n  - Subnet${AZ}:\n      Type: AWS::EC2::Subnet\n```\n\n## Fn::Stringify\n\n`Fn::Stringify` will take the passed value and transform it to a JSON string. This is useful for parameters that require a JSON document as a string. Using this function, you can keep writing your configuration in YAML and let the function transform it into a JSON string.\n\nAnother useful application is the use of this function in a config file passed as `--cli-input-json` parameter.\n\n```yaml\n# stack.config.yml\n\nStackName: MyStack\n\nTemplateBody:\n  Fn::Stringify: !Include mytemplate.yml\n\nParameters:\n  - ParameterKey: Foo\n    ParameterValue: Bar\n```\n\nYou can then simply run the following command to deploy a stack:\n\n```\ncfn-include stack.config.yml \u003e stack.config.json\naws cloudformation create-stack --cli-input-json file://stack.config.json\n```\n\n## Fn::Uniq\n\nThis function filters only the unique elements of an array\n\n```yaml\nSecurityGroupIngress:\n  Fn::Uniq:\n    Fn::Flatten:\n      - [1, 2]\n      - [3, 4]\n      - [1, 4, 6]\n```\n\nResults in:\n\n```json\n{\n  \"SecurityGroupIngress\": [\n    1,\n    2,\n    3,\n    4,\n    6\n  ]\n}\n```\n\n## Fn::Compact\n\nThis function removes falsy elements same as [lodash](https://lodash.com/docs/4.17.15#compact)\n\n```yaml\nSecurityGroupIngress:\n  Fn::Compact:\n    - 1\n    - a\n    - \"\"\n    - false\n    - true\n```\n\nResults in:\n\n```json\n{\n  \"SecurityGroupIngress\": [\n    1,\n    \"a\",\n    true\n  ]\n}\n```\n\n## Fn::Concat\n\n_.concat\n\n```yaml\nFn::Concat:\n  - [a, b, c]\n  - d\n```\n\nResults in:\n\n```json\n[\n  \"a\",\n  \"b\",\n  \"c\",\n  \"d\"\n]\n```\n\n## Fn::Sort\n\n`$ ./bin/cli.js [examples/sort.yaml](examples/sort.yaml)`\n\n```json\n[\n  1,\n  20,\n  22,\n  30,\n  30,\n  33.3,\n  40,\n  5.5,\n  50,\n  50\n]\n```\n\n## Fn::SortedUniq\n\n`$ ./bin/cli.js [examples/sortedUniq.yaml](examples/sortedUniq.yaml)`\n\n```json\n[\n  1,\n  20,\n  22,\n  30,\n  33.3,\n  40,\n  5.5,\n  50\n]\n```\n\n## Fn::SortBy\n\n`$ ./bin/cli.js [examples/sortBy.yaml](examples/sortBy.yaml)`\n\n```json\n[\n  {\n    \"name\": \"Ana\",\n    \"age\": 12\n  },\n  {\n    \"name\": \"Ana\",\n    \"age\": 31\n  },\n  {\n    \"name\": \"Bob\",\n    \"age\": 17\n  },\n  {\n    \"name\": \"Colby\",\n    \"age\": 35\n  },\n  {\n    \"name\": \"Fred\",\n    \"age\": 50\n  },\n  {\n    \"name\": \"Jack\",\n    \"age\": 40\n  },\n  {\n    \"name\": \"Ted\",\n    \"age\": 20\n  },\n  {\n    \"name\": \"Zed\",\n    \"age\": 90\n  }\n]\n```\n\n## Fn::SortObject\n\nSee: [examples/sortObject.yaml](examples/sortObject.yaml)\n\n`$ ./bin/cli.js examples/sortObject.yaml`\n\n```json\n{\n  \"a\": \"hi\",\n  \"c\": \"z\",\n  \"h\": 20,\n  \"i\": true,\n  \"z\": 1\n}\n```\n\n## Fn::ObjectKeys\n\nThis function uses [Object.keys](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys)\n\n```yaml\nFamilyNames:\n  Fn::ObjectKeys:\n    Ted: 18 \n    Lucy: 5\n    Tom: 10\n```\n\nResults in:\n\n```yaml\nFamilyNames:\n  - Ted\n  - Lucy\n  - Tom\n```\n\n## Fn::ObjectValues\n\nThis function uses [Object.values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)\n\n```yaml\nFamilyAges:\n  Fn::ObjectValues:\n    Ted: 18 \n    Lucy: 5\n    Tom: 10\n```\n\nResults in:\n\n```yaml\nFamilyAges:\n  - 18\n  - 5\n  - 10\n```\n\n## Fn::Filenames\n\n```yaml\nFn::Filenames:\n  location: \"../t/fixtures\"\n  omitExtension: true\n```\n\n```json\n[\n  \"deep\",\n  \"foobar\",\n  \"subfolder\",\n  \"synopsis\",\n  \"verydeep\",\n  \"include1\",\n  \"include2\"\n]\n```\n\n## Fn::StringSplit\n\nUseful for injected Includes which you need to run `Fn::Map` upon.\n\n```yaml\nFn::StringSplit:\n  string: \"A,B,C\"\n  separator: \",\" # defaults to this so it can be omitted\n```\n\n```yaml\n- A\n- B\n- C\n```\n\n## Fn::Without\n\n```yaml\nFn::Without:\n  - [\"a\", \"b\", \"c\", \"d\"]\n  - [\"b\", \"c\"]\n```\n\n```yaml\n- \"a\",\n- \"d\"\n```\n\n## Fn::Omit\n\n[omit_object](t/includes/omit_object.json)\n[omit_array](t/includes/omit_array.json)\n\n```yaml\nb: b\n```\n\n## Fn::OmitEmpty\n\nSee [omitEmpty test file](t/omitEmpty.json), file and expectations (output). \n\nIn summary falsy values are omitted from an object except `false` and `0`.\n\n## Fn::Eval\n\nOpt in to use `eval` in your templates. This is disabled by default.\n\n`--enable eval` is required to turn on options.doEval in the include function.\n\n```yaml\nFn::Eval:\n  state: [1, 2, 3]\n  script: \u003e\n    state.map((v) =\u003e 2 * v);\n```\n\n```yaml\n- 2\n- 4\n- 6\n```\n\n## Fn::IfEval\n\nOpt in to use `eval` in your templates. This is disabled by default.\n\n`--enable eval` is required to turn on options.doEval in the include function.\n\n```yaml\nFn::IfEval:\n  inject:\n    lastName: bear\n  # doLog: true\n  evalCond: ('$lastName' === 'bear')\n  truthy:\n    Name: Yogi\n    LastName: Bear\n  falsy:\n    Name: Fred\n    LastName: Flint\n```\n\n```yaml\nName: Yogi\nLastName: Bear\n```\n\n## Fn::JoinNow\n\n```yaml\nFn::JoinNow:\n  - \"\"\n  - - \"arn:aws:s3:::c1-acme-iam-cache-engine-\"\n    - ${AWS::AccountId}\n    - \"-us-east-1$CFT_STACK_SUFFIX\"\n```\n\n```yaml\narn:aws:s3:::c1-acme-iam-cache-engine-${AWS::AccountId}-us-east-1$CFT_STACK_SUFFIX\n```\n\n## Fn::ApplyTags\n\nSee [ApplyTags test file](t/tests/applyTags.yml).\n\nFields:\n`(T|t)ags`: sequence of {Key, Value} objects to me merged in as Tags properties of a taggable resource.\n`resources`: Object mapping of resources, this is usually your root `CFT.Resources` block.\n\n## Fn::UpperCamelCase\n\n```yaml\nName: !UpperCamelCase foo-bar # yields FooBar\n```\n\n## Fn::Outputs\n\nThis helper transformation simplifies the definition of output variables and exports.\n\n```yaml\nOutputs:\n  Fn::Outputs:\n    Version: !GetEnv [VERSION, \"1.0.0\"]\n    BucketArn: ${Bucket.Arn}\n    BucketPolicy:\n      Condition: HasBucketPolicy\n      Value: ${BucketPolicy}\n    Subnets:\n      - ${SubnetA},${SubnetB},${Provided}\n      - Provided: ${SubnetC}\n```\n\nThis will translate into:\n\n```yaml\nOutputs:\n  Version:\n    Value: !Sub \"1.0.0\"\n    Export:\n      Name: !Sub ${AWS::StackName}:Version\n\n  BucketArn:\n    Value: !Sub ${Bucket.Arn}\n    Export:\n      Name: !Sub ${AWS::StackName}:BucketArn\n\n  BucketPolicy:\n    Value: !Sub ${BucketPolicy}\n    Condition: HasBucketPolicy\n    Export:\n      Name: !Sub ${AWS::StackName}:BucketPolicy\n\n  Subnets:\n    Value:\n      Fn::Sub:\n        - ${SubnetA},${SubnetB},${Provided}\n        - Provided: ${SubnetC}\n    Export:\n      Name: !Sub ${AWS::StackName}:Subnets\n```\n\n## More Examples\n\nSee [/examples](https://github.com/monken/cfn-include/tree/master/examples) for templates that call an API Gateway endpoint to collect AMI IDs for all regions. There is also a good amount of [tests](https://github.com/monken/cfn-include/tree/master/t) that might be helpful.\n\nA common pattern is to process a template, validate it against the AWS [validate-template](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/validate-template.html) API, minimize it and upload the result to S3. You can do this with a single line of code:\n\n```bash\ncfn-include example.template -t -m | aws s3 cp - s3://bucket-name/output.template\n```\n\n## Proxy Support\n\n`cfn-include` honors proxy settings defined in the `https_proxy` environmental variable. The module will attempt to load `proxy-agent`. Make sure `proxy-agent` is installed since it is not a dependency for this module.\n\n## Compatibility\n\nNode.js versions 8 and up are supported both on Windows and Linux.\n\n## Web Service\n\n    curl https://api.netcubed.de/latest/template?[options] -XPOST -d @\u003cpath\u003e\n\n- `path`\n\n  the contents of `path` will be `POST`ed to the web service. See `man curl` for details.\n\nOptions:\n\nOptions are query parameters.\n\n- `validate=false` do not validate template [true]\n\nTo compile the synopsis run the following command.\n\n```\ncurl -Ssf -XPOST https://api.netcubed.de/latest/template -d '{\"Fn::Include\":\"https://raw.githubusercontent.com/monken/cfn-include/master/examples/synopsis.json\"}' \u003e output.template\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonken%2Fcfn-include","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonken%2Fcfn-include","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonken%2Fcfn-include/lists"}