Gro's code generation system (.gen.* files) in @fuzdev/gro.
Gen files produce source code at build time. Discovered by the .gen.
filename pattern, executed by gro gen, output committed alongside source.
gro gen --check verifies no drift.
Output file is produced by dropping the .gen. segment:
| Gen file | Output file |
|---|---|
theme.gen.css.ts | theme.css |
css_classes_fixture.gen.json.ts | css_classes_fixture.json |
README.gen.md.ts | README.md |
auth_attack_surface.gen.json.ts | auth_attack_surface.json |
The gen source file always has a .ts extension (.gen.ts, .gen.css.ts, …).
An optional extension between .gen. and .ts overrides the output extension.
.gen. segment per filename (duplicates are invalid).gen. (.gen.css.ts is valid, .gen.foo.bar.ts is not)A gen file exports a gen value — either a function or a config object:
type Gen = GenFunction | GenConfig;Both importable from @fuzdev/gro or @fuzdev/gro/gen.ts.
type GenFunction = (ctx: GenContext) => RawGenResult | Promise<RawGenResult>;// theme.gen.css.ts — simple form
import type {Gen} from '@fuzdev/gro';
export const gen: Gen = ({origin_path}) => {
const banner = `/* generated by ${origin_path} */`;
return `${banner}\n:root { --my-var: 1; }\n`;
};interface GenConfig {
generate: GenFunction;
dependencies?: GenDependencies;
}// highlight_priorities.gen.ts — config form with dependencies
import type {Gen} from '@fuzdev/gro';
export const gen: Gen = {
generate: ({origin_path}) => {
return `// generated by ${origin_path}\nexport const data = {};\n`;
},
dependencies: {files: ['src/lib/theme_highlight.css']},
};| Property | Type | Description |
|---|---|---|
origin_id | PathId | absolute path of the gen file |
origin_path | string | origin_id relative to the project root |
config | GroConfig | the project's Gro configuration |
svelte_config | ParsedSvelteConfig | parsed svelte.config.js |
filer | Filer | filesystem tracker (file contents, dependency graph) |
log | Logger | scoped logger |
timings | Timings | performance measurement |
invoke_task | InvokeTask | invoke other Gro tasks |
changed_file_id | PathId \| undefined | set during dependency resolution; undefined during generation |
Most used: origin_path (generated-by banners), log, and filer
(reading source files).
type RawGenResult = string | RawGenFile | null | Array<RawGenResult>;export const gen: Gen = () => {
return '// generated content\n';
};
// theme.gen.css.ts → writes theme.cssinterface RawGenFile {
content: string;
filename?: string; // override output name (can be relative or absolute path)
format?: boolean; // run the formatter (default: true)
}export const gen: Gen = () => {
return {content: '{"key": "value"}', filename: 'data.json', format: false};
};Relative filename resolves from the gen file's directory. Absolute paths
write to that exact location (e.g., blog.gen.ts writes static/blog/feed.xml).
export const gen: Gen = (ctx) => {
if (some_condition) return null; // produce no output
return 'content';
};Nested arrays are flattened:
export const gen: Gen = () => {
return [
{content: 'export const A = 1;', filename: 'a.ts'},
{content: 'export const B = 2;', filename: 'b.ts'},
];
};Duplicate output file IDs within a single gen file are invalid. A single gen
file can produce many output files — e.g., skill_docs.gen.ts generates a
manifest, per-skill data files, and per-page +page.svelte routes.
Control when a gen file re-runs during watch mode. Without dependencies, it
re-runs only when the gen file or its imports change (tracked by filer). Use
GenConfig for broader triggers:
type GenDependencies = 'all' | GenDependenciesConfig | GenDependenciesResolver;For gen tasks that depend on the entire source tree rather than specific files:
export const gen: Gen = {
generate: async (ctx) => {
/* ... */
},
dependencies: 'all',
};export const gen: Gen = {
generate: ({origin_path}) => {
/* ... */
},
dependencies: {
patterns: [/\.svelte$/, /\.ts$/],
files: ['src/lib/theme_highlight.css'],
},
};patterns are tested against absolute paths. files can be relative
(resolved to absolute) or absolute.
Receives GenContext and returns a config, 'all', or null.
changed_file_id is set on context during dependency resolution:
type GenDependenciesResolver = (
ctx: GenContext,
) => GenDependenciesConfig | 'all' | null | Promise<GenDependenciesConfig | 'all' | null>;gro gen # run all gen files in src/
gro gen src/lib/ # run gen files in a specific directory
gro gen src/lib/foo.gen.ts # run a specific gen file
gro gen --check # verify no drift (used by gro check and CI)| Arg | Default | Description |
|---|---|---|
_ | ['src'] | input paths (files or directories to scan) |
--root_dirs | [process.cwd()] | root directories to resolve input paths against |
--check | false | exit nonzero if any generated files have changed |
gro gen --check compares generated output against existing files; if any is
new or changed, it fails with a message to run gro gen. Called by gro check
as part of CI.
fuz_css utility classes are no longer a gen task in most projects — the
vite_plugin_fuz_css Vite plugin scans source files, extracts CSS class usage
via AST, and exposes a bundled virtual:fuz.css module (with HMR) containing
only the classes, base styles, and theme variables actually used. See
./css-patterns §Project Setup.
The Gro generator equivalent, gen_fuz_css() in a fuz.gen.css.ts (accepts
GenFuzCssOptions), still writes a committed fuz.css file, but the plugin is
preferred.
fuz_css uses theme.gen.css.ts to generate the full base theme:
import type {Gen} from '@fuzdev/gro';
import {default_themes} from './themes.ts';
import {render_theme_style} from './theme.ts';
export const gen: Gen = ({origin_path}) => {
const banner = `/* generated by ${origin_path} */`;
const theme = default_themes[0]!;
const theme_style = render_theme_style(theme, {
comments: true,
empty_default_theme: false,
specificity: 1,
});
return `${banner}\n${theme_style}\n`;
};API documentation metadata is no longer produced by a gen task. Instead the
svelte-docinfo Vite plugin analyzes TypeScript and Svelte source files at
build/dev time and exposes the result through virtual:svelte-docinfo. Add the
plugin in vite.config.ts and build a LibraryJson at runtime with
library_json_from_modules — see ./documentation-system for the full setup.
// vite.config.ts
import svelte_docinfo from 'svelte-docinfo/vite.js';
// ...plugins: [sveltekit(), svelte_docinfo()]There is no committed library.gen.ts, library.json, or library.ts.
fuz_blog provides blog.gen.ts for Atom feeds, feed data, and slug routes:
export * from '@fuzdev/fuz_blog/blog.gen.ts';Consumer projects re-export the gen. Returns an array of feed.xml (at an
absolute path in static/), feed.ts, and one +page.svelte per slug route.
Test fixtures can use gen files for snapshot data:
import type {Gen} from '@fuzdev/gro';
import {create_tx_app_surface_spec} from './auth_attack_surface_helpers.ts';
export const gen: Gen = () => {
return JSON.stringify(create_tx_app_surface_spec().surface);
};
// auth_attack_surface.gen.json.ts → auth_attack_surface.jsonGen files can generate TypeScript types from runtime registries. zzz reads action specs to produce typed collections, metatypes, and handler interfaces:
import type {Gen} from '@fuzdev/gro/gen.ts';
import {all_action_specs} from './action_specs.ts';
export const gen: Gen = ({origin_path}) => `
// generated by ${origin_path}
export const ActionMethods = [
${all_action_specs.map((s) => `'${s.method}'`).join(',\n')}
] as const;
`;zzz's real generators delegate the heavy lifting to fuz_app's
@fuzdev/fuz_app/actions/action_codegen.ts helpers (compose_gen_file,
generate_action_method_enums, …) over all_action_specs.
A single gen file can generate entire route trees. skill_docs.gen.ts
auto-discovers skills and generates manifests, data files, and +page.svelte routes:
import type {Gen} from '@fuzdev/gro/gen.ts';
export const gen: Gen = ({origin_path}) => {
// ... discover skills, read markdown ...
return [
{content: manifest_content, filename: 'skills_manifest.ts'},
{content: skill_data, filename: join(skill_route_dir, 'skill_data.ts')},
{content: page_content, filename: join(skill_route_dir, '+page.svelte')},
// ... more files
];
};| Export | Type | Source | Purpose |
|---|---|---|---|
Gen | Type | @fuzdev/gro/gen.ts | GenFunction or GenConfig |
GenFunction | Type | @fuzdev/gro/gen.ts | (ctx: GenContext) => RawGenResult |
GenConfig | Interface | @fuzdev/gro/gen.ts | generate + optional dependencies |
GenContext | Interface | @fuzdev/gro/gen.ts | context passed to gen functions |
RawGenResult | Type | @fuzdev/gro/gen.ts | string, RawGenFile, null, or nested array |
RawGenFile | Interface | @fuzdev/gro/gen.ts | output file with content, filename, format |
GenDependencies | Type | @fuzdev/gro/gen.ts | 'all', config object, or resolver function |
GenDependenciesConfig | Interface | @fuzdev/gro/gen.ts | patterns? (RegExp[]) and files? (PathId[]) |
Gen and GenContext are also re-exported from @fuzdev/gro (the package
index).