selfdoc

Auto-generate API documentation from source code using inline directives

API Reference

selfdoc

selfdoc: Code-aware static site generator with directive-based content extraction.

_detect_version

def _detect_version()

Detect package version, preferring pyproject.toml over installed metadata.

Order: pyproject.toml in the source tree (accurate during editable installs) -> importlib.metadata (works for regular installs) -> "unknown".

main

def main()

Entry point for the selfdoc CLI.

selfdoc.build

Build pipeline for selfdoc: template scanning, directive resolution, HTML output.

_stub_resolver

def _stub_resolver(name, arg, body)

Placeholder resolver that produces a visible unresolved marker.

build

def build(dir_path='.', config=None)

Build docs from templates + directives.

  1. Load config from selfdoc.json
  2. Scan docs/ directory for .md template files
  3. For each template, resolve directives using language-specific extractor
  4. Convert resolved markdown to HTML
  5. Write HTML to output directory
  6. Copy non-.md files (images, CSS, etc.) to output

Args: dir_path: Project root directory. config: Pre-loaded config dict (if None, loads from selfdoc.json).

Returns: Dict of {output_path: True} for files written.

selfdoc.check

Check command -- validate directives and report documentation coverage.

Scans docs/ templates for directives, attempts to resolve each one, and reports per-directive status (OK or FAILED). For Python projects, also computes coverage: how many public symbols are referenced by :::module directives vs. the total public symbols in source files.

DirectiveResult

Result of validating a single directive.

CoverageStats

Coverage of public symbols by :::module directives.

CheckResult

Aggregate result of check_docs().

check_docs

def check_docs(dir_path='.', config=None)

Validate all directives in docs templates and report coverage.

Scans docs/ for .md templates, parses directives, attempts to resolve each one, and computes coverage for Python projects.

Args: dir_path: Project root directory. config: Pre-loaded config dict (if None, loads from selfdoc.json).

Returns: CheckResult with per-directive results and optional coverage stats.

_compute_python_coverage

def _compute_python_coverage(config, base_dir, referenced_modules)

Count public symbols in source files vs. those referenced by directives.

A "public symbol" is a top-level function or class whose name does not start with underscore. Each :::module directive that resolves to a file counts all public symbols in that file as "documented".

_extract_public_symbols

def _extract_public_symbols(filepath)

Parse a Python file and return names of public top-level functions/classes.

_resolve_module_to_relpath

def _resolve_module_to_relpath(arg, source_paths, base_dir)

Resolve a module argument to a path relative to base_dir.

Mirrors the resolution logic in extractors/python.py but returns the relative path instead of the absolute path.

print_results

def print_results(result)

Print check results to stdout in a human-readable format.

selfdoc.cli

CLI interface for selfdoc.

_detect_language

def _detect_language()

Auto-detect project language from project files.

Returns (language, source_paths) tuple or (None, None) if undetectable.

_detect_main_module

def _detect_main_module()

Detect the main module name for the starter template.

_cmd_init

def _cmd_init(args)

Initialize selfdoc in the current project.

_cmd_build

def _cmd_build(args)

Build the documentation site.

_cmd_serve

def _cmd_serve(args)

Serve the documentation site locally with SSE-based live reload.

_cmd_deploy

def _cmd_deploy(args)

Deploy the documentation site.

_detect_version

def _detect_version()

Detect project version from pyproject.toml or package.json.

_cmd_check

def _cmd_check(args)

Check documentation coverage and consistency.

run

def run()

Parse arguments and dispatch to the appropriate subcommand.

selfdoc.config

Config loader for selfdoc.json.

ConfigError

Raised when selfdoc.json is present but invalid.

_validate_deploy

def _validate_deploy(deploy)

Validate the deploy section if present.

Raises ConfigError if provider is unrecognized or required fields are missing.

load_config

def load_config(dir_path='.')

Load and validate selfdoc.json from dir_path.

Returns the validated config dict, or None if selfdoc.json does not exist. Raises ConfigError on malformed or invalid configuration.

selfdoc.deploy

Deploy providers for selfdoc documentation sites.

Supports:

DeployError

Raised when a deploy operation fails.

deploy_cloudflare_pages

def deploy_cloudflare_pages(output_dir, project_name, version)

