diff --git a/.ecrc b/.ecrc index 4e244a2..bb0f71a 100644 --- a/.ecrc +++ b/.ecrc @@ -5,6 +5,7 @@ "\\.min\\.css$", "\\.min\\.js$", "^vendor/", - "^runtime/" + "^runtime/", + "scaffold-lock\\.json$" ] } diff --git a/.editorconfig b/.editorconfig index ef7ce10..6b45e5d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,6 +13,18 @@ trim_trailing_whitespace = true [*.js] indent_size = 2 +[*.scss] +indent_size = 2 + +[*.css] +indent_size = 2 + +[package.json] +indent_size = 2 + +[package-lock.json] +indent_size = 2 + [*.md] indent_size = 2 trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 56db1bf..82335aa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -22,14 +22,21 @@ *.ttf binary # Exclude files from the archive -/.github/dependabot.yml export-ignore -/.github/workflows export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.github export-ignore +/.gitignore export-ignore +/.styleci.yml 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 +/rector.php export-ignore /runtime export-ignore +/scaffold-lock.json export-ignore /tests export-ignore # Avoid merge conflicts in CHANGELOG diff --git a/.github/linters/.editorconfig-checker.json b/.github/linters/.editorconfig-checker.json new file mode 100644 index 0000000..bb0f71a --- /dev/null +++ b/.github/linters/.editorconfig-checker.json @@ -0,0 +1,11 @@ +{ + "Exclude": [ + "phpstan-baseline\\.neon$", + "^tests/runtime/", + "\\.min\\.css$", + "\\.min\\.js$", + "^vendor/", + "^runtime/", + "scaffold-lock\\.json$" + ] +} diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml index fba3f57..bccf2d9 100644 --- a/.github/linters/.gitleaks.toml +++ b/.github/linters/.gitleaks.toml @@ -1,6 +1,6 @@ title = "gitleaks config" -[[allowlists]] +[allowlist] description = "Allow test fixture data with dummy credentials" paths = [ '''tests/support/data/.*\.php''', diff --git a/.gitignore b/.gitignore index 848ddae..304001d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# AI agents (if present) +.codex +.claude + # codecoverage (if present) code_coverage @@ -24,13 +28,14 @@ nbproject # node_modules (if present) node_modules package-lock.json - -# phpstorm project (if present) -.idea +!src/assets/package-lock.json # phpactor (if present) .phpactor.* +# phpstorm project (if present) +.idea + # phpunit (if present) .phpunit.cache .phpunit.result.cache @@ -52,3 +57,4 @@ Thumbs.db .buildpath .project .settings +phpunit.xml diff --git a/.prettierignore b/.prettierignore index 9793904..1886a83 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,3 +16,6 @@ tests/runtime/** # Tool configs maintained by hand to keep their array order meaningful. composer-require-checker.json + +# Auto-generated by yii2-extensions/scaffold; never hand-edited. +scaffold-lock.json diff --git a/.styleci.yml b/.styleci.yml index 40c1c55..8995a69 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,7 +1,7 @@ preset: psr12 risky: true -version: 8.1 +version: 8.3 finder: exclude: diff --git a/CHANGELOG.md b/CHANGELOG.md index 53242b0..8c9cecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. 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.3.0 Under development + +- feat!: ship `ecs.php` and `rector.php` wrappers from `src/config/` via `scaffold.json`; metadata moves to `php-forge/baseline`. + ## 0.2.0 May 04, 2026 - docs: add social media badge for following on X in `README.md`. diff --git a/README.md b/README.md index 9eb2c1b..6081139 100644 --- a/README.md +++ b/README.md @@ -13,19 +13,29 @@ Share one set of rules across multiple repositories via Composer.

