Skip to content

Commit

Permalink
Tag version 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-granados committed Feb 9, 2024
1 parent cc876a4 commit b32a0f3
Show file tree
Hide file tree
Showing 19 changed files with 1,039 additions and 2 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/all_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: "All Tests"

on:
pull_request:
push:

jobs:
test:
name: "Run all checks for all supported PHP versions"

runs-on: "ubuntu-22.04"

strategy:
fail-fast: false
matrix:
php-version:
- "8.0"
- "8.1"
- "8.2"
- "8.3"

steps:
- name: "Checkout"
uses: "actions/checkout@v4"

- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
tools: composer

- name: Get composer cache directory
id: composercache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v4
with:
path: ${{ steps.composercache.outputs.dir }}
key: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}"

- name: "Install composer dependencies"
run: "composer install --no-interaction --no-progress"

- name: "Run tests"
run: "composer tests"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/vendor/
composer.lock
.idea
.phpunit.cache
122 changes: 120 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,120 @@
# rector-rule
RectorPHP rule to convert PHPDoc annotations for static analysis to PHP attributes
# PHP Static Analysis RectorPHP Rule
[![Continuous Integration](https://github.com/php-static-analysis/rector-rule/workflows/All%20Tests/badge.svg)](https://github.com/php-static-analysis/rector-rule/actions)
[![Latest Stable Version](https://poser.pugx.org/php-static-analysis/rector-rule/v/stable)](https://packagist.org/packages/php-static-analysis/rector-rule)
[![PHP Version Require](http://poser.pugx.org/php-static-analysis/rector-rule/require/php)](https://packagist.org/packages/php-static-analysis/rector-rule)
[![License](https://poser.pugx.org/php-static-analysis/rector-rule/license)](https://github.com/php-static-analysis/rector-rule/blob/main/LICENSE)
[![Total Downloads](https://poser.pugx.org/php-static-analysis/rector-rule/downloads)](https://packagist.org/packages/php-static-analysis/rector-rule/stats)

Since the release of PHP 8.0 more and more libraries, frameworks and tools have been updated to use attributes instead of annotations in PHPDocs.

However, static analysis tools like PHPStan have not made this transition to attributes and they still rely on annotations in PHPDocs for a lot of their functionality.

This is a set of RectorPHP rules that allows us to convert standard PHP static analysis annotations into a new set of attributes that replace these annotations. These attributes are defined in [this repository](https://github.com/php-static-analysis/attributes)

## Example

In order to show how code would look with these attributes, we can look at the following example. This is how a class looks like with the current annotations:

```php
<?php

class ArrayAdder
{
/** @var array<string> */
private array $result;

/**
* @param array<string> $array1
* @param array<string> $array2
* @return array<string>
*/
public function addArrays(array $array1, array $array2): array
{
$this->result = $array1 + $array2;
return $this->result;
}
}
```

And this is how it would look like using the new attributes:

```php
<?php

use PhpStaticAnalysis\Attributes\Type;
use PhpStaticAnalysis\Attributes\Param;
use PhpStaticAnalysis\Attributes\Returns;

class ArrayAdder
{
#[Type('array<string>')]
private array $result;

#[Param(array1: 'array<string>')]
#[Param(array2: 'array<string>')]
#[Returns('array<string>')]
public function addArrays(array $array1, array $array2): array
{
$this->array = $array1 + $array2;
return $this->array;
}
}
```

## Installation

First of all, to make the attributes available for your codebase use:

```
composer require php-static-analysis/attributes
```

To use these rules, install this package:

```
composer require --dev php-static-analysis/rector-rule
```

## Using the rules

To replace all the annotations that this package covers, use the set provided by it:

```php
use Rector\Config\RectorConfig;
use PhpStaticAnalysis\RectorRule\Set\PhpStaticAnalysisSetList;

return RectorConfig::configure()
->withSets([
PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES
]);
```

If you only want to replace some annotations and leave the others as they are, use the rule configured with the annotations that you need. For example, if you only want to replace the `@return` and `@param` annotations, use this configuration:

```php
use Rector\Config\RectorConfig;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use PhpStaticAnalysis\Attributes\Param;
use PhpStaticAnalysis\Attributes\Returns;
use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;

return RectorConfig::configure()
->withConfiguredRule(
AnnotationsToAttributesRector::class,
[
new AnnotationToAttribute('param', Param::class),
new AnnotationToAttribute('return', Returns::class),
]
);
```

These are the available attributes and their corresponding PHPDoc annotations:

| Attribute | PHPDoc Annotation |
|---------------------------------------------------------------------------------------------|-------------------|
| [IsReadOnly](https://github.com/php-static-analysis/attributes/blob/main/doc/IsReadOnly.md) | `@readonly` |
| [Param](https://github.com/php-static-analysis/attributes/blob/main/doc/Param.md) | `@param` |
| [Returns](https://github.com/php-static-analysis/attributes/blob/main/doc/Returns.md) | `@return` |
| [Template](https://github.com/php-static-analysis/attributes/blob/main/doc/Template.md) | `@template` |
| [Type](https://github.com/php-static-analysis/attributes/blob/main/doc/Type.md) | `@var` |

63 changes: 63 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "php-static-analysis/rector-rule",
"description": "RectorPHP rule to convert PHPDoc annotations for static analysis to PHP attributes",
"type": "rector-extension",
"keywords": ["dev", "static analysis"],
"license": "MIT",
"autoload": {
"psr-4": {
"PhpStaticAnalysis\\RectorRule\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"test\\PhpStaticAnalysis\\RectorRule\\": "tests/"
}
},
"authors": [
{
"name": "Carlos Granados",
"email": "[email protected]"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": ">=8.0",
"php-static-analysis/attributes": "^0.1 || dev-main",
"rector/rector": "^0.19 || ^1.0"
},
"require-dev": {
"php-static-analysis/phpstan-extension": "dev-main",
"php-static-analysis/psalm-plugin": "dev-main",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.0",
"symplify/easy-coding-standard": "^12.1",
"vimeo/psalm": "^5",
"webmozart/assert": "^1.11"
},
"scripts": {
"tests": [
"@ecs",
"@psalm",
"@phpunit",
"@phpstan",
"@rector"
],
"psalm": "psalm",
"ecs": "ecs",
"ecs-fix": "ecs --fix",
"phpunit": "phpunit",
"phpstan": "phpstan analyse",
"rector": "rector --dry-run",
"rector-fix": "rector",
"rector-debug": "rector --clear-cache --xdebug --dry-run"
},
"config": {
"allow-plugins": {
"phpstan/extension-installer": true
},
"sort-packages": true
}
}
25 changes: 25 additions & 0 deletions config/sets/php-static-analysis-annotations-to-attributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use PhpStaticAnalysis\Attributes\IsReadOnly;
use PhpStaticAnalysis\Attributes\Param;
use PhpStaticAnalysis\Attributes\Returns;
use PhpStaticAnalysis\Attributes\Template;
use PhpStaticAnalysis\Attributes\Type;
use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(
AnnotationsToAttributesRector::class,
[
new AnnotationToAttribute('param', Param::class),
new AnnotationToAttribute('readonly', IsReadOnly::class),
new AnnotationToAttribute('return', Returns::class),
new AnnotationToAttribute('template', Template::class),
new AnnotationToAttribute('var', Type::class),
]
);
};
15 changes: 15 additions & 0 deletions ecs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;

return ECSConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withPreparedSets(
psr12: true,
);
7 changes: 7 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
parameters:
level: max
paths:
- src
- tests
excludePaths:
- tests/Fixture/*
19 changes: 19 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
convertDeprecationsToExceptions="true"
failOnRisky="true"
failOnWarning="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
23 changes: 23 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" ?>
<psalm
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"

errorLevel="1"
findUnusedBaselineEntry="true"
findUnusedCode="false"
>
<projectFiles>
<directory name="src" />
<directory name="tests" />
<ignoreFiles>
<directory name="vendor" />
<directory name="tests/Fixture" />
</ignoreFiles>
</projectFiles>

<plugins>
<pluginClass class="PhpStaticAnalysis\PsalmPlugin\Plugin" />
</plugins>
</psalm>
18 changes: 18 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use PhpStaticAnalysis\RectorRule\Set\PhpStaticAnalysisSetList;

return RectorConfig::configure()
->withPaths([
__DIR__ . '/src',
__DIR__ . '/tests',
])
->withSkip([
__DIR__ . '/tests/Fixture',
])
->withSets([
PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES
]);
Loading

0 comments on commit b32a0f3

Please sign in to comment.