From 7bba3a7cef9f68987d7df37660681256b59eba86 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 4 May 2026 19:47:37 -0400 Subject: [PATCH 1/2] feat: convert into `yii2-extensions/scaffold` provider; centralize ECS, Rector, metadata and super-linter standards under `src/`. --- .ecrc | 10 ++ .gitattributes | 19 ++-- .github/linters/.codespellrc | 2 + .github/linters/.gitleaks.toml | 7 ++ .github/linters/.markdown-lint.yml | 5 + .github/workflows/ecs.yml | 2 + .gitignore | 3 + .prettierignore | 18 ++++ .prettierrc.json | 39 ++++++++ .stylelintignore | 1 + CHANGELOG.md | 14 ++- README.md | 149 ++++++++++++++++++++--------- composer-require-checker.json | 3 + composer.json | 36 +++++-- docs/configuration.md | 10 -- docs/development.md | 44 --------- docs/examples.md | 7 -- docs/installation.md | 13 +-- docs/svgs/features-mobile.svg | 101 +++++++------------ docs/svgs/features.svg | 98 +++++++------------ docs/testing.md | 78 --------------- ecs.php | 13 +-- rector.php | 8 +- src/Example.php | 13 --- src/ecs-81.php | 25 +++++ src/ecs-82.php | 25 +++++ src/ecs-83.php | 25 +++++ src/ecs-84.php | 25 +++++ {config => src}/ecs.php | 18 +++- src/rector-81.php | 35 +++++++ src/rector-82.php | 36 +++++++ src/rector-83.php | 36 +++++++ src/rector-84.php | 36 +++++++ {config => src}/rector.php | 17 ++-- tests/ExampleTest.php | 27 ------ tests/bootstrap.php | 0 36 files changed, 586 insertions(+), 412 deletions(-) create mode 100644 .ecrc create mode 100644 .github/linters/.codespellrc create mode 100644 .github/linters/.gitleaks.toml create mode 100644 .github/linters/.markdown-lint.yml create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 .stylelintignore create mode 100644 composer-require-checker.json delete mode 100644 docs/configuration.md delete mode 100644 docs/development.md delete mode 100644 docs/examples.md delete mode 100644 docs/testing.md delete mode 100644 src/Example.php create mode 100644 src/ecs-81.php create mode 100644 src/ecs-82.php create mode 100644 src/ecs-83.php create mode 100644 src/ecs-84.php rename {config => src}/ecs.php (72%) create mode 100644 src/rector-81.php create mode 100644 src/rector-82.php create mode 100644 src/rector-83.php create mode 100644 src/rector-84.php rename {config => src}/rector.php (60%) delete mode 100644 tests/ExampleTest.php delete mode 100644 tests/bootstrap.php diff --git a/.ecrc b/.ecrc new file mode 100644 index 0000000..4e244a2 --- /dev/null +++ b/.ecrc @@ -0,0 +1,10 @@ +{ + "Exclude": [ + "phpstan-baseline\\.neon$", + "^tests/runtime/", + "\\.min\\.css$", + "\\.min\\.js$", + "^vendor/", + "^runtime/" + ] +} diff --git a/.gitattributes b/.gitattributes index fdf0ca4..56db1bf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,24 +21,17 @@ *.gif binary *.ttf binary -# Avoid merge conflicts in CHANGELOG -# https://about.gitlab.com/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders/ -/CHANGELOG.md merge=union - # Exclude files from the archive -/.editorconfig export-ignore -/.gitattributes export-ignore -/.github export-ignore -/.gitignore export-ignore -/.styleci.yml export-ignore +/.github/dependabot.yml export-ignore +/.github/workflows export-ignore /codeception.yml export-ignore -/composer-require-checker.json export-ignore /docs export-ignore -/ecs.php export-ignore /infection.json* export-ignore /phpstan*.neon* export-ignore /phpunit.xml.dist export-ignore -/psalm.xml export-ignore -/rector.php export-ignore /runtime export-ignore /tests export-ignore + +# Avoid merge conflicts in CHANGELOG +# https://about.gitlab.com/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders/ +/CHANGELOG.md merge=union diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc new file mode 100644 index 0000000..1375eee --- /dev/null +++ b/.github/linters/.codespellrc @@ -0,0 +1,2 @@ +[codespell] +skip = */tests/*,tests/**,*/composer.lock,*/composer.json diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml new file mode 100644 index 0000000..bccf2d9 --- /dev/null +++ b/.github/linters/.gitleaks.toml @@ -0,0 +1,7 @@ +title = "gitleaks config" + +[allowlist] +description = "Allow test fixture data with dummy credentials" +paths = [ + '''tests/support/data/.*\.php''', +] diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 0000000..0a6d8fc --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,5 @@ +--- +MD007: + indent: 2 +MD013: false +MD033: false diff --git a/.github/workflows/ecs.yml b/.github/workflows/ecs.yml index e18f15c..73388d3 100644 --- a/.github/workflows/ecs.yml +++ b/.github/workflows/ecs.yml @@ -19,3 +19,5 @@ permissions: jobs: easy-coding-standard: uses: yii2-framework/actions/.github/workflows/ecs.yml@main + with: + command-options: check src --config src/ecs-83.php --ansi diff --git a/.gitignore b/.gitignore index d4c5c11..848ddae 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ package-lock.json # phpstorm project (if present) .idea +# phpactor (if present) +.phpactor.* + # phpunit (if present) .phpunit.cache .phpunit.result.cache diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..9793904 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,18 @@ +**/*.min.css +**/*.min.js + +# Vite-built bundles (committed dist/) and lockfiles. +**/dist/** +**/node_modules/** +**/package-lock.json + +# Yii AssetManager publishes a hashed copy of src/assets/ under tests/runtime/ +# whenever phpunit runs; the tree is regenerated on every test run, never +# authored, and ignored by git already. +tests/runtime/** + +# License texts ship verbatim — never auto-formatted. +**/LICENSE* + +# Tool configs maintained by hand to keep their array order meaningful. +composer-require-checker.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..93ac03e --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,39 @@ +{ + "tabWidth": 4, + "useTabs": false, + "singleQuote": false, + "trailingComma": "all", + "printWidth": 80, + "overrides": [ + { + "files": [ + "*.js", + "*.jsx", + "*.ts", + "*.tsx", + "*.vue", + "*.css", + "*.scss", + "*.html", + "*.yml", + "*.yaml" + ], + "options": { + "tabWidth": 2 + } + }, + { + "files": "*.md", + "options": { + "embeddedLanguageFormatting": "off", + "tabWidth": 2 + } + }, + { + "files": ["package.json", "package-lock.json"], + "options": { + "tabWidth": 2 + } + } + ] +} diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..fd04c4f --- /dev/null +++ b/.stylelintignore @@ -0,0 +1 @@ +**/*.min.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 6102953..8e3c186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,16 @@ # Changelog -## 0.1.1 Under development +All notable changes to this project will be documented in this file. -- Enh #3: Add social media badge for following on X in `README.md` (@terabytesoftw) +The format is based on [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.2.0 Under development + +- docs: add social media badge for following on X in `README.md`. +- feat: convert into `yii2-extensions/scaffold` provider; centralize ECS, Rector, metadata and super-linter standards under `src/`. ## 0.1.0 January 24, 2026 -- Enh #1: Added shared configuration files under `config/` for Composer-based reuse (@terabytesoftw) -- Bug #2: Update quality code section with `Super-Linter` and `StyleCI` badges (@terabytesoftw) +- feat: add shared configuration files under `config/` for Composer-based reuse. +- docs: update quality code section with `Super-Linter` and `StyleCI` badges. diff --git a/README.md b/README.md index 5b2eb8c..e5ef4b3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- PHP Forge + PHP Forge

