Skip to content

Commit c4f3f09

Browse files
phpstan-botclaude
authored andcommitted
Add CLAUDE.md with project documentation and development guidelines
Comprehensive documentation covering the project goal, repository structure, PHP 7.4+ compatibility requirement, development commands, how the extension works, testing approach, coding style, and CI setup. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a8ec273 commit c4f3f09

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

CLAUDE.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# CLAUDE.md
2+
3+
This is the `phpstan/phpstan-webmozart-assert` extension for [PHPStan](https://phpstan.org/). It provides type-narrowing support for [webmozart/assert](https://github.com/webmozart/assert) assertion methods.
4+
5+
## Project Goal
6+
7+
PHPStan cannot natively understand type narrowing from `Webmozart\Assert\Assert` static method calls. This extension teaches PHPStan to refine types after assertions like `Assert::integer($a)`, `Assert::notNull($a)`, `Assert::isInstanceOf($a, Foo::class)`, etc. After an assertion call, PHPStan understands the variable's type has been narrowed accordingly.
8+
9+
The extension also supports `nullOr*`, `all*`, and `allNullOr*` method prefixes, as well as negative assertions like `allNotNull`, `allNotInstanceOf`, and `allNotSame`.
10+
11+
## Repository Structure
12+
13+
```
14+
src/Type/WebMozartAssert/
15+
AssertTypeSpecifyingExtension.php # The single main extension class
16+
stubs/
17+
Assert.stub # PHPStan stub for Assert methods not covered by the library's own PHPDocs
18+
tests/Type/WebMozartAssert/
19+
AssertTypeSpecifyingExtensionTest.php # Type inference tests
20+
AssertTypeSpecifyingExtensionTestBleedingEdge.php # Type inference tests with bleeding edge config
21+
ImpossibleCheckTypeMethodCallRuleTest.php # Impossible check detection tests
22+
MethodReturnTypeRuleTest.php # Return type rule tests
23+
data/ # Test fixture PHP files (type.php, array.php, bug-*.php, etc.)
24+
extension.neon # PHPStan extension config (registers the service and stub)
25+
phpstan.neon # PHPStan config for analysing this project itself
26+
phpstan-baseline.neon # PHPStan baseline for this project
27+
```
28+
29+
## PHP Version Requirement
30+
31+
This extension supports **PHP 7.4+**. All code must be compatible with PHP 7.4. The `composer.json` platform is pinned to PHP 7.4.6.
32+
33+
## Library Version Support
34+
35+
The extension supports **webmozart/assert ^1.11.0 || ^2.0**. CI tests run with both `--prefer-lowest` and highest dependency versions.
36+
37+
## Development Commands
38+
39+
All commands are defined in the `Makefile`:
40+
41+
- **`make check`** — runs all checks (lint, cs, tests, phpstan)
42+
- **`make tests`** — runs PHPUnit tests (`vendor/bin/phpunit`)
43+
- **`make lint`** — runs PHP parallel lint on `src/` and `tests/`
44+
- **`make cs`** — runs PHP_CodeSniffer with the phpstan/build-cs standard
45+
- **`make cs-fix`** — auto-fixes coding standard violations
46+
- **`make cs-install`** — clones and installs the `phpstan/build-cs` coding standard (2.x branch)
47+
- **`make phpstan`** — runs PHPStan at level 8 on `src/` and `tests/`
48+
- **`make phpstan-generate-baseline`** — regenerates the PHPStan baseline
49+
50+
## How It Works
51+
52+
The extension registers `AssertTypeSpecifyingExtension` as a `phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension` in `extension.neon`. This class implements `StaticMethodTypeSpecifyingExtension` and `TypeSpecifierAwareExtension`.
53+
54+
For each supported `Assert::*` method, the extension translates the assertion into an equivalent PHP expression (using php-parser AST nodes) that PHPStan's type specifier already understands. For example, `Assert::integer($a)` is translated to `is_int($a)`, and `Assert::stringNotEmpty($a)` becomes `is_string($a) && $a !== ''`.
55+
56+
The `getExpressionResolvers()` method returns a map of assertion method names to closures that build the equivalent AST expressions.
57+
58+
## Testing Approach
59+
60+
Tests use PHPStan's `TypeInferenceTestCase` and `RuleTestCase` base classes:
61+
62+
- **Type inference tests** (`AssertTypeSpecifyingExtensionTest`): Use `assertType()` calls in fixture files under `tests/Type/WebMozartAssert/data/` to verify PHPStan resolves the correct types after assertions.
63+
- **Rule tests** (`ImpossibleCheckTypeMethodCallRuleTest`): Verify that impossible/always-true assertion checks are correctly detected.
64+
- **Return type tests** (`MethodReturnTypeRuleTest`): Verify return type rules work correctly with the extension.
65+
66+
Test data files are excluded from PHPStan analysis via `phpstan.neon` (`excludePaths: tests/*/data/*`).
67+
68+
## Coding Style
69+
70+
- **Indentation**: Tabs for PHP, XML, and NEON files; spaces for YAML files (see `.editorconfig`)
71+
- **Coding standard**: Uses `phpstan/build-cs` (2.x branch) — PHP_CodeSniffer with PHPStan's custom ruleset
72+
- **Strict types**: All PHP files use `declare(strict_types = 1)` (note the spaces around `=`)
73+
- **Namespace**: `PHPStan\Type\WebMozartAssert`
74+
75+
## CI
76+
77+
GitHub Actions workflow (`.github/workflows/build.yml`) runs on the `2.0.x` branch and pull requests:
78+
79+
- **Lint**: PHP 7.4–8.4
80+
- **Coding Standard**: PHP 8.2 with `phpstan/build-cs`
81+
- **Tests**: PHP 7.4–8.4 matrix with lowest/highest dependencies
82+
- **Static Analysis (PHPStan)**: PHP 7.4–8.4 matrix with lowest/highest dependencies

0 commit comments

Comments
 (0)