@intentius/chant-lexicon-aws 0.20.0 → 0.22.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "4ae49ba58f7394ceaba8508c998178e1b13207da2deaf6e51e6340774baea3a2",
4
+ "manifest.json": "09898a0a59ba358390d650c4387dd81b6d48f5469c6ab4e66eb932452b941299",
5
5
  "meta.json": "ef04b67841e39eed4550d4ec0527ebb2a0a367dc7628728522168f11b67a7a9f",
6
6
  "types/index.d.ts": "2a5fb678eae51c9ce44c59696e3e708b5d7dcbc91b24da7be199f010a9a63361",
7
7
  "rules/hardcoded-region.ts": "5a0eaf7ab391231fe6cd51426ece29539cb4b36f31c8dd060956638fed55722a",
@@ -59,5 +59,5 @@
59
59
  "skills/chant-aws-eks.md": "8789255709ff004ad0a875fd5999edcdc66fc6e33d710db058d9f42703bcfdfe",
60
60
  "skills/chant-aws-carve-terraform.md": "f4c6fe1c702250665f90d82b3bdaba5ea50ae75e380a8ae321dad6eb1c39683e"
61
61
  },
62
- "composite": "ad8f56986d9aa3b2b502fe18aef713c744880fc8b5109df270027ab789a4d904"
62
+ "composite": "5a0569b0420e50a37cc206b437b19be0813524b51326c099084c0e448642de2f"
63
63
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "AWS",
6
6
  "intrinsics": [
@@ -14,49 +14,57 @@
14
14
  "name": "Ref",
15
15
  "description": "Reference a parameter or resource",
16
16
  "outputKey": "Ref",
17
- "isTag": false
17
+ "isTag": false,
18
+ "foldsAsCall": true
18
19
  },
19
20
  {
20
21
  "name": "GetAtt",
21
22
  "description": "Fn::GetAtt — get resource attribute",
22
23
  "outputKey": "Fn::GetAtt",
23
- "isTag": false
24
+ "isTag": false,
25
+ "foldsAsCall": true
24
26
  },
25
27
  {
26
28
  "name": "If",
27
29
  "description": "Fn::If — conditional value",
28
30
  "outputKey": "Fn::If",
29
- "isTag": false
31
+ "isTag": false,
32
+ "foldsAsCall": true
30
33
  },
31
34
  {
32
35
  "name": "Join",
33
36
  "description": "Fn::Join — join values with delimiter",
34
37
  "outputKey": "Fn::Join",
35
- "isTag": false
38
+ "isTag": false,
39
+ "foldsAsCall": true
36
40
  },
37
41
  {
38
42
  "name": "Select",
39
43
  "description": "Fn::Select — select value by index",
40
44
  "outputKey": "Fn::Select",
41
- "isTag": false
45
+ "isTag": false,
46
+ "foldsAsCall": true
42
47
  },
43
48
  {
44
49
  "name": "Split",
45
50
  "description": "Fn::Split — split string by delimiter",
46
51
  "outputKey": "Fn::Split",
47
- "isTag": false
52
+ "isTag": false,
53
+ "foldsAsCall": true
48
54
  },
49
55
  {
50
56
  "name": "Base64",
51
57
  "description": "Fn::Base64 — encode to Base64",
52
58
  "outputKey": "Fn::Base64",
53
- "isTag": false
59
+ "isTag": false,
60
+ "foldsAsCall": true
54
61
  },
55
62
  {
56
63
  "name": "GetAZs",
57
64
  "description": "Fn::GetAZs — list Availability Zones",
58
65
  "outputKey": "Fn::GetAZs",
59
- "isTag": false
66
+ "isTag": false,
67
+ "foldsAsCall": true
60
68
  }
61
69
  ],
62
70
  "pseudoParameters": {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAA+G,MAAM,0BAA0B,CAAC;AAwB3K;;sFAEsF;AACtF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,aA+vBvB,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAA+G,MAAM,0BAA0B,CAAC;AAwB3K;;sFAEsF;AACtF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,aAkxBvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-aws",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "AWS CloudFormation lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -80,7 +80,7 @@
80
80
  "typescript": "^5.9.3"
81
81
  },
82
82
  "peerDependencies": {
83
- "@intentius/chant": "^0.20.0",
83
+ "@intentius/chant": "^0.22.0",
84
84
  "typescript": "^5.9.3"
85
85
  }
86
86
  }
@@ -52,6 +52,11 @@ export async function packageLexicon(opts: PackageOptions = {}): Promise<Package
52
52
  description: i.description,
53
53
  outputKey: intrinsicOutputKey(i.name),
54
54
  isTag: i.isTag,
55
+ // chant #1044 — carried through verbatim for the same reason as
56
+ // `isTag`: the packaged manifest is what a consumer reads to
57
+ // learn which intrinsics fold, so recomputing it here would be a
58
+ // second source of truth able to drift from ../plugin.ts.
59
+ foldsAsCall: i.foldsAsCall,
55
60
  }),
56
61
  );
57
62
 
package/src/plugin.ts CHANGED
@@ -52,17 +52,36 @@ export const awsPlugin: LexiconPlugin = {
52
52
  return discoverLintRules(rulesDir, import.meta.url);
53
53
  },
54
54
 
