Skip to content

Commit

Permalink
V0.11
Browse files Browse the repository at this point in the history
* Catch all attributes in ShouldNotDepend

* Disable php cs fixer on test fixtures

* Introduce PHP 8.3

* Catch all attributes in CanOnlyDepend

* Test attribute args are catched

* Remove deprecated selectors

* Use namespaced name on shouldBeNamed assertion

* Trim initial backslash in shouldBeNamed fqcn parameter

* Sanitize rule names to match PHPStan identifier regex

* Change default rule name

* Adapt var tag extractor to PhpParser 5

* PHPStan 2.0

* Replace Selector::namespace() and Selector::abstract() in docs
  • Loading branch information
carlosas authored Dec 27, 2024
1 parent 55154db commit e88e15e
Show file tree
Hide file tree
Showing 117 changed files with 381 additions and 360 deletions.
1 change: 1 addition & 0 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
strategy:
matrix:
php-version:
- "7.4"
- "8.3"
dependencies:
- "highest"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<img src="https://img.shields.io/packagist/php-v/phpat/phpat?style=for-the-badge" alt="PHP Version">
</a>
<a>
<img src="https://img.shields.io/badge/phpstan-%5E1.3-blue?style=for-the-badge" alt="PHPStan Version">
<img src="https://img.shields.io/badge/phpstan-%5E2.0-blue?style=for-the-badge" alt="PHPStan Version">
</a>
<a>
<img src="https://img.shields.io/badge/contributions-welcome-green.svg?style=for-the-badge" alt="Contributions welcome">
Expand Down
8 changes: 5 additions & 3 deletions ci/php-cs-fixer.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<?php declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
->in([dirname(__DIR__) . '/src', dirname(__DIR__) . '/tests']);
->in([
dirname(__DIR__) . '/src',
dirname(__DIR__) . '/tests/architecture',
dirname(__DIR__) . '/tests/unit',
]);

