@intentius/chant 0.121.0 → 0.122.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,6 +1,7 @@
1
1
  import { build } from "../../build.js";
2
2
  import type { Serializer } from "../../serializer.js";
3
3
  import type { LexiconPlugin } from "../../lexicon.js";
4
+ import { runPostSynthChecks, type PostSynthDiagnostic } from "../../lint/post-synth.js";
4
5
  import { type FoldRankResult } from "../../discovery/fold-rank.js";
5
6
  /**
6
7
  * Build command options
@@ -109,6 +110,17 @@ export interface BuildResult {
109
110
  /** This build's resolved build-time parameters (#1064) — see `BuildResult.buildParams` (../../build.ts). Empty when the project declares/supplies none. */
110
111
  buildParams?: import("../../provenance.js").BuildParamProvenance[];
111
112
  }
113
+ /**
114
+ * Run each lexicon plugin's own post-synth checks over a build result, each
115
+ * plugin seeing only its own lexicon's output. Shared by `chant build` and
116
+ * `chant lint` (#3750), so the two run the same checks over the same scoping;
117
+ * each caller then applies `lint.presets`, `lint.rules` and inline
118
+ * suppressions its own way. A plugin with no checks yields no entry.
119
+ */
120
+ export declare function runLexiconPostSynthChecks(plugins: readonly LexiconPlugin[], result: Parameters<typeof runPostSynthChecks>[1], env: string | undefined, opts?: Parameters<typeof runPostSynthChecks>[3]): Array<{
121
+ plugin: LexiconPlugin;
122
+ diagnostics: PostSynthDiagnostic[];
123
+ }>;
112
124
  /**
113
125
  * Execute the build command
114
126
  */
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAepC,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAiBnD,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAMrG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2CAA2C;IAC3C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE;QAAE,WAAW,EAAE,UAAU,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAA;KAAE,CAAC;CAChF;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAoB/C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2JAA2J;IAC3J,WAAW,CAAC,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;CACjE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2wB9E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAMrF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBpF;AAiDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAIlD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAItD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GACxC,MAAM,IAAI,CAmCZ"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAepC,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAgBrF,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAMrG;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,2CAA2C;IAC3C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE;QAAE,WAAW,EAAE,UAAU,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAA;KAAE,CAAC;CAChF;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAoB/C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2JAA2J;IAC3J,WAAW,CAAC,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;CACjE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAChD,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAC9C,KAAK,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,mBAAmB,EAAE,CAAA;CAAE,CAAC,CAsBtE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA0vB9E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAMrF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBpF;AAiDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAIlD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAItD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,YAAY,EACrB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GACxC,MAAM,IAAI,CAmCZ"}
@@ -42,6 +42,15 @@ export declare function loadPluginRules(plugins: string[], configDir: string): P
42
42
  * project" this id exists to prevent.
43
43
  */
44
44
  export declare const LEXICON_RESOLUTION_RULE_ID = "LEX001";
45
+ /**
46
+ * The diagnostic id `chant lint` reports a lint target that does not build
47
+ * under (chant #3750). The lexicons' post-synth checks read a build result, so
48
+ * when the build fails they cannot run; this says so instead of letting the
49
+ * lint pass in silence. Like {@link LEXICON_RESOLUTION_RULE_ID} it is not a
50
+ * rule: it has no severity setting and no disable form. The message is the
51
+ * build's own.
52
+ */
53
+ export declare const BUILD_FAILURE_RULE_ID = "LEX002";
45
54
  /**
46
55
  * Lint command options
47
56
  */
@@ -70,6 +79,13 @@ export interface LintOptions {
70
79
  * `sandbox` option (../../components/discover.ts).
71
80
  */
72
81
  sandbox?: boolean;
82
+ /**
83
+ * chant #3750 — run each loaded lexicon's post-synth checks over an
84
+ * in-memory build of the target (default `true`, what the CLI always does).
85
+ * `false` lints source alone; it exists for test harnesses that check an
86
+ * example's source rules, not for hiding findings from a user.
87
+ */
88
+ postSynth?: boolean;
73
89
  }
74
90
  /**
75
91
  * Lint command result
@@ -1 +1 @@
1
- {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAW,MAAM,iBAAiB,CAAC;AA8BzE;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAW5D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAmBhC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,WAAW,CAAC;AA+JnD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACrC,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,qCAAqC;IACrC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAiVD;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAqN3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GACtC,MAAM,IAAI,CAiCZ"}
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAW,MAAM,iBAAiB,CAAC;AAsCzE;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAW5D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAmBhC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,WAAW,CAAC;AAsBnD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,WAAW,CAAC;AA2I9C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACrC,uBAAuB;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,qCAAqC;IACrC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AA+cD;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA+N3E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAIxD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GACtC,MAAM,IAAI,CAiCZ"}
@@ -79,6 +79,53 @@ export interface EmulatorIdentity {
79
79
  * `localhost` connection meant for the emulator.
80
80
  */
81
81
  export declare function hostPortInUse(port: number, timeoutMs?: number): Promise<boolean>;