Deploy to Cloudflare Pages using the Wrangler CLI.

Requires wrangler (Cloudflare CLI) to be installed and authenticated (via wrangler login or CLOUDFLARE_API_TOKEN env var).

Args: output_dir: Path to the built HTML output directory. project_name: Cloudflare Pages project name. version: Version string for the commit message.

Raises: DeployError: If wrangler is not installed or the deploy fails.

deploy_github_pages

def deploy_github_pages(output_dir, version)

Deploy to GitHub Pages by force-pushing output to gh-pages branch.

Uses a temporary directory to build a fresh commit without touching the current working tree. Creates a .nojekyll file to prevent Jekyll processing on GitHub.

Args: output_dir: Path to the built HTML output directory. version: Version string for the commit message.

Raises: DeployError: If git operations fail or remote is unreachable.

_run_git

def _run_git(args, cwd)

Run a git command in the given directory, raising DeployError on failure.

selfdoc.directives

Directive parser for :::name arg blocks in markdown files.

Directive syntax: :::name arg optional body lines :::

Directives inside fenced code blocks ( or ~~~) are ignored. Unclosed directives at EOF raise DirectiveError.

DirectiveError

Raised when a directive is malformed (e.g. unclosed at EOF).

Directive

A parsed directive block.

parse_directives

def parse_directives(content: str) -> list[Directive]

Extract all directive blocks from markdown content.

Returns a list of Directive dataclass instances in document order. Directives inside fenced code blocks are ignored. Raises DirectiveError if a directive is opened but never closed.

resolve_directives

def resolve_directives(content: str, resolver: callable) -> str

Replace each directive block with the output of resolver(name, arg, body).

Non-directive content passes through unchanged. Directives inside fenced code blocks are left as-is (they are not directives).

selfdoc.html

Convert Markdown files to static HTML with a built-in minimal converter.

No external dependencies -- handles headings, code blocks, inline code, paragraphs, lists, links, bold/italic, and tables.

generate_html

def generate_html(markdown_files, project_name=None, version=None)

Convert Markdown files to static HTML.

Args: markdown_files: Dict mapping relative paths to MD content. project_name: Project name for titles and sidebar. version: Version string for display (optional).

Returns: Dict mapping file paths (.html) to HTML content.

md_to_html

def md_to_html(text)

Convert Markdown text to HTML.

Handles: headings, code blocks, inline code, paragraphs, unordered lists, ordered lists, links, bold, italic, tables.

_parse_table

def _parse_table(table_lines)

Parse markdown table lines into an HTML

.

Expects lines like:

Header1Header2
Cell1Cell2

The separator line (containing only |, -, and spaces) is detected and used to separate header from body rows.

_inline_format

def _inline_format(text)

Apply inline formatting: links, bold, italic, inline code.

_escape_html

def _escape_html(text)

Escape HTML special characters.

_md_to_html_path

def _md_to_html_path(md_path)

Convert a .md path to .html.

_build_nav

def _build_nav(markdown_files)

Build navigation items from the markdown file list.

Returns list of dicts: {"label": str, "path": str (html path)}

_render_nav

def _render_nav(nav_items, prefix, current_path='')

Render the sidebar navigation HTML.

_extract_title

def _extract_title(md_content, fallback)

Extract the first heading from markdown content as the page title.

_wrap_page

def _wrap_page(body_html, nav_html, title, project_name, version)

Wrap converted HTML body in the full page template.

selfdoc.resolver

Resolver factory -- dispatches directives to language-specific extractors.

_load_custom_directive

def _load_custom_directive(script_path, name)

Dynamically import a custom directive script and return its module.

Args: script_path: Absolute path to the Python script. name: Directive name (used as the module name for importlib).

Returns: The loaded module, or None if loading fails.

Raises: FileNotFoundError: If the script file does not exist. AttributeError: If the module has no 'resolve' callable. Exception: Any other import/load error.

make_resolver

def make_resolver(config, base_dir='.')

Create a resolver function for the project's language.

Custom directives from config["directives"] take priority over built-in language extractors. Each entry maps a directive name to a relative path (from project root) of a Python script that exports resolve(arg, config).

Args: config: Validated config dict from selfdoc.json. base_dir: Project root directory (for resolving relative paths).

