@intentius/chant-lexicon-aws 0.0.5 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,437 +1,21 @@
1
1
  # @intentius/chant-lexicon-aws
2
2
 
3
- > Part of the [chant](../../README.md) monorepo. Published as [`@intentius/chant-lexicon-aws`](https://www.npmjs.com/package/@intentius/chant-lexicon-aws) on npm.
3
+ AWS CloudFormation lexicon for [chant](https://intentius.io/chant/) declare infrastructure as typed TypeScript that serializes to CloudFormation JSON templates.
4
4
 
5
- AWS CloudFormation lexicon for chant declare infrastructure as flat, typed TypeScript that serializes to CloudFormation JSON templates.
6
-
7
- ## Overview
8
-
9
- This package provides:
10
-
11
- - **CloudFormation serializer** — converts chant declarables to CloudFormation JSON templates
12
- - **Intrinsic functions** — type-safe `Fn::Sub`, `Fn::GetAtt`, `Fn::Join`, etc.
13
- - **Pseudo-parameters** — `AWS::Region`, `AWS::AccountId`, `AWS::StackName`, etc.
14
- - **Resource types** — generated constructors for S3, Lambda, IAM, and all CloudFormation resource types
15
- - **Lint rules** — AWS-specific validation (e.g. hardcoded region detection)
16
- - **Code generation** — generates TypeScript types from CloudFormation resource specs
17
- - **LSP/MCP support** — completions and hover for AWS resource types
18
-
19
- ## CloudFormation Concepts
20
-
21
- ### Templates
22
-
23
- Chant builds a CloudFormation template from your declarations. Every exported resource becomes a logical resource in the `Resources` section. The serializer automatically:
24
-
25
- - Wraps everything in `AWSTemplateFormatVersion: "2010-09-09"`
26
- - Converts camelCase properties to PascalCase (CloudFormation convention)
27
- - Resolves `AttrRef` references to `Fn::GetAtt`
28
- - Resolves resource references to `Ref` intrinsics
29
-
30
- ```typescript
31
- // This declaration...
32
- export const dataBucket = new Bucket({
33
- bucketName: Sub`${AWS.StackName}-data`,
34
- versioningConfiguration: $.versioningEnabled,
35
- });
36
-
37
- // ...becomes this in the template:
38
- // "DataBucket": {
39
- // "Type": "AWS::S3::Bucket",
40
- // "Properties": {
41
- // "BucketName": { "Fn::Sub": "${AWS::StackName}-data" },
42
- // "VersioningConfiguration": { "Status": "Enabled" }
43
- // }
44
- // }
45
- ```
46
-
47
- Build a template with:
48
-
49
- ```typescript
50
- import { awsDomain } from "@intentius/chant-lexicon-aws";
51
- import { build } from "@intentius/chant";
52
-
53
- const result = await build("./src/infra", awsDomain);
54
- ```
55
-
56
- ### Parameters
57
-
58
- CloudFormation parameters become template `Parameters` entries. Declare them using `CoreParameter`-implementing entities — the serializer detects them and places them in the `Parameters` section instead of `Resources`.
59
-
60
- ```typescript
61
- // Parameters appear in the template as:
62
- // "Parameters": {
63
- // "EnvName": { "Type": "String", "Default": "prod" }
64
- // }
65
- ```
66
-
67
- ### Outputs
68
-
69
- Use `output()` to create explicit stack outputs. The serializer collects them into the template's `Outputs` section. Cross-lexicon `AttrRef` usage is also auto-detected and promoted to outputs.
70
-
71
- ```typescript
72
- import { output } from "@intentius/chant";
73
-
74
- // Explicit output
75
- const bucketArn = output(dataBucket.arn, "DataBucketArn");
76
-
77
- // In the template:
78
- // "Outputs": {
79
- // "DataBucketArn": {
80
- // "Value": { "Fn::GetAttr": ["DataBucket", "Arn"] }
81
- // }
82
- // }
83
- ```
84
-
85
- ### Tagging
86
-
87
- Tags are standard CloudFormation `Key`/`Value` arrays. Pass them as `tags` props on any resource that supports them:
88
-
89
- ```typescript
90
- export const bucket = new Bucket({
91
- bucketName: "my-bucket",
92
- tags: [
93
- { key: "Environment", value: "production" },
94
- { key: "Team", value: "platform" },
95
- ],
96
- });
97
- ```
98
-
99
- To apply tags across all members of a composite, use `propagate`:
100
-
101
- ```typescript
102
- import { propagate } from "@intentius/chant";
103
-
104
- export const api = propagate(
105
- LambdaApi({ name: "myApi", code: lambdaCode }),
106
- { tags: [{ key: "env", value: "prod" }] },
107
- );
108
- // All expanded members (role, function, permission) will have these tags
109
- ```
110
-
111
- See [Composites](#composites) for more on `propagate`.
112
-
113
- ## Intrinsic Functions
114
-
115
- ### Fn::Sub
116
-
117
- ```typescript
118
- import { Sub, AWS } from "@intentius/chant-lexicon-aws";
119
-
120
- const url = Sub`https://${bucket.domainName}/path`;
121
- const arn = Sub`arn:aws:s3:::${AWS.Region}:${AWS.AccountId}:*`;
122
- ```
123
-
124
- ### Fn::GetAtt
125
-
126
- ```typescript
127
- // Preferred: use AttrRef directly
128
- const arnRef = myBucket.arn;
129
-
130
- // Or explicit:
131
- import { GetAtt } from "@intentius/chant-lexicon-aws";
132
- const bucketArn = GetAtt("MyBucket", "Arn");
133
- ```
134
-
135
- ### Fn::Ref, Fn::Join, Fn::If, Fn::Select, Fn::Split, Fn::Base64
136
-
137
- ```typescript
138
- import { Ref, Join, If, Select, Split, Base64 } from "@intentius/chant-lexicon-aws";
139
-
140
- const paramRef = Ref("MyParameter");
141
- const joined = Join("-", ["prefix", AWS.StackName, "suffix"]);
142
- const value = If("UseProduction", "prod-value", "dev-value");
143
- const firstItem = Select(0, Split(",", "a,b,c"));
144
- const userData = Base64("#!/bin/bash\necho hello");
145
- ```
146
-
147
- ## Pseudo-Parameters
148
-
149
- ```typescript
150
- import { AWS, Sub } from "@intentius/chant-lexicon-aws";
151
-
152
- const endpoint = Sub`https://s3.${AWS.Region}.${AWS.URLSuffix}`;
153
- ```
154
-
155
- | Pseudo-parameter | Description |
156
- |---|---|
157
- | `AWS.StackName` | Name of the stack |
158
- | `AWS.Region` | AWS region where stack is created |
159
- | `AWS.AccountId` | AWS account ID |
160
- | `AWS.StackId` | Stack ID |
161
- | `AWS.URLSuffix` | Domain suffix (usually `amazonaws.com`) |
162
- | `AWS.Partition` | Partition (`aws`, `aws-cn`, `aws-us-gov`) |
163
- | `AWS.NotificationARNs` | Notification ARNs |
164
- | `AWS.NoValue` | Removes property when used with `Fn::If` |
165
-
166
- ## Examples
167
-
168
- Two runnable examples live in `examples/`. Both have tests you can run with `bun test`.
169
-
170
- ### Getting Started (`examples/getting-started/`)
171
-
172
- Declares 4 resources across separate files: two S3 buckets, an IAM role, and a Lambda function.
173
-
174
- ```
175
- src/
176
- ├── _.ts # Barrel — re-exports lexicon + auto-discovers sibling files
177
- ├── defaults.ts # Shared config: encryption, versioning, public access block
178
- ├── data-bucket.ts # S3 bucket using barrel defaults
179
- ├── logs-bucket.ts # S3 bucket for access logs
180
- ├── role.ts # IAM role with Lambda assume-role policy
181
- └── handler.ts # Lambda function referencing role and bucket
182
- ```
183
-
184
- **Patterns demonstrated:**
185
-
186
- 1. **Flat declarations** — sub-resources like `encryptionDefault` and `publicAccessBlock` are their own named exports in `defaults.ts`, then referenced by other files via the barrel
187
- 2. **Barrel sharing** — `import * as _ from "./_"` gives every file access to all siblings via `_.$`
188
- 3. **Cross-resource references** — `$.dataBucket.arn` and `$.functionRole.arn` automatically serialize to `Fn::GetAtt`
189
- 4. **Intrinsics** — `Sub` with pseudo-parameters for dynamic naming: `Sub`\``${AWS.StackName}-data`\`
190
-
191
- ```typescript
192
- // handler.ts — references role and bucket from other files
193
- export const handler = new _.Function({
194
- functionName: _.Sub`${_.AWS.StackName}-handler`,
195
- handler: "index.handler",
196
- runtime: "nodejs20.x",
197
- role: _.$.functionRole.arn, // cross-file AttrRef
198
- code: lambdaCode,
199
- environment: { variables: { BUCKET_ARN: _.$.dataBucket.arn } },
200
- });
201
- ```
202
-
203
- ### Advanced (`examples/advanced/`)
204
-
205
- Builds on the getting-started patterns with composites, composite presets, custom lint rules, and IAM inline policies.
5
+ This package provides generated constructors for all CloudFormation resource and property types, type-safe intrinsic functions (`Sub`, `Ref`, `Join`, etc.), pseudo-parameters (`AWS.Region`, `AWS.AccountId`, etc.), composites for grouping related resources, and AWS-specific lint rules. It also includes LSP and MCP server support for editor completions and hover.
206
6
 
7
+ ```bash
8
+ npm install --save-dev @intentius/chant @intentius/chant-lexicon-aws
207
9
  ```
208
- src/
209
- ├── _.ts # Barrel — also re-exports Composite from core
210
- ├── chant.config.ts # Lint config: strict preset + custom plugin
211
- ├── defaults.ts # Encryption, versioning, access block, Lambda trust policy
212
- ├── data-bucket.ts # S3 bucket
213
- ├── lambda-api.ts # Composite factory + SecureApi/HighMemoryApi presets
214
- ├── health-api.ts # Uses SecureApi preset — minimal health check
215
- ├── upload-api.ts # Uses SecureApi + S3 PutObject policy
216
- ├── process-api.ts # Uses HighMemoryApi + S3 read/write policy
217
- └── lint/
218
- └── api-timeout.ts # Custom WAW012 rule: Lambda API timeout check
219
- ```
220
-
221
- **What it adds over getting-started:**
222
-
223
- - **Composites** — `LambdaApi` groups a Role + Function + Permission into a reusable unit (see [Composites](#composites))
224
- - **Composite presets** — `SecureApi` and `HighMemoryApi` wrap `LambdaApi` with sensible defaults for different workloads
225
- - **Inline IAM policies** — `upload-api.ts` and `process-api.ts` attach `Role_Policy` objects to restrict S3 access per-API
226
- - **Custom lint rules** — `api-timeout.ts` enforces API Gateway's 29-second timeout limit (see [Custom Lint Rules](#custom-lint-rules))
227
- - **Lint configuration** — `chant.config.ts` extends the strict preset and loads the custom plugin
228
-
229
- The advanced example produces 10 CloudFormation resources: 1 S3 bucket + 3 composites × 3 resources each (role, function, permission).
230
-
231
- ## Composites
232
-
233
- Composites group related resources into reusable factories. A composite is a function that takes typed props and returns named members:
234
-
235
- ```typescript
236
- import { Composite, Sub, AWS } from "@intentius/chant-lexicon-aws";
237
-
238
- export const LambdaApi = Composite<LambdaApiProps>((props) => {
239
- const role = new Role({
240
- assumeRolePolicyDocument: $.lambdaTrustPolicy,
241
- managedPolicyArns: [$.lambdaBasicExecutionArn],
242
- policies: props.policies,
243
- });
244
-
245
- const func = new Function({
246
- functionName: props.name,
247
- runtime: props.runtime,
248
- handler: props.handler,
249
- code: props.code,
250
- role: role.arn, // cross-reference within the composite
251
- timeout: props.timeout,
252
- memorySize: props.memorySize,
253
- });
254
-
255
- const permission = new Permission({
256
- functionName: func.arn,
257
- action: "lambda:InvokeFunction",
258
- principal: "apigateway.amazonaws.com",
259
- });
260
-
261
- return { role, func, permission };
262
- }, "LambdaApi");
263
- ```
264
-
265
- Instantiate it like a function call:
266
-
267
- ```typescript
268
- export const healthApi = LambdaApi({
269
- name: Sub`${AWS.StackName}-health`,
270
- runtime: "nodejs20.x",
271
- handler: "index.handler",
272
- code: { zipFile: `exports.handler = async () => ({ statusCode: 200 });` },
273
- });
274
- ```
275
-
276
- During build, composites expand to flat resources: `healthApi_role`, `healthApi_func`, `healthApi_permission`.
277
-
278
- ### `withDefaults` — composite presets
279
-
280
- Wraps a composite with pre-applied defaults. Defaulted props become optional:
281
-
282
- ```typescript
283
- import { withDefaults } from "@intentius/chant";
284
-
285
- const SecureApi = withDefaults(LambdaApi, {
286
- runtime: "nodejs20.x",
287
- handler: "index.handler",
288
- timeout: 10,
289
- memorySize: 256,
290
- });
291
-
292
- // Only name and code are required now
293
- export const healthApi = SecureApi({
294
- name: Sub`${AWS.StackName}-health`,
295
- code: { zipFile: `exports.handler = async () => ({ statusCode: 200 });` },
296
- });
297
-
298
- // Composable — stack defaults on top of defaults
299
- const HighMemoryApi = withDefaults(SecureApi, { memorySize: 2048, timeout: 25 });
300
- ```
301
-
302
- `withDefaults` preserves the original composite's identity — it shares the same `_id` and `compositeName`, and does not create a new registry entry.
303
-
304
- ### `propagate` — shared properties
305
-
306
- Attaches properties that merge into every member of a composite during expansion:
307
-
308
- ```typescript
309
- import { propagate } from "@intentius/chant";
310
-
311
- export const api = propagate(
312
- LambdaApi({ name: "myApi", code: lambdaCode }),
313
- { tags: [{ key: "env", value: "prod" }] },
314
- );
315
- // role, func, and permission all get the env tag
316
- ```
317
-
318
- Merge semantics:
319
- - **Scalars** — member-specific value wins over shared
320
- - **Arrays** (e.g. tags) — shared values are prepended, then member values appended
321
- - **`undefined`** — stripped from shared props, never overwrites
322
-
323
- ## Custom Lint Rules
324
-
325
- Chant's lint engine runs TypeScript AST visitors. You can write project-specific rules that enforce domain conventions.
326
10
 
327
- ### Anatomy of a lint rule
328
-
329
- A lint rule implements the `LintRule` interface:
330
-
331
- ```typescript
332
- import type { LintRule, LintDiagnostic, LintContext } from "@intentius/chant/lint/rule";
333
- import * as ts from "typescript";
334
-
335
- export const apiTimeoutRule: LintRule = {
336
- id: "WAW012", // unique ID (WAW = AWS-specific prefix)
337
- severity: "error", // "error" | "warning"
338
- category: "correctness", // "correctness" | "style" | "security"
339
-
340
- check(context: LintContext): LintDiagnostic[] {
341
- const { sourceFile } = context;
342
- const diagnostics: LintDiagnostic[] = [];
343
-
344
- function visit(node: ts.Node): void {
345
- // Walk the AST looking for violations...
346
- if (ts.isCallExpression(node)) {
347
- // Check call arguments, report diagnostics
348
- }
349
- ts.forEachChild(node, visit);
350
- }
351
-
352
- visit(sourceFile);
353
- return diagnostics;
354
- },
355
- };
356
- ```
357
-
358
- The `check` function receives a `LintContext` containing the TypeScript `sourceFile` and returns an array of diagnostics with file, line, column, and message.
359
-
360
- ### Example: API Gateway timeout (`WAW012`)
361
-
362
- The advanced example includes a custom rule that flags Lambda API composites with `timeout > 29` — API Gateway's synchronous limit:
363
-
364
- ```typescript
365
- // lint/api-timeout.ts
366
- const API_FACTORIES = new Set(["LambdaApi", "SecureApi", "HighMemoryApi"]);
367
-
368
- export const apiTimeoutRule: LintRule = {
369
- id: "WAW012",
370
- severity: "error",
371
- category: "correctness",
372
-
373
- check(context: LintContext): LintDiagnostic[] {
374
- // Walks AST for calls to API factory functions,
375
- // checks timeout property value, reports if > 29
376
- },
377
- };
378
- ```
379
-
380
- ### Registering custom rules
381
-
382
- Add a `chant.config.ts` to your project root:
383
-
384
- ```typescript
385
- // chant.config.ts
386
- export default {
387
- lint: {
388
- extends: ["@intentius/chant/lint/presets/strict"],
389
- rules: {
390
- COR004: "off", // disable a built-in rule
391
- },
392
- plugins: ["./lint/api-timeout.ts"], // load custom rules
393
- },
394
- };
395
- ```
396
-
397
- The `plugins` array accepts relative paths. Each plugin module should export a `LintRule` object (named or as `apiTimeoutRule`, etc.).
398
-
399
- ### Built-in AWS lint rules
400
-
401
- **`hardcoded-region`** — detects hardcoded AWS region strings:
402
-
403
- ```typescript
404
- // Bad — hardcoded region
405
- const endpoint = "s3.us-east-1.amazonaws.com";
406
-
407
- // Good — use pseudo-parameter
408
- const endpoint = Sub`s3.${AWS.Region}.amazonaws.com`;
409
- ```
410
-
411
- ## Code Generation
412
-
413
- The AWS lexicon uses core's `generatePipeline` with AWS-specific callbacks:
414
-
415
- - `codegen/generate.ts` — calls core `generatePipeline<SchemaParseResult>` with AWS callbacks
416
- - `codegen/naming.ts` — extends core `NamingStrategy` with AWS data tables
417
- - `codegen/package.ts` — calls core `packagePipeline` with AWS manifest and skill collector
418
- - `spec/fetch.ts` — uses core `fetchWithCache` + `extractFromZip` for CloudFormation schema
419
-
420
- ## Template Import
421
-
422
- Convert existing CloudFormation JSON/YAML to TypeScript:
423
-
424
- ```typescript
425
- import { parseTemplate } from "@intentius/chant-lexicon-aws";
426
-
427
- const ir = parseTemplate(cfTemplate);
428
- // Generate TypeScript from the intermediate representation
429
- ```
11
+ **[Documentation →](https://intentius.io/chant/lexicons/aws/)**
430
12
 
431
13
  ## Related Packages
432
14
 
433
- - `@intentius/chant` core functionality, type system, and CLI
434
- - `@intentius/chant-test-utils` — testing utilities
15
+ | Package | Role |
16
+ |---------|------|
17
+ | [@intentius/chant](https://www.npmjs.com/package/@intentius/chant) | Core type system, CLI, build pipeline |
18
+ | [@intentius/chant-lexicon-gitlab](https://www.npmjs.com/package/@intentius/chant-lexicon-gitlab) | GitLab CI lexicon |
435
19
 
436
20
  ## License
437
21
 
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "algorithm": "xxhash64",
3
3
  "artifacts": {
4
- "manifest.json": "41f6aec36bdf4377",
5
- "meta.json": "85e3d7584599ea7e",
6
- "types/index.d.ts": "f773e9083412c5d8",
7
- "rules/s3-encryption.ts": "33a8de06c8bf8d62",
4
+ "manifest.json": "732c6ae3a38b318b",
5
+ "meta.json": "1d77155af909175f",
6
+ "types/index.d.ts": "14a646c172b78c4b",
7
+ "rules/s3-encryption.ts": "e1da7d27b7dde0ed",
8
8
  "rules/hardcoded-region.ts": "c65b9015c7c361c",
9
9
  "rules/iam-wildcard.ts": "bec23d388862210a",
10
- "rules/ext001.ts": "39739637b5254007",
10
+ "rules/ext001.ts": "6cee52ad4c80834d",
11
11
  "rules/waw015.ts": "73e577dbe1af3918",
12
12
  "rules/waw011.ts": "d609d2e87d0d7440",
13
13
  "rules/cf-refs.ts": "2241531899151bca",
@@ -15,7 +15,7 @@
15
15
  "rules/waw010.ts": "44c6b02d5750ec77",
16
16
  "rules/waw013.ts": "b680dc528776a5e1",
17
17
  "rules/waw014.ts": "6022eb08a789dd7b",
18
- "skills/aws-cloudformation.md": "433b8205e2a7843b"
18
+ "skills/chant-aws.md": "89279045873ee536"
19
19
  },
20
- "composite": "6d2ef0b7172259e1"
20
+ "composite": "1222efccc082253f"
21
21
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws",
3
- "version": "0.0.5",
3
+ "version": "0.0.8",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "AWS",
6
6
  "intrinsics": [