/skills/fuz-stack/references/code-generation
  • docs
  • skills
  • fuz-stack
    • Code Generation
    • CSS Patterns
    • Database Query Patterns
    • Dependency Injection
    • Documentation System
    • fuz_util
    • mdz — Strict Markdown Dialect
    • Approved npm Dependencies
    • Path References in Documentation
    • Approved Rust Dependencies
    • Rust Patterns for the Fuz Ecosystem
    • Rust Performance Patterns
    • Rust Spine & Consumer Servers
    • Svelte 5 Patterns
    • Task Patterns
    • Testing Patterns
    • TSDoc Comment Style Guide
    • Twin Implementations (TS ↔ Rust)
    • WASM Patterns
    • Zod Schemas
  • grimoire
  • tools
  • hash

Code Generation

Gro's .gen.* files produce source at build time; output is committed alongside source and gro gen --check (part of gro check) fails on drift. Two former gen targets are now Vite plugins — fuz_css utility classes (vite_plugin_fuz_css → virtual:fuz.css) and API metadata (svelte-docinfo → virtual:svelte-docinfo, ./documentation-system) — so most projects have few or no gen files; the live ones are listed under §Patterns.

File Naming

Drop the .gen. segment to get the output: theme.gen.css.ts → theme.css, README.gen.md.ts → README.md, foo.gen.ts → foo.ts. The source is always .ts; an optional extension between .gen. and .ts sets the output extension. Exactly one .gen. segment, at most one extension after it, and the output name can't equal the gen name.

The gen Export

A gen file exports gen: a function from GenContext to RawGenResult (or a promise of one), or a {generate, dependencies?} config object. Types come from @fuzdev/gro/gen.ts (Gen, GenContext also re-exported from @fuzdev/gro).

// theme.gen.css.ts — fuz_css's base theme import type { Gen } from '@fuzdev/gro'; import { default_themes } from './themes.ts'; import { render_style_variables } from './theme.ts'; import { default_variables } from './variables.ts'; /** @nodocs */ export const gen: Gen = ({ origin_path }) => { const banner = `/** * generated by ${origin_path} -- DO NOT EDIT DIRECTLY! * * This file contains all style variables. For optimized output that includes only * the variables your code uses, use the Vite plugin or Gro generator instead: * * import 'virtual:fuz.css'; // Vite plugin - recommended * import './fuz.css'; // Gro generator * * Direct import of this file is for utility-only mode or non-bundled usage. * See: https://css.fuz.dev/docs/classes */`; const theme = default_themes[0]!; // the default theme's variables are the system's defaults, so they render // into the base layer; runtime theme overrides beat them from fuz.theme. // the theme itself is empty (it inherits the defaults), so the full set is // rendered as a variable set - the internal ramp variables included, which // a theme can't carry const theme_style = render_style_variables(default_variables, { comments: true, layer: 'fuz.base' }); return `${banner} /* theme: ${theme.name} */ ${theme_style} ${banner} `; };

GenContext: origin_id (absolute path), origin_path (project-relative; use it in generated-by banners), config (GroConfig), svelte_config (lazy promise), filer (filesystem tracker — reading source files), log, timings, invoke_task, and changed_file_id (set only during dependency resolution).

RawGenResult = string | RawGenFile | null | Array<RawGenResult>:

  • string — one file at the default name
  • {content, filename?, format?} — filename overrides the output (relative to the gen file's directory, or absolute — blog.gen.ts writes static/blog/feed.xml); format: false skips the formatter
  • null — skip generation
  • array (nested arrays flatten) — many files from one gen; duplicate output IDs within one gen file are invalid

Dependencies

Without dependencies, a gen re-runs in watch mode only when the gen file or its imports change (tracked by filer). Use the config form for broader triggers:

export const gen: Gen = { generate: ({ origin_path }) => { /* ... */ }, dependencies: { patterns: [/\.svelte$/, /\.ts$/], files: ['src/lib/theme_highlight.css'] } };

dependencies is 'all' (any change — for gens over the whole source tree, e.g. fuz_css's css_classes_fixture.gen.json.ts → css_classes_fixture.json snapshot of its class definitions), a {patterns, files} config (patterns test absolute paths; files may be relative), or a resolver (ctx) => config | 'all' | null that reads ctx.changed_file_id.

CLI

gro gen # all gen files in src/ gro gen src/lib/ # a directory gro gen src/lib/foo.gen.ts # one file gro gen --check # verify no drift (CI)

Positional args default to ['src']; --root_dirs (default [process.cwd()]) resolves them.

Patterns in the Ecosystem

  • Re-exported gens — fuz_blog ships blog.gen.ts (Atom feed, feed data, one +page.svelte per slug); consumers re-export it with export * from '@fuzdev/fuz_blog/blog.gen.ts'.
  • Codegen from runtime registries — zzz reads all_action_specs to emit typed method enums, metatypes, and handler interfaces, delegating to fuz_app's @fuzdev/fuz_app/actions/action_codegen.ts helpers (compose_gen_file, generate_action_method_enums, …).
  • Route-tree generation — fuz_docs's skill_docs.gen.ts discovers skills and returns a manifest, per-skill data files, and +page.svelte routes from one gen.
  • Task registry — a src/gro_tasks.gen.ts exporting gro's gen_task_registry writes the ProjectTasks augmentation that types invoke_task for the project's own tasks (./task-patterns); svelte-docinfo is the exemplar.