From Nette Coding Standard to DressCode
Nette Coding Standard, the nette/coding-standard package with its ecs command, is no
longer developed, and version 3 is the last one. Its standard lives on in DressCode, built in under the name nette.
Moving a project, ncs.php and ncs.xml included, takes a few lines of configuration, and the only
surprise is the first fix, which reformats more files than you expect.
What Has Changed
Nette Coding Standard was a thin wrapper around PHP CS Fixer and PHP_CodeSniffer with a bundle of rules from Slevomat: two
tools, two configurations (ncs.php for the fixer, ncs.xml for the sniffer) and the ecs
command that ran it all.
In DressCode, the standard is a preset. It is called nette and is part of DressCode, so every project has
it available, whether it uses Nette or not. It is based on PER Coding Style, which it adjusts to the layout of the Nette libraries
(tabs, two blank lines between methods and more), and it also uses the sets cleanup, types and
correctness, turning off a few of their decisions; exactly what it contains is shown in the overview of standards and sets. Nothing else is needed:
- no package besides DressCode itself;
nette/coding-standardstays at version 3 and you remove it from your project; - no command besides
dresscode;ecsis not used anymore.
Installation and Configuration
composer require --dev dresscode/dresscode
Keep in mind that DressCode requires PHP 8.4 to 8.6, and because it is a development dependency, your project must run on one
of these versions too. The PHP version the tool runs on and the version your code is written for are two different numbers,
though: DressCode reads the target version from the composer.json of the project, see Installation. If your project runs on an older PHP, install
DressCode globally instead.
Put a dresscode.neon into the root of the project, with the standard and the extra sets you want:
use:
- nette
- compilerOptimizations # optional
nameResolution: certain
# optional: native types wherever PHP reads them
types:
declaration:
parameter: required
property: required
return: required
paths:
- src
- tests
Version 3 skipped the directories expected, tmp and fixtures* automatically. DressCode
skips tmp too; add the others to excludePaths if your project has them, for example
excludePaths: [tests/**/expected, tests/**/fixtures*].
Some fixes rely on a function being global, including what the compilerOptimizations
set does. DressCode makes them without your permission only when it knows what is in your namespaces. That is why the
configuration says nameResolution: certain, and if you really have some functions or constants in namespaces, you
also list them in the namespaces key; without that, such fixes are only reported. The page Functions and Constants in Namespaces explains why.
Then you check and fix with DressCode itself:
dresscode check
dresscode fix
A setting that differs from version 3 only in its value is written as a decision. A project that wants one blank line
between methods instead of two, and does not want === everywhere there is ==, adds:
blankLines:
aroundMethods: 1
expressions:
comparison:
loose: keep
Converting the Configuration
There is no command that converts ncs.php and ncs.xml, but they are usually a few lines long, so you
carry them over by hand. To find the decision that replaces a fixer or a sniff of version 3, search for its name in dresscode catalogue:
dresscode catalogue | grep strict_comparison
It prints the decision, what it is about, and the names of the rules of other tools it covers:
expressions.comparison.loose A loose comparison, ... (covers strict_comparison, SlevomatCodingStandard.Operators.DisallowEqualOperators).
| version 3 | DressCode |
|---|---|
ncs.php with 'fixer' => false |
the decision the fixer covers, with the value keep |
ncs.xml with <rule ref="$presets/optimize-fn.xml"/> |
the compilerOptimizations set in the use key |
ncs.xml with <exclude-pattern> |
the excludePaths key |
ncs.xml with <exclude-pattern> inside <rule> |
an override in the overrides key that gives the decision keep for those paths |
--config-file overrides.php |
dresscode.neon in the root of the project |
--preset php81, --preset php |
nothing; DressCode takes the target PHP version from your composer.json |
Then replace ecs check and ecs fix with dresscode check and dresscode fix
in your CI, Git hooks and editor, uninstall nette/coding-standard, and delete ncs.php and
ncs.xml.
The First Fix Reformats More Than You Expect
DressCode is not the same as version 3 line by line, and that is on purpose. Some differences fix what version 3 left alone:
a capital letter at the start of a comment // Comment, a /* enum */ comment before case,
declare(strict_types=1) on the line of the opening tag, a non-breaking space written literally in a string. Across
the Nette packages, this came to more than a hundred files out of almost three thousand.
Make it a separate commit: dresscode fix, a commit with no other changes, done. Going through it line by line is
not worth it; what is worth it is knowing that the commit contains nothing else.
What Has Stayed
- The
phpcs:ignorecomments with the names of PHP_CodeSniffer and Slevomat sniffs keep working; dresscode migrate suppressions rewrites them todresscode:ignore. - Custom sniffs and fixers, if there were any, are rewritten following the guide; a rewritten sniff is usually several times shorter.