Returns: A callable(name, arg, body) -> str that resolves directives to markdown.

extractors

selfdoc.extractors

selfdoc.extractorsthon

Python source extractor -- resolves directives by extracting from .py files.

Uses stdlib ast for parsing, no external dependencies. Handles:

resolve_python

def resolve_python(name, arg, body, source_paths, base_dir)

Dispatch a directive to the appropriate Python extraction handler.

Args: name: Directive name (module, test, schema, cli, config). arg: Directive argument (path, module name, etc.). body: Body lines of the directive block. source_paths: List of source directories from selfdoc.json. base_dir: Project root directory.

Returns: Markdown string with the extracted content.

_handle_module

def _handle_module(arg, body, source_paths, base_dir)

Extract module docstring, functions, and classes.

Resolves dotted.path or file path to a .py file, parses with ast, and formats the result as markdown.

_resolve_module_path

def _resolve_module_path(arg, source_paths, base_dir)

Try to resolve a module argument to an actual .py file path.

Tries: dotted-to-path conversion within each source path, then direct path.

_format_function

def _format_function(node, heading_level=2)

Format a function/method node as markdown.

Skips private items (leading _) unless they have a docstring.

_format_class

def _format_class(node)

Format a class node as markdown, including its public methods.

_build_signature

def _build_signature(node)

Build a human-readable function signature string from ast.arguments.

_annotation_str

def _annotation_str(node)

Convert an annotation AST node to a string, or empty string if None.

_handle_test

def _handle_test(arg, body, source_paths, base_dir)

Extract test source code from a test file.

arg format: [TestClassName or test_function_name]

_extract_node_source

def _extract_node_source(source_lines, node)

Extract source lines for an AST node, stripping common indent.

_handle_schema

def _handle_schema(arg, body, source_paths, base_dir)

Extract schema information from JSON or Python dataclass.

arg format: - path/to/file.json -> render JSON keys as table - dotted.module ClassName -> extract dataclass fields

_schema_from_json

def _schema_from_json(file_path, base_dir)

Render a JSON file as a documented table of keys, types, and values.

_json_type_name

def _json_type_name(value)

Get a human-readable type name for a JSON value.

_json_value_repr

def _json_value_repr(value)

Get a compact representation of a JSON value for table display.

_schema_from_dataclass

def _schema_from_dataclass(module_path, class_name, source_paths, base_dir)

Extract dataclass/class fields with types and defaults from source.

_extract_class_fields

def _extract_class_fields(class_node, source)

Extract fields from a class (dataclass or regular class with annotations).

Produces a markdown table with Field, Type, Default, and Description columns.

_get_inline_comment

def _get_inline_comment(source_lines, lineno)

Extract an inline # comment from a source line (1-based lineno).

_format_default

def _format_default(default_str)

Format a default value for table display.

_handle_cli

def _handle_cli(arg, body, source_paths, base_dir)

Extract CLI help/usage information from a module.

For v1: extracts the module docstring and any string constants named HELP or USAGE, formatted as a code block.

_handle_config

def _handle_config(arg, body, source_paths, base_dir)

Extract config file contents as a documented table.

Supports JSON and TOML. Detects format from file extension.

_config_from_json

def _config_from_json(full_path, display_path)

Parse JSON config and render as a key-value table.

_config_from_toml

def _config_from_toml(full_path, display_path)

Parse TOML config and render as a key-value table.

_flatten_toml

def _flatten_toml(data, prefix, rows)

Recursively flatten TOML data into table rows.

selfdoc.extractors.go

Go source extractor -- resolves directives by extracting from .go files.

Uses regex-based parsing (no Go toolchain required). Handles:

resolve_go

def resolve_go(name, arg, body, source_paths, base_dir)

Dispatch a directive to the appropriate Go extraction handler.

Args: name: Directive name (module, test, schema, cli, config). arg: Directive argument (path, package name, etc.). body: Body lines of the directive block. source_paths: List of source directories from selfdoc.json. base_dir: Project root directory.

Returns: Markdown string with the extracted content.

_handle_module

def _handle_module(arg, body, source_paths, base_dir)

Extract package doc, exported funcs, types, consts, and vars.

