@intentius/chant 0.18.0 → 0.18.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.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/graph.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAcnE"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/cli/handlers/graph.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAcnE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.18.0",
3
+ "version": "0.18.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",
@@ -26,6 +26,28 @@ vi.mock("../../graph-layout", () => ({
26
26
  getLayoutEngine: (name?: string) => ({ name: name ?? "dagre", layout: (input: unknown) => layoutMock(input) }),
27
27
  }));
28
28
 
29
+ // --live path deps. `graph` isn't `requiresPlugins`, so the live handler loads
30
+ // plugins itself; mock that plus observation/build/config (existing tests only
31
+ // hit the Op-graph and source-view modes, so these mocks don't touch them).
32
+ const loadPluginsMock = vi.fn();
33
+ const resolveLexMock = vi.fn();
34
+ vi.mock("../plugins", () => ({
35
+ loadPlugins: (...a: unknown[]) => loadPluginsMock(...a),
36
+ resolveProjectLexicons: (...a: unknown[]) => resolveLexMock(...a),
37
+ }));
38
+ const observeMock = vi.fn();
39
+ vi.mock("../../lifecycle/observe", () => ({
40
+ observeResources: (...a: unknown[]) => observeMock(...a),
41
+ }));
42
+ vi.mock("../../config", () => ({
43
+ loadChantConfig: () => Promise.resolve({ config: {} }),
44
+ }));
45
+ vi.mock("../../build", () => ({
46
+ build: () => Promise.resolve({ errors: [] }),
47
+ partitionByLexicon: () => ({}),
48
+ computeStackGraph: () => ({}),
49
+ }));
50
+
29
51
  const { runGraph } = await import("./graph");
30
52
 
31
53
  function makeArgs(overrides: Partial<ParsedArgs> = {}): ParsedArgs {
@@ -204,4 +226,26 @@ describe("runGraph", () => {
204
226
  expect(stderrBuf.join("\n")).toContain("boom");
205
227
  });
206
228
  });
229
+
230
+ describe("live graph (--live)", () => {
231
+ // Regression: `graph` is not `requiresPlugins`, so `ctx.plugins` is empty. The
232
+ // live path must load the project's plugins itself — otherwise it wrongly
233
+ // reports "No lexicons implement describeResources" and observes nothing.
234
+ test("loads plugins for --live when ctx.plugins is empty", async () => {
235
+ resolveLexMock.mockResolvedValue(["aws"]);
236
+ loadPluginsMock.mockResolvedValue([
237
+ { name: "aws", serializer: {}, describeResources: () => Promise.resolve({}) },
238
+ ]);
239
+ observeMock.mockResolvedValue({
240
+ observations: [{ lexicon: "aws", resources: { "web-vpc": { type: "AWS::EC2::VPC", status: "OK" } } }],
241
+ errors: [],
242
+ });
243
+ const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, env: "prod" }), plugins: [], serializers: [] });
244
+ expect(exit).toBe(0);
245
+ expect(loadPluginsMock).toHaveBeenCalled();
246
+ const out = stdoutBuf.join("\n");
247
+ expect(out).not.toContain("No lexicons implement describeResources");
248
+ expect(out).toContain("web-vpc");
249
+ });
250
+ });
207
251
  });
@@ -12,6 +12,7 @@ import { toMermaid } from "../../graph-mermaid";
12
12
  import { toDot } from "../../graph-dot";
13
13
  import { getLayoutEngine, toLayoutInput, type NodeSize } from "../../graph-layout";
14
14
  import { lintCommand } from "../commands/lint";
15
+ import { loadPlugins, resolveProjectLexicons } from "../plugins";
15
16
  import { readFileSync } from "node:fs";
16
17
  import { formatError, formatWarning, formatBold } from "../format";
17
18
  import type { CommandContext } from "../registry";
@@ -53,7 +54,7 @@ async function runGraphLive(
53
54
  ctx: CommandContext,
54
55
  format: "ir" | "mermaid" | "dot" | "layout",
55
56
  ): Promise<number> {
56
- const { args, plugins } = ctx;
57
+ const { args } = ctx;
57
58
  const environment = args.env;
58
59
  if (!environment) {
59
60
  console.error(formatError({ message: "chant graph --live needs an environment: --live --env <name>" }));
@@ -62,6 +63,10 @@ async function runGraphLive(
62
63
 
63
64
  const projectPath = resolve(".");
64
65
  const { config } = await loadChantConfig(projectPath);
66
+ // `graph` is not `requiresPlugins` (Op/source-graph modes must work without a
67
+ // lexicon), so `ctx.plugins` is empty. The live path needs the project's
68
+ // observation plugins — load them here, mirroring the lifecycle handlers.
69
+ const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(await resolveProjectLexicons(projectPath));
65
70
  if (config.environments && !config.environments.includes(environment)) {
66
71
  console.error(formatError({
67
72
  message: `Unknown environment "${environment}"`,