Skip to content

Commit c3ecd70

Browse files
authored
Merge pull request #14 from Kocal/pulse
2 parents 8b58002 + 8c2cd68 commit c3ecd70

File tree

3 files changed

+361
-0
lines changed

3 files changed

+361
-0
lines changed

CODE_OF_CONDUCT.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Code of Conduct
2+
3+
Be kind and respectful to everyone. We want this to be a welcoming space for all contributors.
4+
5+
If you experience any issues, feel free to reach out to the maintainers.

CONTRIBUTING.md

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
# Contributing to PHPStan Symfony UX
2+
3+
Thank you for your interest in contributing to PHPStan Symfony UX! This document provides guidelines and instructions for contributing to the project.
4+
5+
## Table of Contents
6+
7+
- [Code of Conduct](#code-of-conduct)
8+
- [Getting Started](#getting-started)
9+
- [Development Setup](#development-setup)
10+
- [Creating a New Rule](#creating-a-new-rule)
11+
- [Testing](#testing)
12+
- [Code Quality](#code-quality)
13+
- [Submitting a Pull Request](#submitting-a-pull-request)
14+
- [Project Structure](#project-structure)
15+
16+
## Code of Conduct
17+
18+
See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) for details on our code of conduct and how to report issues.
19+
20+
## Getting Started
21+
22+
1. **Fork the repository** on GitHub
23+
2. **Clone your fork** locally:
24+
```bash
25+
git clone https://github.com/YOUR_USERNAME/phpstan-symfony-ux.git
26+
cd phpstan-symfony-ux
27+
```
28+
3. **Install dependencies**:
29+
```bash
30+
composer install
31+
```
32+
33+
## Development Setup
34+
35+
### Prerequisites
36+
37+
- PHP 8.2 or higher
38+
- Composer
39+
40+
### Available Commands
41+
42+
The project provides several Composer scripts to help with development:
43+
44+
```bash
45+
# Run all quality checks and tests
46+
composer qa-fix
47+
48+
# Run PHPStan analysis
49+
composer phpstan
50+
51+
# Run tests
52+
composer test
53+
54+
# Check code style
55+
composer cs
56+
57+
# Fix code style automatically
58+
composer cs-fix
59+
```
60+
61+
## Creating a New Rule
62+
63+
### 1. Create the Rule Class
64+
65+
Create your rule in the appropriate directory under `src/Rules/`:
66+
- `src/Rules/TwigComponent/` for TwigComponent rules
67+
- `src/Rules/LiveComponent/` for LiveComponent rules
68+
69+
Each rule must:
70+
- Implement PHPStan's `Rule` interface
71+
- Return errors via `RuleErrorBuilder`
72+
- Have a descriptive name ending with `Rule`
73+
74+
**Example structure:**
75+
76+
```php
77+
<?php
78+
79+
declare(strict_types=1);
80+
81+
namespace Kocal\PHPStanSymfonyUX\Rules\TwigComponent;
82+
83+
use Kocal\PHPStanSymfonyUX\NodeAnalyzer\AttributeFinder;
84+
use PhpParser\Node;
85+
use PhpParser\Node\Stmt\Class_;
86+
use PHPStan\Analyser\Scope;
87+
use PHPStan\Rules\Rule;
88+
use PHPStan\Rules\RuleErrorBuilder;
89+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
90+
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
91+
92+
/**
93+
* @implements Rule<Class_>
94+
*/
95+
final class MyNewRule implements Rule
96+
{
97+
public function getNodeType(): string
98+
{
99+
return Class_::class;
100+
}
101+
102+
public function processNode(Node $node, Scope $scope): array
103+
{
104+
if (! AttributeFinder::findAnyAttribute($node, [AsTwigComponent::class, AsLiveComponent::class])) {
105+
return [];
106+
}
107+
108+
// Validation logic here
109+
110+
if ($errorCondition) {
111+
return [
112+
RuleErrorBuilder::message('Clear and descriptive error message.')
113+
->identifier('symfonyUX.twigComponent.descriptiveName')
114+
->line($node->getLine())
115+
->tip('Suggestion to fix the issue.')
116+
->build(),
117+
];
118+
}
119+
120+
return [];
121+
}
122+
}
123+
```
124+
125+
### 2. Create Tests
126+
127+
Create a test directory structure:
128+
129+
```
130+
tests/Rules/TwigComponent/MyNewRule/
131+
├── MyNewRuleTest.php
132+
├── Fixture/
133+
│ ├── InvalidCase.php
134+
│ ├── ValidCase.php
135+
│ └── NotAComponent.php
136+
└── config/
137+
└── configured_rule.neon
138+
```
139+
140+
**Test class example:**
141+
142+
```php
143+
<?php
144+
145+
declare(strict_types=1);
146+
147+
namespace Kocal\PHPStanSymfonyUX\Tests\Rules\TwigComponent\MyNewRule;
148+
149+
use Kocal\PHPStanSymfonyUX\Rules\TwigComponent\MyNewRule;
150+
use PHPStan\Rules\Rule;
151+
use PHPStan\Testing\RuleTestCase;
152+
153+
/**
154+
* @extends RuleTestCase<MyNewRule>
155+
*/
156+
final class MyNewRuleTest extends RuleTestCase
157+
{
158+
public function testViolations(): void
159+
{
160+
$this->analyse(
161+
[__DIR__ . '/Fixture/InvalidCase.php'],
162+
[
163+
[
164+
'Expected error message.',
165+
10, // Line number
166+
'Expected tip.',
167+
],
168+
]
169+
);
170+
}
171+
172+
public function testNoViolations(): void
173+
{
174+
$this->analyse([__DIR__ . '/Fixture/NotAComponent.php'], []);
175+
$this->analyse([__DIR__ . '/Fixture/ValidCase.php'], []);
176+
}
177+
178+
public static function getAdditionalConfigFiles(): array
179+
{
180+
return [__DIR__ . '/config/configured_rule.neon'];
181+
}
182+
183+
protected function getRule(): Rule
184+
{
185+
return self::getContainer()->getByType(MyNewRule::class);
186+
}
187+
}
188+
```
189+
190+
**Fixtures:**
191+
- `InvalidCase.php`: Code that violates the rule
192+
- `ValidCase.php`: Code that complies with the rule
193+
- `NotAComponent.php`: Code without component attributes (should not trigger errors)
194+
195+
### 3. Document the Rule
196+
197+
Add documentation to `README.md` under the appropriate section (TwigComponent or LiveComponent):
198+
199+
```markdown
200+
### MyNewRule
201+
202+
Description of what the rule checks and why it's important.
203+
204+
\`\`\`yaml
205+
rules:
206+
- Kocal\PHPStanSymfonyUX\Rules\TwigComponent\MyNewRule
207+
\`\`\`
208+
209+
\`\`\`php
210+
// Invalid example
211+
#[AsTwigComponent]
212+
final class BadExample
213+
{
214+
// ...
215+
}
216+
\`\`\`
217+
218+
:x:
219+
220+
<br>
221+
222+
\`\`\`php
223+
// Valid example
224+
#[AsTwigComponent]
225+
final class GoodExample
226+
{
227+
// ...
228+
}
229+
\`\`\`
230+
231+
:+1:
232+
233+
<br>
234+
```
235+
236+
## Testing
237+
238+
Always write comprehensive tests for your rules:
239+
240+
```bash
241+
# Run all tests
242+
composer test
243+
244+
# Run specific test
245+
vendor/bin/phpunit tests/Rules/TwigComponent/MyNewRule/
246+
```
247+
248+
Test cases should include:
249+
- Invalid code that violates the rule
250+
- Valid code that complies with the rule
251+
- Edge cases
252+
- Classes without component attributes
253+
254+
## Code Quality
255+
256+
Before submitting a PR, ensure your code passes all quality checks:
257+
258+
```bash
259+
# Run all checks and auto-fix issues
260+
composer qa-fix
261+
```
262+
263+
This will:
264+
1. Fix code style issues automatically
265+
2. Run PHPStan analysis
266+
3. Run all tests
267+
268+
### Code Style
269+
270+
- Use strict types: `declare(strict_types=1);`
271+
- Follow PSR-12 coding standards
272+
- Use type declarations for all properties, parameters, and return types
273+
- Make classes final when possible
274+
- Use descriptive variable and method names
275+
276+
### Error Messages
277+
278+
- Use clear, descriptive error messages
279+
- Always include a `tip()` with actionable advice
280+
- Use proper error identifiers: `symfonyUX.{package}.{descriptiveName}`
281+
282+
## Submitting a Pull Request
283+
284+
### Before Submitting
285+
286+
1. **Run quality checks**: `composer qa-fix`
287+
2. **Update documentation**: Add/update relevant sections in README.md
288+
3. **Write tests**: Ensure comprehensive test coverage
289+
4. **Commit with clear messages**: Use descriptive commit messages
290+
291+
### PR Guidelines
292+
293+
1. **Create a focused PR**: One feature or fix per PR
294+
2. **Write a clear description**:
295+
- What problem does it solve?
296+
- How does it solve it?
297+
- Are there any breaking changes?
298+
3. **Reference related issues**: Use "Fixes #123" or "Closes #123"
299+
4. **Update the CHANGELOG**: If applicable, add a note about your change
300+
301+
### PR Checklist
302+
303+
- [ ] Code follows project style guidelines
304+
- [ ] All tests pass (`composer test`)
305+
- [ ] PHPStan analysis passes (`composer phpstan`)
306+
- [ ] Code style is correct (`composer cs`)
307+
- [ ] New rules are documented in README.md
308+
- [ ] Tests are comprehensive and cover edge cases
309+
- [ ] Commit messages are clear and descriptive
310+
311+
## Project Structure
312+
313+
```
314+
phpstan-symfony-ux/
315+
├── src/
316+
│ ├── NodeAnalyzer/ # Reusable analyzers
317+
│ └── Rules/ # PHPStan rules
318+
│ ├── LiveComponent/ # LiveComponent-specific rules
319+
│ └── TwigComponent/ # TwigComponent rules
320+
├── tests/
321+
│ └── Rules/ # Tests organized by rule
322+
├── composer.json # Dependencies and scripts
323+
├── extension.neon # PHPStan extension configuration
324+
├── phpstan.dist.neon # PHPStan configuration
325+
├── ecs.php # Easy Coding Standard configuration
326+
└── README.md # User documentation
327+
```
328+
329+
## Best Practices
330+
331+
1. **Naming**: Rules should have descriptive names ending with `Rule`
332+
2. **Identifiers**: Use the format `symfonyUX.{package}.{descriptiveName}`
333+
3. **Error messages**: Be clear, concise, and include actionable tips
334+
4. **Tests**: Cover all scenarios (valid, invalid, edge cases, non-components)
335+
5. **Documentation**: Provide clear examples in README.md
336+
6. **Code review**: Be open to feedback and iterate on your PR
337+
338+
## Questions or Issues?
339+
340+
If you have questions or run into issues:
341+
342+
1. Check existing [GitHub Issues](https://github.com/Kocal/phpstan-symfony-ux/issues)
343+
2. Review the [AGENTS.md](./AGENTS.md) file for AI agent instructions
344+
3. Open a new issue with a clear description
345+
346+
## License
347+
348+
By contributing to this project, you agree that your contributions will be licensed under the MIT License.
349+
350+
---
351+
352+
Thank you for contributing to PHPStan Symfony UX! 🎉

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# PHPStan for Symfony UX
22

3+
![Packagist License](https://img.shields.io/packagist/l/kocal/phpstan-symfony-ux)
4+
![Packagist Version](https://img.shields.io/packagist/v/kocal/phpstan-symfony-ux)
5+
6+
37
A set of PHPStan rules to improve static analysis for [Symfony UX](https://github.com/symfony/ux) applications.
48

59
## Installation

0 commit comments

Comments
 (0)