selfdoc v0.37.1 /selfdoc.gen
On this page

Auto-generate documentation pages and root files from project structure, scanning source code modules and using directive-powered templates.

#selfdoc.gen

#selfdoc.gen

Auto-generate documentation pages from project structure.

#GenResult

Result of a generate_docs call, tracking written and deleted files.

#_should_skip_dir

python
def _should_skip_dir(dirname)

Return True if a directory name should be pruned during source walks.

#_has_generated_marker

python
def _has_generated_marker(filepath)

Check whether a Markdown file has generated: true in its frontmatter.

Returns True if the file starts with --- frontmatter containing generated: true, False otherwise (including when the file does not exist or cannot be read).

#_file_to_module_path

python
def _file_to_module_path(file_path, base_dir, language)

Convert a source file path to a module/package path string.

The path is computed relative to base_dir (the project root) so that the resulting module path matches what :-: ref path="..." expects.

For Python: mylib/config.py -> mylib.config For Go: pkg/handler.go -> pkg/handler For TypeScript/JavaScript: src/utils.ts -> src/utils

#_module_to_filename

python
def _module_to_filename(module_path, language)

Convert a module path to a Markdown filename for docs/.

Replaces dots (Python) or slashes (Go/TS/JS) with dashes. E.g. selfdoc.config -> selfdoc-config.md E.g. pkg/handler -> pkg-handler.md

#_staleness_store_key

python
def _staleness_store_key(config, locale_dir_code, filename)

Compute the hashes.json key for a generated page.

Mirrors the locale-prefixing that build.py and check.py apply so that gen writes seed_hash under the same key those layers read/write. When locales are configured, keys are prefixed with the first locale's code (matching check_docs); locale_dir_code is the subdirectory a page was written under ("" for single-locale projects without a locale subdir).

#_read_go_module_name

python
def _read_go_module_name(base_dir)

Read the module name from go.mod in base_dir.

Returns the last path segment of the module path (e.g. "myapp" from "github.com/user/myapp"), or None if go.mod is missing or unparseable.

#_go_root_package_name

python
def _go_root_package_name(base_dir)

Determine the filename stem for the root Go package.

Reads the module name from go.mod; falls back to the project directory basename.

#_collect_go_packages

python
def _collect_go_packages(source_paths, base_dir, exclude_patterns)

Walk source paths and group .go files by parent directory (package).

Returns a list of (module_path, pkg_dir_abs) tuples sorted by module_path. Excludes test files and files matching exclude_patterns. The module_path is source-path-qualified: for a root package under router/, the module_path is "router" (not "."). For a sub-package middleware/ under router/, it is "router/middleware". This ensures uniqueness across multiple source paths.

#_is_excluded

python
def _is_excluded(rel_path, exclude_patterns)

Check whether a relative path matches any exclusion glob pattern.

Supports **/ prefix as "match at any depth" by stripping the prefix and testing against every path component and the basename. Plain patterns are matched against the full path, the basename, and each directory component.

#_read_existing_description

python
def _read_existing_description(filepath, module_name=None, seed_hash=None)

Return the hand-edited module-page description, or None to reseed.

Consults the ownership predicate rather than trusting the seeded: true frontmatter flag: a description is recomputed (returns None) only when it is machine-owned -- i.e. it matches the current/historical module template for module_name, or the recorded seed_hash. Any other text is a genuine hand edit and is preserved verbatim, EVEN IF a stale seeded: true flag is still present (the "human rewrote but forgot to remove seeded:true" trap is dead).

#_generate_page_content

python
def _generate_page_content(module_name, module_path, nav_order, existing_description=None, docstring_description=None, language=None)

Build the Markdown content for a generated documentation page.

If existing_description is provided, it is used verbatim as the page's description frontmatter value. Otherwise, if docstring_description is provided (extracted from the module's docstring), it is used. Finally, if neither is available, the default auto-generated template is used.

When the description is auto-generated (not from existing_description), seeded: true is added to frontmatter to indicate the description was machine-generated and hasn't been hand-edited.

language is emitted as a lang attribute on the ref directive to disambiguate in multi-language projects.

