Contributing to PHPantom¶
Thanks for your interest in contributing!
Getting Started¶
- Fork and clone the repository
- Follow the build instructions to get a working development environment
- Read ARCHITECTURE.md for an overview of how the codebase is structured
Before Submitting a PR¶
All six CI checks must pass with zero warnings and zero failures:
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --check
find examples/php -name '*.php' -print0 | xargs -0 -n1 php -l
php -d zend.assertions=1 examples/php/scaffolding/assertions.php
php -l examples/laravel/app/Demo.php
phpantom_lsp analyze --project-root examples/laravel --no-colour
Note that clippy runs twice, once for library code and once including test code. The php -l checks ensure the examples/php/ playground remains valid PHP. The php -d zend.assertions=1 run executes assertions.php's runDemoAssertions() to verify that scaffolding/scaffolding.php's stubs actually return what their docblocks claim. The final php -l and phpantom_lsp analyze runs check examples/laravel/ for syntax errors and diagnostic regressions. app/Demo.php carries three deliberate mistakes: Artisan::call('does:not-exist') demonstrates invalid_laravel_command, and one view('welcome', …) call both leaves out a variable the template declares and passes a misspelled key, demonstrating missing_view_variable and unused_view_variable. So the analyze run must report exactly [ERROR] Found 3 errors on those two lines, not [OK] No errors; any other count, or an error on a different line, is a regression.
Code Style¶
- Run
cargo fmtbefore committing - Fix clippy warnings rather than suppressing them. Avoid
#[allow(clippy::...)]unless truly necessary. - Add
///doc comments to all public functions and struct fields
Testing¶
- Integration tests go in
tests/integration/, one file per feature area (completion_*.rs,definition_*.rs,code_action_*.rs, ...) - Use
create_test_backend()fromtests/integration/common/mod.rsfor same-file tests - Use
create_psr4_workspace()for cross-file / PSR-4 tests - A helper (a request wrapper, a label extractor, a position finder) that three or more test files would define belongs in
tests/integration/common/mod.rs, not copied into each file; check there before writing one - Inline
#[cfg(test)]modules insrc/are for unit tests of private helpers; a test that drives aBackendthrough a public handler goes intests/integration/ - Test the happy path, edge cases, and interactions with existing features
- When adding a feature, update the matching demo file under
examples/php/with working examples (and verify withfind examples/php -name '*.php' -print0 | xargs -0 -n1 php -l). For Laravel-specific features, also updateexamples/laravel/app/Demo.php(and verify withphp -l examples/laravel/app/Demo.php).
See BUILDING.md for more on running tests and manual LSP testing.
Changelog¶
Update CHANGELOG.md when your PR adds, changes, or fixes something a user would notice. Add entries under ## [Unreleased] in the appropriate subsection (### Added, ### Fixed, ### Changed, or ### Removed). Write for end users, not developers: describe what changed in the editor, not which internal modules were touched.
Keep entries short and easy to scan:
- Start with a bolded one-line summary, then one or two plain sentences (three at most for a large feature). For a feature, say what the user gets and how to use it. For a fix, say what went wrong from the user's point of view and what happens now.
- Leave out how the code worked before or why the bug happened. That belongs in the commit message.
- Keep the details a user acts on: config keys, CLI flags, and a short code example when it makes the change concrete. One headline number is enough for a performance entry.
- If a section groups its entries under
####headings (Laravel, Blade templates, Type inference, Diagnostics, Performance and memory, and so on), put your entry under the matching one. Related fixes can share one entry. - End with
Contributed by @usernameif you are not the maintainer. Don't reference the issue a change fixes.
Example:
- **`analyze` takes more than one path.** `phpantom_lsp analyze app/ lib/Helper.php tests/` checks everything named, so a pre-commit hook or CI step can pass only the changed files.
Documentation¶
The documentation site is built with Zensical. The only dependency you need is uv.
Preview the docs locally with live reload:
Then open http://127.0.0.1:8000 in your browser. Changes to files in
docs/ and zensical.toml are reflected immediately. If port 8000 is
already in use, pick a different one:
Build the docs for offline use:
The output is written to site/ (gitignored). uv handles creating
a virtual environment and installing all Python dependencies
automatically on first run.
Reporting Issues¶
Open an issue on GitHub with:
- What you expected to happen
- What actually happened
- Steps to reproduce (a minimal PHP snippet is ideal)