Skip to content

Commit dcd36bd

Browse files
committed
feat: add CakePHP rules for Mago
0 parents  commit dcd36bd

26 files changed

Lines changed: 819 additions & 0 deletions

.github/workflows/quality.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Quality
2+
3+
on:
4+
push:
5+
pull_request:
6+
schedule:
7+
- cron: '0 6 * * 1'
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
package:
15+
name: Package (PHP ${{ matrix.php }})
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
php: ['8.1', '8.5']
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: shivammathur/setup-php@v2
26+
with:
27+
php-version: ${{ matrix.php }}
28+
coverage: none
29+
30+
- name: Cache Composer downloads
31+
uses: actions/cache@v4
32+
with:
33+
path: ~/.cache/composer/files
34+
key: composer-${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('composer.json') }}
35+
restore-keys: composer-${{ runner.os }}-php-${{ matrix.php }}-
36+
37+
- name: Install dependencies
38+
run: composer update --no-interaction --prefer-dist --prefer-stable
39+
40+
- name: Validate Composer metadata
41+
run: composer validate --no-check-publish
42+
43+
- name: Check formatting and CakePHP-compatible lint
44+
run: composer run cs-check
45+
46+
- name: Run unit tests
47+
run: composer test
48+
49+
- name: Validate extension registration and corpus expectations
50+
run: |
51+
composer run validate-extension
52+
composer run lint-corpus
53+
54+
cakephp-5:
55+
name: CakePHP 5.x compatibility
56+
runs-on: ubuntu-latest
57+
58+
steps:
59+
- uses: actions/checkout@v4
60+
61+
- uses: shivammathur/setup-php@v2
62+
with:
63+
php-version: '8.2'
64+
coverage: none
65+
66+
- name: Cache Composer downloads
67+
uses: actions/cache@v4
68+
with:
69+
path: ~/.cache/composer/files
70+
key: composer-${{ runner.os }}-php-8.2-${{ hashFiles('composer.json') }}
71+
restore-keys: composer-${{ runner.os }}-php-8.2-
72+
73+
- name: Install dependencies
74+
run: composer update --no-interaction --prefer-dist --prefer-stable
75+
76+
- name: Check CakePHP 5.x compatibility
77+
run: scripts/check-cakephp-5.sh

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/vendor/
2+
/composer.lock
3+
/.phpunit.result.cache
4+
/phpunit.xml
5+
AGENTS.md

