Rule Lifecycle
Phase 1: Entity collection
Section titled “Phase 1: Entity collection”The engine walks the input directory and builds a list of entities that match the current rule. Matching is by annotation ([[codegen::RuleName]]) or anchor comment (// [[codegen::generated::RuleName::...]]).
Phase 2: Grouping (optional)
Section titled “Phase 2: Grouping (optional)”If a RuleName.grouping.luau exists, the engine calls it once with the full entity list:
input: JSON { entities: [...all matched entities...] }output: JSON { "registryId1": "path/to/output.cpp", "registryId2": "path/to/other.cpp", ... }Without a grouping script, routing defaults to 1:1, each entity maps to an output path derived from its source file path.
Phase 3: Preamble
Section titled “Phase 3: Preamble”For each unique output path (as determined by grouping), the engine calls RuleName.preamble.luau once:
input: JSON {} (reserved for future use)output: string (raw text, prepended to the output file)Phase 4: Transformation
Section titled “Phase 4: Transformation”The engine calls RuleName.luau once per matched entity, in the order determined by grouping:
input: JSON { ...single entity AST node... }output: JSON { source: "...", inline: [...] }source: text appended to the entity’s assigned output file.inline: list of{ source: "..." }objects injected at the anchor site in the original header.
Phase 5: File write
Section titled “Phase 5: File write”The engine assembles each output file (preamble + concatenated entity sources) and writes them. For each entity that returned inline items, the original header is patched at the anchor comment.
Error handling
Section titled “Error handling”If any script call raises a Lua error, the engine:
- Logs the error with the entity identifier and source location.
- Skips writing output for that entity.
- Continues processing remaining entities.
- Exits with a non-zero status code after all entities are processed.
This means a single bad entity does not abort the entire run, useful during incremental rule development.
- Grouping runs once with all entities. Preamble runs once per unique output path. Transformation runs once per entity.
- A rule with no grouping script uses 1:1 routing.
- Script errors are per-entity, one failure does not abort the run.
- The
inlinereturn field patches the original header at the anchor comment.