Skip to content
internal/gen
On this page

Auto-generating a project's documentation: one reference page per module or package, the generated index, the CLI reference pages and the root templates.

#internal/gen

#internal/gen

Package gen auto-generates documentation pages from a project's structure.

Two artifacts come out of it. GenerateDocs walks the declared source paths and writes one Markdown reference page per module (Python, TypeScript and the other per-file languages) or per package (Go), plus a generated index page, plus the CLI reference pages for a strictcli-based project. GenerateRootFiles resolves the underscore-prefixed templates a project declares in root_files and writes the project root's own files -- README.md, CLAUDE.md -- from them.

#Machine text is a placeholder, handwritten text is not

Every page this package writes is read-only (0444) and carries a generated: true marker, and only a file carrying that marker is ever overwritten or swept as stale. A page's frontmatter description is the one field a person is expected to rewrite: it is preserved verbatim unless the ownership predicate says the current text is machine residue -- the module template, a legacy index phrase, or the seed hash recorded for that page in the staleness store. The seeded: true marker is an output, never an input to that decision: a page whose description was hand-rewritten while the marker stayed behind keeps its text.

#GenResult

Go go
type GenResult struct

GenResult is what one GenerateDocs call did: the pages it wrote and the stale pages it deleted, each path relative to the docs directory (and prefixed with the locale subdirectory for a multi-locale project).

#GenerateDocs

Go go
func GenerateDocs(config map[string]any, baseDir, versionOverride string, handle *effects.Handle) (GenResult, error)

GenerateDocs auto-discovers a project's source files and generates its documentation pages.

Source entries are grouped by language and one generation pass runs per group; the stale sweep runs once afterwards, so one language's output is never deleted by another language's pass. For a multi-locale project the pages are generated under docs// for each declared locale; a single-locale project with no locale subdirectory generates into docs/ directly.

A project that declares no source entries is an error: every page written here is derived from source code, so there is nothing to write and an "API reference index covering 0 modules" would be an empty artifact that reads like a real reference page. A caller that knows the project is codeless skips this call and generates only its root files.

versionOverride, when non-empty, is recorded on config under the runtime version-override key, which is what the var directive reads for project.version. It is set here as well as in GenerateRootFiles because config is the one object that reaches every directive resolver, and the two calls share it.

#FileToModulePath

Go go
func FileToModulePath(filePath, baseDir, language string) (string, bool)

FileToModulePath converts a source file path to the module or package path a ref directive names, relative to baseDir (the project root).

Python drops a trailing /__init__ and joins the rest with dots, so mylib/config.py becomes mylib.config and mylib/__init__.py becomes mylib. Every other language keeps the path separators, so pkg/handler.go becomes pkg/handler and src/utils.ts becomes src/utils.

It reports false for a path with no module path at all -- the project root's own __init__.py, whose package is the project directory rather than any importable name.

#ModuleToFilename

Go go
func ModuleToFilename(modulePath, language string) string

ModuleToFilename converts a module path to the Markdown filename its page is written to, replacing Python's dots or every other language's slashes with dashes: selfdoc.config becomes selfdoc-config.md, pkg/handler becomes pkg-handler.md.

#GenerateRootFiles

Go go
func GenerateRootFiles(config map[string]any, baseDir, versionOverride string, handle *effects.Handle) ([]string, error)

GenerateRootFiles resolves a project's root-file templates and writes them to the project root.

config's root_files key lists the templates (paths like "docs/_CLAUDE.md"). Each one's basename must start with an underscore, which the output name drops: docs/_CLAUDE.md generates CLAUDE.md. The template's frontmatter is dropped, its directives are resolved through the project's own resolver, and the result is written read-only (0444) under the auto-generated header.

Every directive's attributes are validated BEFORE anything is resolved, so an unknown or a missing required attribute is a hard error naming the template and the true line in it -- the same refusal selfdoc check makes, rather than a page that renders an error marker where its content belongs.

An existing output file whose first line is not the auto-generated header is never overwritten: that is a hard error naming the exact header line to add in order to adopt the file.

versionOverride, when non-empty, is recorded on config under the runtime version-override key, which is what the var directive reads for project.version.

It returns the output names, relative to baseDir.

Search