$rules = [
'@PER' => true,
'@PHP80Migration:risky' => true,
'@PHP82Migration' => true,
'@PhpCsFixer' => true,
PhpCsFixerCustomFixers\Fixer\DeclareAfterOpeningTagFixer::name() => true,
PhpCsFixerCustomFixers\Fixer\PhpdocArrayStyleFixer::name() => true,
Expand Down
2 changes: 1 addition & 1 deletion ci/phpstan-phpat.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ parameters:
level: 8
paths:
- ../src
- ../tests/unit/rules
- ../tests/architecture
reportUnmatchedIgnoredErrors: false
ignoreErrors:
-
message: "#no value type specified in iterable type array\\.$#"
Expand Down
11 changes: 7 additions & 4 deletions ci/psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@
</PossiblyNullReference>
<MoreSpecificReturnType>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/ClassAttributeExtractor.php" /></errorLevel>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/AllAttributesExtractor.php" /></errorLevel>
<errorLevel type="suppress"><file name="../src/Statement/Builder/StatementBuilderFactory.php" /></errorLevel>
</MoreSpecificReturnType>
<LessSpecificReturnStatement>
<errorLevel type="suppress"><file name="../src/Statement/Builder/StatementBuilderFactory.php" /></errorLevel>
</LessSpecificReturnStatement>
<MissingClosureParamType>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/ClassAttributeExtractor.php" /></errorLevel>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/AllAttributesExtractor.php" /></errorLevel>
</MissingClosureParamType>
<MissingClosureReturnType>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/ClassAttributeExtractor.php" /></errorLevel>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/AllAttributesExtractor.php" /></errorLevel>
</MissingClosureReturnType>
<InvalidStringClass>
<errorLevel type="suppress"><file name="../src/Statement/Builder/StatementBuilderFactory.php" /></errorLevel>
Expand All @@ -56,10 +59,6 @@
<errorLevel type="suppress"><directory name="../tests/unit/rules/" /></errorLevel>
</PropertyNotSetInConstructor>

<MissingClassConstType>
<errorLevel type="suppress"><directory name="../src/" /></errorLevel>
</MissingClassConstType>

<DeprecatedMethod>
<errorLevel type="suppress"><file name="../src/Rule/Extractor/Relation/DocComment/ClassScope/PropertyTagExtractor.php" /></errorLevel>
</DeprecatedMethod>
Expand All @@ -72,5 +71,9 @@
<errorLevel type="suppress"><directory name="../src/Selector/" /></errorLevel>
<errorLevel type="suppress"><directory name="../src/Rule/" /></errorLevel>
</UndefinedDocblockClass>

<PossiblyNullArgument>
<errorLevel type="suppress"><file name="../src/Rule/Assertion/Relation/RelationAssertion.php" /></errorLevel>
</PossiblyNullArgument>
</issueHandlers>
</psalm>
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
],
"require": {
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^1.3"
"phpstan/phpstan": "^2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "3.46",
"kubawerlos/php-cs-fixer-custom-fixers": "3.18",
"phpunit/phpunit": "^9.0 || ^10.0",
"vimeo/psalm": "^5.0"
"friendsofphp/php-cs-fixer": "3.46.*",
"kubawerlos/php-cs-fixer-custom-fixers": "3.18.*",
"phpunit/phpunit": "^9.0 || 10.5.*",
"vimeo/psalm": "5.19.*"
},
"autoload": {
"psr-4": {
Expand Down
8 changes: 8 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Changelog
All notable changes to this project will be documented in this file.

## 0.11.0
* Use namespaced names on shouldBeNamed assertion
* Catch all attributes in dependency assertions
* Sanitize rule names to match PHPStan identifier pattern
* Add PHPStan identifiers from rule names
* Add support for PHPStan 2.0
* Drop support for PHPStan 1.*

## 0.10.20
* Fix parent interfaces not recognized as extended.

Expand Down
2 changes: 1 addition & 1 deletion docs/documentation/assertions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Assertion is the type of verification that can be done in the selected classes.

## shouldBeNamed()
It asserts that the selected classes are **named** as specified.
It asserts that the selected classes are **named** as the namespaced name specified.

## shouldBeFinal()
It asserts that the selected classes are declared as **final**.
Expand Down
6 changes: 6 additions & 0 deletions docs/documentation/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ final class ConfigurationTest
}
```

## Rule identifiers

When a rule is violated, the error message will contain an identifier that you can use to ignore the error.

Currently, the error identifier is based on the rule method name.

## Dynamic Rule Sets

It is possible to dynamically create rules by returning an iterable of Rules from your method:
Expand Down
6 changes: 3 additions & 3 deletions docs/documentation/selectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ Example:

```php
Selector::AND(
Selector::namespace('App\User'),
Selector::abstract()
Selector::inNamespace('App\User'),
Selector::isAbstract()
)
```

Expand All @@ -96,7 +96,7 @@ Selects classes that do not match the inner Selector.

```php
Selector::NOT(
Selector::namespace('App\User')
Selector::inNamespace('App\User')
)
```

Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ final class MyFirstTest
public function test_domain_does_not_depend_on_other_layers(): Rule
{
return PHPat::rule()
->classes(Selector::namespace('App\Domain'))
->classes(Selector::inNamespace('App\Domain'))
->shouldNotDependOn()
->classes(
Selector::namespace('App\Application'),
Selector::namespace('App\Infrastructure'),
Selector::inNamespace('App\Application'),
Selector::inNamespace('App\Infrastructure'),
Selector::classname(SuperForbiddenClass::class),
Selector::classname('/^SomeVendor\\\.*\\\ForbiddenSubfolder\\\.*/', true)
)
Expand Down
4 changes: 2 additions & 2 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ services:
tags:
- phpstan.rules.rule
-
class: PHPat\Rule\Assertion\Relation\ShouldNotDepend\ClassAttributeRule
class: PHPat\Rule\Assertion\Relation\ShouldNotDepend\AllAttributesRule
tags:
- phpstan.rules.rule
-
Expand Down Expand Up @@ -178,7 +178,7 @@ services:
tags:
- phpstan.rules.rule
-
class: PHPat\Rule\Assertion\Relation\CanOnlyDepend\ClassAttributeRule
class: PHPat\Rule\Assertion\Relation\CanOnlyDepend\AllAttributesRule
tags:
- phpstan.rules.rule
-
Expand Down
4 changes: 2 additions & 2 deletions src/Rule/Assertion/Declaration/DeclarationAssertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static function (array $statement) use ($subject): bool {
}
);

return array_reduce(
return array_values(array_reduce(
$applicableStatements,
function (array $errors, array $statement) use ($node, $scope, $subject): array {
[$ruleName, $selector, $subjectExcludes, $tips, $params] = $statement;
Expand All @@ -77,7 +77,7 @@ function (array $errors, array $statement) use ($node, $scope, $subject): array
return $errors;
},
[]
);
));
}

public function prepareMessage(string $ruleName, string $message): string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

namespace PHPat\Rule\Assertion\Relation\CanOnlyDepend;

use PHPat\Rule\Extractor\Relation\ClassAttributeExtractor;
use PHPat\Rule\Extractor\Relation\AllAttributesExtractor;
use PHPStan\Node\InClassNode;
use PHPStan\Rules\Rule;

/**
* @implements Rule<InClassNode>
*/
final class ClassAttributeRule extends CanOnlyDepend implements Rule
final class AllAttributesRule extends CanOnlyDepend implements Rule
{
use ClassAttributeExtractor;
use AllAttributesExtractor;
}
27 changes: 17 additions & 10 deletions src/Rule/Assertion/Relation/RelationAssertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Type\FileTypeMapper;

abstract class RelationAssertion implements Assertion
Expand Down Expand Up @@ -75,11 +75,11 @@ abstract protected function extractNodeClassNames(Node $node, Scope $scope): arr
abstract protected function getMessage(string $ruleName, string $subject, string $target): string;

/**
* @param array<SelectorInterface> $targets
* @param array<SelectorInterface> $targetExcludes
* @param array<class-string> $nodes
* @param array<string> $tips
* @return array<RuleError>
* @param array<SelectorInterface> $targets
* @param array<SelectorInterface> $targetExcludes
* @param array<class-string> $nodes
* @param array<string> $tips
* @return list<IdentifierRuleError>
*/
abstract protected function applyValidation(
string $ruleName,
Expand All @@ -100,7 +100,14 @@ protected function ruleApplies(Scope $scope, array $nodes): bool
}

// Can not skip if the rule is a ShouldExtend, ShouldImplement, ShouldInclude or ShouldApplyAttribute rule
if (is_a($this, ShouldExtend::class) || is_a($this, ShouldImplement::class) || is_a($this, ShouldInclude::class) || is_a($this, ShouldApplyAttribute::class)) {
$classReflection = $this->reflectionProvider->getClass(get_class($this));

if (
$classReflection->isSubclassOf(ShouldExtend::class)
|| $classReflection->isSubclassOf(ShouldImplement::class)
|| $classReflection->isSubclassOf(ShouldInclude::class)
|| $classReflection->isSubclassOf(ShouldApplyAttribute::class)
) {
return true;
}

Expand All @@ -110,7 +117,7 @@ protected function ruleApplies(Scope $scope, array $nodes): bool

foreach ($nodes as $node) {
$class = $scope->getClassReflection();
if ($class !== null && !(new Classname($node, false))->matches($class)) {
if (!(new Classname($node, false))->matches($class)) {
return true;
}
}
Expand All @@ -119,8 +126,8 @@ protected function ruleApplies(Scope $scope, array $nodes): bool
}

/**
* @param array<class-string> $nodes
* @return array<RuleError>
* @param array<class-string> $nodes
* @return list<IdentifierRuleError>
* @throws ShouldNotHappenException
*/
protected function validateGetErrors(Scope $scope, array $nodes): array
Expand Down
15 changes: 15 additions & 0 deletions src/Rule/Assertion/Relation/ShouldNotDepend/AllAttributesRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace PHPat\Rule\Assertion\Relation\ShouldNotDepend;

use PHPat\Rule\Extractor\Relation\AllAttributesExtractor;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Rules\Rule;

/**
* @implements Rule<InClassMethodNode>
*/
final class AllAttributesRule extends ShouldNotDepend implements Rule
{
use AllAttributesExtractor;
}
15 changes: 0 additions & 15 deletions src/Rule/Assertion/Relation/ShouldNotDepend/ClassAttributeRule.php

This file was deleted.

Loading

0 comments on commit e88e15e

Please sign in to comment.