82
+ /** One host address Docker publishes a container port on, as `docker port` prints it. */
83
+ export interface PublishedAddress {
84
+ /** The bound host IP: `0.0.0.0`, `::`, `127.0.0.1`, ... */
85
+ ip: string;
86
+ port: number;
87
+ }
88
+ /**
89
+ * Parse `docker port <name> <port>/tcp` output (`0.0.0.0:5432`, `[::]:5432`,
90
+ * one per line). Lines that do not parse are dropped.
91
+ */
92
+ export declare function parsePublishedAddresses(stdout: string): PublishedAddress[];
93
+ /**
94
+ * The hosts a client on this machine dials to reach a published address,
95
+ * `localhost` first: a wildcard bind (`0.0.0.0`, `::`) answers on the
96
+ * loopback of its family, and a specific IP only on itself.
97
+ */
98
+ export declare function clientHosts(addresses: readonly PublishedAddress[]): {
99
+ host: string;
100
+ port: number;
101
+ }[];
102
+ /** `endpoint` with its host replaced by `host` (`localhost` stays as written). */
103
+ export declare function endpointOnHost(endpoint: string, host: string): string;
104
+ /**
105
+ * Pick the endpoint of a reused container that reaches it (the identity read
106
+ * inside the container matches the one read through the endpoint), trying
107
+ * {@link clientHosts} in order. `notes` says when `localhost` reaches another
108
+ * server and a different address had to be used; `error` says when none of
109
+ * them reaches the emulator.
110
+ */
111
+ export declare function pickReachableEndpoint(opts: {
112
+ name: string;
113
+ hosts: readonly {
114
+ host: string;
115
+ port: number;
116
+ }[];
117
+ endpoint: (port: number) => string;
118
+ identity: EmulatorIdentity;
119
+ /** The identity read inside the container. */
120
+ inside: string;
121
+ /** A hint appended to an `error`, e.g. how to republish on a free port. */
122
+ hint: string;
123
+ }): Promise<{
124
+ endpoint: string;
125
+ notes: string[];
126
+ } | {
127
+ error: string;
128
+ }>;
82
129
  /**
83
130
  * A lexicon's local-emulator capability (#920) — what `chant emulator` needs to
84
131
  * boot it and point tooling at it. The `spec` drives the Docker lifecycle; `env`
@@ -1 +1 @@
1
- {"version":3,"file":"emulator-lifecycle.d.ts","sourceRoot":"","sources":["../../src/op/emulator-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"emulator-lifecycle.d.ts","sourceRoot":"","sources":["../../src/op/emulator-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  export { Op, phase, activity, gate, effect, build, kubectlApply, helmInstall, helmInstallPinned, waitForStack, waitForReady, gitlabPipeline, lifecycleSnapshot, shell, sourceArchive, releasePlan, releaseRecord, composeChangeSet, lifecyclePlanChangeSet, readChangeSetPart, releaseRollbackPlan, releaseRollbackRecord, decide, ensureSecret, teardown, envTeardown, k3dUp, k3dDown, k3sInstall, k3sUninstall, flociUp, flociDown, flociAzUp, flociAzDown, flociGcpUp, flociGcpDown, httpCheck, azGroupEnsure, azGroupDelete, azApply, azDelete, awsApply, awsDelete, gcpApply, gcpDelete, policyGate, guardValidate, workEvidence, spriteCreate, spriteExec, spriteCheckpoint, spriteRestore, listCheckpoints, spriteDestroy, spriteWriteFile, spriteReadFile, spriteListDir, spriteRemove, spriteApplyNetworkPolicy, spriteApplyServices, spriteTaskCreate, spriteTaskRefresh, spriteTaskRelease, spritesUp, spritesDown } from "./builders.js";
2
2
  export { OpResource } from "./resource.js";
3
3
  export { sleep } from "./activity-runtime.js";
4
- export { emulatorLifecycle, emulatorsOf, endpointEnvVars, hostPortInUse } from "./emulator-lifecycle.js";
5
- export type { EmulatorSpec, EmulatorCapability, EmulatorDeclaration, EmulatorIdentity, EmulatorUpArgs, EmulatorLifecycle } from "./emulator-lifecycle.js";
4
+ export { clientHosts, emulatorLifecycle, emulatorsOf, endpointEnvVars, endpointOnHost, hostPortInUse, parsePublishedAddresses, pickReachableEndpoint } from "./emulator-lifecycle.js";
5
+ export type { EmulatorSpec, EmulatorCapability, EmulatorDeclaration, EmulatorIdentity, EmulatorUpArgs, EmulatorLifecycle, PublishedAddress } from "./emulator-lifecycle.js";
6
6
  export { checkFreshness, compare, formatResult, latestRelease, parseVersion, unpinned } from "./emulator-freshness.js";
7
7
  export type { FreshnessResult } from "./emulator-freshness.js";
8
8
  export type { OpConfig, OpSchedule, OpWorkLease, PhaseDefinition, StepDefinition, ActivityStep, GateStep, EffectStep, OutcomeAttribute } from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/op/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/op/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.121.0",
3
+ "version": "0.122.0",
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",
@@ -170,6 +170,42 @@ export interface BuildResult {
170
170
  buildParams?: import("../../provenance").BuildParamProvenance[];
171
171
  }
172
172
 
173
+ /**
174
+ * Run each lexicon plugin's own post-synth checks over a build result, each
175
+ * plugin seeing only its own lexicon's output. Shared by `chant build` and
176
+ * `chant lint` (#3750), so the two run the same checks over the same scoping;
177
+ * each caller then applies `lint.presets`, `lint.rules` and inline
178
+ * suppressions its own way. A plugin with no checks yields no entry.
179
+ */
180
+ export function runLexiconPostSynthChecks(
181
+ plugins: readonly LexiconPlugin[],
182
+ result: Parameters<typeof runPostSynthChecks>[1],
183
+ env: string | undefined,
184
+ opts?: Parameters<typeof runPostSynthChecks>[3],
185
+ ): Array<{ plugin: LexiconPlugin; diagnostics: PostSynthDiagnostic[] }> {
186
+ const batches: Array<{ plugin: LexiconPlugin; diagnostics: PostSynthDiagnostic[] }> = [];
187
+ for (const plugin of plugins) {
188
+ if (!plugin.postSynthChecks) continue;
189
+ const checks = plugin.postSynthChecks();
190
+ if (checks.length === 0) continue;
191
+
192
+ // Scope outputs to this plugin's lexicon so cross-lexicon outputs don't
193
+ // interfere. Outputs are keyed by the serializer's lexicon name (the
194
+ // build partition key), which differs from plugin.name for a dialect like
195
+ // forgejo (plugin "forgejo", serializer "github").
196
+ const outputKey = plugin.serializer.name;
197
+ const scopedOutputs = new Map<string, string | SerializerResult>();
198
+ const pluginOutput = result.outputs.get(outputKey);
199
+ if (pluginOutput !== undefined) {
200
+ scopedOutputs.set(outputKey, pluginOutput);
201
+ }
202
+
203
+ const scopedResult = { ...result, outputs: scopedOutputs };
204
+ batches.push({ plugin, diagnostics: runPostSynthChecks(checks, scopedResult, env, opts) });
205
+ }
206
+ return batches;
207
+ }
208
+
173
209
  /**
174
210
  * Execute the build command
175
211
  */
@@ -549,24 +585,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
549
585
  }
550
586
 