#_resolve_project_name

python
def _resolve_project_name(config, base_dir)

Resolve the project name for the API reference index description.

Resolution order (single source of truth: the config name key):

  1. Explicit top-level name in selfdoc.json wins.
  2. Otherwise, when there is exactly one source entry, derive the name

from it (an unambiguous single-source project): a root source path (. / / / empty) resolves to the project directory basename; any other single path resolves to its basename.

  1. Otherwise (zero or multiple source entries), return None -- the

name is ambiguous, and a generic count-only description is used instead. Generic beats wrong.

#_read_existing_index_description

python
def _read_existing_index_description(filepath, seed_hash=None)

Return the hand-edited gen-index description, or None to reseed.

Consults the ownership predicate: returns None (recompute + add seeded: true) when the description is machine-owned -- i.e. it matches the current index format, a KNOWN legacy machine-seed phrase, or the recorded seed_hash. Any other description is a genuine hand edit and is preserved verbatim, regardless of a stale seeded: true flag.

#_generate_index_content

python
def _generate_index_content(generated_pages, project_name, existing_description=None)

Build the gen-index.md page listing all generated pages with links.

generated_pages is a list of (module_name, md_filename) tuples, already sorted by module name.

project_name is used to derive the auto-generated description. When it is None (an ambiguous multi-source project with no configured name), a generic count-only description with no project name is used instead -- generic beats wrong.

If existing_description is provided (from a hand-edited page), it is preserved verbatim. Otherwise, a content-aware description is generated from the project name and module count, and seeded: true is added to frontmatter.

#_remove_stale_generated

python
def _remove_stale_generated(docs_dir, new_filenames)

Delete previously generated files that are no longer in the new set.

Only removes files whose frontmatter contains generated: true.

Returns a list of deleted filenames (basenames, not full paths).

#_get_locale_docs_dirs

python
def _get_locale_docs_dirs(config, base_dir)

Return a list of (locale_code, docs_dir) for generation.

For single-locale projects without locale subdirectories, returns [("", docs_dir)] so generation goes to docs/ directly. For multi-locale projects, returns [(code, docs/code/), ...] for each configured locale.

#generate_docs

python
def generate_docs(config, base_dir='.')

Auto-discover project source files and generate documentation pages.

For multi-language projects, groups source entries by language and runs a generation pass for each language group. Stale cleanup runs once after all groups so one language's output is never deleted by another's pass.

For multi-locale projects, generates pages under docs/{locale_code}/ for each configured locale. For single-locale projects without locale subdirectories, generates directly under docs/.

Returns a GenResult with written and deleted file paths relative to the docs directory.

#_record_seed_hashes

python
def _record_seed_hashes(config, locale_code, locale_docs_dir, filenames, stored_hashes)

Record/clear per-page seed_hash for the pages gen wrote this run.

filenames is an iterable of basenames (relative to locale_docs_dir). Merges into stored_hashes in place, preserving all build/check-owned fields.

#_generate_docs_for_dir

python
def _generate_docs_for_dir(config, base_dir, language, extractor, docs_dir, source_paths, seed_hash_of=None)

Generate docs for a single language group in one directory.

source_paths is the list of source path strings for this language group (already extracted from config by the caller).

seed_hash_of is an optional callable mapping a page filename to its recorded seed_hash (from the staleness store), used to decide whether an existing machine-seeded description should be reseeded or preserved.

Stale cleanup and index generation are NOT done here -- the caller (generate_docs) handles them after all language groups have generated.

Returns a tuple of (GenResult, index_pages) where index_pages is a list of (module_name, md_filename) for the combined index page.

#_make_root_file_header

python
def _make_root_file_header(template_path)

Build the header comment for a generated root file.

#generate_root_files

python
def generate_root_files(config, base_dir='.')

Resolve root-file templates and write them to the project root.

Reads config["root_files"] (a list of template paths like "docs/_CLAUDE.md"). Each template is resolved via the project's directive resolver, then written with an auto-generated header and read-only (0o444) permissions.

Returns a list of output paths relative to base_dir.

Search