@intentius/chant 0.12.0 → 0.12.1

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 +1 @@
1
- {"version":3,"file":"graph-ir.d.ts","sourceRoot":"","sources":["../src/graph-ir.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,cAAc,CAAC;AAK7D;;;;;;;;GAQG;AAEH,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iCAAiC;AACjC,MAAM,WAAW,MAAM;IACrB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,mCAAmC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,qEAAqE;AACrE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,IAAI,EAAE,KAAK,CAAC;IACZ,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED,gFAAgF;AAChF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,QAAQ,CAAC;CAClB;AAyID;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAmDT"}
1
+ {"version":3,"file":"graph-ir.d.ts","sourceRoot":"","sources":["../src/graph-ir.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,cAAc,CAAC;AAK7D;;;;;;;;GAQG;AAEH,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iCAAiC;AACjC,MAAM,WAAW,MAAM;IACrB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,mCAAmC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,qEAAqE;AACrE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,IAAI,EAAE,KAAK,CAAC;IACZ,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED,gFAAgF;AAChF,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,QAAQ,CAAC;CAClB;AA6ID;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAmDT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -42,6 +42,30 @@ describe("buildGraphIr", () => {
42
42
  });
43
43
  });
44
44
 
45
+ test("treats a foreign AttrRef (different @intentius/chant copy) as a ref, not an opaque intrinsic (#511)", () => {
46
+ // A lexicon built against a *separate* copy of chant produces AttrRefs that
47
+ // fail `instanceof AttrRef` here but carry the global-symbol brand + shape.
48
+ // (This is the pinhole install scenario; before #511 it flattened to
49
+ // `{$intrinsic}` with no edge.)
50
+ const vpc = decl({ lexicon: "aws", entityType: "Vpc" });
51
+ const foreignRef = {
52
+ [Symbol.for("chant.intrinsic")]: true,
53
+ parent: new WeakRef(vpc),
54
+ attribute: "VpcId",
55
+ _setLogicalName() {}, // shape utils.isAttrRefLike duck-types on
56
+ getLogicalName: () => undefined, // resolves via object identity in the reverse map
57
+ };
58
+ const sg = decl({ lexicon: "aws", entityType: "SecurityGroup", props: { VpcId: foreignRef } });
59
+ const entities = new Map<string, Declarable>([
60
+ ["vpc", vpc],
61
+ ["sg", sg],
62
+ ]);
63
+
64
+ const ir = buildGraphIr(entities);
65
+ expect(ir.edges).toEqual([{ from: "sg", to: "vpc", kind: "ref", viaAttr: "VpcId" }]);
66
+ expect(ir.nodes.find((n) => n.id === "sg")!.attrs).toEqual({ VpcId: { $ref: "vpc.VpcId" } });
67
+ });
68
+
45
69
  test("excludes property-kind declarables and keeps resources", () => {
46
70
  const resource = decl({ lexicon: "k8s", entityType: "Deployment" });
47
71
  const prop = decl({ lexicon: "k8s", entityType: "Probe", kind: "property" as const });
package/src/graph-ir.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { relative, isAbsolute } from "node:path";
2
2
  import { AttrRef } from "./attrref";
3
+ import { isAttrRefLike } from "./utils";
3
4
  import { type Declarable, isDeclarable } from "./declarable";
4
5
  import { isLexiconOutput } from "./lexicon-output";
5
6
  import { getProvenance } from "./provenance";
@@ -113,7 +114,11 @@ function project(value: unknown, seen: Set<unknown>, reverse: Map<object, string
113
114
  if (t === "string" || t === "number" || t === "boolean") return value;
114
115
  if (t !== "object") return undefined; // functions, symbols, undefined
115
116
 
116
- if (value instanceof AttrRef) {
117
+ // Duck-type, not `instanceof`: a lexicon built against a different copy of
118
+ // `@intentius/chant` produces AttrRefs that fail `instanceof AttrRef` but carry
119
+ // the same shape. Without this, a real cross-resource reference falls through to
120
+ // the intrinsic branch below and is silently flattened to `{$intrinsic}` (#511).
121
+ if (isAttrRefLike(value)) {
117
122
  const to = refTarget(value, reverse);
118
123
  return { $ref: to ? `${to}.${value.attribute}` : value.attribute } satisfies AttrRefEnvelope;
119
124
  }
@@ -192,7 +197,7 @@ function collectEdges(
192
197
  const seen = new Set<unknown>();
193
198
  const visit = (value: unknown, viaAttr: string): void => {
194
199
  if (value === null || typeof value !== "object") return;
195
- if (value instanceof AttrRef) {
200
+ if (isAttrRefLike(value)) {
196
201
  const to = refTarget(value, reverse);
197
202
  if (to && to !== from && nodeIds.has(to)) {
198
203
  edges.push({ from, to, kind: "ref", viaAttr });