551
587
  if (result.errors.length === 0 && options.plugins) {
552
- for (const plugin of options.plugins) {
553
- if (!plugin.postSynthChecks) continue;
554
- const checks = plugin.postSynthChecks();
555
- if (checks.length === 0) continue;
556
-
557
- // Scope outputs to this plugin's lexicon so cross-lexicon outputs don't
558
- // interfere. Outputs are keyed by the serializer's lexicon name (the
559
- // build partition key), which differs from plugin.name for a dialect like
560
- // forgejo (plugin "forgejo", serializer "github").
561
- const outputKey = plugin.serializer.name;
562
- const scopedOutputs = new Map<string, string | SerializerResult>();
563
- const pluginOutput = result.outputs.get(outputKey);
564
- if (pluginOutput !== undefined) {
565
- scopedOutputs.set(outputKey, pluginOutput);
566
- }
567
-
568
- const scopedResult = { ...result, outputs: scopedOutputs };
569
- const postDiags = runPostSynthChecks(checks, scopedResult, env, { activityContracts, telemetry });
588
+ for (const { plugin, diagnostics: postDiags } of runLexiconPostSynthChecks(options.plugins, result, env, { activityContracts, telemetry })) {
570
589
  // `lint.presets` (chant #2113) filters WHICH check ids are reported at
571
590
  // all, before `lint.rules`/inline suppression act on the reported
572
591
  // ones. It's a no-op for a lexicon that ships no `lintPresets()` (the
@@ -317,9 +317,15 @@ resource "aws_s3_bucket_public_access_block" "assets" {
317
317
  expect(text).toContain("aws_s3_bucket_versioning.assets (VersioningConfiguration)");
318
318
  expect(text).toContain("aws_s3_bucket_public_access_block.assets (PublicAccessBlockConfiguration)");
319
319
 
320
- // And the emitted project still lints clean (no errors).
320
+ // And the emitted project still lints clean (no errors). Since #3750 the
321
+ // lint runs the aws post-synth checks too, and WAW042 is expected here:
322
+ // the Terraform declares no bucket policy, so the carved bucket faithfully
323
+ // has no TLS-only deny either. The carve reproduces what was declared; it
324
+ // does not add policy, so that one finding is allowed and nothing else.
321
325
  const lint = await lintCommand({ path: out, format: "stylish" });
322
- expect(lint.diagnostics.filter((d) => d.severity === "error")).toEqual([]);
326
+ const errors = lint.diagnostics.filter((d) => d.severity === "error");
327
+ expect(errors.filter((d) => d.ruleId !== "WAW042")).toEqual([]);
328
+ expect(errors.map((d) => d.ruleId)).toEqual(["WAW042"]);
323
329
  } finally {
324
330
  rmSync(dir, { recursive: true, force: true });
325
331
  }
@@ -1,10 +1,12 @@
1
1
  import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
2
- import { lintCommand, isLintRule, loadPluginRules, LEXICON_RESOLUTION_RULE_ID, type LintOptions } from "./lint";
2
+ import { lintCommand, isLintRule, loadPluginRules, LEXICON_RESOLUTION_RULE_ID, BUILD_FAILURE_RULE_ID, type LintOptions } from "./lint";
3
3
  import { loadPlugins, resolveProjectLexicons } from "../plugins";
4
4
  import { mkdir, rm, writeFile } from "node:fs/promises";
5
5
  import { join, resolve } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
  import { execFileSync } from "node:child_process";
8
+ import { mkdtempSync, realpathSync, symlinkSync } from "node:fs";
9
+ import { fileURLToPath } from "node:url";
8
10
  import { params, setBuildParams } from "../../params";
9
11
 
10
12
  describe("lintCommand", () => {
@@ -959,3 +961,109 @@ describe("lintCommand build-time parameters (#2249)", () => {
959
961
  expect(params).toEqual({});
960
962
  });
961
963
  });
964
+
965
+ /**
966
+ * chant #3750 — `chant lint` runs each loaded lexicon's own post-synth checks
967
+ * over an in-memory build of the lint target, the ones `chant build` runs.
968
+ * The sql lexicon's SQLCH101 is the issue's repro: `ENGINE = MergeTre` failed
969
+ * the build and linted clean. The project imports the workspace's sql
970
+ * lexicon through a `node_modules` link, as an installed project would.
971
+ */
972
+ describe("lintCommand — lexicon post-synth checks (#3750)", () => {
973
+ const repoNodeModules = resolve(fileURLToPath(new URL(".", import.meta.url)), "../../../../../node_modules");
974
+ let root: string;
975
+
976
+ const schema = (engine: string, idType = "UInt64") =>
977
+ 'import { database, table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
978
+ "export const shopDb = database`CREATE DATABASE shop ENGINE = Atomic`;\n" +
979
+ "export const events = table`\n" +
980
+ ` CREATE TABLE \${shopDb}.events (id ${idType}, kind String)\n` +
981
+ ` ENGINE = ${engine}\n` +
982
+ " ORDER BY (kind, id)`;\n";
983
+
984
+ async function project(engine: string, rules?: Record<string, string>, idType?: string): Promise<void> {
985
+ await writeFile(
986
+ join(root, "chant.config.json"),
987
+ JSON.stringify({ lexicons: ["sql"], sql: { dialect: "clickhouse" }, ...(rules ? { lint: { rules } } : {}) }),
988
+ );
989
+ await writeFile(join(root, "src", "schema.ts"), schema(engine, idType));
990
+ }
991
+
992
+ beforeEach(async () => {
993
+ root = realpathSync(mkdtempSync(join(tmpdir(), "chant-3750-")));
994
+ await mkdir(join(root, "src"), { recursive: true });
995
+ symlinkSync(repoNodeModules, join(root, "node_modules"), "dir");
996
+ process.env.NO_COLOR = "1";
997
+ });
998
+
999
+ afterEach(async () => {
1000
+ await rm(root, { recursive: true, force: true });
1001
+ delete process.env.NO_COLOR;
1002
+ });
1003
+
1004
+ test("a lexicon post-synth error fails the lint, at the project root and at src", async () => {
1005
+ await project("MergeTre");
1006
+ for (const path of [root, join(root, "src")]) {
1007
+ const result = await lintCommand({ path, format: "stylish" });
1008
+ expect(result.success).toBe(false);
1009
+ const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH101");
1010
+ expect(diag, result.output).toBeDefined();
1011
+ expect(diag!.severity).toBe("error");
1012
+ expect(diag!.message).toContain('"MergeTre"');
1013
+ // No line of its own: reported at 1:1 in the file that declared the table.
1014
+ expect(diag!.file).toBe(join(root, "src", "schema.ts"));
1015
+ expect([diag!.line, diag!.column]).toEqual([1, 1]);
1016
+ expect(result.output).toContain("SQLCH101");
1017
+ }
1018
+ });
1019
+
1020
+ test("a column type the pinned server does not have is reported (SQLCH121)", async () => {
1021
+ await project("MergeTree", undefined, "UInt46");
1022
+ const result = await lintCommand({ path: root, format: "stylish" });
1023
+ expect(result.success).toBe(false);
1024
+ const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH121");
1025
+ expect(diag, result.output).toBeDefined();
1026
+ expect(diag!.message).toContain("UInt46");
1027
+ });
1028
+
1029
+ test("postSynth: false lints source alone", async () => {
1030
+ await project("MergeTre");
1031
+ const result = await lintCommand({ path: root, format: "stylish", postSynth: false });
1032
+ expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
1033
+ });
1034
+
1035
+ test("a clean project reports nothing from the post-synth pass", async () => {
1036
+ await project("MergeTree");
1037
+ const result = await lintCommand({ path: root, format: "stylish" });
1038
+ expect(result.diagnostics.filter((d) => /^SQL|^LEX/.test(d.ruleId)), result.output).toEqual([]);
1039
+ });
1040
+
1041
+ test("lint.rules overrides a post-synth finding's severity, and turns it off", async () => {
1042
+ await project("MergeTre", { SQLCH101: "warning" });
1043
+ const warned = await lintCommand({ path: root, format: "stylish" });
1044
+ expect(warned.diagnostics.find((d) => d.ruleId === "SQLCH101")?.severity).toBe("warning");
1045
+ expect(warned.success).toBe(true);
1046
+
1047
+ await project("MergeTre", { SQLCH101: "off" });
1048
+ const off = await lintCommand({ path: root, format: "stylish" });
1049
+ expect(off.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
1050
+ });
1051
+
1052
+ test("a target that does not build reports the build error and skips the checks", async () => {
1053
+ await project("MergeTre");
1054
+ // A table interpolating a name that is not declared does not build.
1055
+ await writeFile(
1056
+ join(root, "src", "broken.ts"),
1057
+ 'import { table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
1058
+ 'import { events } from "./schema";\n' +
1059
+ "export const copy = table`CREATE TABLE shop.copy (id UInt64) ENGINE = MergeTree ORDER BY ${(events as any).columns.nope}`;\n",
1060
+ );
1061
+ const result = await lintCommand({ path: root, format: "stylish" });
1062
+ expect(result.success).toBe(false);
1063
+ const failures = result.diagnostics.filter((d) => d.ruleId === BUILD_FAILURE_RULE_ID);
1064
+ expect(failures.length, result.output).toBeGreaterThan(0);
1065
+ expect(failures.every((d) => d.severity === "error")).toBe(true);
1066
+ expect(failures.map((d) => d.message).join("\n")).toContain("is undefined");
1067
+ expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
1068
+ });
1069
+ });
@@ -1,4 +1,4 @@
1
- import { resolve, join, relative } from "path";
1
+ import { resolve, join, relative, dirname } from "path";
2
2
  import type { BuildParamProvenance } from "../../provenance";
3
3
  import { readFileSync, writeFileSync, readdirSync } from "fs";
4
4
  import { runLint, parseDisableComments } from "../../lint/engine";
@@ -24,6 +24,14 @@ import { walkDiscovery, workspaceMemberDirs } from "../../discovery/walk";
24
24
  import { buildParamValues, resolveBuildParams } from "../../build-params";
25
25
  import { setBuildParams } from "../../params";
26
26
  import { isNoLexiconDetected } from "../../detectLexicon";
27
+ import { build } from "../../build";
28
+ import { loadChantConfigUpward, resolveOwnershipEnv, resolveOwnershipMarker } from "../../config";
29
+ import { resolveBuildModes, resolveProjectBuildOptions } from "../build-options";
30
+ import { resolveTelemetryAttribution } from "../../telemetry-attribution";
31
+ import { applyConfiguredPreset, applyConfiguredSeverity, resolvePresetIds } from "../../lint/config";
32
+ import { applyInlineSuppressions } from "../../lint/suppressions";
33
+ import { getProvenance } from "../../provenance";
34
+ import { runLexiconPostSynthChecks } from "./build";
27
35
 
28
36
  // Import config loader
29
37
  import { loadConfig, resolveRulesForFile, resolveConfiguredSeverity, findProjectRoot } from "../../lint/config";
@@ -130,6 +138,16 @@ function lexiconResolutionDiagnostic(projectRoot: string, error: Error): LintDia
130
138
  };
131
139
  }
132
140
 
141
+ /**
142
+ * The diagnostic id `chant lint` reports a lint target that does not build
143
+ * under (chant #3750). The lexicons' post-synth checks read a build result, so
144
+ * when the build fails they cannot run; this says so instead of letting the
145
+ * lint pass in silence. Like {@link LEXICON_RESOLUTION_RULE_ID} it is not a
146
+ * rule: it has no severity setting and no disable form. The message is the
147
+ * build's own.
148
+ */
149
+ export const BUILD_FAILURE_RULE_ID = "LEX002";
150
+
133
151
  /**
134
152
  * The plugins of lexicons that the project's source imports from and that are not in `configured`, for their
135
153
  * property-kind class names (#3184). A package that is not installed, or that fails to load, is skipped.
@@ -295,6 +313,13 @@ export interface LintOptions {
295
313
  * `sandbox` option (../../components/discover.ts).
296
314
  */
297
315
  sandbox?: boolean;
316
+ /**
317
+ * chant #3750 — run each loaded lexicon's post-synth checks over an
318
+ * in-memory build of the target (default `true`, what the CLI always does).
319
+ * `false` lints source alone; it exists for test harnesses that check an
320
+ * example's source rules, not for hiding findings from a user.
321
+ */
322
+ postSynth?: boolean;
298
323
  }
299
324
 
300
325
  /**
@@ -630,6 +655,132 @@ async function runOpCheckDiagnostics(
630
655
  return { diagnostics, suppressed };
631
656
  }
632
657
 
658
+ /**
659
+ * Run each loaded lexicon's own post-synth checks (#3750), the ones `chant
660
+ * build` runs after it serializes, over an in-memory build of the lint target.
661
+ *
662
+ * The build is `chant build`'s: the same `build()` call with options from the
663
+ * same assembler (`../build-options.ts`), and the same per-lexicon scoping of
664
+ * outputs (`runLexiconPostSynthChecks`, ./build.ts). Nothing is written. It
665
+ * builds `infraPath`, the target the caller asked to lint, never the project
666
+ * root above it, so `chant lint <dir>` costs a build of `<dir>` and nothing
667
+ * more (the same scoping {@link runOpCheckDiagnostics} documents). It is
668
+ * skipped outright when no loaded lexicon ships post-synth checks, which keeps
669
+ * a project with no lexicon, and every core-only fixture, from building at
670
+ * all.
671
+ *
672
+ * A target that does not build reports each build error under
673
+ * {@link BUILD_FAILURE_RULE_ID} and skips the checks. Findings go through
674
+ * `lint.presets`, then `lint.rules`, then inline `chant-ignore` comments, the
675
+ * order `chant build` applies them in. A finding carries no line (see
676
+ * ../../lint/post-synth.ts's `PostSynthDiagnostic`), so it is reported at
677
+ * `1:1` in the file that declared its entity, or at the config file (the
678
+ * project root without one) when it names none.
679
+ */
680
+ async function runLexiconPostSynthDiagnostics(
681
+ infraPath: string,
682
+ plugins: readonly LexiconPlugin[],
683
+ buildParams?: BuildParamProvenance[],
684
+ sandbox?: boolean,
685
+ ): Promise<{ diagnostics: LintDiagnostic[]; suppressed: Array<LintDiagnostic & { reason?: string }> }> {
686
+ const diagnostics: LintDiagnostic[] = [];
687
+ const suppressed: Array<LintDiagnostic & { reason?: string }> = [];
688
+ const withChecks = plugins.filter((plugin) => (plugin.postSynthChecks?.() ?? []).length > 0);
689
+ if (withChecks.length === 0) return { diagnostics, suppressed };
690
+
691
+ const projectRoot = findProjectRoot(infraPath);
692
+ const lintConfig = loadConfig(projectRoot);
693
+ // Where a finding that names no declared entity is reported: the config the
694
+ // build loads once it is known (past a lint-only fragment), else the nearest.
695
+ let fallbackFile = findProjectConfig(projectRoot).configPath ?? projectRoot;
696
+ const buildFailure = (message: string, at?: { file?: string; line?: number; column?: number }): LintDiagnostic => ({
697
+ file: at?.file ?? fallbackFile,
698
+ line: at?.line ?? 1,
699
+ column: at?.column ?? 1,
700
+ ruleId: BUILD_FAILURE_RULE_ID,
701
+ severity: "error",
702
+ message,
703
+ });
704
+
705
+ let result: Awaited<ReturnType<typeof build>>;
706
+ let env: string | undefined;
707
+ let telemetry: Awaited<ReturnType<typeof resolveTelemetryAttribution>>;
708
+ try {
709
+ const loaded = await loadChantConfigUpward(infraPath);
710
+ const config = loaded.config;
711
+ const configDir = loaded.configPath ? dirname(loaded.configPath) : infraPath;
712
+ if (loaded.configPath) fallbackFile = loaded.configPath;
713
+ // The caller's parameters when it resolved them (the CLI does, from the
714
+ // same upward config walk); otherwise the declared defaults and `env`
715
+ // mappings of the config this build loads. Not lintCommand's own fallback:
716
+ // that one reads the config at the lint root, which may be a lint-only
717
+ // fragment with no `buildParams` (a `src/chant.config.json`).
718
+ const params = buildParams ?? resolveBuildParams(config.buildParams, { env: process.env }).provenance;
719
+ env = resolveOwnershipEnv(config, params);
720
+ telemetry = await resolveTelemetryAttribution(configDir, config as unknown as Record<string, unknown>, env);
721
+ // Every lexicon the lint loaded, as `chant build` serializes with every
722
+ // lexicon it loaded: a check may read another lexicon's entities, and the
723
+ // outputs are scoped per plugin below either way.
724
+ result = await build(
725
+ infraPath,
726
+ plugins.map((plugin) => plugin.serializer),
727
+ undefined,
728
+ resolveProjectBuildOptions({
729
+ config,
730
+ configDir,
731
+ plugins,
732
+ modes: resolveBuildModes(config, { sandbox }),
733
+ ownership: resolveOwnershipMarker(config, params),
734
+ buildParams: params,
735
+ telemetry,
736
+ }),
737
+ );
738
+ } catch (err) {
739
+ diagnostics.push(buildFailure(err instanceof Error ? err.message : String(err)));
740
+ return { diagnostics, suppressed };
741
+ }
742
+
743
+ if (result.errors.length > 0) {
744
+ const seen = new Set<string>();
745
+ for (const error of result.errors) {
746
+ const at = error as unknown as { file?: string; line?: number; column?: number };
747
+ const key = `${at.file ?? ""}:${at.line ?? ""}:${error.message}`;
748
+ if (seen.has(key)) continue;
749
+ seen.add(key);
750
+ diagnostics.push(buildFailure(error.message, at));
751
+ }
752
+ return { diagnostics, suppressed };
753
+ }
754
+
755
+ const activityContracts = await loadActivityContracts(plugins);
756
+ const fileOf = (entity?: string): string => {
757
+ const declared = entity ? result.entities.get(entity) : undefined;
758
+ return (declared && getProvenance(declared)?.sourceFile) || fallbackFile;
759
+ };
760
+ const toLint = (d: { checkId: string; severity: LintDiagnostic["severity"]; message: string; entity?: string; lexicon?: string }): LintDiagnostic => ({
761
+ file: fileOf(d.entity),
762
+ line: 1,
763
+ column: 1,
764
+ ruleId: d.checkId,
765
+ severity: d.severity,
766
+ message: `${d.entity ? `[${d.entity}] ` : ""}${d.message}`,
767
+ });
768
+
769
+ for (const { plugin, diagnostics: raw } of runLexiconPostSynthChecks(withChecks, result, env, { activityContracts, telemetry })) {
770
+ const presetIds = resolvePresetIds(plugin.lintPresets?.(), lintConfig.presets?.[plugin.name] ?? "recommended");
771
+ const afterPreset = applyConfiguredPreset(raw, presetIds, lintConfig.rules).diagnostics;
772
+ const afterConfig = applyConfiguredSeverity(afterPreset, lintConfig.rules).diagnostics;
773
+ const inline = applyInlineSuppressions(afterConfig, result.entities, lintConfig.rules);
774
+ for (const d of inline.diagnostics) diagnostics.push(toLint(d));
775
+ for (const d of inline.suppressed) suppressed.push({ ...toLint(d), reason: "chant-ignore" });
776
+ for (const m of inline.meta) {
777
+ diagnostics.push({ file: m.file, line: m.line, column: 1, ruleId: m.checkId, severity: m.severity, message: m.message });
778
+ }
779
+ }
780
+
781
+ return { diagnostics, suppressed };
782
+ }
783
+
633
784
  /**
634
785
  * Apply fixes to a file
635
786
  */
@@ -817,6 +968,16 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
817
968
  suppressed.push(...postOpResult.suppressed);
818
969
  }
