Implement Generate
The generate lifecycle method is the heart of a lexicon — it fetches upstream schemas, parses them, and produces TypeScript types, a runtime index, and a registry. Core provides generatePipeline to orchestrate this; you supply provider-specific callbacks.
Generation Pipeline
Section titled “Generation Pipeline”import { generatePipeline, type GeneratePipelineConfig } from "@intentius/chant/codegen/generate";
const result = await generatePipeline({ fetchSchemas: async (opts) => fetchMySchemas(opts.force), parseSchema: (name, data) => parseMySchema(data), createNaming: (results) => new NamingStrategy(results, myConfig), generateRegistry: (results, naming) => buildLexiconJSON(results, naming), generateTypes: (results, naming) => buildTypesDTS(results, naming), generateRuntimeIndex: (results, naming) => buildRuntimeIndex(results, naming), augmentSchemas: async (schemas, opts, log) => { /* patches, overlays */ }, augmentResults: (results, opts, log) => { /* fallbacks, synthetic resources */ },});See
lexicons/aws/src/codegen/generate.tsfor the complete AWS generation pipeline.
Pipeline data flow
Section titled “Pipeline data flow”The pipeline executes these steps in order:
fetchSchemas(opts)→Map<typeName, Buffer>— raw schema files keyed by type nameaugmentSchemas(schemas, opts, log)(optional) — patch or overlay schemas before parsing. Skipped whenopts.schemaSourceis provided (e.g. during testing). Returns{ schemas, extraResults?, warnings? }parseSchema(typeName, data)→T | null— parse each schema buffer. Returnnullto skip a fileaugmentResults(results, opts, log)(optional) — add synthetic resources or fallbacks after parsing. Returns{ results, warnings? }createNaming(results)→NamingStrategy— build the naming strategy from all parsed resultsgenerateRegistry(results, naming)→string— JSON content for the lexicon registrygenerateTypes(results, naming)→string— TypeScript declaration content (.d.ts)generateRuntimeIndex(results, naming)→string— runtime index with factory exports (index.ts)
ParsedResult contract
Section titled “ParsedResult contract”Your parser’s return type must extend ParsedResult:
interface ParsedResult { propertyTypes: Array<{ name: string }>; // property type definitions enums: Array<unknown>; // enum definitions}The pipeline uses .propertyTypes.length and .enums.length for stats only — the arrays are passed through untouched to your generate callbacks. Extend ParsedResult with any additional fields your callbacks need:
interface MyParsedResult extends ParsedResult { typeName: string; description: string; properties: Map<string, PropertyDef>; attributes: string[];}See
lexicons/aws/src/spec/parse.tsfor the AWS parser that produces aParsedResult.
Naming Strategy
Section titled “Naming Strategy”The NamingStrategy class implements a 5-phase collision-free naming algorithm for TypeScript class names. Supply your provider’s data tables via NamingConfig:
import { NamingStrategy, type NamingConfig, type NamingInput } from "@intentius/chant/codegen/naming";
const config: NamingConfig = { priorityNames: { "Provider::S3::Bucket": "Bucket" }, priorityAliases: {}, priorityPropertyAliases: {}, serviceAbbreviations: {}, shortName: (t) => t.split("::").pop()!, serviceName: (t) => t.split("::")[1],};
const naming = new NamingStrategy(inputs, config);See
lexicons/aws/src/codegen/naming.tsfor the AWS naming configuration with real data tables.
Fetch Utilities
Section titled “Fetch Utilities”fetchWithCache and extractFromZip handle HTTP download + caching + zip extraction:
import { fetchWithCache, extractFromZip } from "@intentius/chant/codegen/fetch";
const zipData = await fetchWithCache({ url: SCHEMA_URL, cacheFile: CACHE_PATH });const schemas = await extractFromZip(zipData, (name) => name.endsWith(".json"));See
lexicons/aws/src/spec/fetch.tsfor the AWS schema fetcher.
Runtime Factories
Section titled “Runtime Factories”Use createResource and createProperty to generate Declarable-marked constructors:
import { createResource, createProperty } from "@intentius/chant/runtime";
const MyResource = createResource("Provider::Service::Type", "my-lexicon", { arn: "Arn" });const MyProperty = createProperty("Provider::Service::Type.PropType", "my-lexicon");Writing Generated Artifacts
Section titled “Writing Generated Artifacts”After generatePipeline returns a GenerateResult, write the files using writeGeneratedArtifacts:
import { writeGeneratedArtifacts } from "@intentius/chant/codegen/generate";
writeGeneratedArtifacts({ baseDir: pkgDir, // root of your lexicon package generatedSubdir: "src/generated", // default; can be customized files: { "lexicon.json": result.lexiconJSON, "index.d.ts": result.typesDTS, "index.ts": result.indexTS, },});See
lexicons/aws/src/codegen/generate.tsfor the complete generate + write flow.
Helper Utilities
Section titled “Helper Utilities”Runtime Index Generator
Section titled “Runtime Index Generator”import { generateRuntimeIndex, type RuntimeIndexConfig } from "@intentius/chant/codegen/generate-runtime-index";
const indexTS = generateRuntimeIndex(resources, properties, { lexiconName: "my-lexicon", intrinsicReExports: [], pseudoReExports: [],});Registry Builder
Section titled “Registry Builder”import { buildRegistry, serializeRegistry } from "@intentius/chant/codegen/generate-registry";
const registry = buildRegistry(results, naming, { shortName: (t) => naming.shortName(t), buildEntry: (r, shortName) => ({ resourceType: r.typeName, kind: "resource" }), buildPropertyEntry: (r, shortName) => ({ resourceType: r.typeName, kind: "property" }),});const lexiconJSON = serializeRegistry(registry);JSON Schema Utilities
Section titled “JSON Schema Utilities”For lexicons with JSON Schema-based specs:
import { resolvePropertyType, extractConstraints, isEnumDefinition } from "@intentius/chant/codegen/json-schema";resolvePropertyType(prop, schema, resolveDefName)— resolve a schema property to a TypeScript type string. Handles$ref,oneOf/anyOf, arrays, objects, and primitives. Inlineenumarrays produce sorted string-literal union types (e.g."Allow" | "Deny"). When a$refpoints to an enum definition, it callsresolveDefNameto produce a named enum type (e.g.Bucket_Status); passnullto fall back to"string"extractConstraints(prop)— extract validation constraints (min/max, pattern, allowed values, enum arrays)isEnumDefinition(def)— detect if a schema definition is a pure string enum (hasenumarray, noproperties)
PseudoParameter
Section titled “PseudoParameter”import { PseudoParameter, createPseudoParameters } from "@intentius/chant/pseudo-parameter";
const pseudos = createPseudoParameters({ "My::Region": "The deployment region", "My::AccountId": "The account identifier",});Import Utilities
Section titled “Import Utilities”For template import (converting existing templates to chant TypeScript):
import { BaseValueParser } from "@intentius/chant/import/base-parser";import { hasIntrinsicInValue, irUsesIntrinsic, collectDependencies } from "@intentius/chant/import/ir-utils";BaseValueParser— abstract base class for parsing template values into IR nodeshasIntrinsicInValue(value)— check if a raw value contains intrinsic function callsirUsesIntrinsic(node, name)— check if an IR node uses a specific intrinsiccollectDependencies(ir)— collect all resource dependencies from an IR tree
Intrinsic Interpolation
Section titled “Intrinsic Interpolation”For lexicons with string interpolation intrinsics (like CloudFormation’s Fn::Sub):
import { buildInterpolatedString, defaultInterpolationSerializer } from "@intentius/chant/intrinsic-interpolation";
const result = buildInterpolatedString(templateString, variables);Next Steps
Section titled “Next Steps”With generation working, the next step is to create a serializer that converts evaluated resources to your target format.