Skip to content

Commit af20829

Browse files
committed
create psalm plugin
1 parent cd223ca commit af20829

15 files changed

+213
-170
lines changed

Diff for: .github/workflows/code-coverage.yml

-36
This file was deleted.

Diff for: .github/workflows/security-analysis.yml

-27
This file was deleted.

Diff for: .github/workflows/unit-tests.yml

-48
This file was deleted.

Diff for: .gitignore

-6
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,3 @@
1515

1616
# php-cs-fixer cache
1717
.php_cs.cache
18-
19-
# phpunit cache
20-
.phpunit.result.cache
21-
22-
# test logs
23-
/tests/logs/*

Diff for: .php_cs.dist

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ return PhpCsFixer\Config::create()
55
\Symfony\Component\Finder\Finder::create()
66
->in([
77
__DIR__ . '/src',
8-
__DIR__ . '/tests',
98
])
109
)
1110
->setRiskyAllowed(true)

Diff for: .phpcs.xml

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<description>The coding standard for PHP Standard Library.</description>
55

66
<file>src</file>
7-
<file>tests</file>
87

98
<arg name="basepath" value="."/>
109
<arg name="colors"/>

Diff for: README.md

+49-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,62 @@
1-
# Repository Template
1+
# PSL Psalm Plugin
22

3-
![Unit tests status](https://github.com/php-standard-library/repository-template/workflows/unit%20tests/badge.svg)
4-
![Static analysis status](https://github.com/php-standard-library/repository-template/workflows/static%20analysis/badge.svg)
5-
![Security analysis status](https://github.com/php-standard-library/repository-template/workflows/security%20analysis/badge.svg)
6-
![Coding standards status](https://github.com/php-standard-library/repository-template/workflows/coding%20standards/badge.svg)
7-
[![Type Coverage](https://shepherd.dev/github/php-standard-library/repository-template/coverage.svg)](https://shepherd.dev/github/php-standard-library/repository-template)
3+
![Static analysis status](https://github.com/php-standard-library/psalm-plugin/workflows/static%20analysis/badge.svg)
4+
[![Type Coverage](https://shepherd.dev/github/php-standard-library/psalm-plugin/coverage.svg)](https://shepherd.dev/github/php-standard-library/psalm-plugin)
5+
[![Total Downloads](https://poser.pugx.org/php-standard-library/psalm-plugin/d/total.svg)](https://packagist.org/packages/php-standard-library/psalm-plugin)
6+
[![Latest Stable Version](https://poser.pugx.org/php-standard-library/psalm-plugin/v/stable.svg)](https://packagist.org/packages/php-standard-library/psalm-plugin)
7+
[![License](https://poser.pugx.org/php-standard-library/psalm-plugin/license.svg)](https://packagist.org/packages/php-standard-library/psalm-plugin)
8+
9+
## Installation
10+
11+
Supported installation method is via [composer](https://getcomposer.org):
12+
13+
```shell
14+
composer install php-standard-library/psalm-plugin --dev
15+
```
16+
17+
## Usage
18+
19+
To enable the plugin, add the `Psl\Psalm\Plugin` class to your psalm configuration using `psalm-plugin` binary as follows:
20+
21+
```shell
22+
php vendor/bin/psalm-plugin enable php-standard-library/psalm-plugin
23+
```
24+
25+
## Type improvements
26+
27+
Given the following example:
28+
29+
```php
30+
use Psl\Type;
31+
32+
$specification = Type\shape([
33+
'name' => Type\string(),
34+
'age' => Type\int(),
35+
'location' => Type\optional(Type\shape([
36+
'city' => Type\string(),
37+
'state' => Type\string(),
38+
'country' => Type\string(),
39+
]))
40+
]);
41+
42+
$input = $specification->coerce($_GET['user']);
43+
44+
/** @psalm-trace $input */
45+
```
46+
47+
Psalm assumes that `$input` is of type `array<"age"|"location"|"name", array<"city"|"country"|"state", string>|int|string>`.
48+
49+
If we enable the `php-standard-library/psalm-plugin` plugin, you will get a more specific
50+
and correct type of `array{name: string, age: int, location?: array{city: string, state: string, country: string}}`.
851

952
## Sponsors
1053

1154
Thanks to our sponsors and supporters:
1255

13-
1456
| JetBrains |
1557
|---|
1658
| <a href="https://www.jetbrains.com/?from=PSL ( PHP Standard Library )" title="JetBrains" target="_blank"><img src="https://res.cloudinary.com/azjezz/image/upload/v1599239910/jetbrains_qnyb0o.png" height="120" /></a> |
1759

18-
1960
## License
2061

2162
The MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information.

Diff for: composer.json

+13-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "php-standard-library/repository-template",
3-
"description": "PHP Standard Library: Repository Template",
4-
"type": "library",
2+
"name": "php-standard-library/psalm-plugin",
3+
"description": "Psalm plugin for the PHP Standard Library",
4+
"type": "psalm-plugin",
55
"license": "MIT",
66
"authors": [
77
{
@@ -12,27 +12,16 @@
1212
"require": {
1313
"php": "^7.4 || ^8.0",
1414
"azjezz/psl": "^1.5",
15-
"ext-bcmath": "*",
16-
"ext-json": "*",
17-
"ext-mbstring": "*",
18-
"ext-sodium": "*",
19-
"ext-intl": "*"
15+
"vimeo/psalm": "^4.6"
2016
},
2117
"require-dev": {
22-
"phpunit/phpunit": "^9.5",
2318
"friendsofphp/php-cs-fixer": "^2.18",
2419
"roave/security-advisories": "dev-master",
25-
"squizlabs/php_codesniffer": "^3.5",
26-
"vimeo/psalm": "dev-master"
20+
"squizlabs/php_codesniffer": "^3.5"
2721
},
2822
"autoload": {
2923
"psr-4": {
30-
"Psl\\": "src/"
31-
}
32-
},
33-
"autoload-dev": {
34-
"psr-4": {
35-
"Psl\\Tests\\": "tests/"
24+
"Psl\\Psalm\\": "src/"
3625
}
3726
},
3827
"scripts": {
@@ -46,18 +35,21 @@
4635
],
4736
"type:check": "psalm",
4837
"type:coverage": "psalm --shepherd",
49-
"test:unit": "phpunit",
5038
"code:coverage": "php-coveralls -v",
5139
"security:analysis": "psalm --taint-analysis",
5240
"check": [
5341
"@cs:check",
5442
"@type:check",
55-
"@security:analysis",
56-
"@test:unit"
43+
"@security:analysis"
5744
]
5845
},
5946
"config": {
6047
"process-timeout": 1200,
6148
"sort-packages": true
49+
},
50+
"extra": {
51+
"psalm": {
52+
"pluginClass": "Psl\\Psalm\\Plugin"
53+
}
6254
}
63-
}
55+
}

Diff for: phpunit.xml.dist

-21
This file was deleted.

Diff for: psalm.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@
4343
</issueHandlers>
4444

4545
<plugins>
46-
<pluginClass class="Psl\Integration\Psalm\Plugin" />
46+
<pluginClass class="Psl\Psalm\Plugin" />
4747
</plugins>
4848
</psalm>

Diff for: src/.gitkeep

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Psl\Psalm\EventHandler\Type\Optional;
6+
7+
use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent;
8+
use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface;
9+
use Psalm\Type;
10+
use Psl\Iter;
11+
12+
final class FunctionReturnTypeProvider implements FunctionReturnTypeProviderInterface
13+
{
14+
/**
15+
* @return array<lowercase-string>
16+
*/
17+
public static function getFunctionIds(): array
18+
{
19+
return [
20+
'psl\type\optional'
21+
];
22+
}
23+
24+
public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $event): ?Type\Union
25+
{
26+
$argument = Iter\first($event->getCallArgs());
27+
if (null === $argument) {
28+
return null;
29+
}
30+
31+
$type = $event
32+
->getStatementsSource()
33+
->getNodeTypeProvider()
34+
->getType($argument->value);
35+
36+
if (null === $type) {
37+
return null;
38+
}
39+
40+
$clone = clone $type;
41+
$clone->possibly_undefined = true;
42+
43+
return $clone;
44+
}
45+
}

0 commit comments

Comments
 (0)