/** * Component discovery — Phase 2 (#560, epic #551). * * Mirrors chant's existing declarable discovery * (`../discovery/index.ts`'s `discover()`, built on `findInfraFiles`) as * closely as a structurally distinct type allows, and borrows its * file-suffix convention from Op discovery * (`../op/discover.ts`'s `discoverOps()`, `*.op.ts`): a component is any * `Component`-shaped value (see `./component.ts`'s `isComponent`) exported * (by any export name, not just `default`) from a `*.component.ts` file. * * Why a dedicated convention rather than folding into `discover()`: * `Declarable` (`../declarable.ts`) is a lexicon-resource marker — * `{ lexicon, entityType, kind, [DECLARABLE_MARKER]: true }` — and a * `Component` has none of that shape (no `lexicon`, and its `deploy` * composition is data the capability driver interprets, not a serializable * lexicon resource). Reusing `collectEntities`/`isDeclarable` would mean * either stretching the `Declarable` marker to cover an unrelated shape or * silently ignoring components during the existing walk. A parallel, * purpose-built collector keeps both conventions simple: `*.ts` + the * `Declarable` marker for resources, `*.component.ts` + the `Component` * shape for components — exactly how `*.op.ts` is already a parallel, * purpose-built convention for Ops. * * Filename convention (`*.component.ts`) is documented here rather than * inferred from export shape alone so a project can `grep` for its * components the same way it can for `*.op.ts` files, and so discovery does * not have to import (and risk side-effecting) every `.ts` file in the * project looking for stray `Component`-shaped objects. * * chant #1051 — `discoverComponents` unconditionally `await import()`s every * discovered file in the CLI's own process, the same exposure #1045 Phase 2 * closed for lexicon-resource discovery (`../discovery/index.ts`'s * `discover({ sandbox: true })`). `{ sandbox: true }` here runs that import * (and the duplicate-name collection below) together, isolated, in one * sandboxed child process instead — see `./sandbox/driver.ts`/`./sandbox/ * run.ts`. Materially simpler than the entity path: a `Component` is plain * JSON (no `AttrRef` cross-references), so the child can hand back its result * with a bare `JSON.stringify` — no entity-wire codec needed (`projectToJson`, * `./component.ts`, already proves the plain-JSON round-trip). */ import { DiscoveryError } from "../errors.js"; import { type Component } from "./component.js"; import type { BuildParamProvenance } from "../provenance.js"; /** One discovered component, paired with the file it was exported from. */ export interface DiscoveredComponent { component: Component; /** The export name the component was found under (informational; components are keyed by their own `.name`, not this). */ exportName: string; filePath: string; } export interface ComponentDiscoveryResult { /** Discovered components, keyed by `component.name` (the schema identity), not by export name or file. */ components: Map; /** Every `*.component.ts` file that was scanned. */ sourceFiles: string[]; errors: DiscoveryError[]; } /** Options for {@link discoverComponents}. */ export interface ComponentDiscoveryOptions { /** * chant #1051 — opt-in: import every discovered `*.component.ts` file * together, isolated, in one sandboxed child process (`./sandbox/run.ts`) * instead of in this (the CLI's own) process. Mirrors `discover({ sandbox: * true })` (`../discovery/index.ts`, chant #1045 Phase 2) for the parallel * `*.component.ts` convention. Default `false` — behavior, including * performance (no bundling, no child process, no IPC), is unchanged unless * requested. */ sandbox?: boolean; /** * chant #1108 — this invocation's resolved build-time parameter values * (../build-params.ts's `resolveBuildParams`, driven by the CLI's * `--param`/`--params-file`/a declared `env` mapping/`chant.config.ts`'s * `buildParams` defaults — see ../cli/build-params-cli.ts's * `resolveCliBuildParams`, the exact resolution `chant build` runs). * Populated into ../params.ts's shared `params` object (`setBuildParams`, * below) before any `*.component.ts` file is scanned/imported, mirroring * ../discovery/index.ts's `discover()` — the lexicon-resource counterpart * of this function, and the thing chant #1108 exists to bring this one to * parity with. Before #1108, no caller populated this, so a live `import { * params } from "@intentius/chant/params"` inside a component file (e.g. a * naming helper deriving a stack name) always saw `{}`. * * Default: none — `params` stays `{}`, matching every caller that doesn't * resolve build-time parameters today (`chant list/describe/graph/lint * --components`, `chant components status`); only the run and generate * call sites (../cli/handlers/run.ts, ../cli/handlers/build.ts) pass a * resolved value. * * Only takes effect for the in-process (non-sandboxed) import path below — * `{ sandbox: true }`'s child process gets its own, unpopulated `params` * module instance, the same pre-existing gap `discover({ sandbox: true })` * has for lexicon resources (chant #1045 Phase 2 never threaded * `buildParams` into its sandboxed child either; out of scope here too). */ buildParams?: BuildParamProvenance[]; } /** One already-imported `*.component.ts` module — the input to {@link collectComponents}. */ export interface ImportedComponentModule { file: string; exports: Record; } /** * Collect every `Component`-shaped export from already-imported `modules`, * enforcing the duplicate-`component.name` rule (across files, or within one * file): a discovery error, matching `collectEntities`'s duplicate-export * handling and `discoverOps`'s duplicate-Op-name handling — except the * identity compared is the schema-level `name` field, since two different * export bindings could otherwise declare the same component name and * silently collide at deploy time. `existing.component !== value` — object * identity, not deep equality — is what lets the SAME component re-exported * under several bindings pass through without tripping the duplicate check. * * Split out from {@link discoverComponents} (#1051) precisely because that * identity check has to run on the LIVE, still-in-memory export values — * identity does not survive a process boundary. That means this function * must run wherever `modules` were actually imported: in this process for * the default (unsandboxed) path below, or inside the sandboxed child for * `{ sandbox: true }` (`./sandbox/driver.ts`, which bundles and calls this * same function), mirroring how `collectEntities` runs inside `../discovery/ * sandbox/driver.ts` for the lexicon-resource run-fallback set (chant #1045 * Phase 2). */ export declare function collectComponents(modules: readonly ImportedComponentModule[]): { components: Map; errors: DiscoveryError[]; }; /** * Discover every `Component` declared under `path`: scan for `*.component.ts` * files, import each, and collect every export whose value satisfies * `isComponent` (any export name — not just `default` — so a file may * declare several related components, matching how a resource file can * export several `Declarable`s). See {@link collectComponents} for the * duplicate-name rule. * * `{ sandbox: true }` (#1051) imports every file together, isolated, in one * sandboxed child process instead (`./sandbox/run.ts`) — the same isolation * `discover({ sandbox: true })` (`../discovery/index.ts`) gives lexicon * resources, chant #1045 Phase 2. */ export declare function discoverComponents(path: string, options?: ComponentDiscoveryOptions): Promise; //# sourceMappingURL=discover.d.ts.map