first commit

This commit is contained in:
DESKTOP-DH6BVPV\chiefsoft
2022-11-15 21:53:02 -05:00
commit 29452e5b6e
1991 changed files with 265605 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = lf
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
+8
View File
@@ -0,0 +1,8 @@
.vscode/
build/
vendor/
composer.lock
.php-cs-fixer.php
*.neon
*.cache
phpunit.xml
+37
View File
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer;
use Nexus\CsConfig\FixerGenerator;
use Nexus\CsConfig\Ruleset\Nexus74;
use PhpCsFixer\Finder;
$finder = Finder::create()
->files()
->in(__DIR__)
->exclude(['build'])
->append([__FILE__])
;
$overrides = [];
$options = [
'finder' => $finder,
'cacheFile' => 'build/.php-cs-fixer.cache',
'customFixers' => FixerGenerator::create('src/Fixer', 'Nexus\\CsConfig\\Fixer'),
'customRules' => [
NoCodeSeparatorCommentFixer::name() => true,
],
];
return Factory::create(new Nexus74(), $overrides, $options)->forLibrary('Nexus CS Config', 'John Paul E. Balandan, CPA', 'paulbalandan@gmail.com', 2020);
+232
View File
@@ -0,0 +1,232 @@
# Changelog
All notable changes to this library will be documented in this file:
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v3.8.0](https://github.com/NexusPHP/cs-config/compare/v3.7.0...v3.8.0) - 2022-11-01
- Bump php-cs-fixer to v3.13
- Add 'case_sensitive' option to 'general_phpdoc_annotation_remove'
- Add 'closure_fn_spacing' option to 'function_declaration'
## [v3.7.0](https://github.com/NexusPHP/cs-config/compare/v3.6.0...v3.7.0) - 2022-10-15
- Use dependabot for updates
- Bump php-cs-fixer version to v3.12
- Use phpstan baseline
- Update action workflows
## [v3.6.0](https://github.com/NexusPHP/cs-config/compare/v3.5.0...v3.6.0) - 2022-09-02
- Add new option to `phpdoc_separation`
- Remove deprecated rules
- Configure `no_trailing_comma_in_singleline`
- Bump php-cs-fixer to ^3.11
- Configure `whitespace_after_comma_in_array`
- Use available option of `phpdoc_order`
- Configure `no_multiple_statements_per_line` rule
- Bump php-cs-fixer to v3.10
- Fix PHPStan error
## [v3.5.0](https://github.com/NexusPHP/cs-config/compare/v3.4.0...v3.5.0) - 2022-07-11
- Change 'concat_space' to none
- Configure new rules in v3.9.1
- \[BC BREAK\] Drop Nexus73 ruleset
- Suppress missing iterable value type hints
- Remove use of deprecated rule
- Deprecate `Nexus/space_after_comment_start`
- Configure new rules in v3.8
## [v3.4.0](https://github.com/NexusPHP/cs-config/compare/v3.3.4...v3.4.0) - 2022-02-09
- Fix code style lint
- Add Nexus81 ruleset
- Deprecate Nexus73 ruleset
- Bump php-cs-fixer version to v3.6
- Bump php version to 7.4
- Prune build workflow
- Revert phpstan level to 8
## [v3.3.4](https://github.com/NexusPHP/cs-config/compare/v3.3.3...v3.3.4) - 2021-11-02
- Update to phpstan 1.0
- Add ignored tags to `phpdoc_to_comment` rule
## [v3.3.3](https://github.com/NexusPHP/cs-config/compare/v3.3.2...v3.3.3) - 2021-10-06
- Enable `no_alternative_syntax` rule
- Change class attributes separation to `none` except for methods
- Remove operator override for braces in Nexus80
- Add support for new fixers added in v3.2.0
- Remove deprecated "tokens: use_trait" option
- Use own custom fixers
- Fix phpstan error on v0.12.99
## [v3.3.2](https://github.com/NexusPHP/cs-config/compare/v3.3.1...v3.3.2) - 2021-09-08
- Fix missing string substitution when `FixerGenerator::create()` fails
## [v3.3.1](https://github.com/NexusPHP/cs-config/compare/v3.3.0...v3.3.1) - 2021-08-31
- Fix case where comment is exactly `//`
## [v3.3.0](https://github.com/NexusPHP/cs-config/compare/v3.2.2...v3.3.0) - 2021-08-31
- Fix grammar usages
- Enable all `class_definition` rules
- Remove references to `liaison/cs-config`
- Add NoCodeSeparatorCommentFixer
- Add SpaceAfterCommentStartFixer
- Add support for custom fixers
- Remove `@internal` annotation from classes in public API
- Bump to php-cs-fixer v3.1
- Add FixerGenerator
- Use phpstan's bleeding edge
## [v3.2.2](https://github.com/NexusPHP/cs-config/compare/v3.2.1...v3.2.2) - 2021-08-07
- Add support for `trait_import` in `class_attributes_separation`
- Do not test on PHP 8.1 yet
## [v3.2.1](https://github.com/NexusPHP/cs-config/compare/v3.2.0...v3.2.1) - 2021-07-07
- Forbid running PHPStan on PHP8.1 (for now)
- Standardize `phpunit.xml.dist` structure.
- Remove `include/require` from statements requiring blank line before.
- Fix for `AbstractRulesetTestCase` when configurable fixer is not yet defined by the ruleset.
- \[Nexus80\] Enable `void_return` fixer
- Limit excluded annotations to `@final` and `@no-final` only
- \[Nexus80\] Enable `final_public_method_for_abstract_class`
- \[Nexus80\] Enable `phpdoc_to_param_type` and `phpdoc_to_return_type`
- Remove `@test` annotations from tests
- Disable `php_unit_test_class_requires_covers`. Let PHPUnit do the job instead.
## [v3.2.0](https://github.com/NexusPHP/cs-config/compare/v3.1.1...v3.2.0) - 2021-06-19
- Enable PHP 8.1 build workflow
- Forbid importing global functions and constants in addition to global classes
- \[Possible BC break\] Refactored stricter `AbstractRulesetTestCase`
- Removed superfluous PHPDoc tags if present in method signature
- Changed default rule for `binary_operator_spaces` to `single_space` for all rulesets
- Changed parent namespace to "Nexus"
- Dropped `phpstan/phpstan-strict-rules`
## [v3.1.1](https://github.com/NexusPHP/cs-config/compare/v3.1.0...v3.1.1) - 2021-06-01
- Changed `native_constant_invocation` to fix only a subset of built in constants
## [v3.1.0](https://github.com/NexusPHP/cs-config/compare/v3.0.3...v3.1.0) - 2021-06-01
- Changed `native_constant_invocation` to fix all built in constants
- Completed options for `native_function_invocation`
- Changed `phpdoc_line_span` and `phpdoc_tag_type` rules
- Allow `@author` tags in `general_phpdoc_annotation_remove` rule
- Await `one_if_phpdoc` option for `class_attributes_separation`
## [v3.0.3](https://github.com/NexusPHP/cs-config/compare/v3.0.2...v3.0.3) - 2021-05-07
- Add test for checking missing built-in rules in ruleset
- Optimize tests' execution times
## [v3.0.2](https://github.com/NexusPHP/cs-config/compare/v3.0.1...v3.0.2) - 2021-05-07
- Allow overriding of `AbstractRulesetTestCase::createRuleset()`
## [v3.0.1](https://github.com/NexusPHP/cs-config/compare/v3.0.0...v3.0.1) - 2021-05-07
- Update branch alias to `3.x-dev`
- Fixed default cache file in `Factory`
- Update references of old configuration in README
- Fix `Nexus74` ruleset to enable `phpdoc_to_property_type`
- Change attribute separation of `const` to `none` in `Nexus80` ruleset
- Use descriptive names for rulesets
## [v3.0.0](https://github.com/NexusPHP/cs-config/compare/v2.2.1...v3.0.0) - 2021-05-06
- Update `friendsofphp/php-cs-fixer` to v3.0.0 Constitution
- New ruleset: `Nexus80`, targeting PHP 8.0+
- Add `Tachycardia` for profiling of slow tests
- Build action is also run on schedule
## [v2.2.1](https://github.com/NexusPHP/cs-config/compare/v2.2.0...v2.2.1) - 2021-05-06
- Fixed faulty build action on running `php-cs-fixer`
- Use range diffs in CHANGELOG
## [v2.2.0](https://github.com/NexusPHP/cs-config/compare/v2.1.5...v2.2.0) - 2021-05-06
- Update `friendsofphp/php-cs-fixer` to v2.19 Testament
- Use `new FixerFactory()` instead of `FixerFactory::create()`
- Add `phpdoc_to_property_type` and `trailing_comma_in_multiline` rules
- Removed deprecated fixers from the rulesets
- Removed deprecated fixer options from the rulesets
- Renamed configuration file to `.php-cs-fixer.dist.php`
## [v2.1.5](https://github.com/NexusPHP/cs-config/compare/v2.1.4...v2.1.5) - 2021-02-20
### Fixed
- Removed the faulty `replace` section in composer.json causing halted installations
- Fixed errors reported by PHPStan on level 8
## [v2.1.4](https://github.com/NexusPHP/cs-config/compare/v2.1.3...v2.1.4) - 2021-01-18
### Added
- Added support for PHP 8
- Bump `friendsofphp/php-cs-fixer` to v2.18.0 Remote Void
## [v2.1.3](https://github.com/NexusPHP/cs-config/compare/v2.1.2...v2.1.3) - 2021-01-07
### Fixed
- Fixed a PHPStan error on the incorrect covariant return type of `Factory::invoke`.
## [v2.1.2](https://github.com/NexusPHP/cs-config/compare/v2.1.1...v2.1.2) - 2021-01-07
### Fixed
- Fixed name of `Nexus74` ruleset which was erroneously set as `Nexus73`.
- Fixed license format in `README`.
## [v2.1.1](https://github.com/NexusPHP/cs-config/compare/v2.1.0...v2.1.1) - 2020-12-12
### Changed
- `increment_style` fixer now uses the `['style' => 'pre']`. Previously, this was `post`.
## [v2.1.0](https://github.com/NexusPHP/cs-config/compare/v2.0.2...v2.0.2) - 2020-12-08
### Added
- Added support for new fixers in [v2.17.0 Desert Beast](https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/tag/v2.17.0).
- Added `Nexus74` ruleset for support on `use_arrow_functions` fixer.
- Added testing for deprecated fixers.
### Changed
- `phpdoc_line_span` has been set to single for all classy elements.
- `binary_operator_spaces` has been set to its default `single_space` for use in this library.
## [v2.0.2](https://github.com/NexusPHP/cs-config/compare/v2.0.1...v2.0.2) - 2020-12-01
### Fixed
- Re-release of previous release due to inconsistency in tagging process.
## [v2.0.1](https://github.com/NexusPHP/cs-config/compare/v2.0.0...v2.0.1) - 2020-12-01
### Changed
- `global_namespace_import` has its option `import_classes` set to `false`.
- Renamed `phpunit.xml.dist`'s `cacheResultFile` attribute
## [v2.0.0](https://github.com/NexusPHP/cs-config/releases/tag/v2.0.0) - 2020-11-28
### Changed
- Initial release in this repository. See [MIGRATION](MIGRATION.md) for the detailed changes
from its predecessor library.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 John Paul E. Balandan, CPA
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+222
View File
@@ -0,0 +1,222 @@
# Nexus CS Config
[![PHP version](https://img.shields.io/packagist/php-v/nexusphp/cs-config)](https://php.net)
![build](https://github.com/NexusPHP/cs-config/workflows/build/badge.svg?branch=develop)
[![Coverage Status](https://coveralls.io/repos/github/NexusPHP/cs-config/badge.svg?branch=develop)](https://coveralls.io/github/NexusPHP/cs-config?branch=develop)
[![Latest Stable Version](https://poser.pugx.org/nexusphp/cs-config/v)](//packagist.org/packages/nexusphp/cs-config)
[![license MIT](https://img.shields.io/github/license/nexusphp/cs-config)](LICENSE)
[![Total Downloads](https://poser.pugx.org/nexusphp/cs-config/downloads)](//packagist.org/packages/nexusphp/cs-config)
This library provides a factory for custom rulesets for [`friendsofphp/php-cs-fixer`][1].
[1]: https://github.com/FriendsOfPHP/PHP-CS-Fixer
## Installation
You can add this library as a local, per-project dependency to your project
using [Composer](https://getcomposer.org/):
composer require nexusphp/cs-config
If you only need this library during development, for instance to run your project's test suite,
then you should add it as a development-time dependency:
composer require --dev nexusphp/cs-config
## Configuration
* Create a `.php-cs-fixer.dist.php` at the root of your project:
```php
<?php
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Ruleset\Nexus73;
return Factory::create(new Nexus73())->forProjects();
```
* Include the cache file in your `.gitignore`. By
default, the cache file will be saved in the project root.
```diff
vendor/
+# php-cs-fixer
+.php-cs-fixer.php
+.php-cs-fixer.cache
```
## Advanced Configuration
### Adding Preformatted License Header
You can create a preformatted license header to all PHP files by using the public `forLibrary()` method
instead of `forProjects()`. This method accepts two required arguments (the library name and author) and
two optional arguments (the email address and starting year of license).
* Scenario 1: Providing all arguments
```diff
<?php
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Ruleset\Nexus73;
-return Factory::create(new Nexus73())->forProjects();
+return Factory::create(new Nexus73())->forLibrary('My Library', 'John Doe', 'john@doe.com', 2020);
```
This setting will configure a license header similar to below:
```php
<?php
/**
* This file is part of My Library.
*
* (c) 2020 John Doe <john@doe.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig;
```
* Scenario 2: Providing only the required arguments
If you opted not to provide any of the optional arguments (i.e., email address, starting license year),
these will not be shown on the license header allowing flexibility on the copyright portion.
```diff
<?php
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Ruleset\Nexus73;
-return Factory::create(new Nexus73())->forProjects();
+return Factory::create(new Nexus73())->forLibrary('My Library', 'John Doe');
```
This will give the following license header:
```php
<?php
/**
* This file is part of My Library.
*
* (c) John Doe
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig;
```
### Overriding Rules in a Ruleset
If you feel that a specific rule in the ruleset is not appropriate for you, you can override it instead of creating a new ruleset:
```diff
<?php
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Ruleset\Nexus73;
-return Factory::create(new Nexus73())->forProjects();
+return Factory::create(new Nexus73(), [
+ 'binary_operator_spaces' => false,
+])->forProjects();
```
### Specifying Options to `PhpCsFixer\Config`
The `Factory` class returns an instance of `PhpCsFixer\Config` and fully supports all of
its properties setup. You can pass an array to the third parameter of `Factory::create()`
containing your desired options.
**Options**
| Key | Allowed Types | Default |
| -------------- | :--------------------------------------: | :----------------------------------: |
| cacheFile | `string` | `.php-cs-fixer.cache` |
| customFixers | `FixerInterface[], iterable, \Traversable` | `[]` |
| finder | `iterable, string[], \Traversable` | default `PhpCsFixer\Finder` instance |
| format | `string` | `txt` |
| hideProgress | `bool` | `false` |
| indent | `string` | `' '` // 4 spaces |
| lineEnding | `string` | `"\n"` |
| phpExecutable | `null, string` | `null` |
| isRiskyAllowed | `bool` | `false` |
| usingCache | `bool` | `true` |
| customRules | `array` | `[]` |
```diff
<?php
use Nexus\CsConfig\Factory;
use Nexus\CsConfig\Ruleset\Nexus73;
-return Factory::create(new Nexus73())->forProjects();
+return Factory::create(new Nexus73(), [], [
+ 'usingCache' => false,
+ 'hideProgress => true,
+])->forProjects();
```
## Customization of Ruleset
What is the purpose of a configuration factory if not able to create a custom ruleset for
an organization-wide usage, right? Well, you are not constrained to use the default rulesets
and putting a long array of overrides. That's pretty nasty.
The way to achieve this is dependent on you but the main idea is creating a new ruleset that
extends `Nexus\CsConfig\Ruleset\AbstractRuleset`. Yup, it's that easy. Then you just need to
provide details for its required four (4) protected properties.
```php
<?php
namespace MyCompany\CodingStandards\Ruleset;
use Nexus\CsConfig\Ruleset\AbstractRuleset;
final class MyCompany extends AbstractRuleset
{
public function __construct()
{
$this->name = 'My Company';
$this->rules = [
'@PSR2' => true,
...
];
$this->requiredPHPVersion = 70400;
$this->autoActivateIsRiskyAllowed = true;
}
}
```
Then, in creating your `.php-cs-fixer.dist.php`, use your own ruleset.
```php
<?php
use Nexus\CsConfig\Factory;
use MyCompany\CodingStandards\Ruleset\MyCompany;
return Factory::create(new MyCompany())->forProjects();
```
## Credits
This project is inspired by and an enhancement of [`ergebnis/php-cs-fixer-config`](https://github.com/ergebnis/php-cs-fixer-config).
## Contributing
Contributions are very much welcome. If you see an improvement or bugfix, open a [PR](https://github.com/NexusPHP/cs-config/pulls) now!
+52
View File
@@ -0,0 +1,52 @@
{
"name": "nexusphp/cs-config",
"type": "library",
"description": "A factory for custom rulesets for PHP CS Fixer.",
"license": "MIT",
"authors": [
{
"name": "John Paul E. Balandan, CPA",
"email": "paulbalandan@gmail.com"
}
],
"require": {
"php": "^7.4 || ^8.0",
"ext-tokenizer": "*",
"friendsofphp/php-cs-fixer": "^3.13"
},
"conflict": {
"liaison/cs-config": "*"
},
"require-dev": {
"nexusphp/tachycardia": "^1.3",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-develop": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Nexus\\CsConfig\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Nexus\\CsConfig\\Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"support": {
"issues": "https://github.com/NexusPHP/cs-config/issues",
"source": "https://github.com/NexusPHP/cs-config.git",
"slack": "https://nexusphp.slack.com"
}
}
+6
View File
@@ -0,0 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Cannot access offset 'header' on array\\<string, mixed\\>\\|bool\\.$#"
count: 1
path: tests/FactoryTest.php
+28
View File
@@ -0,0 +1,28 @@
includes:
- phpstan-baseline.neon.dist
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
parameters:
tmpDir: build/phpstan
level: 8
paths:
- src
- tests
bootstrapFiles:
- vendor/autoload.php
parallel:
processTimeout: 300.0
polluteScopeWithLoopInitialAssignments: false
polluteScopeWithAlwaysIterableForeach: false
checkAlwaysTrueCheckTypeFunctionCall: true
checkAlwaysTrueInstanceof: true
checkAlwaysTrueStrictComparison: true
checkExplicitMixedMissingReturn: true
checkFunctionNameCase: true
checkInternalClassCaseSensitivity: true
checkMissingIterableValueType: false
reportMaybesInMethodSignatures: true
reportStaticMethodSignatures: true
checkTooWideReturnTypesInProtectedAndPublicMethods: true
featureToggles:
disableCheckMissingIterableValueType: false
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile="build/phpunit/test-results"
colors="true"
columns="max"
failOnRisky="true"
failOnWarning="true"
forceCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true"
>
<testsuites>
<testsuite name="NexusPHP CS Config Test Suite">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<coverage cacheDirectory="build/phpunit/code-coverage"
ignoreDeprecatedCodeUnits="true"
processUncoveredFiles="true"
>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<clover outputFile="build/phpunit/logs/clover.xml"/>
<html outputDirectory="build/phpunit/logs/html"/>
</report>
</coverage>
<extensions>
<extension class="Nexus\PHPUnit\Extension\Tachycardia" />
</extensions>
</phpunit>
+203
View File
@@ -0,0 +1,203 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig;
use Nexus\CsConfig\Ruleset\RulesetInterface;
use PhpCsFixer\Config;
use PhpCsFixer\ConfigInterface;
use PhpCsFixer\Finder;
/**
* The Factory class is invoked on each project's `.php-cs-fixer.dist.php` to create
* the specific ruleset for the project.
*/
final class Factory
{
/**
* Current RulesetInterface instance.
*/
private RulesetInterface $ruleset;
/**
* Array of resolved options.
*
* @phpstan-var array{
* cacheFile: string,
* customFixers: iterable<\PhpCsFixer\Fixer\FixerInterface>,
* finder: \PhpCsFixer\Finder|iterable<\SplFileInfo>,
* format: string,
* hideProgress: bool,
* indent: string,
* lineEnding: string,
* phpExecutable: null|string,
* isRiskyAllowed: bool,
* usingCache: bool,
* rules: array<string, mixed>
* }
*/
private array $options;
/**
* @param array{
* cacheFile: string,
* customFixers: iterable<\PhpCsFixer\Fixer\FixerInterface>,
* finder: \PhpCsFixer\Finder|iterable<\SplFileInfo>,
* format: string,
* hideProgress: bool,
* indent: string,
* lineEnding: string,
* phpExecutable: null|string,
* isRiskyAllowed: bool,
* usingCache: bool,
* rules: array<string, mixed>
* } $options
*/
private function __construct(RulesetInterface $ruleset, array $options)
{
$this->ruleset = $ruleset;
$this->options = $options;
}
/**
* Prepares the ruleset and options before the `PhpCsFixer\Config` object
* is created.
*
* @param array<string, mixed> $overrides
* @param array{
* cacheFile?: string,
* customFixers?: iterable<\PhpCsFixer\Fixer\FixerInterface>,
* finder?: \PhpCsFixer\Finder|iterable<\SplFileInfo>,
* format?: string,
* hideProgress?: bool,
* indent?: string,
* lineEnding?: string,
* phpExecutable?: null|string,
* isRiskyAllowed?: bool,
* usingCache?: bool,
* customRules?: array<string, mixed>
* } $options
*/
public static function create(RulesetInterface $ruleset, array $overrides = [], array $options = []): self
{
if (\PHP_VERSION_ID < $ruleset->getRequiredPHPVersion()) {
throw new \RuntimeException(sprintf(
'The "%s" ruleset requires a minimum PHP_VERSION_ID of "%d" but current PHP_VERSION_ID is "%d".',
$ruleset->getName(),
$ruleset->getRequiredPHPVersion(),
\PHP_VERSION_ID,
));
}
// Meant to be used in vendor/ to get to the root directory
$dir = \dirname(__DIR__, 4);
$dir = realpath($dir) ?: $dir;
$defaultFinder = Finder::create()
->files()
->in([$dir])
->exclude(['build'])
;
// Resolve Config options
$options['cacheFile'] ??= '.php-cs-fixer.cache';
$options['customFixers'] ??= [];
$options['finder'] ??= $defaultFinder;
$options['format'] ??= 'txt';
$options['hideProgress'] ??= false;
$options['indent'] ??= ' ';
$options['lineEnding'] ??= "\n";
$options['phpExecutable'] ??= null;
$options['isRiskyAllowed'] = $options['isRiskyAllowed'] ?? ($ruleset->willAutoActivateIsRiskyAllowed() ?: false);
$options['usingCache'] ??= true;
$options['rules'] = array_merge($ruleset->getRules(), $overrides, $options['customRules'] ?? []);
return new self($ruleset, $options);
}
/**
* Creates a `PhpCsFixer\Config` object that is applicable for libraries,
* i.e., has their own header docblock in place.
*/
public function forLibrary(string $library, string $author, string $email = '', ?int $startingYear = null): ConfigInterface
{
$year = (string) $startingYear;
if ('' !== $year) {
$year .= ' ';
}
if ('' !== $email) {
$email = trim($email, '<>');
$email = ' <'.$email.'>';
}
$header = sprintf(
<<<'HEADER'
This file is part of %s.
(c) %s%s%s
For the full copyright and license information, please view
the LICENSE file that was distributed with this source code.
HEADER,
$library,
$year,
$author,
$email,
);
return $this->invoke([
'header_comment' => [
'header' => trim($header),
'comment_type' => 'PHPDoc',
'location' => 'after_declare_strict',
'separate' => 'both',
],
]);
}
/**
* Plain invocation of `Config` with no additional arguments.
*/
public function forProjects(): ConfigInterface
{
return $this->invoke();
}
/**
* The main method of creating the Config instance.
*
* @param array<string, array<string>|bool> $overrides
*
* @internal
*/
private function invoke(array $overrides = []): ConfigInterface
{
$rules = array_merge($this->options['rules'], $overrides);
return (new Config($this->ruleset->getName()))
->registerCustomFixers($this->options['customFixers'])
->setCacheFile($this->options['cacheFile'])
->setFinder($this->options['finder'])
->setFormat($this->options['format'])
->setHideProgress($this->options['hideProgress'])
->setIndent($this->options['indent'])
->setLineEnding($this->options['lineEnding'])
->setPhpExecutable($this->options['phpExecutable'])
->setRiskyAllowed($this->options['isRiskyAllowed'])
->setUsingCache($this->options['usingCache'])
->setRules($rules)
;
}
}
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Fixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Utils;
abstract class AbstractCustomFixer extends AbstractFixer
{
/**
* Vendor namespace in fixer's name.
*/
protected static ?string $namespace;
/**
* Returns the fixer name for easy use in fixer registration and usage.
*/
public static function name(): string
{
$nameParts = explode('\\', static::class);
$namespace = static::$namespace ?? $nameParts[0];
$name = substr(end($nameParts), 0, -\strlen('Fixer'));
return $namespace.'/'.Utils::camelCaseToUnderscore($name);
}
/**
* {@inheritDoc}
*/
public function getName(): string
{
return self::name();
}
}
@@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Fixer\Comment;
use Nexus\CsConfig\Fixer\AbstractCustomFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Removes code separator comments except when used as section boundary.
*/
final class NoCodeSeparatorCommentFixer extends AbstractCustomFixer
{
/**
* {@inheritDoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'There should not be any code separator comments.',
[new CodeSample(
<<<'EOF'
<?php
$code = 'a';
//------------------------
$arr = [];
EOF,
)],
);
}
/**
* {@inheritDoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_COMMENT);
}
/**
* {@inheritDoc}
*
* Must run before NoEmptyCommentFixer, SpaceAfterCommentStartFixer
*/
public function getPriority(): int
{
return 2;
}
/**
* {@inheritDoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = 1, $count = $tokens->count(); $index < $count; ++$index) {
/** @var Token $token */
$token = $tokens[$index];
if (! $token->isGivenKind(T_COMMENT)) {
continue;
}
if (! $this->isCodeSeparatorComment($token->getContent())) {
continue;
}
if ($this->isCommentBlockBoundary($tokens, $index)) {
continue;
}
$tokens->removeLeadingWhitespace($index);
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
}
}
/**
* Checks if the recurring code separator comment is part of a comment
* boundary that serves as a logical division between sections of code.
*
* ```
* //================================== <-- this is used as a boundary
* // SECTION
* //================================== <-- this is used as a boundary
*
* //================================== <-- this is NOT a boundary
*
* ```
*/
private function isCommentBlockBoundary(Tokens $tokens, int $index): bool
{
$prevIndex = $tokens->getPrevNonWhitespace($index);
$nextIndex = $tokens->getNextNonWhitespace($index);
/** @var Token $prevToken */
$prevToken = $tokens[$prevIndex];
$prevTokenIsRegularComment = $prevToken->isGivenKind(T_COMMENT)
&& ! $this->isCodeSeparatorComment($prevToken->getContent());
/** @var Token $nextToken */
$nextToken = $tokens[$nextIndex];
$nextTokenIsRegularComment = $nextToken->isGivenKind(T_COMMENT)
&& ! $this->isCodeSeparatorComment($nextToken->getContent());
return $prevTokenIsRegularComment || $nextTokenIsRegularComment;
}
private function isCodeSeparatorComment(string $comment): bool
{
return Preg::match('/^\/\/\s*[-|=]+$/', $comment) === 1;
}
}
@@ -0,0 +1,108 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Fixer\Comment;
use Nexus\CsConfig\Fixer\AbstractCustomFixer;
use PhpCsFixer\Fixer\DeprecatedFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Simple comments should have one space after the `//`.
*
* @deprecated
*/
final class SpaceAfterCommentStartFixer extends AbstractCustomFixer implements DeprecatedFixerInterface
{
/**
* {@inheritDoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'There should be a single whitespace after the start of a simple comment.',
[
new CodeSample("<?php\n //this is a comment\n"),
new CodeSample("<?php\n // this is another comment\n"),
],
);
}
/**
* {@inheritDoc}
*/
public function getSuccessorsNames(): array
{
return ['single_line_comment_spacing'];
}
/**
* {@inheritDoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_COMMENT);
}
/**
* {@inheritDoc}
*
* Must run after NoEmptyCommentFixer
*/
public function getPriority(): int
{
return 3;
}
/**
* {@inheritDoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = 1, $count = $tokens->count(); $index < $count; ++$index) {
/** @var Token $token */
$token = $tokens[$index];
if (! $token->isGivenKind(T_COMMENT)) {
continue;
}
$comment = $token->getContent();
if (substr($comment, 0, 2) !== '//') {
continue;
}
if ('//' === $comment) {
continue;
}
Preg::match('/^\/\/(\s*)(.+)/', $comment, $matches);
if (' ' === $matches[1]) {
continue;
}
if (Preg::match('/\-+/', $matches[2]) === 1 || Preg::match('/\=+/', $matches[2]) === 1) {
continue;
}
$tokens[$index] = new Token([T_COMMENT, '// '.$matches[2]]);
}
}
}
+91
View File
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig;
use PhpCsFixer\Finder;
use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\Preg;
use Symfony\Component\Finder\SplFileInfo;
/**
* Provides a generator of custom fixers for registration in `PhpCsFixer\Config`.
*
* @implements \IteratorAggregate<FixerInterface>
*/
final class FixerGenerator implements \IteratorAggregate
{
private string $path;
private string $vendor;
private function __construct(string $path, string $vendor)
{
$this->path = $path;
$this->vendor = $vendor;
}
/**
* @throws \RuntimeException
*/
public static function create(string $path, string $vendor): self
{
if ('' === $path) {
throw new \RuntimeException('Path to custom fixers cannot be empty.');
}
if (! is_dir($path)) {
throw new \RuntimeException(sprintf('Path "%s" is not a valid directory.', $path));
}
if ('' === $vendor) {
throw new \RuntimeException('Vendor namespace cannot be empty.');
}
if (Preg::match('/^[A-Z][a-zA-Z0-9\\\\]+$/', $vendor) !== 1) {
throw new \RuntimeException(sprintf('Vendor namespace "%s" is not valid.', $vendor));
}
return new self($path, $vendor);
}
/**
* @return \Traversable<FixerInterface>
*/
public function getIterator(): \Traversable
{
$finder = Finder::create()
->files()
->in($this->path)
->notName('/Abstract(\S+)\.php$/')
->notName('/(\S+)(?<!Fixer)\.php$/')
->sortByName()
;
$fixers = array_filter(array_map(
function (SplFileInfo $file): object {
$fixer = sprintf(
'%s\\%s%s%s',
trim($this->vendor, '\\'),
strtr($file->getRelativePath(), \DIRECTORY_SEPARATOR, '\\'),
$file->getRelativePath() !== '' ? '\\' : '',
$file->getBasename('.'.$file->getExtension()),
);
return new $fixer();
},
iterator_to_array($finder, false),
), static fn (object $fixer): bool => $fixer instanceof FixerInterface);
yield from $fixers;
}
}
@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Ruleset;
abstract class AbstractRuleset implements RulesetInterface
{
/**
* Name of the ruleset.
*/
protected string $name;
/**
* Rules for the ruleset.
*/
protected array $rules = [];
/**
* Minimum PHP version.
*/
protected int $requiredPHPVersion = 0;
/**
* Have this ruleset turn on `$isRiskyAllowed` flag?
*/
protected bool $autoActivateIsRiskyAllowed = false;
/**
* {@inheritDoc}
*/
final public function getName(): string
{
return $this->name ?: trim(strrchr(static::class, '\\') ?: static::class, '\\');
}
/**
* {@inheritDoc}
*/
final public function getRules(): array
{
return $this->rules;
}
/**
* {@inheritDoc}
*/
final public function getRequiredPHPVersion(): int
{
return $this->requiredPHPVersion;
}
/**
* {@inheritDoc}
*/
final public function willAutoActivateIsRiskyAllowed(): bool
{
return $this->autoActivateIsRiskyAllowed;
}
}
+637
View File
@@ -0,0 +1,637 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Ruleset;
/**
* Ruleset for `Nexus` group.
*
* @internal
*/
final class Nexus74 extends AbstractRuleset
{
public function __construct()
{
$this->name = 'Nexus for PHP 7.4';
$this->rules = [
'align_multiline_comment' => ['comment_type' => 'all_multiline'],
'array_indentation' => true,
'array_push' => true,
'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true,
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [],
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => [
'case',
'continue',
'declare',
'default',
'do',
'exit',
'for',
'foreach',
'goto',
'if',
'return',
'switch',
'throw',
'try',
'while',
'yield',
'yield_from',
],
],
'blank_line_between_import_groups' => true,
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'allow_single_line_closure' => true,
'position_after_anonymous_constructs' => 'same',
'position_after_control_structures' => 'same',
'position_after_functions_and_oop_constructs' => 'next',
],
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => [
'elements' => [
'const' => 'none',
'property' => 'none',
'method' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
'space_before_parenthesis' => true,
'inline_constructor_arguments' => true,
],
'class_reference_name_casing' => true,
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => [
'ignored_tags' => [
'todo',
'codeCoverageIgnore',
'codeCoverageIgnoreStart',
'codeCoverageIgnoreEnd',
'phpstan-ignore-line',
'phpstan-ignore-next-line',
],
],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'none'],
'constant_case' => ['case' => 'lower'],
'control_structure_braces' => true,
'control_structure_continuation_position' => ['position' => 'same_line'],
'curly_braces_position' => [
'control_structures_opening_brace' => 'same_line',
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_functions_opening_brace' => 'same_line',
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_classes_opening_brace' => 'same_line',
'allow_single_line_empty_anonymous_classes' => true,
'allow_single_line_anonymous_functions' => true,
],
'date_time_create_from_format_call' => true,
'date_time_immutable' => true,
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => false,
'doctrine_annotation_braces' => false,
'doctrine_annotation_indentation' => false,
'doctrine_annotation_spaces' => false,
'echo_tag_syntax' => [
'format' => 'short',
'long_function' => 'echo',
'shorten_simple_statements_only' => true,
],
'elseif' => true,
'empty_loop_body' => ['style' => 'braces'],
'empty_loop_condition' => ['style' => 'while'],
'encoding' => true,
'ereg_to_preg' => true,
'error_suppression' => [
'mute_deprecation_error' => true,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'escape_implicit_backslashes' => [
'double_quoted' => true,
'heredoc_syntax' => true,
'single_quoted' => false,
],
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_class' => false,
'final_internal_class' => [
'annotation_exclude' => ['@final', '@no-final'],
'annotation_include' => ['@internal'],
'consider_absent_docblock_as_internal_class' => false,
],
'final_public_method_for_abstract_class' => false,
'fopen_flag_order' => true,
'fopen_flags' => ['b_mode' => true],
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => [
'closure_function_spacing' => 'one',
'closure_fn_spacing' => 'one',
'trailing_comma_single_line' => false,
],
'function_to_constant' => [
'functions' => [
'get_called_class',
'get_class',
'get_class_this',
'php_sapi_name',
'phpversion',
'pi',
],
],
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => [
'annotations' => [
'package',
'subpackage',
],
'case_sensitive' => false,
],
'general_phpdoc_tag_rename' => [
'case_sensitive' => false,
'fix_annotation' => true,
'fix_inline' => true,
'replacements' => ['inheritDocs' => 'inheritDoc'],
],
'get_class_to_class_keyword' => false,
'global_namespace_import' => [
'import_classes' => false,
'import_constants' => false,
'import_functions' => false,
],
'group_import' => false,
'header_comment' => false,
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'heredoc_to_nowdoc' => true,
'implode_call' => true,
'include' => true,
'increment_style' => ['style' => 'pre'],
'indentation_type' => true,
'integer_literal_case' => true,
'is_null' => true,
'lambda_not_used_import' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => true,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => false,
'method_argument_space' => [
'after_heredoc' => true,
'keep_multiple_spaces_after_comma' => false,
'on_multiline' => 'ensure_fully_multiline',
],
'method_chaining_indentation' => true,
'modernize_strpos' => false,
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
'native_constant_invocation' => [
'fix_built_in' => false,
'include' => [
'DIRECTORY_SEPARATOR',
'PHP_INT_SIZE',
'PHP_SAPI',
'PHP_VERSION_ID',
],
'exclude' => [],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_casing' => true,
'native_function_invocation' => [
'exclude' => [],
'include' => ['@compiler_optimized'],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_type_declaration_casing' => true,
'new_with_braces' => [
'named_class' => true,
'anonymous_class' => true,
],
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => ['fix_non_monolithic_code' => false],
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => false,
'no_break_comment' => ['comment_text' => 'no break'],
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => [
'tokens' => [
'extra',
'break',
'continue',
'curly_brace_block',
'parenthesis_brace_block',
'square_brace_block',
'return',
'throw',
'use',
'switch',
'case',
'default',
],
],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiple_statements_per_line' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_space_around_double_colon' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
'remove_inheritdoc' => false,
],
'no_trailing_comma_in_singleline' => [
'elements' => ['arguments', 'array', 'array_destructuring', 'group_import'],
],
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_trailing_whitespace_in_string' => true,
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'return',
'switch_case',
'yield',
],
],
'no_unneeded_curly_braces' => ['namespaces' => true],
'no_unneeded_final_method' => ['private_methods' => true],
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => false,
'no_unused_imports' => true,
'no_useless_concat_operator' => ['juggle_simple_strings' => true],
'no_useless_else' => true,
'no_useless_nullsafe_operator' => false,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => false],
'no_whitespace_in_blank_line' => true,
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
'normalize_index_brace' => true,
'not_operator_with_space' => false,
'not_operator_with_successor_space' => true,
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
'object_operator_without_whitespace' => true,
'octal_notation' => false, // requires 8.1+
'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
'ordered_class_elements' => [
'order' => [
'use_trait',
'constant_public',
'constant_protected',
'constant_private',
'property_public',
'property_protected',
'property_private',
'construct',
'destruct',
'magic',
'phpunit',
'method_public_static',
'method_protected_static',
'method_private_static',
'method_public',
'method_protected',
'method_private',
],
'sort_algorithm' => 'none',
],
'ordered_imports' => [
'imports_order' => ['class', 'function', 'const'],
'sort_algorithm' => 'alpha',
],
'ordered_interfaces' => false,
'ordered_traits' => true,
'php_unit_construct' => [
'assertions' => [
'assertEquals',
'assertSame',
'assertNotEquals',
'assertNotSame',
],
],
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
'php_unit_expectation' => ['target' => 'newest'],
'php_unit_fqcn_annotation' => true,
'php_unit_internal_class' => ['types' => ['normal', 'final']],
'php_unit_method_casing' => ['case' => 'camel_case'],
'php_unit_mock' => ['target' => 'newest'],
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => ['target' => 'newest'],
'php_unit_no_expectation_annotation' => [
'target' => 'newest',
'use_class_const' => true,
],
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_size_class' => false,
'php_unit_strict' => [
'assertions' => [
'assertAttributeEquals',
'assertAttributeNotEquals',
'assertEquals',
'assertNotEquals',
],
],
'php_unit_test_annotation' => ['style' => 'prefix'],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'self',
'methods' => [],
],
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_align' => [
'align' => 'vertical',
'tags' => [
'method',
'param',
'property',
'return',
'throws',
'type',
'var',
],
],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => [
'tags' => [
'example',
'id',
'internal',
'inheritdoc',
'inheritdocs',
'link',
'source',
'toc',
'tutorial',
],
],
'phpdoc_line_span' => [
'const' => 'multi',
'method' => 'multi',
'property' => 'multi',
],
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => [
'replacements' => [
'property-read' => 'property',
'property-write' => 'property',
'type' => 'var',
'link' => 'see',
],
],
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => ['order' => ['param', 'return', 'throws']],
'phpdoc_order_by_value' => [
'annotations' => [
'author',
'covers',
'coversNothing',
'dataProvider',
'depends',
'group',
'internal',
'method',
'property',
'property-read',
'property-write',
'requires',
'throws',
'uses',
],
],
'phpdoc_return_self_reference' => [
'replacements' => [
'this' => '$this',
'@this' => '$this',
'$self' => 'self',
'@self' => 'self',
'$static' => 'static',
'@static' => 'static',
],
],
'phpdoc_scalar' => [
'types' => [
'boolean',
'callback',
'double',
'integer',
'real',
'str',
],
],
'phpdoc_separation' => [
'groups' => [
['deprecated', 'link', 'see', 'since'],
['author', 'copyright', 'license'],
['category', 'package', 'subpackage'],
['property', 'property-read', 'property-write'],
],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
'phpdoc_to_comment' => ['ignored_tags' => [
'phpstan-var',
'phpstan-return',
]],
'phpdoc_to_param_type' => false,
'phpdoc_to_property_type' => ['scalar_types' => true],
'phpdoc_to_return_type' => false,
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
'phpdoc_types_order' => [
'null_adjustment' => 'always_first',
'sort_algorithm' => 'alpha',
],
'phpdoc_var_annotation_correct_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'psr_autoloading' => ['dir' => null],
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'mt_rand',
'srand' => 'mt_srand',
],
],
'regular_callable_call' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => true,
'self_static_accessor' => true,
'semicolon_after_instruction' => true,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simple_to_complex_string_variable' => true,
'simplified_if_return' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
'single_import_per_statement' => ['group_to_single_imports' => true],
'single_line_after_imports' => true,
'single_line_comment_spacing' => true,
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
'single_line_throw' => false,
'single_quote' => ['strings_containing_single_quote_chars' => false],
'single_space_after_construct' => [
'constructs' => [
'abstract',
'as',
'attribute',
'break',
'case',
'catch',
'class',
'clone',
'comment',
'const',
'const_import',
'continue',
'do',
'echo',
'else',
'elseif',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'function_import',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'match',
'named_argument',
'new',
'open_tag_with_echo',
'php_doc',
'php_open',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'throw',
'trait',
'try',
'use',
'use_lambda',
'use_trait',
'var',
'while',
'yield',
'yield_from',
],
],
'single_trait_insert_per_statement' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_increment' => true,
'standardize_not_equals' => true,
'statement_indentation' => true,
'static_lambda' => true,
'strict_comparison' => true,
'strict_param' => true,
'string_length_to_empty' => true,
'string_line_ending' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['arrays', 'arguments'],
],
'trim_array_spaces' => true,
'types_spaces' => ['space' => 'none', 'space_multiple_catch' => null],
'unary_operator_spaces' => true,
'use_arrow_functions' => true,
'visibility_required' => ['elements' => ['const', 'method', 'property']],
'void_return' => false,
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'yoda_style' => [
'always_move_variable' => true,
'equal' => true,
'identical' => true,
'less_and_greater' => null,
],
];
$this->requiredPHPVersion = 70400;
$this->autoActivateIsRiskyAllowed = true;
}
}
+637
View File
@@ -0,0 +1,637 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Ruleset;
/**
* Ruleset for `Nexus` group.
*
* @internal
*/
final class Nexus80 extends AbstractRuleset
{
public function __construct()
{
$this->name = 'Nexus for PHP 8.0';
$this->rules = [
'align_multiline_comment' => ['comment_type' => 'all_multiline'],
'array_indentation' => true,
'array_push' => true,
'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true,
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [],
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => [
'case',
'continue',
'declare',
'default',
'do',
'exit',
'for',
'foreach',
'goto',
'if',
'return',
'switch',
'throw',
'try',
'while',
'yield',
'yield_from',
],
],
'blank_line_between_import_groups' => true,
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'allow_single_line_closure' => true,
'position_after_anonymous_constructs' => 'same',
'position_after_control_structures' => 'same',
'position_after_functions_and_oop_constructs' => 'next',
],
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => [
'elements' => [
'const' => 'none',
'property' => 'none',
'method' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
'space_before_parenthesis' => true,
'inline_constructor_arguments' => true,
],
'class_reference_name_casing' => true,
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => [
'ignored_tags' => [
'todo',
'codeCoverageIgnore',
'codeCoverageIgnoreStart',
'codeCoverageIgnoreEnd',
'phpstan-ignore-line',
'phpstan-ignore-next-line',
],
],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'none'],
'constant_case' => ['case' => 'lower'],
'control_structure_braces' => true,
'control_structure_continuation_position' => ['position' => 'same_line'],
'curly_braces_position' => [
'control_structures_opening_brace' => 'same_line',
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_functions_opening_brace' => 'same_line',
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_classes_opening_brace' => 'same_line',
'allow_single_line_empty_anonymous_classes' => true,
'allow_single_line_anonymous_functions' => true,
],
'date_time_create_from_format_call' => true,
'date_time_immutable' => true,
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => false,
'doctrine_annotation_braces' => false,
'doctrine_annotation_indentation' => false,
'doctrine_annotation_spaces' => false,
'echo_tag_syntax' => [
'format' => 'short',
'long_function' => 'echo',
'shorten_simple_statements_only' => true,
],
'elseif' => true,
'empty_loop_body' => ['style' => 'braces'],
'empty_loop_condition' => ['style' => 'while'],
'encoding' => true,
'ereg_to_preg' => true,
'error_suppression' => [
'mute_deprecation_error' => true,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'escape_implicit_backslashes' => [
'double_quoted' => true,
'heredoc_syntax' => true,
'single_quoted' => false,
],
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_class' => false,
'final_internal_class' => [
'annotation_exclude' => ['@final', '@no-final'],
'annotation_include' => ['@internal'],
'consider_absent_docblock_as_internal_class' => true,
],
'final_public_method_for_abstract_class' => true,
'fopen_flag_order' => true,
'fopen_flags' => ['b_mode' => true],
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => [
'closure_function_spacing' => 'one',
'closure_fn_spacing' => 'one',
'trailing_comma_single_line' => false,
],
'function_to_constant' => [
'functions' => [
'get_called_class',
'get_class',
'get_class_this',
'php_sapi_name',
'phpversion',
'pi',
],
],
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => [
'annotations' => [
'package',
'subpackage',
],
'case_sensitive' => false,
],
'general_phpdoc_tag_rename' => [
'case_sensitive' => false,
'fix_annotation' => true,
'fix_inline' => true,
'replacements' => ['inheritDocs' => 'inheritDoc'],
],
'get_class_to_class_keyword' => true,
'global_namespace_import' => [
'import_classes' => false,
'import_constants' => false,
'import_functions' => false,
],
'group_import' => false,
'header_comment' => false,
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'heredoc_to_nowdoc' => true,
'implode_call' => true,
'include' => true,
'increment_style' => ['style' => 'pre'],
'indentation_type' => true,
'integer_literal_case' => true,
'is_null' => true,
'lambda_not_used_import' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => true,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => false,
'method_argument_space' => [
'after_heredoc' => true,
'keep_multiple_spaces_after_comma' => false,
'on_multiline' => 'ensure_fully_multiline',
],
'method_chaining_indentation' => true,
'modernize_strpos' => true,
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
'native_constant_invocation' => [
'fix_built_in' => false,
'include' => [
'DIRECTORY_SEPARATOR',
'PHP_INT_SIZE',
'PHP_SAPI',
'PHP_VERSION_ID',
],
'exclude' => [],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_casing' => true,
'native_function_invocation' => [
'exclude' => [],
'include' => ['@compiler_optimized'],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_type_declaration_casing' => true,
'new_with_braces' => [
'named_class' => true,
'anonymous_class' => true,
],
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => ['fix_non_monolithic_code' => false],
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => false,
'no_break_comment' => ['comment_text' => 'no break'],
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => [
'tokens' => [
'extra',
'break',
'continue',
'curly_brace_block',
'parenthesis_brace_block',
'square_brace_block',
'return',
'throw',
'use',
'switch',
'case',
'default',
],
],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiple_statements_per_line' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_space_around_double_colon' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
'remove_inheritdoc' => false,
],
'no_trailing_comma_in_singleline' => [
'elements' => ['arguments', 'array', 'array_destructuring', 'group_import'],
],
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_trailing_whitespace_in_string' => true,
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'return',
'switch_case',
'yield',
],
],
'no_unneeded_curly_braces' => ['namespaces' => true],
'no_unneeded_final_method' => ['private_methods' => true],
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => false,
'no_unused_imports' => true,
'no_useless_concat_operator' => ['juggle_simple_strings' => true],
'no_useless_else' => true,
'no_useless_nullsafe_operator' => true,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => false],
'no_whitespace_in_blank_line' => true,
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
'normalize_index_brace' => true,
'not_operator_with_space' => false,
'not_operator_with_successor_space' => true,
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
'object_operator_without_whitespace' => true,
'octal_notation' => false, // requires 8.1+
'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
'ordered_class_elements' => [
'order' => [
'use_trait',
'constant_public',
'constant_protected',
'constant_private',
'property_public',
'property_protected',
'property_private',
'construct',
'destruct',
'magic',
'phpunit',
'method_public_static',
'method_protected_static',
'method_private_static',
'method_public',
'method_protected',
'method_private',
],
'sort_algorithm' => 'none',
],
'ordered_imports' => [
'imports_order' => ['class', 'function', 'const'],
'sort_algorithm' => 'alpha',
],
'ordered_interfaces' => false,
'ordered_traits' => true,
'php_unit_construct' => [
'assertions' => [
'assertEquals',
'assertSame',
'assertNotEquals',
'assertNotSame',
],
],
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
'php_unit_expectation' => ['target' => 'newest'],
'php_unit_fqcn_annotation' => true,
'php_unit_internal_class' => ['types' => ['normal', 'final']],
'php_unit_method_casing' => ['case' => 'camel_case'],
'php_unit_mock' => ['target' => 'newest'],
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => ['target' => 'newest'],
'php_unit_no_expectation_annotation' => [
'target' => 'newest',
'use_class_const' => true,
],
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_size_class' => false,
'php_unit_strict' => [
'assertions' => [
'assertAttributeEquals',
'assertAttributeNotEquals',
'assertEquals',
'assertNotEquals',
],
],
'php_unit_test_annotation' => ['style' => 'prefix'],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'self',
'methods' => [],
],
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_align' => [
'align' => 'vertical',
'tags' => [
'method',
'param',
'property',
'return',
'throws',
'type',
'var',
],
],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => [
'tags' => [
'example',
'id',
'internal',
'inheritdoc',
'inheritdocs',
'link',
'source',
'toc',
'tutorial',
],
],
'phpdoc_line_span' => [
'const' => 'multi',
'method' => 'multi',
'property' => 'multi',
],
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => [
'replacements' => [
'property-read' => 'property',
'property-write' => 'property',
'type' => 'var',
'link' => 'see',
],
],
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => ['order' => ['param', 'return', 'throws']],
'phpdoc_order_by_value' => [
'annotations' => [
'author',
'covers',
'coversNothing',
'dataProvider',
'depends',
'group',
'internal',
'method',
'property',
'property-read',
'property-write',
'requires',
'throws',
'uses',
],
],
'phpdoc_return_self_reference' => [
'replacements' => [
'this' => '$this',
'@this' => '$this',
'$self' => 'self',
'@self' => 'self',
'$static' => 'static',
'@static' => 'static',
],
],
'phpdoc_scalar' => [
'types' => [
'boolean',
'callback',
'double',
'integer',
'real',
'str',
],
],
'phpdoc_separation' => [
'groups' => [
['deprecated', 'link', 'see', 'since'],
['author', 'copyright', 'license'],
['category', 'package', 'subpackage'],
['property', 'property-read', 'property-write'],
],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
'phpdoc_to_comment' => ['ignored_tags' => [
'phpstan-var',
'phpstan-return',
]],
'phpdoc_to_param_type' => ['scalar_types' => true],
'phpdoc_to_property_type' => ['scalar_types' => true],
'phpdoc_to_return_type' => ['scalar_types' => true],
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
'phpdoc_types_order' => [
'null_adjustment' => 'always_first',
'sort_algorithm' => 'alpha',
],
'phpdoc_var_annotation_correct_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'psr_autoloading' => ['dir' => null],
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'mt_rand',
'srand' => 'mt_srand',
],
],
'regular_callable_call' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => true,
'self_static_accessor' => true,
'semicolon_after_instruction' => true,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simple_to_complex_string_variable' => true,
'simplified_if_return' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
'single_import_per_statement' => ['group_to_single_imports' => true],
'single_line_after_imports' => true,
'single_line_comment_spacing' => true,
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
'single_line_throw' => false,
'single_quote' => ['strings_containing_single_quote_chars' => false],
'single_space_after_construct' => [
'constructs' => [
'abstract',
'as',
'attribute',
'break',
'case',
'catch',
'class',
'clone',
'comment',
'const',
'const_import',
'continue',
'do',
'echo',
'else',
'elseif',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'function_import',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'match',
'named_argument',
'new',
'open_tag_with_echo',
'php_doc',
'php_open',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'throw',
'trait',
'try',
'use',
'use_lambda',
'use_trait',
'var',
'while',
'yield',
'yield_from',
],
],
'single_trait_insert_per_statement' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_increment' => true,
'standardize_not_equals' => true,
'statement_indentation' => true,
'static_lambda' => true,
'strict_comparison' => true,
'strict_param' => true,
'string_length_to_empty' => true,
'string_line_ending' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['arrays', 'arguments', 'parameters'],
],
'trim_array_spaces' => true,
'types_spaces' => ['space' => 'none', 'space_multiple_catch' => null],
'unary_operator_spaces' => true,
'use_arrow_functions' => true,
'visibility_required' => ['elements' => ['const', 'method', 'property']],
'void_return' => true,
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'yoda_style' => [
'always_move_variable' => true,
'equal' => true,
'identical' => true,
'less_and_greater' => null,
],
];
$this->requiredPHPVersion = 80000;
$this->autoActivateIsRiskyAllowed = true;
}
}
+637
View File
@@ -0,0 +1,637 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Ruleset;
/**
* Ruleset for `Nexus` group.
*
* @internal
*/
final class Nexus81 extends AbstractRuleset
{
public function __construct()
{
$this->name = 'Nexus for PHP 8.1';
$this->rules = [
'align_multiline_comment' => ['comment_type' => 'all_multiline'],
'array_indentation' => true,
'array_push' => true,
'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true,
'backtick_to_shell_exec' => true,
'binary_operator_spaces' => [
'default' => 'single_space',
'operators' => [],
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => [
'case',
'continue',
'declare',
'default',
'do',
'exit',
'for',
'foreach',
'goto',
'if',
'return',
'switch',
'throw',
'try',
'while',
'yield',
'yield_from',
],
],
'blank_line_between_import_groups' => true,
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'allow_single_line_closure' => true,
'position_after_anonymous_constructs' => 'same',
'position_after_control_structures' => 'same',
'position_after_functions_and_oop_constructs' => 'next',
],
'cast_spaces' => ['space' => 'single'],
'class_attributes_separation' => [
'elements' => [
'const' => 'none',
'property' => 'none',
'method' => 'one',
'trait_import' => 'none',
],
],
'class_definition' => [
'multi_line_extends_each_single_line' => true,
'single_item_single_line' => true,
'single_line' => true,
'space_before_parenthesis' => true,
'inline_constructor_arguments' => true,
],
'class_reference_name_casing' => true,
'clean_namespace' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true,
'comment_to_phpdoc' => [
'ignored_tags' => [
'todo',
'codeCoverageIgnore',
'codeCoverageIgnoreStart',
'codeCoverageIgnoreEnd',
'phpstan-ignore-line',
'phpstan-ignore-next-line',
],
],
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'none'],
'constant_case' => ['case' => 'lower'],
'control_structure_braces' => true,
'control_structure_continuation_position' => ['position' => 'same_line'],
'curly_braces_position' => [
'control_structures_opening_brace' => 'same_line',
'functions_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_functions_opening_brace' => 'same_line',
'classes_opening_brace' => 'next_line_unless_newline_at_signature_end',
'anonymous_classes_opening_brace' => 'same_line',
'allow_single_line_empty_anonymous_classes' => true,
'allow_single_line_anonymous_functions' => true,
],
'date_time_create_from_format_call' => true,
'date_time_immutable' => true,
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'declare_strict_types' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => false,
'doctrine_annotation_braces' => false,
'doctrine_annotation_indentation' => false,
'doctrine_annotation_spaces' => false,
'echo_tag_syntax' => [
'format' => 'short',
'long_function' => 'echo',
'shorten_simple_statements_only' => true,
],
'elseif' => true,
'empty_loop_body' => ['style' => 'braces'],
'empty_loop_condition' => ['style' => 'while'],
'encoding' => true,
'ereg_to_preg' => true,
'error_suppression' => [
'mute_deprecation_error' => true,
'noise_remaining_usages' => false,
'noise_remaining_usages_exclude' => [],
],
'escape_implicit_backslashes' => [
'double_quoted' => true,
'heredoc_syntax' => true,
'single_quoted' => false,
],
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'final_class' => false,
'final_internal_class' => [
'annotation_exclude' => ['@final', '@no-final'],
'annotation_include' => ['@internal'],
'consider_absent_docblock_as_internal_class' => true,
],
'final_public_method_for_abstract_class' => true,
'fopen_flag_order' => true,
'fopen_flags' => ['b_mode' => true],
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => [
'closure_function_spacing' => 'one',
'closure_fn_spacing' => 'one',
'trailing_comma_single_line' => false,
],
'function_to_constant' => [
'functions' => [
'get_called_class',
'get_class',
'get_class_this',
'php_sapi_name',
'phpversion',
'pi',
],
],
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => [
'annotations' => [
'package',
'subpackage',
],
'case_sensitive' => false,
],
'general_phpdoc_tag_rename' => [
'case_sensitive' => false,
'fix_annotation' => true,
'fix_inline' => true,
'replacements' => ['inheritDocs' => 'inheritDoc'],
],
'get_class_to_class_keyword' => true,
'global_namespace_import' => [
'import_classes' => false,
'import_constants' => false,
'import_functions' => false,
],
'group_import' => false,
'header_comment' => false,
'heredoc_indentation' => ['indentation' => 'start_plus_one'],
'heredoc_to_nowdoc' => true,
'implode_call' => true,
'include' => true,
'increment_style' => ['style' => 'pre'],
'indentation_type' => true,
'integer_literal_case' => true,
'is_null' => true,
'lambda_not_used_import' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => true,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'mb_str_functions' => false,
'method_argument_space' => [
'after_heredoc' => true,
'keep_multiple_spaces_after_comma' => false,
'on_multiline' => 'ensure_fully_multiline',
],
'method_chaining_indentation' => true,
'modernize_strpos' => true,
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
'native_constant_invocation' => [
'fix_built_in' => false,
'include' => [
'DIRECTORY_SEPARATOR',
'PHP_INT_SIZE',
'PHP_SAPI',
'PHP_VERSION_ID',
],
'exclude' => [],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_casing' => true,
'native_function_invocation' => [
'exclude' => [],
'include' => ['@compiler_optimized'],
'scope' => 'namespaced',
'strict' => true,
],
'native_function_type_declaration_casing' => true,
'new_with_braces' => [
'named_class' => true,
'anonymous_class' => true,
],
'no_alias_functions' => ['sets' => ['@all']],
'no_alias_language_construct_call' => true,
'no_alternative_syntax' => ['fix_non_monolithic_code' => false],
'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => false,
'no_break_comment' => ['comment_text' => 'no break'],
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => [
'tokens' => [
'extra',
'break',
'continue',
'curly_brace_block',
'parenthesis_brace_block',
'square_brace_block',
'return',
'throw',
'use',
'switch',
'case',
'default',
],
],
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiple_statements_per_line' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_space_around_double_colon' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => ['positions' => ['inside', 'outside']],
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => [
'allow_mixed' => true,
'allow_unused_params' => true,
'remove_inheritdoc' => false,
],
'no_trailing_comma_in_singleline' => [
'elements' => ['arguments', 'array', 'array_destructuring', 'group_import'],
],
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_trailing_whitespace_in_string' => true,
'no_unneeded_control_parentheses' => [
'statements' => [
'break',
'clone',
'continue',
'echo_print',
'return',
'switch_case',
'yield',
],
],
'no_unneeded_curly_braces' => ['namespaces' => true],
'no_unneeded_final_method' => ['private_methods' => true],
'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_cast' => true,
'no_unset_on_property' => false,
'no_unused_imports' => true,
'no_useless_concat_operator' => ['juggle_simple_strings' => true],
'no_useless_else' => true,
'no_useless_nullsafe_operator' => true,
'no_useless_return' => true,
'no_useless_sprintf' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => false],
'no_whitespace_in_blank_line' => true,
'non_printable_character' => ['use_escape_sequences_in_strings' => true],
'normalize_index_brace' => true,
'not_operator_with_space' => false,
'not_operator_with_successor_space' => true,
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true],
'object_operator_without_whitespace' => true,
'octal_notation' => true,
'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'],
'ordered_class_elements' => [
'order' => [
'use_trait',
'constant_public',
'constant_protected',
'constant_private',
'property_public',
'property_protected',
'property_private',
'construct',
'destruct',
'magic',
'phpunit',
'method_public_static',
'method_protected_static',
'method_private_static',
'method_public',
'method_protected',
'method_private',
],
'sort_algorithm' => 'none',
],
'ordered_imports' => [
'imports_order' => ['class', 'function', 'const'],
'sort_algorithm' => 'alpha',
],
'ordered_interfaces' => false,
'ordered_traits' => true,
'php_unit_construct' => [
'assertions' => [
'assertEquals',
'assertSame',
'assertNotEquals',
'assertNotSame',
],
],
'php_unit_dedicate_assert' => ['target' => 'newest'],
'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
'php_unit_expectation' => ['target' => 'newest'],
'php_unit_fqcn_annotation' => true,
'php_unit_internal_class' => ['types' => ['normal', 'final']],
'php_unit_method_casing' => ['case' => 'camel_case'],
'php_unit_mock' => ['target' => 'newest'],
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => ['target' => 'newest'],
'php_unit_no_expectation_annotation' => [
'target' => 'newest',
'use_class_const' => true,
],
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_size_class' => false,
'php_unit_strict' => [
'assertions' => [
'assertAttributeEquals',
'assertAttributeNotEquals',
'assertEquals',
'assertNotEquals',
],
],
'php_unit_test_annotation' => ['style' => 'prefix'],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'self',
'methods' => [],
],
'php_unit_test_class_requires_covers' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => true],
'phpdoc_align' => [
'align' => 'vertical',
'tags' => [
'method',
'param',
'property',
'return',
'throws',
'type',
'var',
],
],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag_normalizer' => [
'tags' => [
'example',
'id',
'internal',
'inheritdoc',
'inheritdocs',
'link',
'source',
'toc',
'tutorial',
],
],
'phpdoc_line_span' => [
'const' => 'multi',
'method' => 'multi',
'property' => 'multi',
],
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => [
'replacements' => [
'property-read' => 'property',
'property-write' => 'property',
'type' => 'var',
'link' => 'see',
],
],
'phpdoc_no_empty_return' => false,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => ['order' => ['param', 'return', 'throws']],
'phpdoc_order_by_value' => [
'annotations' => [
'author',
'covers',
'coversNothing',
'dataProvider',
'depends',
'group',
'internal',
'method',
'property',
'property-read',
'property-write',
'requires',
'throws',
'uses',
],
],
'phpdoc_return_self_reference' => [
'replacements' => [
'this' => '$this',
'@this' => '$this',
'$self' => 'self',
'@self' => 'self',
'$static' => 'static',
'@static' => 'static',
],
],
'phpdoc_scalar' => [
'types' => [
'boolean',
'callback',
'double',
'integer',
'real',
'str',
],
],
'phpdoc_separation' => [
'groups' => [
['deprecated', 'link', 'see', 'since'],
['author', 'copyright', 'license'],
['category', 'package', 'subpackage'],
['property', 'property-read', 'property-write'],
],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_tag_casing' => ['tags' => ['inheritDoc']],
'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']],
'phpdoc_to_comment' => ['ignored_tags' => [
'phpstan-var',
'phpstan-return',
]],
'phpdoc_to_param_type' => ['scalar_types' => true],
'phpdoc_to_property_type' => ['scalar_types' => true],
'phpdoc_to_return_type' => ['scalar_types' => true],
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']],
'phpdoc_types_order' => [
'null_adjustment' => 'always_first',
'sort_algorithm' => 'alpha',
],
'phpdoc_var_annotation_correct_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'psr_autoloading' => ['dir' => null],
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'mt_rand',
'srand' => 'mt_srand',
],
],
'regular_callable_call' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => true,
'self_static_accessor' => true,
'semicolon_after_instruction' => true,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simple_to_complex_string_variable' => true,
'simplified_if_return' => true,
'simplified_null_return' => false,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => ['elements' => ['const', 'property']],
'single_import_per_statement' => ['group_to_single_imports' => true],
'single_line_after_imports' => true,
'single_line_comment_spacing' => true,
'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']],
'single_line_throw' => false,
'single_quote' => ['strings_containing_single_quote_chars' => false],
'single_space_after_construct' => [
'constructs' => [
'abstract',
'as',
'attribute',
'break',
'case',
'catch',
'class',
'clone',
'comment',
'const',
'const_import',
'continue',
'do',
'echo',
'else',
'elseif',
'extends',
'final',
'finally',
'for',
'foreach',
'function',
'function_import',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'interface',
'match',
'named_argument',
'new',
'open_tag_with_echo',
'php_doc',
'php_open',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'return',
'static',
'throw',
'trait',
'try',
'use',
'use_lambda',
'use_trait',
'var',
'while',
'yield',
'yield_from',
],
],
'single_trait_insert_per_statement' => true,
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
'standardize_increment' => true,
'standardize_not_equals' => true,
'statement_indentation' => true,
'static_lambda' => true,
'strict_comparison' => true,
'strict_param' => true,
'string_length_to_empty' => true,
'string_line_ending' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'switch_continue_to_break' => true,
'ternary_operator_spaces' => true,
'ternary_to_elvis_operator' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['arrays', 'arguments', 'parameters'],
],
'trim_array_spaces' => true,
'types_spaces' => ['space' => 'none', 'space_multiple_catch' => null],
'unary_operator_spaces' => true,
'use_arrow_functions' => true,
'visibility_required' => ['elements' => ['const', 'method', 'property']],
'void_return' => true,
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'yoda_style' => [
'always_move_variable' => true,
'equal' => true,
'identical' => true,
'less_and_greater' => null,
],
];
$this->requiredPHPVersion = 80000;
$this->autoActivateIsRiskyAllowed = true;
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Ruleset;
interface RulesetInterface
{
/**
* Name of this ruleset.
*/
public function getName(): string;
/**
* Defined rules for this ruleset.
*/
public function getRules(): array;
/**
* Returns the minimum `PHP_VERSION_ID`
* that is required by this ruleset.
*/
public function getRequiredPHPVersion(): int;
/**
* Does this ruleset have risky rules?
*
* If yes and `PhpCsFixer\Config` has the `$isRiskyAllowed`
* flag set to `false`, those risky rules won't be run.
*
* Set this flag to `true` to automatically setup
* the `$isRiskyAllowed` flag.
*/
public function willAutoActivateIsRiskyAllowed(): bool;
}
@@ -0,0 +1,373 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Test;
use Nexus\CsConfig\Fixer\AbstractCustomFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\DeprecatedFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionInterface;
use PhpCsFixer\FixerDefinition\CodeSampleInterface;
use PhpCsFixer\FixerDefinition\FileSpecificCodeSampleInterface;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
use PhpCsFixer\FixerNameValidator;
use PhpCsFixer\Linter\CachingLinter;
use PhpCsFixer\Linter\LinterInterface;
use PhpCsFixer\Linter\ProcessLinter;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PHPUnit\Framework\TestCase;
/**
* Used for testing the fixers.
*
* Most of the tests here are directly from `PhpCsFixer\Tests\Test\AbstractFixerTestCase`
* with some modifications and additions, since the test case is not shipped to production.
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
* @author John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*/
abstract class AbstractCustomFixerTestCase extends TestCase
{
protected AbstractCustomFixer $fixer;
protected LinterInterface $linter;
protected function setUp(): void
{
parent::setUp();
$this->fixer = $this->createFixer();
$this->linter = $this->getLinter();
}
private static function assertTokens(Tokens $expectedTokens, Tokens $inputTokens): void
{
self::assertSame($expectedTokens->count(), $inputTokens->count(), 'Both Tokens collections should have the same size.');
/** @var Token $expectedToken */
foreach ($expectedTokens as $index => $expectedToken) {
/** @var Token $inputToken */
$inputToken = $inputTokens[$index];
self::assertTrue(
$expectedToken->equals($inputToken),
sprintf("Token at index %d must be:\n%s,\ngot:\n%s.", $index, $expectedToken->toJson(), $inputToken->toJson()),
);
}
}
private static function assertValidDescription(string $fixerName, string $descriptionType, string $description): void
{
self::assertMatchesRegularExpression('/^[A-Z`][^"]+\.$/', $description, sprintf('[%s] The %s must start with capital letter or a ` and end with dot.', $fixerName, $descriptionType));
self::assertStringNotContainsString('phpdocs', $description, sprintf('[%s] `PHPDoc` must not be in the plural in %s.', $fixerName, $descriptionType));
self::assertCorrectCasing($description, 'PHPDoc', sprintf('[%s] `PHPDoc` must be in correct casing in %s.', $fixerName, $descriptionType));
self::assertCorrectCasing($description, 'PHPUnit', sprintf('[%s] `PHPUnit` must be in correct casing in %s.', $fixerName, $descriptionType));
self::assertFalse(strpos($descriptionType, '``'), sprintf('[%s] The %s must not contain sequential backticks.', $fixerName, $descriptionType));
}
private static function assertCorrectCasing(string $needle, string $haystack, string $message): void
{
self::assertSame(substr_count(strtolower($haystack), strtolower($needle)), substr_count($haystack, $needle), $message);
}
final public function testIsRisky(): void
{
$riskyDescription = $this->fixer->getDefinition()->getRiskyDescription();
if ($this->fixer->isRisky()) {
self::assertIsString($riskyDescription);
self::assertValidDescription($this->fixer->getName(), 'risky description', (string) $riskyDescription);
} else {
self::assertNull($riskyDescription, sprintf('[%s] Fixer is not risky so no description of it is expected.', $this->fixer->getName()));
}
$reflection = new \ReflectionMethod($this->fixer, 'isRisky');
self::assertSame(
! $this->fixer->isRisky(),
$reflection->getDeclaringClass()->getName() === AbstractFixer::class,
sprintf(
'[%s] Fixer is %s so the method "AbstractFixer::isRisky()" must be %s.',
$this->fixer->getName(),
$this->fixer->isRisky() ? 'risky' : 'not risky',
$this->fixer->isRisky() ? 'overridden' : 'used',
),
);
}
final public function testNameIsValid(): void
{
$nameValidator = new FixerNameValidator();
$customFixerName = $this->fixer->getName();
self::assertTrue(
$nameValidator->isValid($customFixerName, true),
sprintf('Fixer name "%s" is not valid.', $customFixerName),
);
}
final public function testFixerIsFinal(): void
{
self::assertTrue(
(new \ReflectionClass($this->fixer))->isFinal(),
sprintf('Fixer "%s" must be declared "final".', $this->fixer->getName()),
);
}
final public function testDeprecatedFixersHaveCorrectSummary(): void
{
self::assertStringNotContainsString(
'DEPRECATED',
$this->fixer->getDefinition()->getSummary(),
'Fixer cannot contain word "DEPRECATED" in summary',
);
$comment = (new \ReflectionClass($this->fixer))->getDocComment();
self::assertIsString($comment, sprintf('[%s] Fixer is missing a class-level PHPDoc.', $this->fixer->getName()));
$comment = (string) $comment;
if ($this->fixer instanceof DeprecatedFixerInterface) {
self::assertStringContainsString('@deprecated', $comment);
} else {
self::assertStringNotContainsString('@deprecated', $comment);
}
}
final public function testFixerConfigurationDefinitions(): void
{
if (! $this->fixer instanceof ConfigurableFixerInterface) {
$this->addToAssertionCount(1); // not applied to the fixer without configuration
return;
}
$configurationDefinition = $this->fixer->getConfigurationDefinition();
self::assertInstanceOf(FixerConfigurationResolverInterface::class, $configurationDefinition);
foreach ($configurationDefinition->getOptions() as $option) {
self::assertInstanceOf(FixerOptionInterface::class, $option);
self::assertNotEmpty($option->getDescription());
self::assertTrue(
$option->hasDefault(),
sprintf(
'Option `%s` of fixer `%s` should have a default value.',
$option->getName(),
$this->fixer->getName(),
),
);
self::assertStringNotContainsString(
'DEPRECATED',
$option->getDescription(),
'Option description cannot contain word "DEPRECATED"',
);
}
}
final public function testFixerDefinitions(): void
{
$fixerName = $this->fixer->getName();
$definition = $this->fixer->getDefinition();
$fixerIsConfigurable = $this->fixer instanceof ConfigurableFixerInterface;
self::assertValidDescription($fixerName, 'summary', $definition->getSummary());
$samples = $definition->getCodeSamples();
self::assertNotEmpty($samples, sprintf('[%s] Code samples are required.', $fixerName));
$configSamplesProvided = [];
$dummyFileInfo = new \SplFileInfo(__FILE__);
foreach ($samples as $counter => $sample) {
self::assertIsInt($counter);
++$counter;
self::assertInstanceOf(CodeSampleInterface::class, $sample, sprintf('[%s] Sample #%d must be an instance of "%s".', $fixerName, $counter, CodeSampleInterface::class));
$code = $sample->getCode();
self::assertNotEmpty($code, sprintf('[%s] Code provided by sample #%d must not be empty.', $fixerName, $counter));
self::assertSame("\n", substr($code, -1), sprintf('[%s] Sample #%d must end with linebreak', $fixerName, $counter));
$config = $sample->getConfiguration();
if (null !== $config) {
self::assertTrue($fixerIsConfigurable, sprintf('[%s] Sample #%d has configuration, but the fixer is not configurable.', $fixerName, $counter));
self::assertIsArray($config, sprintf('[%s] Sample #%d configuration must be an array or null.', $fixerName, $counter));
$configSamplesProvided[$counter] = $config;
} elseif ($fixerIsConfigurable) {
if (! $sample instanceof VersionSpecificCodeSampleInterface) {
self::assertArrayNotHasKey('default', $configSamplesProvided, sprintf('[%s] Multiple non-versioned samples with default configuration.', $fixerName));
}
$configSamplesProvided['default'] = true;
}
if ($sample instanceof VersionSpecificCodeSampleInterface && ! $sample->isSuitableFor(\PHP_VERSION_ID)) {
continue;
}
if ($fixerIsConfigurable) {
// always re-configure as the fixer might have been configured with diff. configuration from previous sample
$this->fixer->configure(null === $config ? [] : $config);
}
Tokens::clearCache();
$tokens = Tokens::fromCode($code);
$this->fixer->fix(
$sample instanceof FileSpecificCodeSampleInterface ? $sample->getSplFileInfo() : $dummyFileInfo,
$tokens,
);
self::assertTrue($tokens->isChanged(), sprintf('[%s] Sample #%d is not changed during fixing.', $fixerName, $counter));
$duplicatedCodeSample = array_search(
$sample,
\array_slice($samples, 0, $counter - 1),
false,
);
self::assertFalse(
$duplicatedCodeSample,
sprintf('[%s] Sample #%d duplicates #%d.', $fixerName, $counter, ++$duplicatedCodeSample),
);
}
if ($fixerIsConfigurable) {
if (isset($configSamplesProvided['default'])) {
reset($configSamplesProvided);
self::assertSame('default', key($configSamplesProvided), sprintf('[%s] First sample must be for the default configuration.', $fixerName));
}
if (\count($configSamplesProvided) < 2) {
self::fail(sprintf('[%s] Configurable fixer only provides a default configuration sample and none for its configuration options.', $fixerName));
}
$options = $this->fixer->getConfigurationDefinition()->getOptions();
foreach ($options as $option) {
self::assertMatchesRegularExpression('/^[a-z_]+[a-z]$/', $option->getName(), sprintf('[%s] Option %s is not snake_case.', $fixerName, $option->getName()));
}
}
}
/**
* Tests if a fixer fixes a given string to match the expected result.
*
* It is used both if you want to test if something is fixed or if it is not touched by the fixer.
*
* It also makes sure that the expected output does not change when run through the fixer. That means that you
* do not need two test cases like [$expected] and [$expected, $input] (where $expected is the same in both cases)
* as the latter covers both of them.
*
* This method throws an exception if $expected and $input are equal to prevent test cases that accidentally do
* not test anything.
*
* @param string $expected The expected fixer output
* @param null|string $input The fixer input, or null if it should intentionally be equal to the output
*/
protected function doTest(string $expected, ?string $input = null): void
{
if ($expected === $input) {
throw new \LogicException('Input parameter must not be equal to expected parameter.'); // @codeCoverageIgnore
}
$file = new \SplFileInfo(__FILE__);
if (null !== $input) {
self::assertNull($this->lintSource($input));
Tokens::clearCache();
$tokens = Tokens::fromCode($input);
self::assertTrue($this->fixer->isCandidate($tokens), 'Fixer must be a candidate for input code.');
self::assertFalse($tokens->isChanged(), 'Fixer must not touch Tokens on candidate check.');
$this->fixer->fix($file, $tokens);
self::assertSame(
$expected,
$tokens->generateCode(),
'Code build on input code must match expected code.',
);
self::assertTrue($tokens->isChanged(), 'Tokens collection built on input code must be marked as changed after fixing.');
$tokens->clearEmptyTokens();
/** @var Token[] $tokensArray */
$tokensArray = $tokens->toArray();
self::assertSame(
\count($tokens),
\count(array_unique(array_map(static fn (Token $token): string => spl_object_hash($token), $tokensArray))),
'Token items inside Tokens collection must be unique.',
);
unset($tokensArray);
Tokens::clearCache();
$expectedTokens = Tokens::fromCode($expected);
self::assertTokens($expectedTokens, $tokens);
}
self::assertNull($this->lintSource($expected));
Tokens::clearCache();
$tokens = Tokens::fromCode($expected);
$this->fixer->fix($file, $tokens);
self::assertSame(
$expected,
$tokens->generateCode(),
'Code build on expected code must not change.',
);
self::assertFalse($tokens->isChanged(), 'Tokens collection built on expected code must not be marked as changed after fixing.');
}
protected function createFixer(): AbstractCustomFixer
{
/** @phpstan-var class-string<AbstractCustomFixer> $customFixer */
$customFixer = Preg::replace('/^(Nexus\\\\CsConfig)\\\\Tests(\\\\.+)Test$/', '$1$2', static::class);
return new $customFixer();
}
/**
* @codeCoverageIgnore
*/
protected function lintSource(string $source): ?string
{
try {
$this->linter->lintSource($source)->check();
return null;
} catch (\Throwable $e) {
return sprintf('Linting "%s" failed with message: %s.', $source, $e->getMessage());
}
}
private function getLinter(): LinterInterface
{
static $linter = null;
if (null === $linter) {
$linter = new CachingLinter(new ProcessLinter());
}
return $linter;
}
}
@@ -0,0 +1,224 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Test;
use Nexus\CsConfig\Ruleset\RulesetInterface;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\FixerConfiguration\DeprecatedFixerOptionInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionInterface;
use PhpCsFixer\Preg;
use PHPUnit\Framework\TestCase;
/**
* Used for testing the rulesets.
*/
abstract class AbstractRulesetTestCase extends TestCase
{
/**
* @var array<string, FixerInterface>
*/
private static array $builtInFixers = [];
/**
* @var array<int, string>
*/
private static array $configuredFixers = [];
/**
* @var array<string, array<string, bool|string|string[]>|bool>
*/
private static array $enabledFixers = [];
/**
* @codeCoverageIgnore
*/
public static function setUpBeforeClass(): void
{
$fixerProvider = FixerProvider::create(static::createRuleset());
self::$builtInFixers = $fixerProvider->builtin();
self::$configuredFixers = $fixerProvider->configured();
self::$enabledFixers = $fixerProvider->enabled();
}
/**
* @codeCoverageIgnore
*/
public static function tearDownAfterClass(): void
{
FixerProvider::reset();
self::$builtInFixers = [];
self::$configuredFixers = [];
self::$enabledFixers = [];
}
protected static function createRuleset(): RulesetInterface
{
/** @phpstan-var class-string<RulesetInterface> $className */
$className = Preg::replace('/^(Nexus\\\\CsConfig)\\\\Tests(\\\\.+)Test$/', '$1$2', static::class);
return new $className();
}
// =========================================================================
// TESTS
// =========================================================================
final public function testAllConfiguredFixersAreNotUsingPresets(): void
{
$fixersThatArePresets = array_filter(
self::$enabledFixers,
static fn (string $fixer): bool => substr($fixer, 0, 1) === '@',
ARRAY_FILTER_USE_KEY,
);
self::assertEmpty($fixersThatArePresets, sprintf(
'[%s] Ruleset should not be using rule sets (presets) as fixers. Found: "%s".',
static::createRuleset()->getName(),
implode('", "', array_keys($fixersThatArePresets)),
));
}
final public function testAllBuiltInFixersNotDeprecatedAreConfiguredInThisRuleset(): void
{
$fixersNotConfigured = array_diff(array_keys(self::$builtInFixers), self::$configuredFixers);
sort($fixersNotConfigured);
$c = \count($fixersNotConfigured);
self::assertEmpty($fixersNotConfigured, sprintf(
'[%s] Non-deprecated built-in %s "%s" %s not configured in the ruleset.',
static::createRuleset()->getName(),
$c > 1 ? 'fixers' : 'fixer',
implode('", "', $fixersNotConfigured),
$c > 1 ? 'are' : 'is',
));
}
final public function testAllConfiguredFixersInThisRulesetAreBuiltInAndNotDeprecated(): void
{
$fixersNotBuiltIn = array_diff(self::$configuredFixers, array_keys(self::$builtInFixers));
sort($fixersNotBuiltIn);
$c = \count($fixersNotBuiltIn);
self::assertEmpty($fixersNotBuiltIn, sprintf(
'[%s] Ruleset used %s "%s" which %s unknown and/or deprecated in PhpCsFixer.',
static::createRuleset()->getName(),
$c > 1 ? 'fixers' : 'fixer',
implode('", "', $fixersNotBuiltIn),
$c > 1 ? 'are' : 'is',
));
}
final public function testAllConfiguredFixersInThisRulesetAreSortedByName(): void
{
$fixers = self::$configuredFixers;
$sorted = $fixers;
sort($sorted);
self::assertSame($sorted, $fixers, sprintf(
'[%s] Fixers are not sorted by name.',
static::createRuleset()->getName(),
));
}
final public function testHeaderCommentFixerIsDisabledByDefault(): void
{
self::assertArrayHasKey('header_comment', self::$enabledFixers);
self::assertFalse(self::$enabledFixers['header_comment']);
}
/**
* @codeCoverageIgnore
*/
public function provideConfigurableFixersCases(): iterable
{
$fixers = FixerProvider::create(static::createRuleset())->builtin();
ksort($fixers);
foreach ($fixers as $name => $fixer) {
if ($fixer instanceof ConfigurableFixerInterface) {
$options = $fixer->getConfigurationDefinition()->getOptions();
$goodOptions = array_map(
static fn (FixerOptionInterface $option): string => $option->getName(),
array_filter(
$options,
static fn (FixerOptionInterface $option): bool => ! $option instanceof DeprecatedFixerOptionInterface,
),
);
$deprecatedOptions = array_map(
static fn (FixerOptionInterface $option): string => $option->getName(),
array_filter(
$options,
static fn (FixerOptionInterface $option): bool => $option instanceof DeprecatedFixerOptionInterface,
),
);
yield $name => [$name, $goodOptions, $deprecatedOptions];
}
}
}
/**
* @dataProvider provideConfigurableFixersCases
*/
final public function testEnabledConfigurableFixerUsesAllAvailableOptionsNotDeprecated(string $name, array $goodOptions, array $deprecatedOptions): void
{
/** @var null|array<string, bool|string|string[]>|bool $ruleConfiguration */
$ruleConfiguration = self::$enabledFixers[$name] ?? null;
if (null === $ruleConfiguration) {
self::markTestSkipped(sprintf('`%s` is not yet defined in this ruleset.', $name)); // @codeCoverageIgnore
}
if (false === $ruleConfiguration) {
// fixer is turned off
$this->addToAssertionCount(1);
return;
}
$ruleConfiguration = \is_array($ruleConfiguration) ? $ruleConfiguration : [];
$ruleConfiguration = array_keys($ruleConfiguration);
$missingOptions = array_diff($goodOptions, $ruleConfiguration);
$usedDeprecatedOptions = array_intersect($deprecatedOptions, $ruleConfiguration);
$extraUsedOptions = array_diff($ruleConfiguration, $goodOptions);
self::assertEmpty($missingOptions, sprintf(
'Enabled configurable fixer "%s" does not use its available array %s "%s". Missing %s: "%s".',
$name,
\count($goodOptions) > 1 ? 'options' : 'option',
implode('", "', $goodOptions),
\count($missingOptions) > 1 ? 'options' : 'option',
implode('", "', $missingOptions),
));
self::assertEmpty($usedDeprecatedOptions, sprintf(
'Enabled configurable fixer "%s" uses deprecated %s: "%s".',
$name,
\count($usedDeprecatedOptions) > 1 ? 'options' : 'option',
implode('", "', $usedDeprecatedOptions),
));
self::assertEmpty($extraUsedOptions, sprintf(
'%s "%s" for enabled configurable fixer "%s" %s not defined by PhpCsFixer.',
\count($extraUsedOptions) > 1 ? 'Options' : 'Option',
implode('", "', $extraUsedOptions),
$name,
\count($extraUsedOptions) > 1 ? 'are' : 'is',
));
}
}
+114
View File
@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/**
* This file is part of Nexus CS Config.
*
* (c) 2020 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Nexus\CsConfig\Test;
use Nexus\CsConfig\Ruleset\RulesetInterface;
use PhpCsFixer\Fixer\DeprecatedFixerInterface;
use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\FixerFactory;
use PhpCsFixer\RuleSet\RuleSet;
final class FixerProvider
{
/**
* Built-in fixers from php-cs-fixer.
*
* @var array<string, FixerInterface>
*/
private static array $builtIn = [];
/**
* Configured fixers from a ruleset.
*
* @var array<int, string>
*/
private array $configured = [];
/**
* Enabled fixers from a ruleset.
*
* @var array<string, array<string, bool|string|string[]>|bool>
*/
private array $enabled = [];
/**
* @param array<int, string> $configured
* @param array<string, array<string, bool|string|string[]>|bool> $enabled
*/
private function __construct(array $configured, array $enabled)
{
$this->configured = $configured;
$this->enabled = $enabled;
}
public static function create(RulesetInterface $ruleset): self
{
if ([] === self::$builtIn) {
$fixers = array_filter(
(new FixerFactory())->registerBuiltInFixers()->getFixers(),
static fn (FixerInterface $fixer): bool => ! $fixer instanceof DeprecatedFixerInterface,
);
foreach ($fixers as $fixer) {
// workaround for using `array_combine` with PHPStan on PHP < 80000
self::$builtIn[$fixer->getName()] = $fixer;
}
}
$rules = $ruleset->getRules();
$configured = array_map(static function ($ruleConfiguration): bool {
// force enable all rules
return true;
}, $rules);
return new self(array_keys((new RuleSet($configured))->getRules()), $rules);
}
public static function reset(): void
{
self::$builtIn = [];
}
/**
* Returns the names and instances of built-in fixers.
*
* @return array<string, FixerInterface>
*/
public function builtin(): array
{
return self::$builtIn;
}
/**
* Returns the names of the configured fixers.
*
* @return array<int, string>
*/
public function configured(): array
{
return $this->configured;
}
/**
* Returns the enabled rules from a ruleset and
* their configuration.
*
* @return array<string, array<string, bool|string|string[]>|bool>
*/
public function enabled(): array
{
return $this->enabled;
}
}