-## Features +## System requirements - - - Feature Overview - +- [`PHP`](https://www.php.net/downloads) 8.3 or higher. +- [`Composer`](https://getcomposer.org/download/) for dependency management. ## Installation ```bash -composer require php-forge/coding-standard:^0.2 --dev +composer require php-forge/coding-standard:^0.3 --dev ``` +Or add the dependency manually to `composer.json`: + +```json +{ + "require-dev": { + "php-forge/coding-standard": "^0.3" + } +} +``` + +Then run `composer update`. + ## Configuration files This package ships shared ECS and Rector configurations under @@ -127,15 +137,11 @@ return static function (RectorConfig $rectorConfig): void { }; ``` -## Scaffolded distribution (optional) +## Scaffolded distribution -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: +This package is a [`yii2-extensions/scaffold`](https://github.com/yii2-extensions/scaffold) provider for the +**root `ecs.php` and `rector.php` wrapper templates** (sourced from `src/config/` via `scaffold.json`). Consumers can +opt in by allowing the plugin and listing this package as an authorised provider: ```bash composer require yii2-extensions/scaffold:^0.1 --dev @@ -150,6 +156,7 @@ composer require yii2-extensions/scaffold:^0.1 --dev }, "extra": { "scaffold": { + "auto": false, "allowed-packages": [ "php-forge/coding-standard" ] @@ -158,45 +165,20 @@ composer require yii2-extensions/scaffold:^0.1 --dev } ``` -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 +With `auto: false`, the plugin does not run on `composer install`; sync the wrappers manually: ```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) +vendor/bin/scaffold reapply --provider=php-forge/coding-standard ``` +Both wrappers ship in mode `preserve`; written once on first install, never overwritten so consumer edits to paths +or PHP target version survive subsequent runs. + +## Related packages + +For dev environment scaffolding, see [`php-forge/baseline`](https://github.com/php-forge/baseline). The two packages +are independent; adopt either, both, or neither. + ## Composer scripts Follow the same convention used across PHP Forge repositories: @@ -210,10 +192,6 @@ Follow the same convention used across PHP Forge repositories: } ``` -## Documentation - -- 📚 [Installation Guide](docs/installation.md) - ## Package information [![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) diff --git a/composer.json b/composer.json index d10fa05..9c9b6bd 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "php-forge/coding-standard", "type": "library", - "description": "Centralized ECS, Rector, and tooling configurations for PHP projects.", + "description": "Centralized ECS and Rector configurations for PHP projects.", "keywords": [ "coding-standard", "ecs", @@ -10,11 +10,17 @@ "scaffold-provider" ], "license": "BSD-3-Clause", + "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": ">=8.3", "rector/rector": "^2.1", "symplify/easy-coding-standard": "^13.0" }, + "require-dev": { + "php-forge/baseline": "dev-main", + "yii2-extensions/scaffold": "dev-main" + }, "autoload": { "psr-4": { "PHPForge\\CodingStandard\\": "./" @@ -25,33 +31,18 @@ "dev-main": "0.3.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" - } + "manifest": "scaffold.json", + "auto": false, + "allowed-packages": [ + "php-forge/baseline" + ] } }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "yii2-extensions/scaffold": true + } }, "scripts": { "ecs": "./vendor/bin/ecs check src --config src/ecs-83.php --fix", diff --git a/docs/installation.md b/docs/installation.md deleted file mode 100644 index 4f32a9b..0000000 --- a/docs/installation.md +++ /dev/null @@ -1,38 +0,0 @@ -# Installation guide - -## System requirements - -- [`PHP`](https://www.php.net/downloads) 8.3 or higher. -- [`Composer`](https://getcomposer.org/download/) for dependency management. - -## Installation - -### Method 1: Using [Composer](https://getcomposer.org/download/) (recommended) - -Install the extension. - -```bash -composer require php-forge/coding-standard:^0.2 --dev -``` - -### Method 2: Manual installation - -Add to your `composer.json`. - -```json -{ - "require-dev": { - "php-forge/coding-standard": "^0.2" - } -} -``` - -Then run. - -```bash -composer update -``` - -## Next steps - -- 📖 [Readme](../README.md) diff --git a/scaffold-lock.json b/scaffold-lock.json new file mode 100644 index 0000000..55fbf6f --- /dev/null +++ b/scaffold-lock.json @@ -0,0 +1,94 @@ +{ + "providers": { + "php-forge/baseline": { + "version": "dev-main", + "path": "vendor/php-forge/baseline" + } + }, + "files": { + ".editorconfig": { + "hash": "sha256:f0cafe474d79d769f397f2e8839c642ca3ef1a0ce38b6e9f82ed9e49bccf84f6", + "provider": "php-forge/baseline", + "source": "metadata/.editorconfig", + "mode": "append" + }, + ".gitattributes": { + "hash": "sha256:88b62c371df01eac6e0298625a03baee372bd4048a6452cc2a1aeee0d49eba10", + "provider": "php-forge/baseline", + "source": "metadata/gitattributes", + "mode": "replace" + }, + ".gitignore": { + "hash": "sha256:9e5e968a4f71578af06247a009998c24d27682fa88f4c0883de2e4bec80d45ca", + "provider": "php-forge/baseline", + "source": "metadata/.gitignore", + "mode": "append" + }, + ".styleci.yml": { + "hash": "sha256:825f8c744ffbd2bc2369712e7192b8694129a8ecbc3fd91dc9300fccecf827bd", + "provider": "php-forge/baseline", + "source": "metadata/.styleci.yml", + "mode": "replace" + }, + ".ecrc": { + "hash": "sha256:8227fada934c245fc98e67d691a9c8bee48b86adbbac9fbb6282057ca321d9b5", + "provider": "php-forge/baseline", + "source": "metadata/.ecrc", + "mode": "replace" + }, + ".prettierignore": { + "hash": "sha256:d12c54d82c23d562342765ceda6897ca26b73eba0c700c127408c0a9bc17d595", + "provider": "php-forge/baseline", + "source": "metadata/.prettierignore", + "mode": "replace" + }, + ".prettierrc.json": { + "hash": "sha256:4bf1ad096981736c7bd00136026e046f4b23fcefa1f8db84dcd0bacac19e97a2", + "provider": "php-forge/baseline", + "source": "metadata/.prettierrc.json", + "mode": "replace" + }, + ".stylelintignore": { + "hash": "sha256:12186f0a5c42b4f894f7bdda1b1ca5ebc69f92d906aa9075a459d4d08fe4edc1", + "provider": "php-forge/baseline", + "source": "metadata/.stylelintignore", + "mode": "replace" + }, + "composer-require-checker.json": { + "hash": "sha256:f4fbbc7876fa3f695b69dd7dc7ad4637d33dfab97fe445b476de26480f85055d", + "provider": "php-forge/baseline", + "source": "metadata/composer-require-checker.json", + "mode": "preserve" + }, + ".github/linters/.codespellrc": { + "hash": "sha256:a9afcf57f68542d7cc308af4ca923ef6bde18de7a606b99190b8a15bdef612ef", + "provider": "php-forge/baseline", + "source": "metadata/.github/linters/.codespellrc", + "mode": "replace" + }, + ".github/linters/.gitleaks.toml": { + "hash": "sha256:c500506cb29afadfd898384f12bcabdf5b494f6f2da982217e0a6e33b10f6ec6", + "provider": "php-forge/baseline", + "source": "metadata/.github/linters/.gitleaks.toml", + "mode": "replace" + }, + ".github/linters/.markdown-lint.yml": { + "hash": "sha256:5d41c7471e15fea1b307a39791436179c5db6ae7c7daf00042d21750117bead4", + "provider": "php-forge/baseline", + "source": "metadata/.github/linters/.markdown-lint.yml", + "mode": "replace" + }, + ".github/linters/actionlint.yml": { + "hash": "sha256:5c4071e2aa711e7d2e6bbb9c06d82399feab06ef5ff8feae4f9b6a61b383852f", + "provider": "php-forge/baseline", + "source": "metadata/.github/linters/actionlint.yml", + "mode": "replace" + }, + ".github/linters/.editorconfig-checker.json": { + "hash": "sha256:8227fada934c245fc98e67d691a9c8bee48b86adbbac9fbb6282057ca321d9b5", + "provider": "php-forge/baseline", + "source": "metadata/.github/linters/.editorconfig-checker.json", + "mode": "replace" + } + } +} \ No newline at end of file diff --git a/scaffold.json b/scaffold.json new file mode 100644 index 0000000..9c6439e --- /dev/null +++ b/scaffold.json @@ -0,0 +1,10 @@ +{ + "copy": [ + { "from": "src/config/ecs.php", "to": "ecs.php" }, + { "from": "src/config/rector.php", "to": "rector.php" } + ], + "modes": { + "ecs.php": "preserve", + "rector.php": "preserve" + } +} diff --git a/ecs.php b/src/config/ecs.php similarity index 100% rename from ecs.php rename to src/config/ecs.php diff --git a/rector.php b/src/config/rector.php similarity index 100% rename from rector.php rename to src/config/rector.php