819
970
 
971
+ // chant #3750: each lexicon's own post-synth checks, over an in-memory
972
+ // build of the lint target. Run once, after any `--fix` above, so it sees
973
+ // the source as fixed; a post-synth finding has no fix of its own. Skipped
974
+ // when a lexicon failed to resolve, which LEX001 below already reports.
975
+ if (!loaded.lexiconError && options.postSynth !== false) {
976
+ const lexiconResult = await runLexiconPostSynthDiagnostics(infraPath, loaded.plugins, options.buildParams, options.sandbox);
977
+ diagnostics.push(...lexiconResult.diagnostics);
978
+ suppressed.push(...lexiconResult.suppressed);
979
+ }
980
+
820
981
  // chant #2222: a lexicon the project declared but this run could not
821
982
  // resolve. Appended here, after the `--fix` re-lint block above has finished
822
983
  // reassigning `diagnostics`, so it survives every path; it is a property of
@@ -1,6 +1,33 @@
1
- import { describe, test, expect } from "vitest";
1
+ import { describe, test, expect, vi, beforeEach } from "vitest";
2
2
  import { createServer } from "node:net";
3
- import { emulatorLifecycle, hostPortInUse } from "./emulator-lifecycle";
3
+ import { promisify } from "node:util";
4
+ import type { EmulatorIdentity } from "./emulator-lifecycle";
5
+
6
+ // `up` reads `docker ps` through exec and `docker port` / `docker exec` through
7
+ // execFile; drive their output so the reuse path runs without Docker.
8
+ let dockerPs = "";
9
+ let dockerPort = "";
10
+ let insideId = "";
11
+ const execCalls: string[] = [];
12
+ const execStub = Object.assign(() => {}, {
13
+ [promisify.custom]: (cmd: string) => {
14
+ execCalls.push(cmd);
15
+ return Promise.resolve({ stdout: cmd.startsWith("docker ps") ? dockerPs : "" });
16
+ },
17
+ });
18
+ const execFileStub = Object.assign(() => {}, {
19
+ [promisify.custom]: (_file: string, argv: string[]) =>
20
+ argv[0] === "port"
21
+ ? (dockerPort ? Promise.resolve({ stdout: dockerPort }) : Promise.reject(new Error("no public port")))
22
+ : Promise.resolve({ stdout: `${insideId}\n` }),
23
+ });
24
+ vi.mock("node:child_process", async () => {
25
+ const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
26
+ return { ...actual, exec: execStub, execFile: execFileStub };
27
+ });
28
+
29
+ const { clientHosts, emulatorLifecycle, endpointOnHost, hostPortInUse, parsePublishedAddresses, pickReachableEndpoint } =
30
+ await import("./emulator-lifecycle");
4
31
 
