├── bin └── gen-rules ├── .php-cs-fixer.dist.php ├── src ├── ServiceProvider.php ├── Config.php └── Dev │ └── GenerateRules.php ├── config └── .php-cs-fixer.dist.php ├── LICENSE.md ├── composer.json ├── CHANGELOG.md └── README.md /bin/gen-rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | in(__DIR__); 7 | 8 | return (new MattAllan\LaravelCodeStyle\Config()) 9 | ->setFinder($finder) 10 | ->setRules([ 11 | '@Laravel' => true, 12 | '@Laravel:risky' => true, 13 | ]) 14 | ->setRiskyAllowed(true); 15 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 14 | __DIR__.'/../config/.php-cs-fixer.dist.php' => base_path('.php-cs-fixer.dist.php'), 15 | ], 'config'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /config/.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | setFinder( 8 | PhpCsFixer\Finder::create() 9 | ->in(app_path()) 10 | ->in(config_path()) 11 | ->in(database_path('factories')) 12 | ->in(database_path('seeders')) 13 | ->in(resource_path('lang')) 14 | ->in(base_path('routes')) 15 | ->in(base_path('tests')) 16 | ) 17 | ->setRules([ 18 | '@Laravel' => true, 19 | ]); 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Matt Allan 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "matt-allan/laravel-code-style", 3 | "description": "Code formatting for Laravel projects", 4 | "type": "library", 5 | "license": "MIT", 6 | "homepage": "https://github.com/matt-allan/laravel-code-style", 7 | "authors": [ 8 | { 9 | "name": "Matt Allan", 10 | "email": "matt@mattallan.me" 11 | } 12 | ], 13 | "keywords": [ 14 | "laravel", 15 | "code-style", 16 | "php-cs-fixer", 17 | "psr-2" 18 | ], 19 | "autoload": { 20 | "psr-4": { 21 | "MattAllan\\LaravelCodeStyle\\": "src" 22 | } 23 | }, 24 | "require": { 25 | "php": ">=7.4", 26 | "friendsofphp/php-cs-fixer": "^3.2.0", 27 | "illuminate/support": "^7.0|^8.0" 28 | }, 29 | "require-dev": { 30 | "brick/varexporter": "^0.3.2", 31 | "laravel/framework": "^7.0|^8.0", 32 | "orchestra/testbench": "^5.0|^6.0", 33 | "phpunit/phpunit": "^7.0|^8.0", 34 | "styleci/sdk": "^1.3" 35 | }, 36 | "extra": { 37 | "branch-alias": { 38 | "dev-main": "1.0-dev" 39 | }, 40 | "laravel": { 41 | "providers": [ 42 | "MattAllan\\LaravelCodeStyle\\ServiceProvider" 43 | ] 44 | } 45 | }, 46 | "scripts": { 47 | "test": "phpunit", 48 | "check-style": "php-cs-fixer fix --dry-run --diff", 49 | "fix-style": "php-cs-fixer fix", 50 | "gen-rules": "./bin/gen-rules" 51 | }, 52 | "config": { 53 | "sort-packages": true 54 | }, 55 | "minimum-stability": "dev", 56 | "prefer-stable": true, 57 | "abandoned": "jubeki/laravel-code-style" 58 | } 59 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes will be documented in this file. 4 | 5 | Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 6 | 7 | ## Unreleased 8 | 9 | ### Added 10 | ### Changed 11 | ### Removed 12 | 13 | ## 0.7.1 14 | 15 | - Added deprecation notice to composer.json. 16 | 17 | ## 0.7.0 18 | 19 | ### Added 20 | 21 | - Added the `array_indentation`, `clean_namespace`, `no_alias_language_construct_call`, `lambda_not_used_import`, `switch_continue_to_break`, `phpdoc_inline_tag_normalizer`, `integer_literal_case`, `no_space_around_double_colon`, and `types_spaces` rules. 22 | - Added support for PHP 8.0. 23 | - Added support for PHP-CS-Fixer 3.x 24 | 25 | ### Changed 26 | 27 | - The `method_argument_space` rule was updated to ignore multiline method calls. 28 | 29 | ### Removed 30 | 31 | - Removed the `phpdoc_inline_tag` rule. 32 | - Removed the `braces` rule. 33 | - Dropped PHP 7.2 and PHP 7.3 support. 34 | - Dropped support for `illuminate/support` `5.7.x|5.8.x|^6.0`. You will need to use `^7.0` going forward. 35 | - Removed support for PHP-CS-Fixer versions before 3.2.0. 36 | 37 | ## 0.6.0 38 | 39 | ### Added 40 | 41 | - Added support for Laravel 8. 42 | 43 | ### Changed 44 | 45 | - Switched the `concat_space` rule from `true` to `['spacing' => 'none']`. Functionally it's the same, it's just more readable. 46 | - Changed the default seeders path from `seeds` to `seeders` in the default `.php_cs` config file to match Laravel 8.0. If you haven't edited your `.php_cs` you can pull in the updated version by running `php artisan vendor:publish --provider="MattAllan\LaravelCodeStyle\ServiceProvider" --force`. 47 | 48 | ### Removed 49 | 50 | ### Security 51 | 52 | ## 0.5.1 53 | 54 | ### Added 55 | 56 | - Added support for Laravel 7. 57 | 58 | ## 0.5.0 59 | 60 | ### Added 61 | 62 | - Added the `list_syntax` rule. 63 | - Switched from length sorted imports to alpha sorted imports. 64 | 65 | ## 0.4.0 66 | 67 | ### Added 68 | 69 | - Added the `no_extra_blank_lines` rule for tokens `throw`, `use`, and `use_trait`. This corresponds to StyleCI's `no_blank_lines_after_throw`, `no_blank_lines_between_imports`, and `no_blank_lines_between_traits` 70 | rules. 71 | - Added support for Laravel 6.0. 72 | 73 | ### Deprecated 74 | 75 | ### Fixed 76 | 77 | - Explicitly format the database seeds and factories folders rather than formatting the entire database path and excluding the migrations folder. This change was necessary to prevent migrations from being modified by the fixer. Since this change only affects the default config you will either need to republish the config or manually apply the changes yourself. 78 | 79 | ### Removed 80 | 81 | - Dropped PHP 7.1 support. 82 | 83 | ### Security 84 | 85 | ## 0.3.0 86 | 87 | ### Added 88 | 89 | - Added support for installation in 5.7.* Laravel apps 90 | -------------------------------------------------------------------------------- /src/Config.php: -------------------------------------------------------------------------------- 1 | [ 16 | '@PSR2' => true, 17 | 'align_multiline_comment' => [ 18 | 'comment_type' => 'phpdocs_like', 19 | ], 20 | 'ordered_imports' => [ 21 | 'sort_algorithm' => 'alpha', 22 | ], 23 | 'array_indentation' => true, 24 | 'binary_operator_spaces' => [ 25 | 'operators' => [ 26 | '=>' => null, 27 | '=' => 'single_space', 28 | ], 29 | ], 30 | 'blank_line_after_namespace' => true, 31 | 'blank_line_after_opening_tag' => true, 32 | 'blank_line_before_statement' => [ 33 | 'statements' => [ 34 | 'return', 35 | ], 36 | ], 37 | 'cast_spaces' => true, 38 | 'class_definition' => false, 39 | 'clean_namespace' => true, 40 | 'compact_nullable_typehint' => true, 41 | 'concat_space' => [ 42 | 'spacing' => 'none', 43 | ], 44 | 'declare_equal_normalize' => true, 45 | 'no_alias_language_construct_call' => true, 46 | 'elseif' => true, 47 | 'encoding' => true, 48 | 'full_opening_tag' => true, 49 | 'function_declaration' => true, 50 | 'function_typehint_space' => true, 51 | 'single_line_comment_style' => [ 52 | 'comment_types' => [ 53 | 'hash', 54 | ], 55 | ], 56 | 'heredoc_to_nowdoc' => true, 57 | 'include' => true, 58 | 'indentation_type' => true, 59 | 'integer_literal_case' => true, 60 | 'braces' => false, 61 | 'lowercase_cast' => true, 62 | 'constant_case' => [ 63 | 'case' => 'lower', 64 | ], 65 | 'lowercase_keywords' => true, 66 | 'lowercase_static_reference' => true, 67 | 'magic_constant_casing' => true, 68 | 'magic_method_casing' => true, 69 | 'method_argument_space' => [ 70 | 'on_multiline' => 'ignore', 71 | ], 72 | 'class_attributes_separation' => [ 73 | 'elements' => [ 74 | 'method' => 'one', 75 | ], 76 | ], 77 | 'visibility_required' => [ 78 | 'elements' => [ 79 | 'method', 80 | 'property', 81 | ], 82 | ], 83 | 'native_function_casing' => true, 84 | 'native_function_type_declaration_casing' => true, 85 | 'no_alternative_syntax' => true, 86 | 'no_binary_string' => true, 87 | 'no_blank_lines_after_class_opening' => true, 88 | 'no_blank_lines_after_phpdoc' => true, 89 | 'no_extra_blank_lines' => [ 90 | 'tokens' => [ 91 | 'throw', 92 | 'use', 93 | 'extra', 94 | ], 95 | ], 96 | 'no_closing_tag' => true, 97 | 'no_empty_phpdoc' => true, 98 | 'no_empty_statement' => true, 99 | 'no_leading_import_slash' => true, 100 | 'no_leading_namespace_whitespace' => true, 101 | 'no_multiline_whitespace_around_double_arrow' => true, 102 | 'multiline_whitespace_before_semicolons' => true, 103 | 'no_short_bool_cast' => true, 104 | 'no_singleline_whitespace_before_semicolons' => true, 105 | 'no_space_around_double_colon' => true, 106 | 'no_spaces_after_function_name' => true, 107 | 'no_spaces_around_offset' => [ 108 | 'positions' => [ 109 | 'inside', 110 | ], 111 | ], 112 | 'no_spaces_inside_parenthesis' => true, 113 | 'no_trailing_comma_in_list_call' => true, 114 | 'no_trailing_comma_in_singleline_array' => true, 115 | 'no_trailing_whitespace' => true, 116 | 'no_trailing_whitespace_in_comment' => true, 117 | 'no_unneeded_control_parentheses' => true, 118 | 'no_unneeded_curly_braces' => true, 119 | 'no_unset_cast' => true, 120 | 'no_unused_imports' => true, 121 | 'lambda_not_used_import' => true, 122 | 'no_useless_return' => true, 123 | 'no_whitespace_before_comma_in_array' => true, 124 | 'no_whitespace_in_blank_line' => true, 125 | 'normalize_index_brace' => true, 126 | 'not_operator_with_successor_space' => true, 127 | 'object_operator_without_whitespace' => true, 128 | 'phpdoc_indent' => true, 129 | 'phpdoc_inline_tag_normalizer' => true, 130 | 'phpdoc_no_access' => true, 131 | 'phpdoc_no_package' => true, 132 | 'phpdoc_no_useless_inheritdoc' => true, 133 | 'phpdoc_return_self_reference' => true, 134 | 'phpdoc_scalar' => true, 135 | 'phpdoc_single_line_var_spacing' => true, 136 | 'phpdoc_summary' => true, 137 | 'phpdoc_trim' => true, 138 | 'phpdoc_no_alias_tag' => [ 139 | 'replacements' => [ 140 | 'type' => 'var', 141 | ], 142 | ], 143 | 'phpdoc_types' => true, 144 | 'phpdoc_var_without_name' => true, 145 | 'increment_style' => [ 146 | 'style' => 'post', 147 | ], 148 | 'no_mixed_echo_print' => [ 149 | 'use' => 'echo', 150 | ], 151 | 'return_type_declaration' => [ 152 | 'space_before' => 'none', 153 | ], 154 | 'array_syntax' => [ 155 | 'syntax' => 'short', 156 | ], 157 | 'list_syntax' => [ 158 | 'syntax' => 'short', 159 | ], 160 | 'short_scalar_cast' => true, 161 | 'single_blank_line_at_eof' => true, 162 | 'single_blank_line_before_namespace' => true, 163 | 'single_class_element_per_statement' => true, 164 | 'single_import_per_statement' => true, 165 | 'single_line_after_imports' => true, 166 | 'single_quote' => true, 167 | 'space_after_semicolon' => true, 168 | 'standardize_not_equals' => true, 169 | 'switch_case_semicolon_to_colon' => true, 170 | 'switch_case_space' => true, 171 | 'switch_continue_to_break' => true, 172 | 'ternary_operator_spaces' => true, 173 | 'trailing_comma_in_multiline' => [ 174 | 'elements' => [ 175 | 'arrays', 176 | ], 177 | ], 178 | 'trim_array_spaces' => true, 179 | 'unary_operator_spaces' => true, 180 | 'types_spaces' => [ 181 | 'space' => 'none', 182 | ], 183 | 'line_ending' => true, 184 | 'whitespace_after_comma_in_array' => true, 185 | ], 186 | '@Laravel:risky' => [ 187 | 'no_alias_functions' => true, 188 | 'no_unreachable_default_argument_value' => true, 189 | 'psr_autoloading' => true, 190 | 'self_accessor' => true, 191 | ], 192 | ]; 193 | 194 | public function __construct($name = 'Laravel') 195 | { 196 | parent::__construct($name); 197 | } 198 | 199 | public function setRules(array $rules): ConfigInterface 200 | { 201 | foreach (array_keys(self::RULE_DEFINITIONS) as $key) { 202 | if (($rules[$key] ?? false)) { 203 | unset($rules[$key]); 204 | $rules = array_merge(self::RULE_DEFINITIONS[$key], $rules); 205 | } 206 | } 207 | 208 | return parent::setRules($rules); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Laravel Code Style 2 | [![Packagist License](https://poser.pugx.org/matt-allan/laravel-code-style/license.png)](http://choosealicense.com/licenses/mit/) 3 | [![Latest Stable Version](https://poser.pugx.org/matt-allan/laravel-code-style/version.png)](https://packagist.org/packages/matt-allan/laravel-code-style) 4 | ![Tests](https://github.com/matt-allan/laravel-code-style/workflows/Tests/badge.svg) 5 | 6 | > ⚠️ This package is no longer maintained. See [Jubeki/laravel-code-style](https://github.com/Jubeki/laravel-code-style) for a maintained fork. 7 | 8 | 9 | This package provides automatic code style checking and formatting for Laravel applications and packages. Your code is formatted following Laravel's code style guide. 10 | 11 | The package adds the [php-cs-fixer](https://github.com/FriendsOfPhp/PHP-CS-Fixer) tool and a community maintained ruleset to your application. The ruleset is a best effort attempt to match the code style the Laravel framework itself uses. Check out an [example](./examples/User.php) to see what the code style looks like. 12 | 13 | You might want to use this package if you are writing a Laravel application, package or tutorial and you want to match the framework's code style. 14 | 15 | If you are wondering why this package exists you can [read the announcement post](https://mattallan.me/posts/automate-code-formatting-for-laravel-projects/). 16 | 17 | ## Installation 18 | 19 | > ⚠️ These docs are for the latest version. If you are using an older version you can find the docs for previous releases [here](#releases). 20 | 21 | Require this package with composer. It is recommended to only require the package for development. 22 | 23 | ```shell 24 | composer require matt-allan/laravel-code-style --dev 25 | ``` 26 | 27 | The service provider will be automatically registered using [package discovery](https://laravel.com/docs/5.8/packages#package-discovery). 28 | 29 | If you don't use auto-discovery you should add the service provider to the providers array in `config/app.php`. 30 | 31 | ```php 32 | // existing providers... 33 | MattAllan\LaravelCodeStyle\ServiceProvider::class, 34 | ``` 35 | 36 | Once the package is installed you should publish the configuration. 37 | 38 | ```shell 39 | php artisan vendor:publish --provider="MattAllan\LaravelCodeStyle\ServiceProvider" 40 | ``` 41 | 42 | Publishing the config will add a `.php-cs-fixer.dist.php` configuration file to the root of your project. You may customize this file as needed. The `.php-cs-fixer.dist.php` file should be committed to version control. 43 | 44 | A cache file will be written to `.php_cs.cache` in the project root the first time you run the fixer. You should ignore this file so it is not added to your version control system. 45 | 46 | ```shell 47 | echo '.php_cs.cache' >> .gitignore 48 | ``` 49 | 50 | ## Usage 51 | 52 | Once the package is installed you can check and fix your code formatting with the `php-cs-fixer` command. The command will be available in Composer's `vendor/bin` directory. 53 | 54 | ### Fixing 55 | 56 | To automatically fix the code style of your project you may use the `php-cs-fixer fix` command. 57 | 58 | ```shell 59 | vendor/bin/php-cs-fixer fix 60 | ``` 61 | 62 | This will automatically fix the code style of every file in your project. 63 | 64 | By default only the file names of every file fixed will be shown. To see a full diff of every change append the `--diff` flag. 65 | 66 | ```shell 67 | vendor/bin/php-cs-fixer fix --diff 68 | ``` 69 | 70 | ### Checking 71 | 72 | If you would like to check the formatting without actually altering any files you should use the `fix` command with the `--dry-run` flag. 73 | 74 | ```shell 75 | vendor/bin/php-cs-fixer fix --dry-run --diff 76 | ``` 77 | 78 | In dry-run mode any violations will [cause the command to return a non-zero exit code](https://github.com/FriendsOfPhp/PHP-CS-Fixer#exit-code). You can use this command to fail a CI build or git commit hook. 79 | 80 | ### Composer script 81 | 82 | To make checking and fixing code style easier for contributors to your project it's recommended to add the commands as a [composer script](https://getcomposer.org/doc/articles/scripts.md). 83 | 84 | The following example allows anyone to check the code style by calling `composer check-style` and to fix the code style with `composer fix-style`. 85 | 86 | ```javascript 87 | { 88 | // ... 89 | "scripts": { 90 | "check-style": "php-cs-fixer fix --dry-run --diff", 91 | "fix-style": "php-cs-fixer fix" 92 | } 93 | } 94 | ``` 95 | 96 | ### More Options 97 | 98 | For a complete list of options please consult the [php-cs-fixer documentation](https://github.com/FriendsOfPhp/PHP-CS-Fixer#usage). 99 | 100 | ## Configuration 101 | 102 | The default configuration is published as `.php-cs-fixer.dist.php` in the project root. You can customize this file to change options such as the paths searched or the fixes applied. 103 | 104 | ### Paths 105 | 106 | You can change the paths searched for PHP files by chaining method calls onto the `PhpCsFixer\Finder` instance being passed to the `MattAllan\LaravelCodeStyle\Config::setFinder` method. 107 | 108 | For example, to search the `examples` directory you would append `->in('examples')`: 109 | 110 | ```php 111 | setFinder( 117 | PhpCsFixer\Finder::create() 118 | ->in(app_path()) 119 | // ... 120 | ->in('examples') 121 | ) 122 | // ... 123 | 124 | ``` 125 | 126 | The default paths are setup for a Laravel application. If you are writing a package the path helper functions will not available and you will need to change the paths as necessary, i.e. `PhpCsFixer\Finder::create()->in(__DIR__)`. 127 | 128 | For a complete list of options refer to the [Symfony Finder documentation](https://symfony.com/doc/current/components/finder.html). 129 | 130 | ### Rules 131 | 132 | By default only the `@Laravel` preset is enabled. This preset enforces the [PSR-2 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) as well as nearly 100 other rules such as ordering use statements alphabetically and requiring trailing commas in multiline arrays. 133 | 134 | A `@Laravel:risky` preset is also available. The `@Laravel:risky` preset enables rules that may change code behavior. To enable risky rules you need to add the preset and set `isRiskyEnabled` to true. 135 | 136 | ```php 137 | return (new MattAllan\LaravelCodeStyle\Config()) 138 | ->setFinder( 139 | // ... 140 | ) 141 | ->setRules([ 142 | '@Laravel' => true, 143 | '@Laravel:risky' => true, 144 | ]) 145 | ->setRiskyAllowed(true); 146 | ``` 147 | 148 | It is possible to override a specific rule from the preset. For example, you could disable the `no_unused_imports` rule like this: 149 | 150 | ```php 151 | return (new MattAllan\LaravelCodeStyle\Config()) 152 | ->setFinder( 153 | // ... 154 | ) 155 | ->setRules([ 156 | '@Laravel' => true, 157 | 'no_unused_imports' => false, 158 | ]); 159 | ``` 160 | 161 | For a complete list of available rules please refer to the [php-cs-fixer documentation](https://github.com/FriendsOfPhp/PHP-CS-Fixer#usage). 162 | 163 | ## Continuous Integration 164 | 165 | To automatically fix the code style when someone opens a pull request or pushes a commit check out [StyleCI](https://styleci.io). StyleCI wrote many of the open source fixer rules this package depends on and StyleCI's Laravel preset is the official definition of Laravel's code style. 166 | 167 | ## Editor Support 168 | 169 | Any editor plugin for php-cs-fixer will work. Check the [php-cs-fixer readme](https://github.com/FriendsOfPhp/PHP-CS-Fixer#helpers) for more info. 170 | 171 | ## How It Works 172 | 173 | Laravel does not publish an official php-cs-fixer ruleset. To create the rule set we compare StyleCI's preset to the available php-cs-fixer rules. In some cases StyleCI is using a rule that is no longer available. For these rules we have to dig through the git history of php-cs-fixer and determine which rule replaced the deprecated rule. 174 | 175 | It isn't possible to add your own presets to php-cs-fixer. Instead `PhpCsFixer\Config` is extended to search the rules for our custom presets and merge the rules if they are found. 176 | 177 | To ensure the rules stay in sync an automated test formats the entire Laravel framework and compares the results. If an existing Laravel file does not match our rule set the build is failed. 178 | 179 | ## Releases 180 | 181 | When Laravel changes the code style a new major release is created for this package. You will need to edit the version constraint in your `composer.json` to pull in the updated rules. If you would like your code style to match a previous version of Laravel you may pull in an older release of this package. 182 | 183 | Laravel | Code Style 184 | :---------|:---------- 185 | 5.x | [0.4.x](https://github.com/matt-allan/laravel-code-style/tree/0.4.0) 186 | 6.x-7.x | [0.5.x](https://github.com/matt-allan/laravel-code-style/tree/0.5.0) 187 | 8.x | [0.6.x](https://github.com/matt-allan/laravel-code-style/tree/0.6.0) 188 | 189 | ## Change log 190 | 191 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 192 | 193 | ## Testing 194 | 195 | ``` bash 196 | $ composer test 197 | ``` 198 | 199 | ## Contributing 200 | 201 | Please see [CONTRIBUTING](./.github/CONTRIBUTING.md) for details. 202 | 203 | ## Credits 204 | 205 | - [Matt Allan](https://github.com/matt-allan) 206 | - [All Contributors](../../contributors) 207 | 208 | ## License 209 | 210 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 211 | -------------------------------------------------------------------------------- /src/Dev/GenerateRules.php: -------------------------------------------------------------------------------- 1 | config]. 34 | * 35 | * Multiple StyleCI rules may map to the same PHPCS rule. When that happens 36 | * the rules are merged recursively into a single definition. If a rule is 37 | * not defined in this map it default to [rule => true]. 38 | */ 39 | const STYLECI_TO_PHPCS_MAP = [ 40 | 'align_phpdoc' => [ 41 | 'align_multiline_comment' => [ 42 | 'comment_type' => 'phpdocs_like', 43 | ], 44 | ], 45 | 'alpha_ordered_imports' => [ 46 | 'ordered_imports' => [ 47 | 'sort_algorithm' => 'alpha', 48 | ], 49 | ], 50 | 'binary_operator_spaces' => [ 51 | 'binary_operator_spaces' => [ 52 | 'operators' => [ 53 | // equivalent to not having the align_double_arrow 54 | // or unalign_double_arrow rule enabled 55 | '=>' => null, 56 | ], 57 | ], 58 | ], 59 | 'blank_line_before_return' => [ 60 | 'blank_line_before_statement' => [ 61 | 'statements' => [ 62 | 'return', 63 | ], 64 | ], 65 | ], 66 | 'class_definition' => [ 67 | // TODO: re-enable once it doesn't break anonymous classes 68 | 'class_definition' => false, 69 | ], 70 | 'concat_without_spaces' => [ 71 | 'concat_space' => [ 72 | 'spacing' => 'none', 73 | ], 74 | ], 75 | 'die_to_exit' => [ 76 | 'no_alias_language_construct_call' => true, 77 | ], 78 | 'hash_to_slash_comment' => [ 79 | 'single_line_comment_style' => [ 80 | 'comment_types' => ['hash'], 81 | ], 82 | ], 83 | 'indentation' => [ 84 | 'indentation_type' => true, 85 | ], 86 | 'laravel_braces' => [ 87 | // TODO: enable once braces fixers are split 88 | // See https://github.com/matt-allan/laravel-code-style/issues/47 89 | 'braces' => false, 90 | ], 91 | 'lowercase_constants' => [ 92 | 'constant_case' => [ 93 | 'case' => 'lower', 94 | ], 95 | ], 96 | 'method_argument_space' => [ 97 | 'method_argument_space' => [ 98 | 'on_multiline' => 'ignore', 99 | ], 100 | ], 101 | 'method_separation' => [ 102 | 'class_attributes_separation' => [ 103 | 'elements' => [ 104 | 'method' => 'one', 105 | ], 106 | ], 107 | ], 108 | 'method_visibility_required' => [ 109 | 'visibility_required' => [ 110 | 'elements' => ['method'], 111 | ], 112 | ], 113 | 'no_blank_lines_after_throw' => [ 114 | 'no_extra_blank_lines' => [ 115 | 'tokens' => [ 116 | 'throw', 117 | ], 118 | ], 119 | ], 120 | 'no_blank_lines_between_imports' => [ 121 | 'no_extra_blank_lines' => [ 122 | 'tokens' => [ 123 | 'use', 124 | ], 125 | ], 126 | ], 127 | 'no_blank_lines_between_traits' => [ 128 | 'no_extra_blank_lines' => [ 129 | 'tokens' => [ 130 | 'use_trait', 131 | ], 132 | ], 133 | ], 134 | 'no_extra_consecutive_blank_lines' => [ 135 | 'no_extra_blank_lines' => [ 136 | 'tokens' => [ 137 | 'extra', 138 | ], 139 | ], 140 | ], 141 | 'no_multiline_whitespace_before_semicolons' => [ 142 | 'multiline_whitespace_before_semicolons' => true, 143 | ], 144 | 'no_spaces_inside_offset' => [ 145 | 'no_spaces_around_offset' => [ 146 | 'positions' => [ 147 | 'inside', 148 | ], 149 | ], 150 | 151 | ], 152 | 'no_unused_lambda_imports' => [ 153 | 'lambda_not_used_import' => true, 154 | ], 155 | 'phpdoc_type_to_var' => [ 156 | 'phpdoc_no_alias_tag' => [ 157 | 'replacements' => [ 158 | 'type' => 'var', 159 | ], 160 | ], 161 | ], 162 | 'post_increment' => [ 163 | 'increment_style' => [ 164 | 'style' => 'post', 165 | ], 166 | ], 167 | 'print_to_echo' => [ 168 | 'no_mixed_echo_print' => [ 169 | 'use' => 'echo', 170 | ], 171 | ], 172 | 'property_visibility_required' => [ 173 | 'visibility_required' => [ 174 | 'elements' => ['property'], 175 | ], 176 | ], 177 | 'psr4' => [ 178 | 'psr_autoloading' => true, 179 | ], 180 | 'return_type_declaration' => [ 181 | 'return_type_declaration' => [ 182 | 'space_before' => 'none', 183 | ], 184 | ], 185 | 'short_array_syntax' => [ 186 | 'array_syntax' => [ 187 | 'syntax' => 'short', 188 | ], 189 | ], 190 | 'short_list_syntax' => [ 191 | 'list_syntax' => [ 192 | 'syntax' => 'short', 193 | ], 194 | ], 195 | 'trailing_comma_in_multiline_array' => [ 196 | 'trailing_comma_in_multiline' => [ 197 | 'elements' => ['arrays'], 198 | ], 199 | ], 200 | 'unalign_equals' => [ 201 | 'binary_operator_spaces' => [ 202 | 'operators' => [ 203 | '=' => 'single_space', 204 | ], 205 | ], 206 | ], 207 | 'union_type_without_spaces' => [ 208 | 'types_spaces' => [ 209 | 'space' => 'none', 210 | ], 211 | ], 212 | 'unix_line_endings' => [ 213 | 'line_ending' => true, 214 | ], 215 | ]; 216 | 217 | /** 218 | * @var \StyleCI\SDK\Client|null 219 | */ 220 | private $styleCIClient; 221 | 222 | public function __construct(?StyleCIClient $styleCIClient = null) 223 | { 224 | $this->styleCIClient = $styleCIClient ?? new StyleCIClient(); 225 | $this->registerMacros(); 226 | } 227 | 228 | public function __invoke(): void 229 | { 230 | $path = __DIR__.'/../Config.php'; 231 | 232 | $replaced = preg_replace( 233 | '/(?<=const RULE_DEFINITIONS = )([^;]+)(?=;)/', 234 | static::exportRules(), 235 | file_get_contents($path) 236 | ); 237 | 238 | file_put_contents($path, $replaced); 239 | } 240 | 241 | private function exportRules(): string 242 | { 243 | $rules = VarExporter::export(static::rules()->toArray()); 244 | 245 | return static::indent($rules); 246 | } 247 | 248 | private function indent(string $rules): string 249 | { 250 | return Collection::make(explode("\n", $rules)) 251 | ->map(function (string $line, int $index) { 252 | return $index === 0 ? $line : " $line"; 253 | })->implode("\n"); 254 | } 255 | 256 | private function rules(): Collection 257 | { 258 | return collect($this->styleCIClient->presets()) 259 | ->realize() 260 | ->firstWhere('name', 'laravel') 261 | ->get('fixers') 262 | ->reject(function (string $rule) { 263 | return in_array($rule, self::UNRELEASED_RULES); 264 | }) 265 | ->pipe(function (Collection $rules) { 266 | $fixers = collect($this->styleCIClient->fixers())->realize(); 267 | 268 | [$risky, $notRisky] = $rules->partition(function ($rule) use ($fixers) { 269 | return $fixers->firstWhere('name', $rule)->get('risky'); 270 | }); 271 | 272 | return collect([ 273 | '@Laravel' => $notRisky, 274 | '@Laravel:risky' => $risky, 275 | ]); 276 | }) 277 | ->tap(function (Collection $rules) { 278 | // the @PSR2 preset isn't listed in the StyleCI preset but is used by Laravel. 279 | // @see https://laravel.com/docs/8.x/contributions#coding-style 280 | // @todo: see if this is redundant 281 | $rules->get('@Laravel')->prepend('@PSR2'); 282 | }) 283 | ->map(function (Collection $rules) { 284 | return $rules->reduce(function (Collection $carry, string $rule) { 285 | return $carry->mergeRecursive( 286 | static::STYLECI_TO_PHPCS_MAP[$rule] ?? [$rule => true] 287 | ); 288 | }, collect()); 289 | }); 290 | } 291 | 292 | private function registerMacros() 293 | { 294 | if (! Collection::hasMacro('realize')) { 295 | // "Realize" the collection by recursively converting all 296 | // nested arrays to collections. 297 | Collection::macro('realize', function () { 298 | return $this->map(function ($value) { 299 | return is_array($value) ? (new static($value))->realize() : $value; 300 | }); 301 | }); 302 | } 303 | } 304 | } 305 | --------------------------------------------------------------------------------