AGENTS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Repository Guidelines
2+
3+
## Project Structure & Module Organization
4+
5+
- `src/` contains the PHP extension API and Mago linter rules. Keep reusable
6+
helpers under `src/Linter/` and individual rules under `src/Linter/Rules/`.
7+
- `bin/mago-cakephp-worker` is the package-owned PHP worker launched by Mago.
8+
- `mago.cakephp.toml` is the importable CakePHP formatter and native-rule
9+
configuration.
10+
- `tests/Unit/` holds PHPUnit tests. `tests/corpus/` verifies extension-worker
11+
behavior, while `tests/cakephp5/` configures checks against CakePHP 5.x.
12+
- `docs/compatibility-matrix.md` is the authoritative mapping from CakePHP
13+
CodeSniffer behavior to formatter, native Mago, or extension rules.
14+
15+
## Build, Test, and Development Commands
16+
17+
- `composer update --no-interaction --prefer-dist` installs or refreshes PHP
18+
dependencies and the Mago binary launcher.
19+
- `composer test` runs PHPUnit unit tests.
20+
- `composer run validate-extension` starts the corpus worker and verifies Mago
21+
extension registration.
22+
- `composer run lint-corpus` verifies expected external-rule diagnostics against
23+
the focused corpus; fixtures use `@mago-expect` annotations intentionally.
24+
- `scripts/check-cakephp-5.sh /path/to/cakephp` validates rules against an
25+
existing shallow CakePHP 5.x checkout. Omit the argument to clone one.
26+
27+
## Coding Style & Naming Conventions
28+
29+
Use PHP 8.1-compatible, strict PHP: start files with `declare(strict_types=1);`,
30+
use four-space indentation, and keep classes `final` unless extension is
31+
intentional. Name rule classes with a `Rule` suffix, for example
32+
`TraitSuffixRule`; use vendor-qualified kebab-case Mago codes such as
33+
`mago-cakephp/trait-suffix`. Prefer narrow AST targets and exact `Span` edits.
34+
Run `mago format` for formatting; do not add unrelated default Mago lint rules
35+
to the CakePHP compatibility allow-list.
36+
37+
## Testing Guidelines
38+
39+
Add a PHPUnit test for registration or deterministic helper behavior, plus a
40+
corpus case for each diagnostic or fix. Update the compatibility matrix whenever
41+
a CakePHP CodeSniffer rule changes status. Validate formatter/fixer changes
42+
against CakePHP 5.x before merging.
43+
44+
## Commit & Pull Request Guidelines
45+
46+
This workspace has no accessible Git history, so no local convention can be
47+
derived. Use concise imperative Conventional Commit-style subjects, for example
48+
`feat: add CakePHP docblock rule`. Pull requests should explain compatibility
49+
impact, list matrix changes, include validation output, and link relevant Mago
50+
or CakePHP issues.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Jos Beirnaert
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 all
13+
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 THE
21+
SOFTWARE.

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# CakePHP CodeSniffer rules for Mago
2+
3+
[![Quality gates](https://github.com/josbeir/cakephp-mago-rules/actions/workflows/quality.yml/badge.svg)](https://github.com/josbeir/cakephp-mago-rules/actions/workflows/quality.yml)
4+
[![License](https://img.shields.io/github/license/josbeir/cakephp-mago-rules)](LICENSE)
5+
[![Packagist downloads](https://img.shields.io/packagist/dt/josbeir/cakephp-mago-rules?logo=packagist&label=downloads)](https://packagist.org/packages/josbeir/cakephp-mago-rules)
6+
[![Mago compatibility](https://img.shields.io/badge/Mago-%5E1.47-f97316)](https://mago.carthage.software/)
7+
8+
An upstream-ready Mago extension that targets compatibility with the CakePHP
9+
CodeSniffer standard. Mago remains the formatter; this package supplies the
10+
CakePHP-specific rules that do not have a native Mago equivalent.
11+
12+
## Installation
13+
14+
```sh
15+
composer require --dev josbeir/cakephp-mago-rules carthage-software/mago
16+
```
17+
18+
Add this to the project `mago.toml`:
19+
20+
```toml
21+
extends = "vendor/josbeir/cakephp-mago-rules/mago.cakephp.toml"
22+
```
23+
24+
The imported configuration starts the package-owned worker. No copied worker
25+
or project bootstrap is required. Projects that combine several extensions in
26+
one PHP worker can still override `[extension-hosts.cakephp]` and use their
27+
own entrypoint.
28+
29+
Run `mago extension validate` and `mago format`. For strict CakePHP
30+
compatibility, use an explicit lint allow-list: Mago's normal `lint` command
31+
also enables its broader quality and security rules, which CakePHP PHPCS does
32+
not define.
33+
34+
```sh
35+
mago lint --only no-short-opening-tag,no-error-control-operator,no-assign-in-condition,no-redundant-parentheses,no-redundant-final,no-redundant-use,no-closing-tag,mago-cakephp/trait-suffix,mago-cakephp/public-method-underscore,mago-cakephp/elseif,mago-cakephp/function-docblock
36+
```
37+
38+
## What this does—and does not—replace
39+
40+
This package is a focused CakePHP compatibility layer for Mago, not a
41+
drop-in replacement for PHP_CodeSniffer or every CakePHP CodeSniffer sniff.
42+
Its covered rules are listed in the
43+
[compatibility matrix](docs/compatibility-matrix.md); anything marked
44+
**planned** is deliberately not enforced yet.
45+
46+
Mago is a strong fit when you want one fast PHP toolchain for formatting and
47+
linting, safe automatic fixes for supported diagnostics, and CakePHP-specific
48+
checks integrated into the same command and configuration. The package-owned
49+
worker means a consuming project only needs one `extends` entry—no copied
50+
bootstrap file or per-project rule registration.
51+
52+
Keep PHP_CodeSniffer in place when you require complete CakePHP CodeSniffer
53+
coverage, a specific sniff's options or severity behavior, exact PHPCBF
54+
output, or checks that are still planned here (notably detailed PHPDoc rules,
55+
control-structure rules, and filename/type conventions). Run both tools during
56+
the transition if the CakePHP standard is a release gate.
57+
58+
Formatter output is not intended to be byte-for-byte identical to PHPCBF
59+
output. Compatibility means matching the documented, supported policy—not
60+
emulating PHP_CodeSniffer internals.
61+
62+
## Development validation
63+
64+
Run `composer test`, `composer run validate-extension`, and
65+
`scripts/check-cakephp-5.sh`. The latter accepts an optional existing shallow
66+
CakePHP 5.x checkout, which keeps iterative checks fast:
67+
68+
```sh
69+
scripts/check-cakephp-5.sh /tmp/cakephp-5
70+
```

bin/mago-cakephp-worker

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
declare(strict_types=1);
5+
6+
use Mago\Sdk\Worker;
7+
use MagoCakePHP\CakePhpExtension;
8+
9+
$autoload = dirname(__DIR__, 3) . '/autoload.php';
10+
if (!is_file($autoload)) {
11+
// Support running directly from a source checkout as well as Composer's
12+
// installed vendor/josbeir/cakephp-mago-rules layout.
13+
$autoload = dirname(__DIR__) . '/vendor/autoload.php';
14+
}
15+
16+
require $autoload;
17+
18+
(new Worker(CakePhpExtension::create()))->run();

composer.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "josbeir/cakephp-mago-rules",
3+
"description": "CakePHP coding-standard compatibility rules for Mago.",
4+
"type": "library",
5+
"license": "MIT",
6+
"require": {
7+
"php": "^8.1",
8+
"carthage-software/mago": "^1.47"
9+
},
10+
"require-dev": {
11+
"phpunit/phpunit": "^10.5 || ^11.0"
12+
},
13+
"autoload": {
14+
"psr-4": {
15+
"MagoCakePHP\\": "src/"
16+
}
17+
},
18+
"autoload-dev": {
19+
"psr-4": {
20+
"MagoCakePHP\\Tests\\": "tests/"
21+
}
22+
},
23+
"scripts": {
24+
"test": "phpunit",
25+
"cs-check": "mago format --check && mago lint --only no-short-opening-tag,no-error-control-operator,no-assign-in-condition,no-redundant-parentheses,no-redundant-final,no-redundant-use,no-closing-tag,mago-cakephp/trait-suffix,mago-cakephp/public-method-underscore,mago-cakephp/elseif,mago-cakephp/function-docblock",
26+
"cs-fix": "mago format && mago lint --fix --only no-short-opening-tag,no-error-control-operator,no-assign-in-condition,no-redundant-parentheses,no-redundant-final,no-redundant-use,no-closing-tag,mago-cakephp/trait-suffix,mago-cakephp/public-method-underscore,mago-cakephp/elseif,mago-cakephp/function-docblock",
27+
"validate-extension": "mago --workspace tests/corpus extension validate",
28+
"lint-corpus": "mago --workspace tests/corpus lint --only mago-cakephp/trait-suffix,mago-cakephp/public-method-underscore,mago-cakephp/elseif,mago-cakephp/function-docblock"
29+
},
30+
"config": {
31+
"sort-packages": true
32+
}
33+
}

docs/compatibility-matrix.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Compatibility matrix
2+
3+
The matrix tracks CakePHP CodeSniffer 5.3.x and CakePHP 5.x's `phpcs.xml`.
4+
Every entry must be covered by a corpus fixture before it is marked complete.
5+
6+
| CakePHP concern | Mago implementation | Status |
7+
| --- | --- | --- |
8+
| PSR-12 whitespace, braces, imports, commas and simple strings | `mago.cakephp.toml` formatter profile | validated by CakePHP 5.x corpus |
9+
| Short tags, silenced errors, assignments in conditions, redundant parentheses/final/use, closing tags | Native Mago rules | validated by CakePHP 5.x corpus |
10+
| Trait names end in `Trait` | `mago-cakephp/trait-suffix` | corpus-covered |
11+
| Public non-magic methods do not start with `_` | `mago-cakephp/public-method-underscore` | corpus-covered |
12+
| `elseif`, never `else if` | `mago-cakephp/elseif` with safe edit | corpus-covered |
13+
| Function/method docblocks outside tests | `mago-cakephp/function-docblock` | corpus-covered |
14+
| PHPDoc tag alignment and type ordering | Dedicated extension rules over Mago's docblock trivia | planned next |
15+
| CakePHP control-structure body rules | AST-backed extension rules | planned next |
16+
| CakePHP 5.x filename-to-type roots and return-type BC exception | CakePHP 5.x compatibility suite | planned next |
17+
| Full PHPCS/Slevomat parity | Rule-by-rule migration | tracked; no implicit equivalence claim |
18+
19+
## Validation policy
20+
21+
The pinned CakePHP 5.x checkout is tested on every pull request. A scheduled
22+
job also tests the current 5.x head and reports drift. Mago output must pass
23+
CakePHP PHPCS except for an explicit row in this matrix; byte-identical PHPCBF
24+
output is not required.
25+
26+
Mago's ordinary `lint` command intentionally enables additional quality and
27+
security rules. The compatibility command uses an explicit native/external
28+
allow-list so it does not claim that those additional diagnostics are CakePHP
29+
CodeSniffer behavior.

mago.cakephp.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Import this file from a project's mago.toml with:
2+
# extends = "vendor/josbeir/cakephp-mago-rules/mago.cakephp.toml"
3+
4+
[extension-hosts.cakephp]
5+
command = ["php", "vendor/josbeir/cakephp-mago-rules/bin/mago-cakephp-worker"]
6+
7+
[formatter]
8+
preset = "psr-12"
9+
print-width = 120
10+
single-quote = true
11+
trailing-comma = true
12+
space-after-cast-unary-prefix-operators = false
13+
empty-line-before-return = true
14+
sort-uses = "alphanumeric-ascending"
15+
expand-use-groups = true
16+
17+
[linter.rules]
18+
no-short-opening-tag = { enabled = true, level = "error" }
19+
no-error-control-operator = { enabled = true, level = "error" }
20+
no-assign-in-condition = { enabled = true, level = "error" }
21+
no-redundant-parentheses = { enabled = true, level = "warning" }
22+
no-redundant-final = { enabled = true, level = "warning" }
23+
no-redundant-use = { enabled = true, level = "warning" }
24+
no-closing-tag = { enabled = true, level = "warning" }

mago.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
extends = "mago.cakephp.toml"
2+
3+
[source]
4+
paths = ["src", "tests/Unit"]
5+
6+
[extension-hosts.cakephp]
7+
enabled = false
8+
9+
[extension-hosts.cakephp-dev]
10+
command = ["php", "bin/mago-cakephp-worker"]

0 commit comments

Comments
 (0)