Skip to content

Latest commit

 

History

History
220 lines (165 loc) · 7.39 KB

CONTRIBUTING.md

File metadata and controls

220 lines (165 loc) · 7.39 KB

Contributing to doc-engine-cli

Contributions are welcome from anyone — bug reports, documentation fixes, new templates, and features are all useful. This guide covers what you need to know to get a change merged.

By participating, you agree to follow the Code of Conduct.


Ways to contribute

I want to... Go here
Report a bug Open an issue
Ask a question Discussions → Q&A
Suggest a feature Discussions → Ideas
Report a security issue Security policy — please do not open a public issue
Fix something yourself Read on

Getting set up

git clone https://github.com/leonardosalasd/doc-engine-cli.git
cd doc-engine-cli
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Check that the tool runs before changing anything:

python -m doc_engine --version
python -m pytest tests/ -v

Use python -m doc_engine rather than the bare doc-engine command while working on the project. If you already have a release installed, your shell can keep resolving doc-engine to that copy even inside the virtualenv, and you would end up testing the published version instead of your changes without anything saying so. Running it through python -m always uses the environment you are standing in. (hash -r usually settles the shell, and which doc-engine tells you which one you are about to run.)


Testing

Run the suite before opening a pull request:

python -m pytest tests/ -v

Test on more than one Python version. This matters more than it sounds: v1.1.0 shipped completely broken on Python 3.10 through 3.13 because it was only ever run on 3.14, where deferred annotation evaluation hid an import-time crash. CI now covers 3.10–3.14 on Linux, macOS, and Windows, but catching it locally is faster. If you have uv:

uv run --python 3.10 --no-project --with mistune --with click --with rich \
  --with typst --with mermaidx --with pillow --with tomli --with pytest \
  python -m pytest tests/ -q

Swap 3.10 for any version in the supported range.

New behavior needs a test. Bug fixes need a test that fails before the fix and passes after it — that is what stops the same bug from coming back.


Code style

Formatting and linting are handled by ruff, and CI checks both. Before opening a pull request:

ruff format doc_engine/ tests/
ruff check doc_engine/ tests/

Ruff settles the mechanical questions. The rest is convention — match the surrounding code:

  • Type hints on function signatures.
  • Module-level constants in SCREAMING_SNAKE_CASE, prefixed with _ when private.
  • Helper functions prefixed with _.
  • Tests grouped in classes named TestSomething, one behavior per method.
  • Docstrings where the why is not obvious from the code. Skip them where it is.
  • No decorative comment banners (# ====, # ----). If a comment is needed, write a sentence explaining the reasoning, not a divider.

Keep changes focused. A pull request that fixes one thing is easier to review, and far easier to revert if it turns out to be wrong.


Commit messages

The history uses Conventional Commits:

feat: add support for A4 page size
fix: prevent crash on legacy Windows consoles
docs: document the --watch flag
ci: test on Python 3.14
chore: bump version to 2.0.0

Write the subject in the imperative mood, under ~72 characters. If the change needs explanation, put it in the body: what was broken, why the fix works, and anything a future reader would need in order to not undo it by accident.


Pull requests

  1. Branch from main using a descriptive prefix: feat/, fix/, or docs/.
  2. Make your change, with tests.
  3. Run the suite and confirm it passes.
  4. Open the pull request against main.

Every pull request is reviewed by the repository owner (CODEOWNERS), and CI must be green before merging. CI runs the test suite across every supported Python version and operating system, a smoke job that installs the built package and drives the CLI from a clean directory, a lint and format check, and a build of the Docker image.

In the description, explain what changed and why. If it fixes an open issue, reference it with Fixes #123.


Adding a template

Templates live in doc_engine/templates/ as .typ files. Each one exposes a single setup_doc entry point, and the compiler passes it the document metadata:

#let setup_doc(
  title: "",
  subtitle: "",
  author: "Anonymous",
  date: datetime.today().display(),
  bibliography_file: none,
  accent: none,
  branding: true,
  version: "",
  paper: "a4",
  ..options,
  body,
) = { ... }

The quickest start is to copy an existing template and edit it. A new template should:

  • Honor accent when it is not none, and fall back to its own default color.
  • Honor branding: false by hiding the doc-engine attribution.
  • Pass paper through to set page, rather than hardcoding a size.
  • Render subtitle only when it is not empty.
  • Render the bibliography when bibliography_file is not none.
  • Keep the ..options sink, so a later release can add an option without breaking templates that have not been updated.
  • End every font stack in one Typst ships — New Computer Modern, Libertinus Serif, or DejaVu Sans Mono — so the document looks the same inside a bare container as it does on a laptop full of fonts.

Templates are discovered automatically, so dropping the file in is enough for --template <name> to find it. Add it to the templates table in the README and to the test in tests/test_cli.py that asserts the shipped set.


Project layout

Module Responsibility
cli.py Argument parsing, Git detection, watch loop, output naming
help.py The Rich help screens
settings.py Deciding between a flag, front matter, and the project file
config.py Reading .doc-engine.toml
frontmatter.py Leading --- metadata block
manifest.py Building one document out of several files
linter.py Source checks reported with line and column
converter.py Markdown AST → Typst markup
latex.py LaTeX math → Typst math
diagrams.py Mermaid and SVG blocks
images.py Cutting pictures taller than a page
remote.py Downloading linked images
compiler.py Template injection and PDF compilation

Changes usually belong in exactly one of these. If a change needs to touch all of them, it is worth opening a discussion first to agree on the approach.


Reporting bugs

A good report includes:

  • What you ran and what happened, with the full error output.
  • Your OS, Python version, and doc-engine --version.
  • A minimal Markdown file that reproduces it, if the problem is in a document.

The report that led to v1.1.1 was excellent precisely because it pasted the entire traceback — that made the diagnosis immediate.


License

By contributing, you agree that your contributions are licensed under the MIT License that covers this project.