arg is a package directory path (e.g. "internal/commit"). Finds all .go files in that directory (excluding _test.go), extracts the package doc comment and all exported declarations.

_resolve_package_dir

def _resolve_package_dir(arg, source_paths, base_dir)

Resolve a package path argument to an actual directory.

Tries each source_path prefix, then the base_dir directly.

_extract_package_doc

def _extract_package_doc(file_contents)

Extract the package name and doc comment from Go source files.

The package doc is the contiguous // comment block immediately above the package declaration. Returns (package_name, doc_string).

_collect_comment_block_above

def _collect_comment_block_above(lines, target_line_idx)

Collect contiguous // comment lines immediately above target_line_idx.

Skips blank lines between the comment block and the declaration. Returns the comment text with // prefixes stripped.

_extract_exported_declarations

def _extract_exported_declarations(source)

Extract all exported declarations from a Go source file.

Returns a list of dicts with keys: kind, name, signature, doc.

_extract_const_block

def _extract_const_block(lines, block_start_idx, declarations, seen_names)

Extract exported constants from a const (...) block.

The doc comment for the entire block is attached to the first exported constant. Individual constants may also have their own // comments.

_extract_var_block

def _extract_var_block(lines, block_start_idx, declarations, seen_names)

Extract exported variables from a var (...) block.

_handle_test

def _handle_test(arg, body, source_paths, base_dir)

Extract test source code from a Go test file.

arg format: [TestFuncName]

_resolve_file_path

def _resolve_file_path(file_path, source_paths, base_dir)

Resolve a file path relative to base_dir or source_paths.

_extract_go_function

def _extract_go_function(source, func_name)

Extract a complete function from Go source by name.

Uses brace-counting to find the function body boundaries.

_handle_schema

def _handle_schema(arg, body, source_paths, base_dir)

Extract struct type fields as a markdown table.

arg format: [TypeName] If TypeName is omitted, extracts the first exported struct found.

_extract_structs

def _extract_structs(source)

Extract all exported struct type declarations from Go source.

Returns a list of dicts: {name, doc, fields: [{name, type, tag, comment}]}.

_parse_struct_field

def _parse_struct_field(field_line, lines, line_idx)

Parse a single struct field line.

Returns {name, type, tag, comment} or None if not a field.

_format_struct_table

def _format_struct_table(struct_info)

Format a struct's fields as a markdown table.

_handle_cli

def _handle_cli(arg, body, source_paths, base_dir)

Extract CLI usage/help text and flag definitions from Go source.

Looks for:

_extract_usage_constants

def _extract_usage_constants(source)

Find string constants/functions that return usage text.

Looks for patterns like:

_extract_flag_calls

def _extract_flag_calls(source)

Extract flag.XxxVar and flag.Xxx calls from Go source.

Returns list of {name, type, default, desc}.

_handle_config

def _handle_config(arg, body, source_paths, base_dir)

Extract config file contents as a documented table.

Supports JSON and TOML. Detects format from file extension. Delegates to the same logic as the Python extractor.

_config_from_json

def _config_from_json(full_path, display_path)

Parse JSON config and render as a key-value table.

_config_from_toml

def _config_from_toml(full_path, display_path)

Parse TOML config and render as a key-value table.

_flatten_toml

def _flatten_toml(data, prefix, rows)

Recursively flatten TOML data into table rows.

_json_type_name

def _json_type_name(value)

Get a human-readable type name for a JSON value.

_json_value_repr

def _json_value_repr(value)

Get a compact representation of a JSON value for table display.

selfdoc.extractors.typescript

TypeScript/JavaScript source extractor -- resolves directives by extracting from .ts/.js files.

Uses regex-based parsing (no external dependencies). Handles:

resolve_typescript

def resolve_typescript(name, arg, body, source_paths, base_dir)

Dispatch a directive to the appropriate TypeScript/JS extraction handler.

Args: name: Directive name (module, test, schema, cli, config). arg: Directive argument (path, type name, etc.). body: Body lines of the directive block. source_paths: List of source directories from selfdoc.json. base_dir: Project root directory.

Returns: Markdown string with the extracted content.

_resolve_file_path

def _resolve_file_path(arg, source_paths, base_dir)

Resolve a file path argument to an actual TS/JS file on disk.

