{"_id":"@almamedia-open-source/cdk-project-names","_rev":"1-f8719578cac79cac9e1c8741901c4771","name":"@almamedia-open-source/cdk-project-names","dist-tags":{"latest":"0.0.8"},"versions":{"0.0.8":{"name":"@almamedia-open-source/cdk-project-names","description":"Opinionated AWS CDK utility for explicitly naming resources.","repository":{"type":"git","url":"git+https://github.com/almamedia-open-source/cdk-project-names.git"},"scripts":{"build":"npx projen build","bump":"npx projen bump","clobber":"npx projen clobber","compat":"npx projen compat","compile":"npx projen compile","default":"npx projen default","docgen":"npx projen docgen","eslint":"npx projen eslint","package":"npx projen package","package-all":"npx projen package-all","package:js":"npx projen package:js","post-compile":"npx projen post-compile","post-upgrade":"npx projen post-upgrade","pre-compile":"npx projen pre-compile","release":"npx projen release","test":"npx projen test","test:update":"npx projen test:update","test:watch":"npx projen test:watch","unbump":"npx projen unbump","upgrade":"npx projen upgrade","upgrade-projen":"npx projen upgrade-projen","watch":"npx projen watch","projen":"npx projen"},"author":{"name":"Alma Media","email":"opensource@almamedia.dev"},"devDependencies":{"@almamedia-open-source/cdk-project-context":"0.0.11","@types/jest":"^27.4.0","@types/node":"^14","@typescript-eslint/eslint-plugin":"^5","@typescript-eslint/parser":"^5","aws-cdk-lib":"2.0.0","constructs":"10.0.0","eslint":"^8","eslint-import-resolver-node":"^0.3.6","eslint-import-resolver-typescript":"^2.5.0","eslint-plugin-import":"^2.25.3","jest":"^27.4.3","jest-junit":"^13","jsii":"^1.46.0","jsii-diff":"^1.46.0","jsii-docgen":"^4.2.4","json-schema":"^0.4.0","npm-check-updates":"^12","projen":"^0.50.33","standard-version":"^9","ts-jest":"^27.0.7","typescript":"^4.5.2"},"peerDependencies":{"@almamedia-open-source/cdk-project-context":"v0.0.11","aws-cdk-lib":"^2.0.0","constructs":"^10.0.0"},"dependencies":{"change-case":"^4.1.2"},"keywords":["aws","aws-cdk","awscdk","cdk"],"engines":{"node":">= 14.17.6"},"main":"lib/index.js","license":"Apache-2.0","publishConfig":{"access":"public"},"version":"0.0.8","jest":{"testMatch":["<rootDir>/src/**/__tests__/**/*.ts?(x)","<rootDir>/(test|src)/**/?(*.)+(spec|test).ts?(x)"],"clearMocks":true,"collectCoverage":true,"coverageReporters":["json","lcov","clover","cobertura","text"],"coverageDirectory":"coverage","coveragePathIgnorePatterns":["/node_modules/"],"testPathIgnorePatterns":["/node_modules/"],"watchPathIgnorePatterns":["/node_modules/"],"reporters":["default",["jest-junit",{"outputDirectory":"test-reports"}]],"preset":"ts-jest","globals":{"ts-jest":{"tsconfig":"tsconfig.dev.json"}}},"types":"lib/index.d.ts","stability":"experimental","jsii":{"outdir":"dist","targets":{},"tsc":{"outDir":"lib","rootDir":"src"}},"//":"~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\".","_resolved":"","_integrity":"","_from":"file:dist/js/cdk-project-names@0.0.8.jsii.tgz","bundleDependencies":["change-case"],"bugs":{"url":"https://github.com/almamedia-open-source/cdk-project-names/issues"},"homepage":"https://github.com/almamedia-open-source/cdk-project-names#readme","_id":"@almamedia-open-source/cdk-project-names@0.0.8","_nodeVersion":"14.18.3","_npmVersion":"6.14.15","dist":{"integrity":"sha512-Ri/4S8pgMtDeG/CTADS0HUbuo4AnQslHpvgInOO/V8G1XCuvW3AaKC7YPl8F90J1K0dy4ADbFUOkH9sJSGX42A==","shasum":"8dd232510da6491f5db2713c9563e6310ec19d94","tarball":"https://registry.npmjs.org/@almamedia-open-source/cdk-project-names/-/cdk-project-names-0.0.8.tgz","fileCount":260,"unpackedSize":425418,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh5enkCRA9TVsSAnZWagAA88EQAJtRxj1jAcUxaG/bqR4i\nFfhq1FN2PoYP6/LbZ+xG/YYu5CT4j0ZYen9t0d2Ex3JfwGnMBOYSOXkez/s9\nTNzejxyfvuNsjxMoSYMkQTFVP2olnPhqv3ZA9EJO49VOeMqc4teIvsbtEi1U\n03qpVFdTlMG/4rBOiazY7z7iJgBv9cr5J2NtYgT7ParA76Da5OFRWqod+imM\ncNMgNZqVl8gcn5yDdiZbjdcQdy5q18VVYV5/TDrp6Ak1R1RGYmTROiCg4XWA\n+FVXgDc8ZKw6V/EUochPZBrcdX/fIGJtIGtMkxvtjQjstv2AvJtoobAdBKA4\nvJGIReCEefA65IrcB4dmp8YdoAAvo9wr2kVXQQVPV7tJugD0qSUPq4LJJzhL\nm+Dmso6tLtAhXWvEyfCQC1UYQq9F5lKH2vgljSv75jKI8JaMszIxFSQyOmHB\nH7wl+bqkGBuI7YfY9AAoZrxgSuHHO+KyrD8Tf7BneHzJkBSu4bl2Hm1+LTrA\nr9jPvTGApZK0a5VWdVLyDx49UZD6JIwdCAL9wyVx2MEeDiMbrV8GkBmSLKWf\ns+QcBCZWrN/mL+Daa94rnb9XZUIZFoh3KoVy7ccLwVwIc5lLE2tuUxEroYBw\nqMPKAwuDBzuxdB52oJUcZFCkorTD8HsdNXyhqjblLoznzzz1np8JjHW8bFdU\nRuG0\r\n=v0wg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiZGxijCPT+JaEnvK/vURKR5TKSyP2DI5pmwbbSKla/gIhAJ+m4vJA43vIdZojMDWPlkpKDoj2xixhVPbweRZKxPTW"}]},"_npmUser":{"name":"almamedia-opensource","email":"opensource@almamedia.dev"},"directories":{},"maintainers":[{"name":"almamedia-opensource","email":"opensource@almamedia.dev"},{"name":"ari.palo","email":"ari.palo@almamedia.fi"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cdk-project-names_0.0.8_1642457572793_0.9774470571672706"},"_hasShrinkwrap":false}},"time":{"created":"2022-01-17T22:12:52.743Z","0.0.8":"2022-01-17T22:12:52.970Z","modified":"2022-04-04T13:35:36.570Z"},"maintainers":[{"name":"almamedia-opensource","email":"opensource@almamedia.dev"},{"name":"ari.palo","email":"ari.palo@almamedia.fi"}],"description":"Opinionated AWS CDK utility for explicitly naming resources.","homepage":"https://github.com/almamedia-open-source/cdk-project-names#readme","keywords":["aws","aws-cdk","awscdk","cdk"],"repository":{"type":"git","url":"git+https://github.com/almamedia-open-source/cdk-project-names.git"},"author":{"name":"Alma Media","email":"opensource@almamedia.dev"},"bugs":{"url":"https://github.com/almamedia-open-source/cdk-project-names/issues"},"license":"Apache-2.0","readme":"# ![Alma CDK Project Names](/assets/alma-cdk-project-names.png)\n\n![CDK Version](https://img.shields.io/badge/CDK-v2-informational \"CDK v2\")\n![Stability](https://img.shields.io/badge/Stability-Experimental-yellow \"Stability: Experimental\") [![release](https://github.com/almamedia-open-source/cdk-project-names/actions/workflows/release.yml/badge.svg)](https://github.com/almamedia-open-source/cdk-project-names/actions/workflows/release.yml)\n\n**Opinionated AWS CDK utility for explicitly naming resources.**\n\n[AWS CDK resource naming best practises](https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-apps-names) state that you should not explicitly name resources, but instead let CDK generate resource names to avoid naming collisions and enable replacement operations during deployments.\n\n**But**, having explicit resource naming _with sensible conventions_ can:\n1. also prevent naming collisions\n2. prevent accidental/unwanted replacement operations\n3. make debugging and finding correct resources via CloudWatch or X-Ray easier\n\nThere are many valid arguments why you should aim for totally immutable infrastructure and use generated resource names. But for example, how often you want to [change DynamoDB partition key on the fly](https://bobbyhadz.com/blog/dont-assign-names-cdk-resources) for production database with existing data? You might also have a lot of resources that others (even in different AWS accounts) rely on and hence the name (or ARN) of those resources must not change suddenly! **In the end, how you name (or don't name) your resources is up to you to decide; If you decide to explicitly name (_all or some_) resources, this utility might be for you!**\n\n<br/>\n\n## Important\n\n**🚧 This tool is work-in-progress and experimental!**\n\nAll `@almamedia-open-source/cdk-` prefixed constructs/utilities are based on existing CDK constructs/utilities we've developed & used (in production) internally at [Alma Media](https://www.almamedia.fi/en/) since 2019.\n\n_Breaking changes may occur at any given time without prior warning before first `v1` major is released_, as we rewrite them for CDK v2 and use this opportunity to also redesign & refactor.\n\n[Feedback](https://github.com/almamedia-open-source/cdk-project-names/issues) is most welcome, but do note that we intend to implement these new constructs/utilities and their APIs in such manner that our existing CDK v1 production workloads can easily migrate into these new `@almamedia-open-source/cdk-` constructs/utilities.\n\n<br/>\n\n## Installation\n\n1. Ensure you meet following requirements:\n    - [NodeJS](https://nodejs.org/en/) `v14.17.6` or newer\n    - [AWS Cloud Development Kit](https://aws.amazon.com/cdk/) `v2.0.0` or newer\n\n2. Install peer dependency [`@almamedia-open-source/cdk-project-context`](https://github.com/almamedia-open-source/cdk-project-context):\n    ```shell\n    npm i -D @almamedia-open-source/cdk-project-context\n    ```\n\n3. Install this tool:\n    ```shell\n    npm i -D @almamedia-open-source/cdk-project-names\n    ```\n\n<br/>\n\n## Usage\n\n1. Initialize your CDK App with `Project` construct as documented in [`@almamedia-open-source/cdk-project-context`](https://github.com/almamedia-open-source/cdk-project-context):\n    ```ts\n    import { Project } from '@almamedia-open-source/cdk-project-context';\n\n    // new Project instead of new App\n    const project = new Project({\n      name: 'my-cool-project',\n      author: {\n        organization: 'Acme Corp',\n        name: 'Mad Scientists',\n        email: 'mad.scientists@acme.example.com',\n      },\n      defaultRegion: 'eu-west-1', // defaults to one of: $CDK_DEFAULT_REGION, $AWS_REGION or us-east-1\n      accounts: {\n        dev: {\n          id: '111111111111',\n          config: {\n            baseDomain: 'example.net',\n          },\n        },\n        prod: {\n          id: '222222222222',\n          config: {\n            baseDomain: 'example.com',\n          },\n        },\n      },\n    })\n    ```\n\n2. Define your resource names:\n    ```ts\n    import { Name, UrlName, PathName } from '@almamedia-open-source/cdk-project-names';\n\n    // somewhere inside your CDK stack:\n\n    new dynamodb.Table(this, 'Table', {\n      queueName: Name.it(this, 'MyTable'),\n    });\n\n    new events.EventBus(this, 'EventBus', {\n      topicName: Name.withProject(this, 'MyEventBus'),\n    });\n\n    new s3.Bucket(this, 'Bucket', {\n      bucketName: UrlName.globally(this, 'MyBucket'),\n    });\n\n    new ssm.StringParameter(this, 'Parameter', {\n      parameterName: PathName.withProject(this, 'MyNamespace/MyParameter'),\n      stringValue: 'Foo',\n      tier: ssm.ParameterTier.ADVANCED,\n    });\n    ```\n\n3. Run CDK commands with (optional) `environment-type` (or shorthand: `environment` or `env`) CLI context flag, for example:\n    ```shell\n    npx cdk deploy --context environment=feature/foo-bar\n    ```\n\n4. The resources will be named as following:\n    | Resource  |                     Resource Name                      |\n    | :-------- | :----------------------------------------------------- |\n    | Table     | `FeatureFooBarMyTable`                                 |\n    | EventBus  | `MyCoolProjectFeatureFooBarMyEventBus`                 |\n    | Bucket    | `acme-corp-my-cool-project-feature-foo-bar-my-bucket`  |\n    | Parameter | `/MyCoolProject/FeatureFooBar/MyNamespace/MyParameter` |\n\n<br/>\n\n## High-level Naming Conventions\n\n\n### Case Styles\n\n| Class name |                Style                |                              Purpose                               |      Example output       |\n| :--------- | :---------------------------------- | :----------------------------------------------------------------- | :------------------------ |\n| `Name`     | `PascalCase`                        | Default style for naming resources                                 | `MyResource`              |\n| `UrlName`  | `param-case`                        | URL/DNS compatible values<br/>(e.g. S3 `bucketName`)                   | `my-resource`             |\n| `PathName` | `PascalCase`<br/>separated by<br/>`/` (slash) | Slash separated values<br/>(e.g. SSM `parameterName` with hierarchies) | `/MyNamespace/MyParameter` |\n\n### Specificity Levels\n\nThere are three different “specificity levels” of naming you may choose via available methods:\n|  Method name  |          Purpose          |   Example with application `environment` info    |\n| :------------ | :------------------------ | :------------------ |\n| `it`          | Only base name with environment type if that is available | `StagingMyResource` |\n| `withProject` | Same as above, but prefix with project name (recommended default) | `MyCoolProjectStagingMyResource` |\n| `globally`    | Same as above, but prefix with your organization name as well | `AcmeCorpMyCoolProjectStagingMyResource` |\n\n#### Shorthand syntax\n\nSince `withProject` is often the most sensible default, this tool exposes the following shorthand functions for brevity:\n- `name` – same as `Name.withProject`\n- `urlName` – same as `UrlName.withProject`\n- `pathName` – same as `PathName.withProject`\n\nNote the lowercase first letter.\n\n```ts\nimport { name, urlName, pathName } from '@almamedia-open-source/cdk-project-names';\n\nname(scope, 'MyResource');\nurlName(scope, 'MyResource');\npathName(scope, 'MyResource');\n```\n\n### Prefixes\n\nDepending on the configuration, CDK context and method that is being used, this utility will prefix the names with some or all following values:\n\n| Order |          Value          |              Controlled by               |\n| :---: | :---------------------- | :--------------------------------------- |\n|   1   | Organization            | Used method: `globally` only             |\n|   2   | Project Name            | Used method: `globally` or `withProject` |\n|   3   | Application Environment | If provided via `--context environment`  |\n|   4   | Base Name               | Required string value given by user      |\n\n\n#### Name Structure\n\n| Style | Default | Application `environment` info present |\n| :--: | :--: | :--: |\n| `PascalCase` default  | `[Organization][ProjectName]Basename` | `[Organization][ProjectName]EnvironmentBasename` |\n| `param-case` URL/DNS compatible | `[organization-][project-name-]basename` |  `[organization-][project-name-]environment-basename` |\n| `PascalCase` <br/>separated by `/`  | `/[Organization/][ProjectName/]Basename` | `/[Organization/][ProjectName/]Environment/Basename` |\n\nValues in square brackets `[]` are optional and they are printed depending on which [specificity level is used](#specificity-levels).\n\n<br/>\n\n## Resource Name Limitations\n\n### Allowed Characters\n\nThis tool does not validate for allowed characters, as they vary from service to service. Mostly you should stick to basic alphanumeric characters (`a-z` and `0-9`), with the exception of `PathName` class and it's methods where you may use slash `/` character to describe SSM Parameter name hierarchies.\n\n### Length\n\n**Most AWS resources have resource name length limiation of around 63 characters** but as always, there are exceptions such as:\n- AWS Lambda supports [up to 140 characters for `functionName`](https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html#API_CreateFunction_RequestSyntax)\n- ElastiCache supports [only 50 characters for `clusterName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticache-cache-cluster.html#cfn-elasticache-cachecluster-clustername)\n- Elastic Load Balancing supports [only 32 characters for `targetGroupName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html)\n\nThe various limitations can be found via service specific API docs or somewhat nicely [aggregated for most popular services in this StackOverflow answer](https://stackoverflow.com/a/46290196/11266464).\n\nIf you have lenghty values in organization name, project name, environment type and/or base name you may run into problems. Due to that reason **by default this utility will create an error if your resource name exceeds 63 characters.**\n\n#### PathName exception\n\nThe exception is `PathName` as it is mostly used with AWS Systems Manager Parameter Store Paremeters, which have the [ARN length limit of `1011`](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_PutParameter.html#systemsmanager-PutParameter-request-Name): Therefore with `PathName` we have decided to set the default character limit to `900`. You can always configure that with `maxLength: number` property.\n\n#### Strategies\n\n1. If the resource accepts longer resource names (like AWS Lambda accepts 140 characters for `functionName`), you may specify a custom max length as a prop:\n    ```ts\n    Name.globally(this, 'MyFunction', { maxLength: 140 });\n    ```\n2. Select the naming method carefully:\n\n    - If your AWS account only has single project in it, you should default to using `it` which results into shortest possible resource name, for example `StagingMyResource`. But also consider future-proofing: Will there be other projects in that AWS account in the future?\n\n    - If your AWS account has multiple projects (e.g. microservices) in it, you should default to using `withProject`, which results into values such as `MyCoolProjectStagingMyResource`.\n\n    - Only use `globally` method which prints the longest form (for example `AcmeCorpMyCoolProjectStagingMyResource`) for things such as S3 bucket names.\n\n      You shouldn't really have the need to separate different organizations internally within a single AWS account. Having multiple organizations (business units or development teams etc) deploying workloads into the same AWS account suggests your AWS account organization setup is not necessarily following best practises.\n\n3. **If the name is not important to you: Don't specify the name at all and let CDK handle it!**\n\n4. Consider shorter base name.\n\n5. You should consider of course if you can somehow logically abbreviate/shorten your organization name for example. Be careful with this, as it will affect resources (i.e. perform replacement) that are already deployed!\n\n6. Consider [trimming](#trimming).\n\n7. Roll your own naming for that specific resource. You may want to utilize some of the methods provided by [`@almamedia-open-source/cdk-project-context`](https://github.com/almamedia-open-source/cdk-project-context).\n\n#### Trimming\n\nSet the maximum length and enable trimming:\n```ts\nName.withProject(this, 'MyApplicationTargetGroup', {\n  maxLength: 32,\n  trim: true,\n});\n```\n\nIf the output value of `Name.withProject` is within the `maxLength` (32) character limit, then it returns immediately. If not (as in the above example), the following happens:\n\n1. It creates a hash value from the basename:\n    `E43A285509B095FCE0E474A4E9DF0A1D1D41F09D91F70D6F4873688BC07E6C2B`\n2. Picks first 3 characters from the hash:\n    `E43`\n3. Cuts the output value of `Name.withProject` to first 29 characters:\n    `MyCoolProjectStagingMyApplica`\n4. Adds the first 3 characters from the hash as suffix\n    `MyCoolProjectStagingMyApplicaE43`\n\nNote that trimming happens for the whole output value of `Name.withProject`, which means your organization, project name and environment type prefixes might be affected as well (depending on their length).\n\n\n\n\n\n\n","readmeFilename":"README.md"}