import type { Declarable } from "./declarable.js"; import type { Serializer, SerializerResult } from "./serializer.js"; import type { OwnershipMarker } from "./ownership.js"; import type { BuildError } from "./errors.js"; import type { IntrinsicDef, BuildRootContribution } from "./lexicon.js"; import type { BuildParamProvenance } from "./provenance.js"; import { DiscoveryError } from "./errors.js"; import { LexiconOutput } from "./lexicon-output.js"; import { type FoldDecision } from "./discovery/index.js"; import { type DiscoveredEntitiesJson } from "./discovery/entity-wire.js"; /** * Build manifest describing cross-lexicon outputs and deployment order */ export interface BuildManifest { lexicons: string[]; outputs: Record; deployOrder: string[]; /** Cross-stack apply-ordering graph (see {@link computeStackGraph}). */ stackGraph: StackGraph; } /** * The cross-stack (cross-lexicon) apply-ordering graph chant already computes * while resolving cross-lexicon references — surfaced as tool-agnostic data for * an orchestrator to consume. chant exposes the order; it does not drive the * apply. */ export interface StackGraph { /** Stacks (lexicon partitions) in the build. */ nodes: string[]; /** * Consumer→producer edges: `from` imports a value `to` exports, so `to` must * apply before `from`. Inferred from cross-lexicon references. */ edges: Array<{ from: string; to: string; }>; /** A flat applicable sequence — every producer before its consumers. */ order: string[]; /** * Levels: stacks in the same wave have no inter-dependency and may apply * concurrently. `order` flattened with parallelism made explicit. */ waves: string[][]; /** Dependency cycles, if any (each a list of stacks). Normally empty. */ cycles: string[][]; } /** * Compute the cross-stack apply-ordering graph from resolved entities. Edges are * inferred from cross-lexicon attribute references (a resource in lexicon A * referencing an attribute of a resource in lexicon B ⇒ A depends on B). Returns * the edge set plus a topological order, parallel-safe waves, and any cycles. */ export declare function computeStackGraph(entities: Map, lexiconNames: string[]): StackGraph; /** * Result of the build process */ /** * Optional inputs to the build pipeline. */ export interface BuildOptions { /** * When set, serializers stamp this ownership marker into each resource's * native metadata channel. Resolved from project config by the caller. */ ownership?: OwnershipMarker; /** * The resolved project configuration, passed through to each serializer's * {@link SerializeContext} so a dialect can read its lexicon-scoped settings. */ config?: Record; /** * chant #1022 (epic #1019) — opt-in: fold source modules statically * instead of importing/running them, falling back to run per-file for * anything the folder can't represent. Default `false` (unchanged * behavior). See {@link DiscoveryOptions.fold} in `./discovery/index`. */ fold?: boolean; /** * chant #1039 — lexicon-registered intrinsic tags (e.g. AWS's `Sub`) to * recognize while folding. Passed straight through to * {@link DiscoveryOptions.intrinsics}; ignored unless {@link fold} is set. * The CLI populates this from `options.plugins.flatMap(p => p.intrinsics?.() ?? [])`. */ intrinsics?: IntrinsicDef[]; /** * chant #1063 — the lexicon names loaded for this build. Passed straight * through to {@link DiscoveryOptions.lexicons} in `./discovery/index`; * ignored unless {@link fold} is set. The CLI populates this from * `options.plugins.map(p => p.name)`. */ lexicons?: readonly string[]; /** * chant #1442 — lexicon name → the version of the plugin that served it. * Recorded on {@link BuildResult.lexiconVersions} so a build digest can say * WHAT interpreted the declarations, not only what was declared. The CLI * populates this from `options.plugins`; `build()` only carries it. */ lexiconVersions?: Readonly>; /** * chant #1045 Phase 2 — opt-in: run-fallback files (or, when {@link fold} * isn't set, every file) execute together, isolated, in one sandboxed * child process instead of in-process. Passed straight through to * {@link DiscoveryOptions.sandbox} in `./discovery/index`. Default `false` * (unchanged behavior/performance). */ sandbox?: boolean; /** * chant #1064 — this build's resolved build-time parameter values (see * ./build-params.ts's `resolveBuildParams`, driven by the CLI's * `--param`/`--params-file`/declared `env` mapping/`chant.config.ts` * `buildParams` defaults). Threaded through to `discover()`, which * populates `./params.ts`'s shared `params` object before any project file * is imported or folded, and into the fold session so a `params.` * reference resolves to a literal. Passed through verbatim onto * {@link BuildResult.buildParams} — `build()` itself does no * declaration/validation (that's the CLI/config layer's job); it only * carries the already-resolved records for provenance. */ buildParams?: BuildParamProvenance[]; /** * chant #1548 piece 3 — lexicon-contributed build roots: closures the CLI * binds from each configured plugin's `buildRoots(ctx)` hook (see * `collectBuildRootContributors` in ./cli/plugins.ts), each rendering a * non-chant-source root (a kustomize overlay dir) into entities. Run once, * at the TOP-LEVEL build only (never repeated for nested child projects), * after discovery and before partitioning — so contributed entities are * serialized, ownership-stamped, post-synth-checked and observed exactly * like discovered ones. A contributor that throws becomes a build error * carrying its message (the k8s hook's missing-binary refusal names the * binaries); a contributed name colliding with a discovered entity is a * build error, never a silent overwrite. */ buildRoots?: Array<() => Promise>; } export interface BuildResult { /** Map of lexicon name to serialized output (string or multi-file result) */ outputs: Map; /** Map of entity name to Declarable entity */ entities: Map; /** Resource-level dependency graph from discovery */ dependencies: Map>; /** Array of warnings encountered during the build */ warnings: string[]; /** Array of errors encountered during discovery and build */ errors: Array; /** Build manifest with cross-lexicon dependency info */ manifest: BuildManifest; /** Number of source files processed */ sourceFileCount: number; /** * Per-file fold-vs-run decisions (#1022). Empty unless * {@link BuildOptions.fold} was set. */ foldDecisions: FoldDecision[]; /** * chant #1442 — lexicon name → the version of the plugin that served this * build, passed through verbatim from {@link BuildOptions.lexiconVersions}. * * The other half of what a build digest needs. `hashProps` fingerprints the * declaration; this records what turned it into output. A lexicon is a * generated artifact pinned to an upstream spec, so a bump can change * emitted output with no source change at all — and without this the two * builds are indistinguishable. * * Empty when the caller supplied no plugins (`build()` used as a library, * and most tests). */ lexiconVersions: Record; /** * This build's resolved build-time parameters (#1064) — the build * provenance record for `params.` values, alongside the existing * entity-level provenance (./provenance.ts). Passed through verbatim from * {@link BuildOptions.buildParams}; empty when the project declares/ * supplies none. */ buildParams: BuildParamProvenance[]; } /** * Partitions entities by their lexicon field. * Property-kind Declarables are included in the same partition as their parent * (they get inlined during serialization). * * @param entities - Map of entity name to Declarable * @returns Map of lexicon name to Map of entity name to Declarable */ export declare function partitionByLexicon(entities: Map): Map>; /** * Collect LexiconOutput instances from all entity property trees. * Walks entity properties recursively to find LexiconOutput values. */ export declare function collectLexiconOutputs(entities: Map): LexiconOutput[]; /** * Detect cross-lexicon AttrRefs by walking each entity's property tree. * For each AttrRef whose parent entity belongs to a different lexicon than * the consuming entity, auto-create a LexiconOutput. * * @param entities - Map of entity name to Declarable * @returns Array of auto-detected LexiconOutput instances */ export declare function detectCrossLexiconRefs(entities: Map): LexiconOutput[]; /** What merging build-root contributions produced: non-fatal render notes and * fatal messages (a failed contributor, a name collision). */ export interface BuildRootMergeResult { warnings: string[]; errors: string[]; } /** * Run each build-root contributor (#1548 piece 3) and merge its rendered * entities into `entities`, in place. THE one merge implementation — `build()` * uses it for step 4b, and the graph handler's discover-based paths reuse it * so a rendered kustomize root joins the graphed entity set under exactly the * rules the build applies (#1626): * * - a contributed name colliding with an existing entity is an error, never a * silent overwrite; * - a contributor that throws becomes an error carrying its message (the k8s * hook's missing-binary refusal names the binaries), not a stack trace. * * Errors come back as plain messages; each caller wraps them in its own error * vocabulary (`BuildErrorClass` in `build()`, the CLI's `formatError` on the * graph paths). */ export declare function mergeBuildRootEntities(entities: Map, contributors: ReadonlyArray<() => Promise>): Promise; /** * Builds a lexicon specification by discovering entities, sorting them * topologically, and serializing them using the lexicon serializers. * * @param path - The directory path containing the specification files * @param serializers - The serializers to use for serialization * @returns BuildResult with outputs, entities, warnings, and errors */ export declare function build(path: string, serializers: Serializer[], parentBuildStack?: Set, options?: BuildOptions): Promise; /** * chant #1045 (Phase 1) — build directly from a JSON-encoded discovery * result (see {@link discoverEntitySetJson} in `./discovery/entity-wire.ts`) * instead of pointing `build()` at a directory. * * Decodes the wire entity set back into a live entities map — see * `decodeEntitySet`'s doc for why the decoded entities are functionally * indistinguishable from what `discover()` produces in-process (real * `AttrRef` instances, whole-entity identity preserved by reference, not by * clone) — then runs the exact same post-discovery pipeline `build()` uses * ({@link buildFromDiscoveryResult}), so partitioning, output detection, * serialization, and the manifest are the SAME code path, not a fork of it. * * Dependencies aren't part of the wire format: unlike entities, a dependency * graph is plain name-to-name data with no identity problem, so it's cheaper * and more honest to recompute it from the decoded entities via the same * `buildDependencyGraph()` `discover()` itself uses than to carry a second, * redundant wire shape across the boundary. * * @param label - Used only to seed circular-nested-stack detection; a JSON * entity set has no single source directory the way a `build(path, …)` * call does. Inert today — child projects (`nestedStack()`) aren't * supported by the JSON boundary yet (see `discovery/entity-wire.ts`). */ export declare function buildFromEntitiesJson(json: DiscoveredEntitiesJson, serializers: Serializer[], label?: string, parentBuildStack?: Set, options?: BuildOptions): Promise; //# sourceMappingURL=build.d.ts.map