5
32
  describe("emulatorLifecycle command builders", () => {
6
33
  const emu = emulatorLifecycle({
@@ -74,3 +101,114 @@ describe("hostPortInUse (#3673)", () => {
74
101
  expect(await hostPortInUse(port)).toBe(false);
75
102
  });
76
103
  });
104
+
105
+ describe("a reused container's real address", () => {
106
+ test("parsePublishedAddresses reads docker port output, IPv4 and IPv6", () => {
107
+ expect(parsePublishedAddresses("0.0.0.0:15432\n[::]:15432\n")).toEqual([
108
+ { ip: "0.0.0.0", port: 15432 },
109
+ { ip: "::", port: 15432 },
110
+ ]);
111
+ expect(parsePublishedAddresses("")).toEqual([]);
112
+ });
113
+
114
+ test("clientHosts dials localhost first, then the IPv6 loopback and specific IPs", () => {
115
+ expect(clientHosts([{ ip: "::", port: 5432 }, { ip: "0.0.0.0", port: 5432 }])).toEqual([
116
+ { host: "localhost", port: 5432 },
117
+ { host: "[::1]", port: 5432 },
118
+ ]);
119
+ expect(clientHosts([{ ip: "192.168.5.2", port: 5433 }])).toEqual([{ host: "192.168.5.2", port: 5433 }]);
120
+ });
121
+
122
+ test("endpointOnHost swaps only the host", () => {
123
+ expect(endpointOnHost("postgres://localhost:5432/postgres", "[::1]")).toBe("postgres://[::1]:5432/postgres");
124
+ expect(endpointOnHost("http://localhost:8123", "10.0.0.4")).toBe("http://10.0.0.4:8123");
125
+ expect(endpointOnHost("http://localhost:8123", "localhost")).toBe("http://localhost:8123");
126
+ });
127
+
128
+ const identity = (answers: Record<string, string | Error>): EmulatorIdentity => ({
129
+ server: "Postgres",
130
+ command: ["id"],
131
+ async probe(endpoint) {
132
+ const answer = answers[new URL(endpoint).host];
133
+ if (answer === undefined || answer instanceof Error) throw answer ?? new Error("connection refused");
134
+ return { id: answer, label: answer === "emu" ? "PostgreSQL 18.1" : "PostgreSQL 15.4" };
135
+ },
136
+ });
137
+ const endpoint = (port: number) => `postgres://localhost:${port}/postgres`;
138
+
139
+ test("pickReachableEndpoint names the address that works when localhost reaches another server", async () => {
140
+ const picked = await pickReachableEndpoint({
141
+ name: "chant-postgres",
142
+ hosts: [{ host: "localhost", port: 5432 }, { host: "[::1]", port: 5432 }],
143
+ endpoint,
144
+ identity: identity({ "localhost:5432": "native", "[::1]:5432": "emu" }),
145
+ inside: "emu",
146
+ hint: "",
147
+ });
148
+ expect(picked).toEqual({
149
+ endpoint: "postgres://[::1]:5432/postgres",
150
+ notes: [
151
+ 'emulator "chant-postgres": localhost:5432 reaches another Postgres (PostgreSQL 15.4), not the emulator. ' +
152
+ "The emulator answers on postgres://[::1]:5432/postgres; use that address.",
153
+ ],
154
+ });
155
+ });
156
+
157
+ test("pickReachableEndpoint fails plainly when no published address reaches the emulator", async () => {
158
+ const picked = await pickReachableEndpoint({
159
+ name: "chant-postgres",
160
+ hosts: [{ host: "localhost", port: 5432 }],
161
+ endpoint,
162
+ identity: identity({ "localhost:5432": "native" }),
163
+ inside: "emu",
164
+ hint: "Republish it.",
165
+ });
166
+ expect(picked).toEqual({
167
+ error: 'emulator "chant-postgres" runs, but no address it publishes reaches it: localhost:5432 reaches another Postgres (PostgreSQL 15.4), not the emulator. Republish it.',
168
+ });
169
+ });
170
+
171
+ describe("up, reusing a running container", () => {
172
+ beforeEach(() => {
173
+ dockerPs = "abc123\n";
174
+ dockerPort = "";
175
+ insideId = "emu";
176
+ execCalls.length = 0;
177
+ vi.spyOn(console, "error").mockImplementation(() => {});
178
+ });
179
+ const spec = (answers: Record<string, string | Error>) => ({
180
+ name: "chant-postgres",
181
+ image: "postgres:18",
182
+ containerPort: 5432,
183
+ readyCommand: ["pg_isready"],
184
+ endpoint,
185
+ identity: identity(answers),
186
+ });
187
+
188
+ test("reports the port Docker publishes, not the default", async () => {
189
+ dockerPort = "0.0.0.0:15432\n";
190
+ const lc = emulatorLifecycle(spec({ "localhost:15432": "emu" }));
191
+ expect(await lc.up({ intervalMs: 1 })).toEqual({ endpoint: "postgres://localhost:15432/postgres" });
192
+ expect(execCalls.some((c) => c.startsWith("docker run"))).toBe(false);
193
+ });
194
+
195
+ test("prints the working address when another server holds localhost", async () => {
196
+ dockerPort = "0.0.0.0:5432\n[::]:5432\n";
197
+ const err: string[] = [];
198
+ vi.spyOn(console, "error").mockImplementation((s: string) => { err.push(s); });
199
+ const lc = emulatorLifecycle(spec({ "localhost:5432": "native", "[::1]:5432": "emu" }));
200
+ expect(await lc.up({ intervalMs: 1 })).toEqual({ endpoint: "postgres://[::1]:5432/postgres" });
201
+ expect(err.join("\n")).toContain("localhost:5432 reaches another Postgres (PostgreSQL 15.4), not the emulator");
202
+ expect(err.at(-1)).toBe('emulator "chant-postgres" ready on postgres://[::1]:5432/postgres');
203
+ });
204
+
205
+ test("refuses when no address reaches the emulator, or nothing is published", async () => {
206
+ dockerPort = "0.0.0.0:5432\n";
207
+ await expect(emulatorLifecycle(spec({ "localhost:5432": "native" })).up({ intervalMs: 1 }))
208
+ .rejects.toThrow(/no address it publishes reaches it: localhost:5432 reaches another Postgres/);
209
+ dockerPort = "";
210
+ await expect(emulatorLifecycle(spec({})).up({ intervalMs: 1 }))
211
+ .rejects.toThrow(/publishes no host port for 5432/);
212
+ });
213
+ });
214
+ });
@@ -1,9 +1,10 @@
1
- import { exec } from "node:child_process";
1
+ import { exec, execFile } from "node:child_process";
2
2
  import { connect } from "node:net";
3
3
  import { promisify } from "node:util";
4
4
  import { sleep } from "./activity-runtime";
5
5
 
6
6
  const execAsync = promisify(exec);
7
+ const execFileAsync = promisify(execFile);
7
8
 
8
9
  /**
9
10
  * A local emulator's fixed identity — everything that differs between the
@@ -97,6 +98,97 @@ export function hostPortInUse(port: number, timeoutMs = 1_000): Promise<boolean>
97
98
  });
98
99
  }
99
100
 
101
+ /** One host address Docker publishes a container port on, as `docker port` prints it. */
102
+ export interface PublishedAddress {
103
+ /** The bound host IP: `0.0.0.0`, `::`, `127.0.0.1`, ... */
104
+ ip: string;
105
+ port: number;
106
+ }
107
+
108
+ /**
109
+ * Parse `docker port <name> <port>/tcp` output (`0.0.0.0:5432`, `[::]:5432`,
110
+ * one per line). Lines that do not parse are dropped.
111
+ */
112
+ export function parsePublishedAddresses(stdout: string): PublishedAddress[] {
113
+ const out: PublishedAddress[] = [];
114
+ for (const line of stdout.split("\n")) {
115
+ const match = /^\s*(?:\[([^\]]+)\]|([^\s:]+)):(\d+)\s*$/.exec(line);
116
+ if (match) out.push({ ip: (match[1] ?? match[2])!, port: Number(match[3]) });
117
+ }
118
+ return out;
119
+ }
120
+
121
+ /**
122
+ * The hosts a client on this machine dials to reach a published address,
123
+ * `localhost` first: a wildcard bind (`0.0.0.0`, `::`) answers on the
124
+ * loopback of its family, and a specific IP only on itself.
125
+ */
126
+ export function clientHosts(addresses: readonly PublishedAddress[]): { host: string; port: number }[] {
127
+ const seen = new Set<string>();
128
+ const hosts: { host: string; port: number }[] = [];
129
+ const add = (host: string, port: number): void => {
130
+ const key = `${host}:${port}`;
131
+ if (seen.has(key)) return;
132
+ seen.add(key);
133
+ hosts.push({ host, port });
134
+ };
135
+ for (const { ip, port } of addresses) {
136
+ if (ip === "0.0.0.0" || ip === "127.0.0.1") add("localhost", port);
137
+ }
138
+ for (const { ip, port } of addresses) {
139
+ if (ip === "::" || ip === "::1") add("[::1]", port);
140
+ else if (ip !== "0.0.0.0" && ip !== "127.0.0.1") add(ip.includes(":") ? `[${ip}]` : ip, port);
141
+ }
142
+ return hosts;
143
+ }
144
+
145
+ /** `endpoint` with its host replaced by `host` (`localhost` stays as written). */
146
+ export function endpointOnHost(endpoint: string, host: string): string {
147
+ if (host === "localhost") return endpoint;
148
+ const url = new URL(endpoint);
149
+ url.hostname = host;
150
+ return url.toString().replace(/\/$/, endpoint.endsWith("/") ? "/" : "");
151
+ }
152
+
153
+ /**
154
+ * Pick the endpoint of a reused container that reaches it (the identity read
155
+ * inside the container matches the one read through the endpoint), trying
156
+ * {@link clientHosts} in order. `notes` says when `localhost` reaches another
157
+ * server and a different address had to be used; `error` says when none of
158
+ * them reaches the emulator.
159
+ */
160
+ export async function pickReachableEndpoint(opts: {
161
+ name: string;
162
+ hosts: readonly { host: string; port: number }[];
163
+ endpoint: (port: number) => string;
164
+ identity: EmulatorIdentity;
165
+ /** The identity read inside the container. */
166
+ inside: string;
167
+ /** A hint appended to an `error`, e.g. how to republish on a free port. */
168
+ hint: string;
169
+ }): Promise<{ endpoint: string; notes: string[] } | { error: string }> {
170
+ const { name, hosts, identity, inside } = opts;
171
+ const misses: string[] = [];
172
+ for (const { host, port } of hosts) {
173
+ const ep = endpointOnHost(opts.endpoint(port), host);
174
+ try {
175
+ const answered = await identity.probe(ep);
176
+ if (answered.id.trim() === inside) {
177
+ const notes = misses.length
178
+ ? [`emulator "${name}": ${misses.join("; ")}. The emulator answers on ${ep}; use that address.`]
179
+ : [];
180
+ return { endpoint: ep, notes };
181
+ }
182
+ misses.push(`${host}:${port} reaches another ${identity.server} (${answered.label}), not the emulator`);
183
+ } catch (err) {
184
+ const why = err instanceof Error ? err.message : String(err);
185
+ misses.push(`${host}:${port} does not answer as the emulator (${why})`);
186
+ }
187
+ }
188
+ const tried = misses.length ? `: ${misses.join("; ")}` : "";
189
+ return { error: `emulator "${name}" runs, but no address it publishes reaches it${tried}. ${opts.hint}` };
190
+ }
191
+
100
192
  /**
101
193
  * A lexicon's local-emulator capability (#920) — what `chant emulator` needs to
102
194
  * boot it and point tooling at it. The `spec` drives the Docker lifecycle; `env`
@@ -198,7 +290,7 @@ export function emulatorLifecycle(spec: EmulatorSpec): EmulatorLifecycle {
198
290
  spec.readyCommand?.length ? ["docker", "exec", name, ...spec.readyCommand].join(" ") : undefined;
199
291
 
200
292
  /** One readiness probe: the in-container command when declared, else the HTTP health path. */
201
- async function probe(name: string, port: number, signal?: AbortSignal): Promise<boolean> {
293
+ async function probe(name: string, port: number, signal?: AbortSignal, host = "localhost"): Promise<boolean> {
202
294
  const command = readyExecCommand(name);
203
295
  if (command) {
204
296
  try {
@@ -209,7 +301,7 @@ export function emulatorLifecycle(spec: EmulatorSpec): EmulatorLifecycle {
209
301
  }
210
302
  }
211
303
  try {
212
- const res = await fetch(healthUrl(port), { signal });
304
+ const res = await fetch(endpointOnHost(healthUrl(port), host), { signal });
213
305
  return res.ok && ready(await res.text());
214
306
  } catch {
215
307
  // Not up yet (connection refused / non-2xx) — retry.
@@ -231,10 +323,33 @@ export function emulatorLifecycle(spec: EmulatorSpec): EmulatorLifecycle {
231
323
  // `docker ps` failed — assume not running and try to start it.
232
324
  }
233
325
 
326
+ // A reused container publishes what it was started with, which need not
327
+ // be `port` on localhost: read it from Docker rather than assume it.
328
+ let hosts: { host: string; port: number }[] = [{ host: "localhost", port }];
234
329
  if (running) {
235
330
  // Progress → stderr, so a `--json` consumer (chant emulator, behold) reads
236
331
  // clean JSON on stdout. runOp/Op activities capture both streams regardless.
237
332
  console.error(`emulator container "${name}" already running — reusing`);
333
+ let published: PublishedAddress[] = [];
334
+ try {
335
+ const { stdout } = await execFileAsync("docker", ["port", name, `${spec.containerPort}/tcp`], { signal });
336
+ published = parsePublishedAddresses(stdout);
337
+ } catch {
338
+ // `docker port` fails when nothing is published.
339
+ }
340
+ if (published.length === 0) {
341
+ throw new Error(
342
+ `emulator "${name}" runs, but publishes no host port for ${spec.containerPort}, so nothing on this machine reaches it. ` +
343
+ `Run \`chant emulator down\`, then \`chant emulator up\`.`,
344
+ );
345
+ }
346
+ hosts = clientHosts(published);
347
+ if (args.port !== undefined && !hosts.some((h) => h.port === args.port)) {
348
+ console.error(
349
+ `emulator "${name}" was started on host port ${hosts[0]!.port}, not ${args.port}; reusing it there. ` +
350
+ `Run \`chant emulator down\` first to move it.`,
351
+ );
352
+ }
238
353
  } else {
239
354
  if (await hostPortInUse(port)) {
240
355
  throw new Error(
@@ -249,17 +364,37 @@ export function emulatorLifecycle(spec: EmulatorSpec): EmulatorLifecycle {
249
364
  let ok = false;
250
365
  while (Date.now() < deadline) {
251
366
  if (signal?.aborted) throw new Error(`emulator "${name}" wait aborted`);
252
- if (await probe(name, port, signal)) {
253
- ok = true;
254
- break;
367
+ for (const h of hosts) {
368
+ if (await probe(name, h.port, signal, h.host)) {
369
+ ok = true;
370
+ break;
371
+ }
255
372
  }
373
+ if (ok) break;
256
374
  await sleep(intervalMs, signal);
257
375
  }
258
376
  if (!ok) {
259
377
  throw new Error(`emulator "${name}" did not become ready within ${timeoutMs}ms`);
260
378
  }
261
379
 
262
- const ep = endpoint(port);
380
+ let ep = endpointOnHost(endpoint(hosts[0]!.port), hosts[0]!.host);
381
+ if (running && spec.identity) {
382
+ let inside: string | undefined;
383
+ try {
384
+ inside = (await execFileAsync("docker", ["exec", name, ...spec.identity.command], { signal })).stdout.trim();
385
+ } catch {
386
+ // The container cannot answer for itself; nothing to compare against.
387
+ }
388
+ if (inside) {
389
+ const picked = await pickReachableEndpoint({
390
+ name, hosts, endpoint, identity: spec.identity, inside,
391
+ hint: `Stop the other server, or run \`chant emulator down\`, then \`chant emulator up --port ${spec.containerPort}=<free port>\`.`,
392
+ });
393
+ if ("error" in picked) throw new Error(picked.error);
394
+ for (const note of picked.notes) console.error(note);
395
+ ep = picked.endpoint;
396
+ }
397
+ }
263
398
  console.error(`emulator "${name}" ready on ${ep}`);
264
399
  return { endpoint: ep };
265
400
  }
package/src/op/index.ts CHANGED
@@ -11,8 +11,8 @@ export { Op, phase, activity, gate, effect, build, kubectlApply, helmInstall, he
11
11
  spritesUp, spritesDown } from "./builders";
12
12
  export { OpResource } from "./resource";
13
13
  export { sleep } from "./activity-runtime";
14
- export { emulatorLifecycle, emulatorsOf, endpointEnvVars, hostPortInUse } from "./emulator-lifecycle";
15
- export type { EmulatorSpec, EmulatorCapability, EmulatorDeclaration, EmulatorIdentity, EmulatorUpArgs, EmulatorLifecycle } from "./emulator-lifecycle";
14
+ export { clientHosts, emulatorLifecycle, emulatorsOf, endpointEnvVars, endpointOnHost, hostPortInUse, parsePublishedAddresses, pickReachableEndpoint } from "./emulator-lifecycle";
15
+ export type { EmulatorSpec, EmulatorCapability, EmulatorDeclaration, EmulatorIdentity, EmulatorUpArgs, EmulatorLifecycle, PublishedAddress } from "./emulator-lifecycle";
16
16
  export { checkFreshness, compare, formatResult, latestRelease, parseVersion, unpinned } from "./emulator-freshness";
17
17
  export type { FreshnessResult } from "./emulator-freshness";
18
18
  export type { OpConfig, OpSchedule, OpWorkLease, PhaseDefinition, StepDefinition, ActivityStep, GateStep, EffectStep, OutcomeAttribute } from "./types";