Tries the arg as-is (relative to base_dir and each source path), then with common extensions appended.

_read_file

def _read_file(filepath)

Read a file and return its contents, or raise an error string.

_parse_jsdoc_text

def _parse_jsdoc_text(raw_jsdoc)

Parse raw JSDoc content (the lines between /* and /).

Returns a dict with: - description: the main description text - params: list of {name, description} - returns: return description or None - tags: list of {tag, name, description} for other tags

_find_jsdoc_before

def _find_jsdoc_before(source, pos)

Find the JSDoc block that ends right before pos in the source.

Looks backwards from pos for a / that's part of a / ... / block, allowing only whitespace between the end of the JSDoc and pos.

_format_jsdoc_as_markdown

def _format_jsdoc_as_markdown(jsdoc)

Format a parsed JSDoc dict as markdown text.

_handle_module

def _handle_module(arg, body, source_paths, base_dir)

Extract module-level JSDoc and exported declarations from a TS/JS file.

_extract_module_jsdoc

def _extract_module_jsdoc(source)

Extract the first JSDoc block that appears before any declaration.

A module-level JSDoc is a /* / block at the top of the file, before any import/export/declaration.

_extract_exports

def _extract_exports(source)

Extract all exported declarations with their JSDoc and signatures.

Returns a list of dicts with: name, signature, jsdoc (parsed or None).

_extract_name_from_signature

def _extract_name_from_signature(sig)

Extract the declaration name from an export signature string.

_handle_test

def _handle_test(arg, body, source_paths, base_dir)

Extract test source code from a test file.

arg format: [TestName]

For TS/JS test files, looks for describe("TestName", ...), it("TestName", ...), or test("TestName", ...) blocks.

_extract_test_block

def _extract_test_block(source, target_name)

Find a describe/it/test block by name and extract its source.

Searches for patterns like: describe("Name", ... it("Name", ... test("Name", ... Then tracks brace depth to find the end of the block.

_handle_schema

def _handle_schema(arg, body, source_paths, base_dir)

Extract interface or type definition fields as a markdown table.

arg format: - path/to/file.json -> render JSON keys as table - path/to/file.ts TypeName -> extract interface/type fields - path/to/file.ts -> if only one interface, extract it

_schema_from_json

def _schema_from_json(file_path, base_dir)

Render a JSON file as a documented table of keys, types, and values.

_schema_from_ts

def _schema_from_ts(source, type_name, display_path)

Extract interface or type fields from TypeScript source as a markdown table.

_extract_brace_block

def _extract_brace_block(source, open_brace_pos)

Extract the content between matched braces starting at open_brace_pos.

Returns the content between { and } (exclusive), or None if unmatched.

_parse_interface_fields

def _parse_interface_fields(body)

Parse fields from an interface/type body string.

Each field looks like: fieldName: Type; fieldName?: Type; Possibly preceded by a JSDoc comment or inline comment.

_find_inline_comment

def _find_inline_comment(line)

Find the position of an inline // comment, ignoring those inside strings.

Returns the index of the // or None if no inline comment found.

_handle_cli

def _handle_cli(arg, body, source_paths, base_dir)

Extract CLI help/usage information from a TS/JS file.

Looks for:

_handle_config

def _handle_config(arg, body, source_paths, base_dir)

Extract config file contents as a documented table.

Supports JSON, JSONC (strips // and / / comments), and TOML.

_config_from_json

def _config_from_json(full_path, display_path)

Parse JSON config and render as a key-value table.

_config_from_jsonc

def _config_from_jsonc(full_path, display_path)

Parse JSONC config (strip comments) and render as a key-value table.

_strip_jsonc_comments

def _strip_jsonc_comments(text)

Strip // and / / comments from JSONC text, respecting strings.

_config_from_toml

def _config_from_toml(full_path, display_path)

Parse TOML config and render as a key-value table.

_flatten_toml

def _flatten_toml(data, prefix, rows)

Recursively flatten TOML data into table rows.

_render_json_table

def _render_json_table(data)

Render a JSON dict as a markdown key-value table.

_json_type_name

def _json_type_name(value)

Get a human-readable type name for a JSON value.

_json_value_repr

def _json_value_repr(value)

Get a compact representation of a JSON value for table display.