Evaluation Pipeline
When you run chant build, the tool takes your TypeScript source files through a series of stages to produce deployment-ready output.
Pipeline Overview
Section titled “Pipeline Overview”Stage 1: File Discovery
Section titled “Stage 1: File Discovery”The evaluator scans the project directory for TypeScript source files, applying standard filters:
- Include all
.tsfiles in the source directory - Exclude
*.test.tsand*.spec.ts - Exclude
node_modules
Related: Project Structure
Stage 2: Type-Check and Evaluability (lint, not build)
Section titled “Stage 2: Type-Check and Evaluability (lint, not build)”Type-checking and the evaluability rules are not part of the default chant build. They run in chant lint and in your editor. chant build runs under a TypeScript runtime that strips types without checking them.
Run chant lint, or rely on the editor, to catch type errors and patterns that are valid TypeScript but not statically evaluable. See TypeScript as Data for the full list. Staying inside that subset is what lets a file skip Stage 4’s import/execution entirely on the default fold path, and it is what guarantees the imported source is safe to run when a file falls back; see Folded vs Run.
Related: Evaluability Rules
Stage 3: Resolve Imports
Section titled “Stage 3: Resolve Imports”The tool builds a module graph by following import statements. This handles:
- Relative imports (
import { tags } from "./shared") - Lexicon imports (
import { Bucket, Sub } from "@intentius/chant-lexicon-aws") - Re-exports (
export { bucket } from "./bucket")
The module graph determines which files depend on which, and ensures that cross-file const references can be resolved during evaluation.
Related: Module Graph
Stage 4: Fold or Collect Resources
Section titled “Stage 4: Fold or Collect Resources”By default chant reduces each discovered file’s AST directly to its resource objects, with no module execution. A file that steps outside the fold subset is instead imported with the TypeScript runtime and its exported resource objects collected, which is also what --no-fold forces for every file. This stage describes that run path; see Folded vs Run for which files take which.
export const <name> = new <ResourceType>({...})Running the file does the resolution. The language evaluates the object literal, applies spreads from const sources, and follows cross-file imports. Lexicon constructors turn new <ResourceType>({...}) into a Declarable. Lexicon-registered tagged templates produce intrinsic objects. Accessing resource.attribute on an imported resource yields a symbolic reference.
The evaluability rules from Stage 2 keep this safe. They guarantee the file holds only literals, constants, spreads from constants, and cross-resource references, so importing it has no side effects and always produces the same objects.
Related: Evaluator Engine
Stage 5: Expand Composites
Section titled “Stage 5: Expand Composites”Composite resources are factory patterns that produce multiple related resources from a single declaration. After all resources are extracted, the evaluator expands composite instances:
- Identify composite instances in the extracted resources
- Substitute prop values into the composite’s template
- Resolve
siblingsreferences within the composite - Emit prefixed child resources (e.g.,
myApi.function,myApi.role)
Note: nested deployment units (e.g. AWS nested stacks) are not composites — they are child projects. A child project is a separate subdirectory that builds independently. The parent references it via a lexicon-specific function (e.g. nestedStack()), and discovery skips child project directories entirely. See Multi-Stack Projects for an overview.
Related: Composite Resources, Multi-Stack Projects, Child Projects (Lexicon Authoring)
Stage 6: Emit
Section titled “Stage 6: Emit”The evaluated resources are passed to the lexicon serializer, which produces the target output format. During serialization, the emitter:
- Converts reference values to the target format’s reference mechanism
- Maps TypeScript property names to the target format’s naming convention
- Omits
nulland missing properties
See your lexicon’s serialization documentation for concrete output examples.
Related: Serializer, Lexicon Registry
Error Handling
Section titled “Error Handling”Errors are non-fatal per resource. If one resource fails evaluation, the evaluator reports the error (with file path, line, and column) and continues to the next resource. All errors are collected and reported at the end.
Caching
Section titled “Caching”The evaluator caches two things during a single chant build run:
- Evaluated
constbindings — each binding is evaluated once, even if referenced by multiple resources - Import resolution — each imported binding is resolved once, even if referenced from multiple files
There is no persistent cache across runs.