55
+ /**
56
+ * chant #1044 — every plain-call intrinsic below carries
57
+ * `foldsAsCall: true`, opting its CALL form into `chant build --fold`.
58
+ *
59
+ * Audited one at a time against the criterion in `IntrinsicDef.foldsAsCall`
60
+ * (core's lexicon.ts): the call must be a pure function of its arguments
61
+ * that builds a deterministic data envelope. Each of these constructs its
62
+ * `*Intrinsic` class and stores the arguments verbatim (../intrinsics.ts) —
63
+ * no I/O, no environment, no module state, and no CloudFormation semantics
64
+ * evaluated locally: `Base64("x")` emits `{"Fn::Base64": "x"}` for the
65
+ * deployment to encode, it does not encode anything here. Calling one while
66
+ * folding is therefore indistinguishable from calling it during a real run
67
+ * of the file.
68
+ *
69
+ * `Sub` is the one intrinsic NOT opted in, and cannot be: it is authored as
70
+ * a tagged template (`isTag: true`), which already folds through
71
+ * `foldTaggedTemplate`. `Sub(...)` as a plain call is not its authoring
72
+ * form, and `chant dev check-lexicon` rejects a registration claiming both.
73
+ */
55
74
  intrinsics(): IntrinsicDef[] {
56
75
  return [
57
76
  { name: "Sub", description: "Fn::Sub template string interpolation", isTag: true },
58
- { name: "Ref", description: "Reference a parameter or resource", isTag: false },
59
- { name: "GetAtt", description: "Fn::GetAtt — get resource attribute", isTag: false },
60
- { name: "If", description: "Fn::If — conditional value", isTag: false },
61
- { name: "Join", description: "Fn::Join — join values with delimiter", isTag: false },
62
- { name: "Select", description: "Fn::Select — select value by index", isTag: false },
63
- { name: "Split", description: "Fn::Split — split string by delimiter", isTag: false },
64
- { name: "Base64", description: "Fn::Base64 — encode to Base64", isTag: false },
65
- { name: "GetAZs", description: "Fn::GetAZs — list Availability Zones", isTag: false },
77
+ { name: "Ref", description: "Reference a parameter or resource", isTag: false, foldsAsCall: true },
78
+ { name: "GetAtt", description: "Fn::GetAtt — get resource attribute", isTag: false, foldsAsCall: true },
79
+ { name: "If", description: "Fn::If — conditional value", isTag: false, foldsAsCall: true },
80
+ { name: "Join", description: "Fn::Join — join values with delimiter", isTag: false, foldsAsCall: true },
81
+ { name: "Select", description: "Fn::Select — select value by index", isTag: false, foldsAsCall: true },
82
+ { name: "Split", description: "Fn::Split — split string by delimiter", isTag: false, foldsAsCall: true },
83
+ { name: "Base64", description: "Fn::Base64 — encode to Base64", isTag: false, foldsAsCall: true },
84
+ { name: "GetAZs", description: "Fn::GetAZs — list Availability Zones", isTag: false, foldsAsCall: true },
66
85
  ];
67
86
  },
68
87
 
package/src/serializer.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Declarable, CoreParameter } from "@intentius/chant/declarable";
2
- import { isPropertyDeclarable } from "@intentius/chant/declarable";
2
+ import { isPropertyDeclarable, isResourceDeclarable } from "@intentius/chant/declarable";
3
3
  import type { Serializer, SerializerResult, SerializeContext } from "@intentius/chant/serializer";
4
4
  import { ownershipEntries, type OwnershipMarker } from "@intentius/chant/ownership";
5
5
  import { AWS_TAG_OWNERSHIP_KEYS } from "./ownership";
@@ -82,7 +82,7 @@ function cfnVisitor(entityNames: Map<Declarable, string>): SerializerVisitor {
82
82
  attrRef: (name, attr) => ({ "Fn::GetAtt": [name, attr] }),
83
83
  resourceRef: (name) => ({ Ref: name }),
84
84
  propertyDeclarable: (entity, walk) => {
85
- if (!("props" in entity) || typeof entity.props !== "object" || entity.props === null) {
85
+ if (!isResourceDeclarable(entity) || typeof entity.props !== "object" || entity.props === null) {
86
86
  return undefined;
87
87
  }
88
88
  const props = entity.props as Record<string, unknown>;
@@ -136,7 +136,7 @@ function toProperties(
136
136
  entity: Declarable,
137
137
  entityNames: Map<Declarable, string>
138
138
  ): Record<string, unknown> | undefined {
139
- if (!("props" in entity) || typeof entity.props !== "object" || entity.props === null) {
139
+ if (!isResourceDeclarable(entity) || typeof entity.props !== "object" || entity.props === null) {
140
140
  return undefined;
141
141
  }
142
142
 
@@ -281,7 +281,7 @@ function serializeToTemplate(
281
281
  };
282
282
 
283
283
  // Read resource-level attributes from the second constructor arg
284
- const attrs = ("attributes" in entity && typeof entity.attributes === "object" && entity.attributes !== null)
284
+ const attrs = (isResourceDeclarable(entity) && typeof entity.attributes === "object" && entity.attributes !== null)
285
285
  ? entity.attributes as Record<string, unknown>
286
286
  : undefined;
287
287