Coding standard


@@ -23,42 +23,34 @@ ## Installation ```bash -composer require php-forge/coding-standard:^0.1 --dev +composer require php-forge/coding-standard:^0.2 --dev ``` -## Quick start +## Configuration files -This package provides shared configuration files under `vendor/php-forge/coding-standard/config/`: +This package ships shared ECS and Rector configurations under +`vendor/php-forge/coding-standard/src/`: -- `config/ecs.php` (shared ECS rules, no paths) -- `config/rector.php` (shared Rector rules, no paths) +| File | Purpose | +| ------------------- | ------------------------------------------------------- | +| `src/ecs.php` | Shared ECS base rules, no PHP migration set | +| `src/ecs-81.php` | Base + `@PHP81Migration` PHP-CS-Fixer set | +| `src/ecs-82.php` | Base + `@PHP82Migration` | +| `src/ecs-83.php` | Base + `@PHP83Migration` | +| `src/ecs-84.php` | Base + `@PHP84Migration` | +| `src/rector.php` | Shared Rector base rules, no PHP level set | +| `src/rector-81.php` | Base + `SetList::PHP_81` + `LevelSetList::UP_TO_PHP_81` | +| `src/rector-82.php` | Base + `SetList::PHP_82` + `LevelSetList::UP_TO_PHP_82` | +| `src/rector-83.php` | Base + `SetList::PHP_83` + `LevelSetList::UP_TO_PHP_83` | +| `src/rector-84.php` | Base + `SetList::PHP_84` + `LevelSetList::UP_TO_PHP_84` | -Consumer repositories should create wrapper config files at the repository root. -Wrappers define the paths for that repository and import the shared configuration. +Pick the version that matches the **minimum** PHP your project supports; Rector upgrades code up to that level and +PHP-CS-Fixer enforces matching syntax. The plain `ecs.php` / `rector.php` apply no PHP-version migrations. -### Generic repository +### ECS wrapper (ecs.php) -#### ECS (ecs.php) - -Create `ecs.php` in your repository root: - -```php -withPaths( - [ - __DIR__ . '/src', - __DIR__ . '/tests', - ], -); -``` - -To override or skip rules locally, apply changes after requiring the shared config: +Create `ecs.php` in your repository root, requiring the version that matches +the minimum PHP your project supports (`ecs-83.php` for PHP 8.3, etc.): ```php withPaths( @@ -77,14 +69,15 @@ return $ecsConfigBuilder ) ->withSkip( [ - // add project-specific skips here. + // project-specific skips here. ], ); ``` -#### Rector (rector.php) +### Rector wrapper (rector.php) -Create `rector.php` in your repository root: +Create `rector.php` in your repository root, importing the version that +matches your minimum PHP target: ```php import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector.php'); + $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-83.php'); $rectorConfig->paths( [ @@ -108,12 +101,11 @@ return static function (RectorConfig $rectorConfig): void { }; ``` -### Yii2 repositories - -If you need framework-specific rules (Yii2), keep them in a separate config file (or a separate package) -and import it after the base configuration. Do not mix Yii2-specific rules into the generic base. +### Yii2-specific rules -Example (Rector): +For framework-specific rules, keep them in a separate config file (or a +separate package) and import it after the base configuration. Do not mix Yii2 +rules into the generic base: ```php import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector.php'); + $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector.php'); $rectorConfig->import(__DIR__ . '/rector-yii2.php'); $rectorConfig->paths( @@ -135,6 +127,76 @@ return static function (RectorConfig $rectorConfig): void { }; ``` +## Scaffolded distribution (optional) + +This package is also a [`yii2-extensions/scaffold`](https://github.com/yii2-extensions/scaffold) provider. + +When the scaffold plugin is installed and authorized, `composer install` distributes the canonical metadata and +super-linter configs into your repository root automatically; so the ECS / Rector wrappers above and the shared linter +rules stay in lock-step across every repository that opts in. + +Opt in by adding the plugin and authorizing this package as a provider: + +```bash +composer require yii2-extensions/scaffold:^0.1 --dev +``` + +```json +{ + "config": { + "allow-plugins": { + "yii2-extensions/scaffold": true + } + }, + "extra": { + "scaffold": { + "allowed-packages": [ + "php-forge/coding-standard" + ] + } + } +} +``` + +On the next `composer install` / `composer update`, these files land in your repository root: + +| File | Mode | Purpose | +| ------------------------------------ | ---------- | -------------------------------------------------------- | +| `.editorconfig` | `replace` | Editor settings (UTF-8, LF, indent) | +| `.gitattributes` | `replace` | Text/binary handling, archive excludes | +| `.gitignore` | `append` | Common ignore patterns; project-specific lines preserved | +| `.styleci.yml` | `replace` | StyleCI config (PSR-12 + risky) | +| `.ecrc` | `replace` | editor-config-checker exclusions | +| `.prettierignore` | `replace` | Paths Prettier should skip | +| `.prettierrc.json` | `replace` | Prettier formatting rules | +| `.stylelintignore` | `replace` | Paths stylelint should skip | +| `composer-require-checker.json` | `preserve` | Composer require-checker whitelist (project-specific) | +| `.github/linters/actionlint.yml` | `replace` | actionlint config for Super-Linter | +| `.github/linters/.codespellrc` | `replace` | codespell config | +| `.github/linters/.gitleaks.toml` | `replace` | gitleaks config | +| `.github/linters/.markdown-lint.yml` | `replace` | markdownlint config | +| `ecs.php` | `preserve` | ECS wrapper for the project root | +| `rector.php` | `preserve` | Rector wrapper for the project root | + +Mode semantics: + +- `replace`: lock-step with this package. Local edits trigger a warning and the file is skipped on update. + Use `vendor/bin/scaffold reapply --force` to re-sync. +- `append`: provider content is appended to the existing file. Project lines are never blown away. +- `preserve`: file is written once on first install and never overwritten. + +The scaffolded `ecs.php` / `rector.php` ship with `83` as the default PHP target; switch to `81`, `82`, or `84` to match +your minimum PHP version. Mode `preserve` protects your edits across `composer update`. + +### Scaffold commands + +```bash +vendor/bin/scaffold status # show which files are synced/modified/missing +vendor/bin/scaffold diff # diff between local and provider version +vendor/bin/scaffold reapply [] [--force] # re-apply provider content +vendor/bin/scaffold eject # stop tracking a file (kept on disk) +``` + ## Composer scripts Follow the same convention used across PHP Forge repositories: @@ -150,12 +212,11 @@ Follow the same convention used across PHP Forge repositories: ## Documentation -- [Testing Guide](docs/testing.md) -- [Development Guide](docs/development.md) +- 📚 [Installation Guide](docs/installation.md) ## Package information -[![PHP](https://img.shields.io/badge/%3E%3D8.1-777BB4.svg?style=for-the-badge&logo=php&logoColor=white)](https://www.php.net/releases/8.1/en.php) +[![PHP](https://img.shields.io/badge/%3E%3D8.3-777BB4.svg?style=for-the-badge&logo=php&logoColor=white)](https://www.php.net/releases/8.3/en.php) [![Latest Stable Version](https://img.shields.io/packagist/v/php-forge/coding-standard.svg?style=for-the-badge&logo=packagist&logoColor=white&label=Stable)](https://packagist.org/packages/php-forge/coding-standard) [![Total Downloads](https://img.shields.io/packagist/dt/php-forge/coding-standard.svg?style=for-the-badge&logo=composer&logoColor=white&label=Downloads)](https://packagist.org/packages/php-forge/coding-standard) diff --git a/composer-require-checker.json b/composer-require-checker.json new file mode 100644 index 0000000..66b091b --- /dev/null +++ b/composer-require-checker.json @@ -0,0 +1,3 @@ +{ + "symbol-whitelist": [] +} diff --git a/composer.json b/composer.json index 234d6a1..bd5e615 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,7 @@ "keywords": [ "coding-standard", "php", + "scaffold-provider", "yii2" ], "license": "BSD-3-Clause", @@ -23,19 +24,38 @@ "extra": { "branch-alias": { "dev-main": "0.2.x-dev" + }, + "scaffold": { + "copy": [ + ".editorconfig", + ".gitattributes", + ".gitignore", + ".styleci.yml", + ".ecrc", + ".prettierignore", + ".prettierrc.json", + ".stylelintignore", + "composer-require-checker.json", + ".github/linters/actionlint.yml", + ".github/linters/.codespellrc", + ".github/linters/.gitleaks.toml", + ".github/linters/.markdown-lint.yml", + "ecs.php", + "rector.php" + ], + "modes": { + ".gitignore": "append", + "composer-require-checker.json": "preserve", + "ecs.php": "preserve", + "rector.php": "preserve" + } } }, "config": { "sort-packages": true }, "scripts": { - "ecs": "./vendor/bin/ecs --fix", - "sync-metadata": [ - "curl -fsSL -o .editorconfig https://raw.githubusercontent.com/yii2-extensions/template/main/.editorconfig", - "curl -fsSL -o .gitattributes https://raw.githubusercontent.com/yii2-extensions/template/main/.gitattributes", - "curl -fsSL -o .gitignore https://raw.githubusercontent.com/yii2-extensions/template/main/.gitignore", - "curl -fsSL -o .styleci.yml https://raw.githubusercontent.com/yii2-extensions/template/main/.styleci.yml" - ], - "rector": "./vendor/bin/rector process" + "ecs": "./vendor/bin/ecs check src --config src/ecs-83.php --fix", + "rector": "./vendor/bin/rector process src --config src/rector-83.php" } } diff --git a/docs/configuration.md b/docs/configuration.md deleted file mode 100644 index e1cdf21..0000000 --- a/docs/configuration.md +++ /dev/null @@ -1,10 +0,0 @@ -# Configuration reference - -## Overview - -## Basic configuration - -## Next steps - -- 💡 [Usage Examples](examples.md) -- 🧪 [Testing Guide](testing.md) diff --git a/docs/development.md b/docs/development.md deleted file mode 100644 index fd10316..0000000 --- a/docs/development.md +++ /dev/null @@ -1,44 +0,0 @@ -# Development - -This document describes development workflows and maintenance tasks for the project. - -## Sync Metadata - -To keep configuration files synchronized with the latest template updates, use the `sync-metadata` command. This command -downloads the latest configuration files from the template repository. - -```bash -composer run sync-metadata -``` - -### Updated Files - -This command updates the following configuration files: - -| File | Purpose | -| ---------------- | -------------------------------------------- | -| `.editorconfig` | Editor settings and code style configuration | -| `.gitattributes` | Git attributes and file handling rules | -| `.gitignore` | Git ignore patterns and exclusions | - -## Shared configuration layout - -This package exposes shared configuration files under `config/`. -Consumer repositories should create wrapper config files at their repository root -and import these shared configs. - -### When to Run - -Run this command in the following scenarios: - -- **Periodic Updates** - Monthly or quarterly to benefit from template improvements. -- **After Template Updates** - When the template repository has new configuration improvements. -- **Before Major Releases** - Ensure your project uses the latest best practices. -- **When Issues Occur** - If configuration files become outdated or incompatible. - -### Important Notes - -- This command overwrites existing configuration files with the latest versions from the template. -- Ensure you have committed any custom configuration changes before running this command. -- Review the updated files after syncing to ensure they work with your specific project needs. -- Some projects may require customizations after syncing configuration files. diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index 6e994d5..0000000 --- a/docs/examples.md +++ /dev/null @@ -1,7 +0,0 @@ -# Usage examples - -## Next steps - -- 📚 [Installation Guide](installation.md) -- ⚙️ [Configuration Guide](configuration.md) -- 🧪 [Testing Guide](testing.md) diff --git a/docs/installation.md b/docs/installation.md index 0e56654..3aadbdc 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,9 +2,8 @@ ## System requirements -- [`PHP`](https://www.php.net/downloads) 8.1 or higher. +- [`PHP`](https://www.php.net/downloads) 8.3 or higher. - [`Composer`](https://getcomposer.org/download/) for dependency management. -- [`Yii2`](https://github.com/yiisoft/yii2) 2.0.53+ or 22.x. ## Installation @@ -13,7 +12,7 @@ Install the extension. ```bash -composer require github_username/github_repository-name +composer require php-forge/coding-standard:^0.2 --dev ``` ### Method 2: Manual installation @@ -23,7 +22,7 @@ Add to your `composer.json`. ```json { "require": { - "github_username/github_repository-name": "^1.0" + "php-forge/coding-standard": "^0.2" } } ``` @@ -36,8 +35,4 @@ composer update ## Next steps -Once the installation is complete. - -- ⚙️ [Configuration Reference](configuration.md) -- 💡 [Usage Examples](examples.md) -- 🧪 [Testing Guide](testing.md) +- 📖 [Readme](../README.md) diff --git a/docs/svgs/features-mobile.svg b/docs/svgs/features-mobile.svg index 275ea03..26db843 100644 --- a/docs/svgs/features-mobile.svg +++ b/docs/svgs/features-mobile.svg @@ -1,67 +1,38 @@ - - - -
- - /* Light mode */ - @media (prefers-color-scheme: light) { - .alert-title { color: #000000; } - .alert-content { color: #333333; } - .alert-box { background: rgba(31, 136, 61, 0.1); } - } - - /* Dark mode */ - @media (prefers-color-scheme: dark) { - .alert-title { color: #ffffff; } - .alert-content { color: #ffffff; } - .alert-box { background: rgba(31, 136, 61, 0.2); } - } - -
-
-

Centralized Configuration

-

Easy Coding Standard (ECS) • Rector

-
-
-

Composer-Friendly Approach

-

Update rules in one place

-
-
-

Designed to be Extended

-

Local overrides • Skips remain possible

-
-
-

Minimal Consumer Repositories

-

Define only project paths

-
-
-
-
+ + + + Composer Distribution + Share one config set across every repository via Composer + Wrappers reference vendor/php-forge/coding-standard/src/ + + + + + ECS & Rector Configuration + PER 3.0 + PSR-12 fixers and Rector type-declaration sets + Per-version wrappers for PHP 8.1, 8.2, 8.3 and 8.4 + + + + + Metadata & Linter Standards + .editorconfig, .gitignore, .gitattributes, Prettier, stylelint baselines + Super-Linter configs: actionlint, codespell, gitleaks, markdownlint + + + + + Scaffold Provider + yii2-extensions/scaffold integration distributes files on install + Modes replace, append and preserve protect local edits +
diff --git a/docs/svgs/features.svg b/docs/svgs/features.svg index ad2ff55..2a0aa70 100644 --- a/docs/svgs/features.svg +++ b/docs/svgs/features.svg @@ -1,64 +1,40 @@ - - -
- - /* Light mode */ - @media (prefers-color-scheme: light) { - .alert-title { color: #000000; } - .alert-content { color: #333333; } - .alert-box { background: rgba(31, 136, 61, 0.1); } - } + + + + Composer Distribution + Share one config set across every repository via Composer + Wrappers reference vendor/php-forge/coding-standard/src/ + - /* Dark mode */ - @media (prefers-color-scheme: dark) { - .alert-title { color: #ffffff; } - .alert-content { color: #ffffff; } - .alert-box { background: rgba(31, 136, 61, 0.2); } - } - -
-
-

Centralized Configuration

-

Easy Coding Standard (ECS) • Rector

-
-
-

Composer-Friendly Approach

-

Update rules in one place

-
-
-

Designed to be Extended

-

Local overrides • Skips remain possible

-
-
-

Minimal Consumer Repositories

-

Define only project paths

-
-
-
-
+ + + + ECS & Rector Configuration + PER 3.0 + PSR-12 fixers and Rector type-declaration sets + Per-version wrappers for PHP 8.1, 8.2, 8.3 and 8.4 + + + + + + Metadata & Linter Standards + .editorconfig, .gitignore, .gitattributes, Prettier and stylelint baselines + Super-Linter configs: actionlint, codespell, gitleaks, markdownlint + + + + + + Scaffold Provider + yii2-extensions/scaffold integration distributes files on install + Modes replace, append and preserve protect local edits +
diff --git a/docs/testing.md b/docs/testing.md deleted file mode 100644 index 9db2f98..0000000 --- a/docs/testing.md +++ /dev/null @@ -1,78 +0,0 @@ -# Testing - -This package provides a consistent set of [Composer](https://getcomposer.org/) scripts for local validation. - -Tool references: - -- [Composer Require Checker](https://github.com/maglnet/ComposerRequireChecker) for dependency definition checks. -- [Easy Coding Standard (ECS)](https://github.com/easy-coding-standard/easy-coding-standard) for coding standards. -- [Infection](https://infection.github.io/) for mutation testing. -- [PHPStan](https://phpstan.org/) for static analysis. -- [PHPUnit](https://phpunit.de/) for unit tests. - -## Coding standards (ECS) - -Run Easy Coding Standard (ECS) and apply fixes. - -```bash -composer run ecs -``` - -### Shared configuration - -This repository ships shared configuration files under `config/` for reuse. -Consumer repositories should define their own wrapper `ecs.php` and set project paths there. - -## Dependency definition check - -Verify that runtime dependencies are correctly declared in `composer.json`. - -```bash -composer run check-dependencies -``` - -## Mutation testing (Infection) - -Run mutation testing. - -```bash -composer run mutation -``` - -Run mutation testing with static analysis enabled. - -```bash -composer run mutation-static -``` - -## Static analysis (PHPStan) - -Run static analysis. - -```bash -composer run static -``` - -## Unit tests (PHPUnit) - -Run the full test suite. - -```bash -composer run tests -``` - -## Passing extra arguments - -Composer scripts support forwarding additional arguments using `--`. - -Example: run a specific PHPUnit test or filter by name. - -```bash -composer run tests -- --filter SvgTest -``` - -Example: run PHPStan with a different memory limit: - -```bash -composer run static -- --memory-limit=512M -``` diff --git a/ecs.php b/ecs.php index f6c705f..e5046fe 100644 --- a/ecs.php +++ b/ecs.php @@ -2,15 +2,12 @@ declare(strict_types=1); -/** - * Prefer importing vendor/php-forge/coding-standard/config/ecs.php in consumer repositories. - * - * @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $ecsConfigBuilder - */ -$ecsConfigBuilder = require __DIR__ . '/config/ecs.php'; +/** @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder */ +$builder = require __DIR__ . '/vendor/php-forge/coding-standard/src/ecs-83.php'; -return $ecsConfigBuilder->withPaths( +return $builder->withPaths( [ - __DIR__ . '/config', + __DIR__ . '/src', + __DIR__ . '/tests', ], ); diff --git a/rector.php b/rector.php index 70de101..e1d5c7e 100644 --- a/rector.php +++ b/rector.php @@ -4,15 +4,13 @@ use Rector\Config\RectorConfig; -/** - * Prefer importing vendor/php-forge/coding-standard/config/rector.php in consumer repositories. - */ return static function (RectorConfig $rectorConfig): void { - $rectorConfig->import(__DIR__ . '/config/rector.php'); + $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-83.php'); $rectorConfig->paths( [ - __DIR__ . '/config', + __DIR__ . '/src', + __DIR__ . '/tests', ], ); }; diff --git a/src/Example.php b/src/Example.php deleted file mode 100644 index 7c0d196..0000000 --- a/src/Example.php +++ /dev/null @@ -1,13 +0,0 @@ -withPaths([__DIR__ . '/src', __DIR__ . '/tests']); + * ``` + * + * @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder + */ +$builder = require __DIR__ . '/ecs.php'; + +return $builder->withPhpCsFixerSets(php81Migration: true); diff --git a/src/ecs-82.php b/src/ecs-82.php new file mode 100644 index 0000000..2f1dd63 --- /dev/null +++ b/src/ecs-82.php @@ -0,0 +1,25 @@ +withPaths([__DIR__ . '/src', __DIR__ . '/tests']); + * ``` + * + * @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder + */ +$builder = require __DIR__ . '/ecs.php'; + +return $builder->withPhpCsFixerSets(php82Migration: true); diff --git a/src/ecs-83.php b/src/ecs-83.php new file mode 100644 index 0000000..fb98a20 --- /dev/null +++ b/src/ecs-83.php @@ -0,0 +1,25 @@ +withPaths([__DIR__ . '/src', __DIR__ . '/tests']); + * ``` + * + * @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder + */ +$builder = require __DIR__ . '/ecs.php'; + +return $builder->withPhpCsFixerSets(php83Migration: true); diff --git a/src/ecs-84.php b/src/ecs-84.php new file mode 100644 index 0000000..2bb4966 --- /dev/null +++ b/src/ecs-84.php @@ -0,0 +1,25 @@ +withPaths([__DIR__ . '/src', __DIR__ . '/tests']); + * ``` + * + * @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder + */ +$builder = require __DIR__ . '/ecs.php'; + +return $builder->withPhpCsFixerSets(php84Migration: true); diff --git a/config/ecs.php b/src/ecs.php similarity index 72% rename from config/ecs.php rename to src/ecs.php index cb68994..bdfd7d9 100644 --- a/config/ecs.php +++ b/src/ecs.php @@ -7,15 +7,21 @@ use PhpCsFixer\Fixer\LanguageConstruct\NullableTypeDeclarationFixer; use PhpCsFixer\Fixer\Phpdoc\PhpdocTypesOrderFixer; use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer; +use PhpCsFixer\Fixer\Strict\{DeclareStrictTypesFixer, StrictComparisonFixer, StrictParamFixer}; use PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer; use Symplify\EasyCodingStandard\Config\ECSConfig; /** - * Shared ECS configuration. + * Shared base ECS configuration. * - * This file intentionally contains no project-specific paths. - * Consumer repositories should provide their own wrapper ecs.php - * and set paths there. + * This file intentionally contains no project-specific paths and no PHP-version migration set. Consumer repositories + * should require either this file (no migration) or one of the version-pinned wrappers (`ecs-81.php`, `ecs-82.php`, + * `ecs-83.php`, `ecs-84.php`) and set their own paths. + * + * The "strict" prepared set is intentionally NOT used: it was deprecated in Symplify ECS `13` with guidance to enable + * the underlying fixers explicitly so the consumer keeps direct control over the strict-typing surface. The three + * fixers it used to bundle (`DeclareStrictTypesFixer`, `StrictComparisonFixer`, `StrictParamFixer`) are added as + * individual rules below to preserve behavior. */ return ECSConfig::configure() ->withConfiguredRule( @@ -85,12 +91,14 @@ comments: true, docblocks: true, namespaces: true, - strict: true, ) ->withRules( [ + DeclareStrictTypesFixer::class, NoUnusedImportsFixer::class, OrderedTraitsFixer::class, SingleQuoteFixer::class, + StrictComparisonFixer::class, + StrictParamFixer::class, ], ); diff --git a/src/rector-81.php b/src/rector-81.php new file mode 100644 index 0000000..d4305bd --- /dev/null +++ b/src/rector-81.php @@ -0,0 +1,35 @@ +import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-81.php'); + * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); + * }; + * ``` + */ +return static function (RectorConfig $rectorConfig): void { + (require __DIR__ . '/rector.php')($rectorConfig); + + $rectorConfig->sets( + [ + LevelSetList::UP_TO_PHP_81, + SetList::PHP_81, + ], + ); +}; diff --git a/src/rector-82.php b/src/rector-82.php new file mode 100644 index 0000000..79fde99 --- /dev/null +++ b/src/rector-82.php @@ -0,0 +1,36 @@ +import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-81.php'); + * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); + * }; + * ``` + */ +return static function (RectorConfig $rectorConfig): void { + (require __DIR__ . '/rector.php')($rectorConfig); + + $rectorConfig->sets( + [ + LevelSetList::UP_TO_PHP_82, + SetList::PHP_82, + ], + ); +}; diff --git a/src/rector-83.php b/src/rector-83.php new file mode 100644 index 0000000..616e0a8 --- /dev/null +++ b/src/rector-83.php @@ -0,0 +1,36 @@ +import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-83.php'); + * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); + * }; + * ``` + */ +return static function (RectorConfig $rectorConfig): void { + (require __DIR__ . '/rector.php')($rectorConfig); + + $rectorConfig->sets( + [ + LevelSetList::UP_TO_PHP_83, + SetList::PHP_83, + ], + ); +}; diff --git a/src/rector-84.php b/src/rector-84.php new file mode 100644 index 0000000..62eab19 --- /dev/null +++ b/src/rector-84.php @@ -0,0 +1,36 @@ +import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-84.php'); + * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); + * }; + * ``` + */ +return static function (RectorConfig $rectorConfig): void { + (require __DIR__ . '/rector.php')($rectorConfig); + + $rectorConfig->sets( + [ + LevelSetList::UP_TO_PHP_84, + SetList::PHP_84, + ], + ); +}; diff --git a/config/rector.php b/src/rector.php similarity index 60% rename from config/rector.php rename to src/rector.php index ccc509b..99aa40a 100644 --- a/config/rector.php +++ b/src/rector.php @@ -4,36 +4,31 @@ use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; use Rector\Config\RectorConfig; -use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; use Rector\TypeDeclaration\Rector\Class_\TypedPropertyFromCreateMockAssignRector; /** - * Shared Rector configuration. + * Shared base Rector configuration. * - * This file intentionally contains no project-specific paths. - * Consumer repositories should provide their own wrapper rector.php - * and set paths there. + * This file intentionally contains no project-specific paths and no PHP version-level set. Consumer repositories should + * import either this file (no version target) or one of the version-pinned wrappers (`rector-81.php`, `rector-82.php`, + * `rector-83.php`, `rector-84.php`) and set their own paths. + * + * The version-pinned wrappers add the matching `SetList::PHP_XX` and `LevelSetList::UP_TO_PHP_XX` on top of this base. */ return static function (RectorConfig $rectorConfig): void { $rectorConfig->parallel(); - $rectorConfig->importNames(); - $rectorConfig->sets( [ - SetList::PHP_81, - LevelSetList::UP_TO_PHP_81, SetList::TYPE_DECLARATION, ], ); - $rectorConfig->skip( [ TypedPropertyFromCreateMockAssignRector::class, ], ); - $rectorConfig->rules( [ SimplifyEmptyArrayCheckRector::class, diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php deleted file mode 100644 index b2ffae0..0000000 --- a/tests/ExampleTest.php +++ /dev/null @@ -1,27 +0,0 @@ -getExample(), - "Method should return 'false' by default.", - ); - self::assertSame( - true, - $example->getExample(true), - "Method should return 'true' when legacy parameter is 'true'.", - ); - } -} diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index e69de29..0000000 From 643b8926f6f1a1d20f1d298c16fc2afc4ce36b75 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Mon, 4 May 2026 20:06:40 -0400 Subject: [PATCH 2/2] Apply fixed Coderabbitai review. --- .editorconfig | 1 + .github/linters/.gitleaks.toml | 2 +- .prettierrc.json | 17 +++-------------- CHANGELOG.md | 2 +- README.md | 2 +- composer.json | 2 +- docs/installation.md | 2 +- src/ecs-81.php | 2 +- src/ecs-82.php | 2 +- src/ecs-83.php | 2 +- src/ecs-84.php | 2 +- src/rector-81.php | 7 +++---- src/rector-82.php | 6 ++---- src/rector-83.php | 6 ++---- src/rector-84.php | 6 ++---- 15 files changed, 22 insertions(+), 39 deletions(-) diff --git a/.editorconfig b/.editorconfig index 518c149..ef7ce10 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,7 @@ trim_trailing_whitespace = true indent_size = 2 [*.md] +indent_size = 2 trim_trailing_whitespace = false [*.php] diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml index bccf2d9..fba3f57 100644 --- a/.github/linters/.gitleaks.toml +++ b/.github/linters/.gitleaks.toml @@ -1,6 +1,6 @@ title = "gitleaks config" -[allowlist] +[[allowlists]] description = "Allow test fixture data with dummy credentials" paths = [ '''tests/support/data/.*\.php''', diff --git a/.prettierrc.json b/.prettierrc.json index 93ac03e..8f87fe1 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -6,31 +6,20 @@ "printWidth": 80, "overrides": [ { - "files": [ - "*.js", - "*.jsx", - "*.ts", - "*.tsx", - "*.vue", - "*.css", - "*.scss", - "*.html", - "*.yml", - "*.yaml" - ], + "files": ["**/*.{js,jsx,ts,tsx,vue,css,scss,html,yml,yaml}"], "options": { "tabWidth": 2 } }, { - "files": "*.md", + "files": "**/*.md", "options": { "embeddedLanguageFormatting": "off", "tabWidth": 2 } }, { - "files": ["package.json", "package-lock.json"], + "files": ["**/package.json", "**/package-lock.json"], "options": { "tabWidth": 2 } diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3c186..1f5af48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.2.0 Under development - docs: add social media badge for following on X in `README.md`. -- feat: convert into `yii2-extensions/scaffold` provider; centralize ECS, Rector, metadata and super-linter standards under `src/`. +- feat!: convert into `yii2-extensions/scaffold` provider; centralize ECS, Rector, metadata and super-linter standards under `src/`. ## 0.1.0 January 24, 2026 diff --git a/README.md b/README.md index e5ef4b3..609f8f7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

- PHP Forge + PHP Forge

Coding standard


diff --git a/composer.json b/composer.json index bd5e615..a330818 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": ">=8.1", + "php": ">=8.3", "rector/rector": "^2.1", "symplify/easy-coding-standard": "^13.0" }, diff --git a/docs/installation.md b/docs/installation.md index 3aadbdc..4f32a9b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -21,7 +21,7 @@ Add to your `composer.json`. ```json { - "require": { + "require-dev": { "php-forge/coding-standard": "^0.2" } } diff --git a/src/ecs-81.php b/src/ecs-81.php index b6487b0..ef597ff 100644 --- a/src/ecs-81.php +++ b/src/ecs-81.php @@ -13,7 +13,7 @@ * declare(strict_types=1); * * /** @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder *\/ - * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/config/ecs-81.php'; + * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/src/ecs-81.php'; * * return $builder->withPaths([__DIR__ . '/src', __DIR__ . '/tests']); * ``` diff --git a/src/ecs-82.php b/src/ecs-82.php index 2f1dd63..a26dc91 100644 --- a/src/ecs-82.php +++ b/src/ecs-82.php @@ -13,7 +13,7 @@ * declare(strict_types=1); * * /** @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder *\/ - * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/config/ecs-82.php'; + * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/src/ecs-82.php'; * * return $builder->withPaths([__DIR__ . '/src', __DIR__ . '/tests']); * ``` diff --git a/src/ecs-83.php b/src/ecs-83.php index fb98a20..5ce4827 100644 --- a/src/ecs-83.php +++ b/src/ecs-83.php @@ -13,7 +13,7 @@ * declare(strict_types=1); * * /** @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder *\/ - * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/config/ecs-83.php'; + * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/src/ecs-83.php'; * * return $builder->withPaths([__DIR__ . '/src', __DIR__ . '/tests']); * ``` diff --git a/src/ecs-84.php b/src/ecs-84.php index 2bb4966..63d08be 100644 --- a/src/ecs-84.php +++ b/src/ecs-84.php @@ -13,7 +13,7 @@ * declare(strict_types=1); * * /** @var \Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder $builder *\/ - * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/config/ecs-84.php'; + * $builder = require __DIR__ . '/vendor/php-forge/coding-standard/src/ecs-84.php'; * * return $builder->withPaths([__DIR__ . '/src', __DIR__ . '/tests']); * ``` diff --git a/src/rector-81.php b/src/rector-81.php index d4305bd..efdaf20 100644 --- a/src/rector-81.php +++ b/src/rector-81.php @@ -3,12 +3,12 @@ declare(strict_types=1); use Rector\Config\RectorConfig; -use Rector\Set\ValueObject\{LevelSetList, SetList}; +use Rector\Set\ValueObject\LevelSetList; /** * Rector configuration targeting PHP `8.1` syntax. * - * Layers `SetList::PHP_81` and `LevelSetList::UP_TO_PHP_81` on top of the shared base configuration. + * Layers `LevelSetList::UP_TO_PHP_81` on top of the shared base configuration. * * ```php * import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-81.php'); + * $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-81.php'); * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); * }; * ``` @@ -29,7 +29,6 @@ $rectorConfig->sets( [ LevelSetList::UP_TO_PHP_81, - SetList::PHP_81, ], ); }; diff --git a/src/rector-82.php b/src/rector-82.php index 79fde99..432657e 100644 --- a/src/rector-82.php +++ b/src/rector-82.php @@ -4,12 +4,11 @@ use Rector\Config\RectorConfig; use Rector\Set\ValueObject\LevelSetList; -use Rector\Set\ValueObject\SetList; /** * Rector configuration targeting PHP `8.2` syntax. * - * Layers `SetList::PHP_82` and `LevelSetList::UP_TO_PHP_82` on top of the shared base configuration. + * Layers `LevelSetList::UP_TO_PHP_82` on top of the shared base configuration. * * ```php * import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-81.php'); + * $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-81.php'); * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); * }; * ``` @@ -30,7 +29,6 @@ $rectorConfig->sets( [ LevelSetList::UP_TO_PHP_82, - SetList::PHP_82, ], ); }; diff --git a/src/rector-83.php b/src/rector-83.php index 616e0a8..8102dab 100644 --- a/src/rector-83.php +++ b/src/rector-83.php @@ -4,12 +4,11 @@ use Rector\Config\RectorConfig; use Rector\Set\ValueObject\LevelSetList; -use Rector\Set\ValueObject\SetList; /** * Rector configuration targeting PHP `8.3` syntax. * - * Layers `SetList::PHP_83` and `LevelSetList::UP_TO_PHP_83` on top of the shared base configuration. + * Layers `LevelSetList::UP_TO_PHP_83` on top of the shared base configuration. * * ```php * import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-83.php'); + * $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-83.php'); * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); * }; * ``` @@ -30,7 +29,6 @@ $rectorConfig->sets( [ LevelSetList::UP_TO_PHP_83, - SetList::PHP_83, ], ); }; diff --git a/src/rector-84.php b/src/rector-84.php index 62eab19..d5636fd 100644 --- a/src/rector-84.php +++ b/src/rector-84.php @@ -4,12 +4,11 @@ use Rector\Config\RectorConfig; use Rector\Set\ValueObject\LevelSetList; -use Rector\Set\ValueObject\SetList; /** * Rector configuration targeting PHP `8.4` syntax. * - * Layers `SetList::PHP_84` and `LevelSetList::UP_TO_PHP_84` on top of the shared base configuration. + * Layers `LevelSetList::UP_TO_PHP_84` on top of the shared base configuration. * * ```php * import(__DIR__ . '/vendor/php-forge/coding-standard/config/rector-84.php'); + * $rectorConfig->import(__DIR__ . '/vendor/php-forge/coding-standard/src/rector-84.php'); * $rectorConfig->paths([__DIR__ . '/src', __DIR__ . '/tests']); * }; * ``` @@ -30,7 +29,6 @@ $rectorConfig->sets( [ LevelSetList::UP_TO_PHP_84, - SetList::PHP_84, ], ); };