diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7b072d5..230146c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.9 + rev: v0.14.11 hooks: - id: ruff args: [--fix] diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1080e77 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,325 @@ +# AGENTS.md + +This file provides guidance for AI coding agents working on the **sphinx-design** repository. + +## Project Overview + +sphinx-design is a Sphinx extension for designing beautiful, view size responsive web components. It provides: + +- Grids, cards, dropdowns, tabs, badges, buttons, and icons +- Responsive design inspired by [Bootstrap](https://getbootstrap.com/) (v5), [Material Design](https://material.io), and [Material-UI](https://material-ui.com/) +- Support for both reStructuredText and [MyST Markdown](https://myst-parser.readthedocs.io/) (via integration with myst-parser) + +The extension works with multiple Sphinx themes including alabaster, sphinx-rtd-theme, pydata-sphinx-theme, sphinx-book-theme, furo, and sphinx-immaterial. + +## Repository Structure + +``` +pyproject.toml # Project configuration and dependencies +tox.ini # Tox test environment configuration +package.json # Node.js config for SASS compilation + +sphinx_design/ # Main source code +├── __init__.py # Package init with setup() entry point +├── _compat.py # Compatibility utilities +├── extension.py # Main Sphinx extension setup +├── shared.py # Shared constants and base classes +├── badges_buttons.py # Badge and button directives +├── cards.py # Card directives +├── dropdown.py # Dropdown directive +├── grids.py # Grid directives +├── tabs.py # Tab directives +├── icons.py # Icon roles (Material, FontAwesome, Octicons) +├── article_info.py # Article info directive +└── compiled/ # Compiled static assets (CSS, JS) + +style/ # SASS source files +├── index.scss # Main SCSS entry point +├── _variables.scss # SCSS variables +├── _grids.scss # Grid styles +├── _cards.scss # Card styles +├── _tabs.scss # Tab styles +├── _dropdown.scss # Dropdown styles +└── ... # Other component styles + +tests/ # Test suite +├── conftest.py # Pytest fixtures +├── test_snippets.py # Snippet-based tests +├── test_misc.py # Miscellaneous tests +├── test_snippets/ # Test fixture files for snippets +└── test_misc/ # Test fixture files for misc tests + +docs/ # Documentation source (MyST Markdown) +├── conf.py # Sphinx configuration +├── index.md # Documentation index +├── get_started.md # Getting started guide +├── grids.md # Grid documentation +├── cards.md # Card documentation +├── tabs.md # Tab documentation +├── dropdowns.md # Dropdown documentation +├── badges_buttons.md # Badge and button documentation +└── snippets/ # Code snippets for docs (myst/, rst/) +``` + +## Development Commands + +All commands should be run via [`tox`](https://tox.wiki) for consistency. The project uses `tox-uv` for faster environment creation. + +### Testing + +```bash +# Run all tests (default Python version) +tox + +# Run tests with a specific Python version +tox -e py311 +tox -e py312 + +# Run a specific test file +tox -- tests/test_snippets.py + +# Run a specific test function +tox -- tests/test_snippets.py::test_function_name + +# Run tests without myst-parser dependency +tox -e py311-no-myst + +# Run with coverage +tox -- --cov=sphinx_design + +# Update regression test fixtures +tox -- --force-regen +``` + +### Documentation + +```bash +# Build docs with different themes +tox -e docs-alabaster +tox -e docs-rtd +tox -e docs-pydata +tox -e docs-sbt +tox -e docs-furo +tox -e docs-im + +# Clean build (set CLEAN env var) +CLEAN=1 tox -e docs-furo + +# Build with a different builder (e.g., linkcheck) +BUILDER=linkcheck tox -e docs-furo +``` + +### Code Quality + +```bash +# Type checking with mypy +tox -e mypy + +# Linting with ruff (auto-fix enabled) +tox -e ruff-check -- --fix + +# Formatting with ruff +tox -e ruff-fmt + +# Run pre-commit hooks on all files +pre-commit run --all-files + +# Compile SASS to CSS +npm run css +# or via pre-commit +pre-commit run --all css +``` + +## Code Style Guidelines + +- **Formatter/Linter**: Ruff (configured in `pyproject.toml`) +- **Type Checking**: Mypy (configured in `pyproject.toml`) +- **Pre-commit**: Use pre-commit hooks for consistent code style + +### Best Practices + +- **Type annotations**: Use complete type annotations for all function signatures. +- **Docstrings**: Use Sphinx-style docstrings (`:param:`, `:return:`, `:raises:`). +- **Directive classes**: Extend `SdDirective` (from `shared.py`) for new directives. +- **Warning messages**: Use `WARNING_TYPE = "design"` for consistent warning categorization. +- **Testing**: Write tests for all new functionality. Use `pytest-regressions` for output comparison. + +### Docstring Example + +```python +def create_component( + name: str, + rawtext: str, + *, + classes: Sequence[str] = (), +) -> nodes.container: + """Create a component container node. + + :param name: The component name. + :param rawtext: The raw text content. + :param classes: Additional CSS classes to apply. + :return: A container node with the component. + """ + ... +``` + +## Testing Guidelines + +### Test Structure + +- Tests use `pytest` with fixtures from `conftest.py` +- Regression testing uses `pytest-regressions` for output comparison +- The `sphinx_builder` fixture creates temporary Sphinx projects for testing + +### Writing Tests + +1. Use the `sphinx_builder` fixture to create test Sphinx applications +2. Add test content as `.txt` files in `tests/test_snippets/` or `tests/test_misc/` +3. Use `file_regression` or `data_regression` fixtures for comparing output + +### Example Test Pattern + +`````python +def test_grid_basic(sphinx_builder, file_regression): + builder = sphinx_builder() + builder.src_path.joinpath("index.md").write_text( + """ +# Test + +````{grid} 2 +:gutter: 1 + +```{grid-item} +Item 1 +``` + +```{grid-item} +Item 2 +``` +```` +""", + encoding="utf8", + ) + builder.build() + doctree = builder.get_doctree("index") + file_regression.check(doctree.pformat(), extension=".xml") +````` + +## Pull Request Requirements + +When submitting changes: + +1. **Description**: Include a meaningful description or link explaining the change +2. **Tests**: Include test cases for new functionality or bug fixes +3. **Documentation**: Update docs if behavior changes or new features are added +4. **Changelog**: Update `CHANGELOG.md` under the appropriate section +5. **Code Quality**: Ensure `pre-commit run --all-files` passes + +## Architecture Overview + +### Extension Setup + +The extension follows a modular architecture where each component type has its own module: + +``` +setup() in __init__.py + └── setup_extension() in extension.py + ├── setup_badges_and_buttons() + ├── setup_cards() + ├── setup_grids() + ├── setup_dropdown() + ├── setup_icons() + ├── setup_tabs() + └── setup_article_info() +``` + +### Key Components + +#### Base Classes (`sphinx_design/shared.py`) + +- `SdDirective`: Base class for sphinx-design directives (extends `SphinxDirective`) +- `create_component()`: Factory function for creating component nodes +- `WARNING_TYPE`: Constant for warning categorization + +#### Directives + +Each component type has its own module with directives: + +- **Grids** (`grids.py`): `grid`, `grid-item`, `grid-item-card` directives +- **Cards** (`cards.py`): `card`, `card-header`, `card-footer`, `card-carousel` directives +- **Tabs** (`tabs.py`): `tab-set`, `tab-item` directives +- **Dropdowns** (`dropdown.py`): `dropdown` directive +- **Badges/Buttons** (`badges_buttons.py`): `button-link`, `button-ref` directives and `bdg-*` roles +- **Icons** (`icons.py`): Icon roles for Material, FontAwesome, and Octicons + +#### Static Assets + +Compiled CSS and JS are stored in `sphinx_design/compiled/`: + +- CSS is compiled from SASS sources in `style/` +- JavaScript for tab functionality + +### Styling + +The extension uses SASS for styling: + +1. SASS source files are in `style/` +2. Compiled using `npm run css` (requires Node.js) +3. Output goes to `sphinx_design/compiled/style.min.css` +4. CSS is automatically copied to build output during Sphinx builds + +## Key Files + +- `pyproject.toml` - Project configuration, dependencies, and tool settings +- `sphinx_design/__init__.py` - Package entry point with `setup()` for Sphinx +- `sphinx_design/extension.py` - Main extension setup, CSS/JS handling +- `sphinx_design/shared.py` - Base classes and shared utilities +- `sphinx_design/grids.py` - Grid layout directives +- `sphinx_design/cards.py` - Card component directives +- `sphinx_design/tabs.py` - Tab component directives + +## Debugging + +- Build docs with `-v` flag for verbose output +- Check `docs/_build/html//` for build outputs +- Use `tox -- -v --tb=long` for verbose test output with full tracebacks +- Inspect generated HTML to debug styling issues + +## Common Patterns + +### Adding a New Component + +1. Create a new module in `sphinx_design/` (e.g., `my_component.py`) +2. Define directive class(es) extending `SdDirective` +3. Create a `setup_my_component(app: Sphinx)` function +4. Call the setup function from `setup_extension()` in `extension.py` +5. Add SASS styles in `style/_my_component.scss` +6. Import the SASS file in `style/index.scss` +7. Document in `docs/` +8. Add tests in `tests/` + +### Adding a New Directive Option + +1. Add the option to the directive's `option_spec` dictionary +2. Handle the option in the directive's `run()` method +3. Add appropriate CSS classes or attributes to the output node +4. Document the new option +5. Add tests for the new option + +### Working with SASS + +1. Edit SASS files in `style/` +2. Run `npm run css` to compile (or `pre-commit run --all css`) +3. Compiled output goes to `sphinx_design/compiled/style.min.css` +4. Test with different themes to ensure compatibility + +## Reference Documentation + +- [Docutils Repository](https://github.com/live-clones/docutils) +- [Docutils Documentation](https://docutils.sourceforge.io/) +- [Docutils Nodes](https://docutils.sourceforge.io/docs/ref/doctree.html) +- [Docutils release log](https://docutils.sourceforge.io/RELEASE-NOTES.html) +- [Sphinx Repository](https://github.com/sphinx-doc/sphinx) +- [Sphinx Extension Development](https://www.sphinx-doc.org/en/master/extdev/index.html) +- [Bootstrap Documentation](https://getbootstrap.com/docs/5.0/) +- [SASS Documentation](https://sass-lang.com/documentation) diff --git a/PR_DESCRIPTION.md b/PR_DESCRIPTION.md new file mode 100644 index 0000000..c594d1b --- /dev/null +++ b/PR_DESCRIPTION.md @@ -0,0 +1,14 @@ +## Add AGENTS.md and tox environments for code quality + +This PR adds developer tooling and documentation for AI coding agents. + +### Changes + +- **Add `AGENTS.md`**: Comprehensive guide for AI agents working on this repository, including project overview, repository structure, development commands, code style guidelines, testing patterns, and architecture documentation. + +- **Add tox environments for code quality**: + - `tox -e mypy` — Type checking + - `tox -e ruff-check` — Linting (auto-fix by default) + - `tox -e ruff-fmt` — Formatting + +- **Add `[dependency-groups]` to `pyproject.toml`**: Pinned versions for mypy and ruff matching `.pre-commit-config.yaml` for consistency between CI and local development. diff --git a/pyproject.toml b/pyproject.toml index 6f3c60d..de8a36f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,10 @@ theme-rtd = ["sphinx-rtd-theme~=2.0"] theme-sbt = ["sphinx-book-theme~=1.1"] theme-im = ["sphinx-immaterial~=0.12.2"] +[dependency-groups] +mypy = ["mypy==1.19.1"] +ruff = ["ruff==0.14.11"] + [tool.flit.sdist] exclude = [ "docs/", diff --git a/tox.ini b/tox.ini index 805c762..98a94bf 100644 --- a/tox.ini +++ b/tox.ini @@ -47,3 +47,18 @@ commands_pre = commands = sphinx-build -nW --keep-going {posargs} -b {env:BUILDER:html} docs/ docs/_build/{env:BUILDER:html}/{env:SPHINX_THEME:} commands_post = echo "open docs/_build//{env:BUILDER:html}/{env:SPHINX_THEME:}/index.html" + +[testenv:mypy] +description = Run type checking with mypy +dependency_groups = mypy +commands = mypy {posargs:sphinx_design} + +[testenv:ruff-check] +description = Run linting with ruff (use --fix to auto-fix) +dependency_groups = ruff +commands = ruff check {posargs:--fix} + +[testenv:ruff-fmt] +description = Run formatting with ruff +dependency_groups = ruff +commands = ruff format {posargs}