Konfigurace
Konfigurace je jeden soubor v kořeni projektu: dresscode.neon, nebo dresscode.php,
pokud dáváte přednost PHP. Řeknete v něm, podle jakého standardu se kontroluje a co z něj chcete mít jinak. A to
s přesností, jakou jinde nenajdete: každá část projektu může mít vlastní presety, vlastní styl, vlastní verzi PHP,
vlastní seznam rizikových oprav, které přijímáte, i vlastní pravidla, která jen varují. Zdrojáky, testy i šablony
generátoru tak dostanou každý přesně to, co potřebují, a pořád je to jeden krátký soubor.
Konfigurační soubor
Oba formáty umějí přesně totéž: každý klíč NEONu je pojmenovaný argument konstruktoru třídy
DressCode\Config. Kde PHP předává objekt nebo callback, napíše se v NEONu entita. Následující dva soubory dělají totéž:
presets:
- dresscode/per
lineLength: 100
rules:
dresscode/ordered-imports: true
dresscode/line-length: true
dresscode/useless-else: keep
paths:
- src
- tests
excludePaths:
- tests/fixtures
<?php declare(strict_types=1);
use DressCode\Config;
return new Config(
presets: ['dresscode/per'],
lineLength: 100,
rules: [
'dresscode/ordered-imports' => true,
'dresscode/line-length' => true,
'dresscode/useless-else' => 'keep',
],
paths: ['src', 'tests'],
excludePaths: ['tests/fixtures'],
);
Dál na téhle stránce píšeme NEON, protože se čte lépe. Převod do PHP je vždy mechanický a editor vám v PHP napoví každý klíč.
Soubor se hledá od aktuálního adresáře směrem nahoru a kořenem projektu se stane adresář, ve kterém se našel.
Všechny cesty v konfiguraci jsou relativní k němu. Vedle něj může ležet šablona dresscode.neon.dist (nebo
.php.dist), kterou commitujete; soubor bez .dist ji pak celou nahradí a hodí se pro místní odchylku,
kterou commitovat nechcete. Mít vedle sebe NEON i PHP je chyba, ne přednost jednoho z nich. Jiný soubor vnutíte
přepínačem --config.
Překlep v klíči je chyba při načtení, ne tiše přeskočený řádek, a hláška nabídne klíč, který jste nejspíš
mysleli (Unexpected item 'path', did you mean 'paths'?). Stejně dopadne překlep ve jménu pravidla nebo presetu
(Unknown rule 'strict-comparsion'. Did you mean 'strict-comparison'?) a chybná hodnota volby řekne, která vrstva
ji nastavila. Hodnota, kterou klíč přijmout nemůže, třeba eol: lf, je chyba se jménem souboru, ať ji
napíšete do NEONu, nebo do PHP. Bez konfiguračního souboru platí preset dresscode/per, cesty se zadávají na
příkazové řádce a jiný preset se vybere přepínačem --preset.
Jeden tvar pro projekt, jeho části i presety
Nejdůležitější věc, kterou o konfiguraci DressCode potřebujete vědět: to, co rozhoduje o zpracování souboru, má všude stejný tvar. Říkáme mu profil a tvoří ho tyhle klíče:
| klíč | co říká |
|---|---|
presets |
ze kterých presetů se vychází |
groups |
které skupiny pravidel běží |
rules |
která pravidla běží a s jakými volbami |
indent, eol, lineLength |
odsazení, konec řádku a nejdelší řádek |
php |
pro jakou verzi PHP je kód psaný |
types |
odkud se berou typy kódu |
namespaces |
které funkce a konstanty deklarují jmenné prostory |
nameResolution |
jestli jsou ty seznamy úplné |
fixRisky |
u kterých pravidel přijímáte rizikové opravy |
warnings |
která pravidla jen varují |
Profil má celý projekt: to jsou klíče nejvyšší úrovně vašeho souboru. Vlastní profil může mít každá část projektu, třeba testy nebo jeden adresář. A preset není nic jiného než profil pod jménem. Co umíte napsat pro celý projekt, umíte tedy napsat i pro testy nebo do presetu, který sdílíte mezi projekty, a naopak: preset, který jinde zapínáte pro celý projekt, můžete zapnout jen pro jeho část.
Pět klíčů zůstává rozhodnutím projektu a preset je nastavit nemůže: verze PHP (php), odkud se berou typy
(types), úplnost seznamů (nameResolution), souhlas s rizikovými opravami (fixRisky) a
pravidla, která jen varují (warnings). Preset zná standard, váš kód znáte jen vy. Zbylé klíče konfigurace
pak říkají, co se kontroluje a co si projekt bere z balíčků. Kdo co smí nastavit, shrnuje tabulka:
| klíče | konfigurace | přepis | preset | rozšíření |
|---|---|---|---|---|
presets, groups, rules, indent, eol,
lineLength, namespaces |
ano | ano | ano | ne |
php, nameResolution, fixRisky, warnings |
ano | ano | ne | ne |
types |
ano | ne | ne | ne |
overrides, paths, fileExtensions, baseline, cacheDir |
ano | ne | ne | ne |
extensions, excludePaths, skipWhen, analyses |
ano | ne | ne | ano |
Presety a vrstvy
Preset je pojmenovaný profil. Čtyři vestavěné presety jsou standardy: rozhodují o všem, od odsazení po importy,
a projekt si jeden z nich vezme za základ: dresscode/psr12, dresscode/per podle PER Coding Style 3.1 (potomek PSR-12 a výchozí volba),
dresscode/nette a dresscode/symfony. Vedle nich stojí dresscode/nette-style, samotné
rozvržení kódu podle Nette, které existuje kvůli standardu dresscode/nette, a dresscode/symfony-configurator,
který žádné pravidlo nezapíná a jen vyjmenuje funkce, které Symfony deklaruje ve svém jmenném prostoru. Co přesně
každý z nich zapíná, ukazuje přehled presetů.
presets:
- dresscode/per
Jméno vestavěného presetu nebo pravidla si můžete zkrátit o předponu dresscode/: per znamená
dresscode/per a line-length znamená dresscode/line-length. Hodí se to hlavně na
příkazové řádce a v komentářích dresscode:ignore, kam jméno opisujete z výpisu; v konfiguračním
souboru, který commitujete, je čitelnější celé jméno. Zkratka hledá jen mezi vestavěnými, takže preset nebo pravidlo
z rozšíření se píše vždycky celé i s vendorem.
Pro každý soubor se profily skládají do vrstev, od nejnižší po nejvyšší:
- presety vaší konfigurace, každý nad presety, ze kterých vychází,
- klíče vaší konfigurace, přičemž skupiny leží pod pravidly téhož profilu,
- přepisy, kterým soubor odpovídá, v pořadí zápisu, každý opět nad svými presety,
- příkazová řádka (
--preset,--group,--rule).
Preset, který už leží níž, se podruhé nepokládá. Vyšší vrstva mění jen to, co sama říká, a jak to změní, záleží na druhu hodnoty:
- Hodnota (
indent,eol,lineLength,php,nameResolution) platí z nejvyšší vrstvy, která ji uvádí. - Seznam (
namespaces,fixRisky,warnings) se přes vrstvy sčítá. Přepis pro testy tak k seznamu projektu přidává a nic z něj neubere. - Volby pravidla se slévají. Mapa voleb se slévá po klíčích: když preset nastaví pravidlu
dresscode/braces-positiondevět voleb a vy uvedete jednu, platí ta vaše a zbylých osm zůstane, jak je nastavil preset. Skalár a seznam naopak nahrazují celou hodnotu:multiLine: [arguments]udresscode/trailing-commaznamená jen argumenty, ať preset říkal cokoli, takže kdo chce přidávat, opíše i zděděné položky. Akeepna úrovni pravidla maže všechno, co o něm vrstvy pod ním řekly; mapa uvedená v další vrstvě pak začíná znovu od výchozích hodnot pravidla.
Odkud každá hodnota přišla a co přebila, vypíše dresscode config.
Skupiny pravidel
Katalog má skoro dvě stě pravidel a skládat si z nich konfiguraci položku po položce je práce, kterou za vás
udělají skupiny. Konfigurace pak stojí na dvou otázkách: jak má kód vypadat, na to odpovídá jeden standard, a co po něm
chcete kromě vzhledu, na to odpovídá šest skupin. Skupina je jméno záměru, ne výčet: napíšete cleanup
a s výchozími volbami běží každé pravidlo, které odklízí kód, co je v souboru pro nic.
presets:
- dresscode/per
groups:
- cleanup
- types
Skupin je právě šest a jiné jméno je chyba, která vypíše seznam platných:
| skupina | co zapíná | příklad pravidla |
|---|---|---|
cleanup |
kód, který je tam pro nic | unused-imports, useless-else |
modernization |
konstrukce, kterou cílová verze PHP umí, tam kde totéž říká starší zápis | nullsafe-operator, match-for-simple-switch |
types |
typy zapsané tam, kde je čte PHP | type-hint-required, override-attribute-required |
deprecations |
co cílová verze PHP nebo knihovna zavrhla či zrušila | no-deprecated-functions, no-deprecated-classes |
correctness |
to, co je nejspíš omyl | no-duplicate-assignment, no-unreachable-catch |
optimized-calls |
volání ve tvaru, který PHP optimalizuje už při kompilaci | optimized-call-notation, no-is-null |
Který standard které skupiny nese a co je v nich za pravidla, najdete v přehledu presetů a v přehledu
pravidel; každá stránka pravidla má svou skupinu v řádku faktů pod perexem. Standard dresscode/nette
zapíná cleanup, modernization, types, deprecations a
correctness, ostatní standardy žádnou; skupinu si k nim přidáte sami.
Šest jmen je celý seznam, který se musíte naučit, a nepovyroste: jména jsou uzavřený výčet, takže je nerozšíří ani balíček s vlastními pravidly. Jeho pravidlo se přihlásí do jedné z těch šesti skupin a projektu, který ji zapnul, začne pracovat bez jediného řádku navíc. Katalog roste, seznam jmen ne.
Tři věci, které skupina záměrně nedělá:
- Skupina nenese volby. Zapne pravidlo s výchozími hodnotami. Chcete-li u některého jinou, napište ho do
rules: skupina leží pod pravidly téhož profilu, takže projekt má vždycky poslední slovo. Stejně tak cokoli ze skupiny vypnete jménem s hodnotoukeep. - Skupina o vzhledu kódu nerozhoduje. Mezery, odsazení, uvozovky, pořadí členů a další rozhodnutí o vzhledu
jsou věcí standardu. Pravidlo, které je rozhodnutím o vzhledu, nebo politika, ke které seznam dodává projekt
(
forbidden-functions), proto do žádné skupiny nepatří a zapíná se jménem. - Skupina žádné pravidlo nejmenuje. Pravidlo, které v projektu běžet nemůže, protože cílí na novější PHP, chce typy nebo knihovnu, kterou projekt nemá, ze skupiny tiše vypadne. Konfigurace kvůli tomu nespadne a nemusíte ji upravovat, když projekt zvedne verzi PHP nebo zapne typy: pravidlo prostě začne běžet.
groups:
- cleanup
rules:
dresscode/useless-else: keep # ze skupiny nechci tohle
dresscode/unused-imports: # a tomuhle měním volbu
searchAnnotations: false
Na jeden běh přidá skupinu přepínač --group cleanup (i opakovaně) a --only cleanup běh na
její pravidla naopak zúží, což se hodí, když chcete velkou opravu rozdělit do samostatných commitů. Které skupiny
nakonec platí, vypíše dresscode config na řádku Groups a u každého pravidla ze skupiny stojí
vrstva group cleanup.
Styl, verze PHP a jmenné prostory
Styl je odsazovací jednotka, konec řádku a délka řádku, každé pod svým klíčem. Každé platí z nejvyšší vrstvy, která ho říká, obvykle tedy ze standardu, a když ho neříká žádná, pak tabulátor, ten konec řádku, který v souboru převládá, a žádný limit délky. Určit si ho samozřejmě můžete sami:
indent: 4
eol: LF
lineLength: 100
Hodnota indent je počet mezer, nebo tab. Hodnota eol je LF nebo
CRLF (velkými písmeny, jak se ty zkratky píšou; lf je chyba), dále majority pro
sjednocení každého souboru na jeho převažující konec řádku (výchozí), nebo platform pro konec řádku
stroje, na kterém DressCode běží.
Hodnota lineLength je nejdelší řádek, který projde, v šířce, jak ho vidíte: tabulátor se počítá do
další zarážky. false délku neomezuje, i když ji vrstva pod ním nastavila. Standardy
dresscode/psr12 a dresscode/per mají 120 znaků, dresscode/nette 140 znaků a
dresscode/symfony žádný limit. Délka je jedna pro všechna pravidla, která ji potřebují: dresscode/line-length ohlásí širší řádek,
dresscode/multi-line-signature a dresscode/multi-line-condition rozlomí signaturu a podmínku na
řádku širším než limit, dresscode/binary-operator-spacing nepřitáhne přiřazení na řádek levé strany,
kdyby tím řádek limit přesáhl, a dresscode/multi-line-array podle ní skládá položky dlouhého pole
za sebe.
Cílová verze PHP je vlastnost projektu a čte se z composer.json jako nejnižší verze, kterou dovoluje
require.php; pravidla pro novější syntaxi se pod ní sama vynechají. DressCode rozumí běžným zápisům
omezení: ^8.1, ~8.1, >=8.1 s horní mezí i bez ní, 8.1 - 8.3 a jejich
kombinacím přes ||. Z jiného tvaru, třeba <8.4 nebo *, nejnižší verzi poznat
nejde, a tak platí výchozí PHP 8.0. Starší verzi než PHP 8.0 DressCode nepodporuje: když ji projekt dovoluje nebo ji
nastavíte, zkontroluje kód jako PHP 8.0 a upozorní, že oprava může zapsat syntaxi, kterou starší PHP nezná. Klíč
php tedy uvádějte jen tehdy, když se verze od composer.json liší, nebo když ji z něj DressCode
nepřečte. Do přepisu ho napište, když má část projektu běžet na jiném PHP. Uvozovky psát můžete a nemusíte, obojí
je správně:
php: 8.2
Zápis php: '8.2' znamená totéž. Verze bez uvozovek je pro NEON číslo a DressCode ho čte jako verzi, jejíž
minor je jednociferný, což každé vydané PHP mělo: php: 8 i php: 8.0 tedy znamenají 8.0.
Stejně jako verzi PHP může pravidlo vyžadovat i balíček v nějaké verzi, když hlídá jeho API; pravidlo pro
nové API nette/forms 3.3 se v projektu, který ho nemá, prostě nespustí. Verze balíčku se čte z
composer.json a z instalovaných balíčků vedle něj a měří se tím, na čem projekt stojí: u balíčku,
který si projekt vyžaduje sám, je to nejnižší verze, kterou jeho omezení dovolí, protože kód psaný pro novější by se
rozbil všude, kam to omezení pustí starší. U balíčku, který přišel jen s jiným, rozhoduje ta nainstalovaná. Pravidlo
se tedy zapne, až když zvednete omezení ve svém composer.json.
Funkce a konstanty ve jmenných prostorech, které projekt deklaruje, vyjmenuje klíč namespaces se
seznamy functions a constants, a klíč nameResolution: certain řekne, že jiné nejsou.
DressCode pak ví, jestli nekvalifikované strlen() ve jmenném prostoru znamená globální funkci, a opravy, které
na tom stojí, přestanou být rizikové. Položky se píšou jako v příkazu
use, i se skupinami, které patří do uvozovek. Bez nameResolution platí uncertain a
takové opravy čekají na svolení. Proč na tom tolik záleží, vysvětluje stránka Funkce a konstanty ve jmenných prostorech.
nameResolution: certain
namespaces:
constants:
- 'App\{VERSION, DEBUG}'
Seznamy se sčítají přes všechny vrstvy: presety do nich přidávají funkce svých frameworků a přepis funkce, které
deklaruje jen jeho část projektu. Klíč nameResolution nastaví konfigurace nebo přepis, preset ne: framework
zná preset, váš kód jen vy.
Typy z PHPStanu
Klíč types: phpstan řekne, že se typy kódu berou z PHPStanu nainstalovaného v projektu, s jeho
konfigurací phpstan.neon a s jeho rozšířeními. Až s ním můžou běžet pravidla, která bez typů
nedávají smysl, třeba přepis zastaralého API knihoven nebo #[\Override] u přepsané metody:
types: phpstan
Stejně jako verze PHP je to rozhodnutí projektu, a preset ho proto nastavit nemůže; uvádí se na nejvyšší úrovni
konfigurace. Pravidlo, které typy potřebuje a které zapíná preset, se bez klíče types potichu vynechá.
Pravidlo, které jste zapnuli jménem, je bez klíče types chyba konfigurace, protože běh, ve kterém by pravidlo
chybělo, by tvrdil, že je kód v pořádku. Co všechno typy umožní a co stojí, popisuje stránka Typy z PHPStanu.
Pravidla a jejich volby
Klíč rules je mapa, ve které je jménu pravidla přiřazena jedna ze čtyř věcí:
truezapne pravidlo s výchozími volbami;keepříká, že pravidlo nic nevynucuje: kód zůstane, jak je. Je to jediné slovo pro „nesahej na to“, stejné u celého pravidla i u jedné jeho volby (falsez PHP zápisu znamená totéž);- hodnota u pravidla, které je jedním rozhodnutím:
dresscode/yoda: forbidden,dresscode/string-quotes: single,dresscode/kind-in-class-name: required. Je to zkratka za mapu s jedinou volbou a stránka pravidla říká, kterou; - mapa voleb.
Jména jsou ta z přehledu pravidel a z výpisu dresscode check;
volby každého pravidla najdete i s příklady na jeho stránce a vypíše je
dresscode explain <pravidlo>.
rules:
dresscode/strict-comparison: true
dresscode/useless-else: keep
dresscode/string-quotes: single
dresscode/trailing-comma:
multiLine: [arrays, arguments]
dresscode/multi-line-array:
shape: keep
Poslední řádek ukazuje keep uvnitř mapy: volba, která pojmenovává rozhodnutí (tvar, polohu, zarovnání),
ho přijme a pravidlo pak tohle jedno rozhodnutí nevynucuje, ale zbytek hlídá dál. Bez toho by se muselo vypnout celé.
Dvě věci, na kterých se dá zakopnout:
- Seznam ve volbě nahrazuje výchozí seznam, neslučuje se s ním.
multiLine: [arguments]zapne koncovou čárku u argumentů a vypne ji u polí, i když u polí byla v presetu. Chcete-li přidávat, opište i zděděné hodnoty. Mapa se naopak slévá, takže u ní stačí uvést jen klíč, který měníte. - Jméno pravidla z jiného nástroje není platný klíč.
no_unused_importsaniSlevomatCodingStandard.Namespaces.UnusedUsessem nepatří. DressCode je zná a v chybové hlášce vám řekne, které jeho pravidlo jim odpovídá, ale do konfigurace patří jméno jeho. Celý cizí konfigurační soubor převede příkazdresscode import.
Místo jména lze všude použít název třídy, což se hodí u vlastních pravidel, která pak nemusíte nikde registrovat:
rules:
App\CodeStyle\ExceptionMessagePeriodRule: true
Na jeden běh se pravidlo zapíná a vypíná z příkazové řádky:
--rule dresscode/line-length=off.
Jiný profil pro část projektu
Projekt málokdy vypadá všude stejně. Knihovní kód chcete co nejrychlejší, testy mají vlastní hlavičku a vlastní
pomocné funkce, šablony generátoru jiné odsazení. Většina nástrojů na to má jen jedno: pravidlo pro některé cesty
vypnout. DressCode dá každé části projektu celý vlastní profil. Přepis v klíči overrides platí pro
soubory, které odpovídají jeho paths, a smí v něm stát cokoli, co smí stát v profilu projektu, presety
počínaje:
presets:
- dresscode/nette
nameResolution: certain
overrides:
# knihovna píše volání tak, jak je PHP umí optimalizovat
- paths: [src]
groups: [optimized-calls]
# testy si ve svém jmenném prostoru deklarují pomocné funkce
- paths: [tests]
nameResolution: uncertain
rules: {dresscode/blank-lines: {afterImports: 2}}
warnings: [dresscode/property-phpdoc-required]
# šablony generátoru se odsazují dvěma mezerami
- paths: [resources/stubs]
indent: 2
Co z toho vyjde:
- Soubory v
srcdostanou k Nette Coding Standardu navíc skupinuoptimized-calls, která zapíše volání tak, aby je PHP mohlo optimalizovat. Přepis leží nad klíči konfigurace, takže pravidlu, které nastavují oba, dá poslední slovo přepis; o volbách, které přepis nezmíní, dál rozhoduje projekt. - V
testsříkánameResolution: uncertain, že seznamy funkcí z konfigurace pro testy úplné nejsou. Opravy, které stojí na tom, že je funkce globální, se tam jen ohlásí jako rizikové a hlídač nevyjmenovaných deklarací tam mlčí, takže pomocná funkce testu do konfigurace psát nemusíte. Zdrojáky přitom dál těží z jistoty; podrobnosti jsou na stránce Funkce a konstanty ve jmenných prostorech. - Tamtéž
{afterImports: 2}změní jediný klíč a ostatní čísla z presetu zůstanou, awarningspřidá k seznamu projektu pravidlo, které v testech jen varuje. - Šablony v
resources/stubsse odsazují dvěma mezerami a ve všem ostatním platí totéž co ve zbytku projektu.
Cesty mají stejnou syntaxi jako excludePaths a počítají se od kořene projektu. Soubor, který odpovídá
několika přepisům, dostane jejich vrstvy v pořadí zápisu, takže pozdější přepis má poslední slovo. Hodnota
keep pravidlo pro tyto soubory vypne a pozdější přepis ho pro soubory, které odpovídají oběma, může zase
zapnout. Pravidlo, které má pro část projektu platit jen s jinou hodnotou, nevypínejte; dejte mu tu hodnotu v přepisu.
Každý přepis DressCode projde hned na začátku běhu, i když mu žádný soubor neodpovídá, takže překlep ve jménu pravidla nebo presetu i volbu, kterou pravidlo nezná, ohlásí rovnou a se jménem přepisu:
Error: Unknown rule 'dresscode/strict-comparsion'. Did you mean 'dresscode/strict-comparison'? (in the override for tests)
Co pro konkrétní soubor nakonec platí, ukáže dresscode config --file tests/CartTest.phpt: presety, styl,
jistotu jmen i každou volbu s vrstvou, která ji nastavila.
Varování a rizikové opravy
Každé porušení je chyba a shodí build, dokud ho konfigurace nezměkčí. Pravidlo v seznamu warnings dál
hlásí a výpis ho počítá zvlášť, ale exit kód zůstane 0; práh dá přepínač
--max-warnings <n>. Hodí se to u toho, co fix neopraví, hlavně u délky řádku;
u opravitelných pravidel je po fix stejně prázdno.
warnings:
- dresscode/line-length
Riziková oprava je taková, která může změnit, co kód dělá. Většinou je to vlastnost konkrétního místa:
get_class($x) na $x::class je bezpečné, dokud $x nemůže být null, takže
dresscode/modern-class-name-reference opraví, co bezpečně umí, a rizikový výskyt jen ohlásí. Jiné pravidlo
ale bezpečné místo z kódu poznat nemůže, a pak je riziková každá jeho oprava: dresscode/strict-call doplní
do in_array() parametr $strict = true, a kód, který spoléhal na volné porovnání, pak může najít
něco jiného. Shrnutí řekne, kolik rizikových oprav čeká, a ve formátu json má každé takové porušení
příznak risky.
Zapnout pravidlo, ať jménem, nebo presetem, ještě neznamená souhlasit s jeho rizikovými opravami. Souhlas dává projekt
klíčem fixRisky, seznamem pravidel, jejichž rizikové opravy přijímá; fix pak udělá jen ty a
ostatní ohlásí. Preset tenhle souhlas dát nemůže a DressCode preset, který by se o to pokusil, odmítne. Git hook nebo
editor proto nepotřebují žádný přepínač: opraví, co projekt přijal, a zbytek ohlásí. Přepínač
--fix-risky dovolí rizikové opravy všech pravidel na jeden běh:
fixRisky:
- dresscode/strict-call
- dresscode/modern-class-name-reference
Oba seznamy se přes vrstvy sčítají, takže přepis může jen pro svou část projektu přijmout rizikové opravy, které jinde přijmout nechcete, nebo nechat pravidlo jen varovat.
Bez souhlasu se rizikové místo hlásí jako každé jiné porušení, které se neopravilo, a exit kód je 1.
Ticho by znamenalo, že „rizikové“ je synonymum pro „ignorované“. Shrnutí přitom jmenuje pravidla, jejichž opravy
čekají, takže víte, co do seznamu napsat.
Jestli jste rizikové opravy pravidla přijali, ukáže dresscode config: u pravidla stojí
risky fixes accepted, a u pravidla, jehož riziková je každá oprava a svolení zatím nemá,
risky fixes only reported; pravidlo, které jen varuje, nese only warns. Jméno v fixRisky,
jehož pravidlo neběží nikde, ani v žádném přepisu, ohlásí každý běh jako varování, aby v konfiguraci nezůstal
řádek, který nic nedělá.
Cesty
paths říká, co se kontroluje: soubory a adresáře relativně ke kořeni projektu. Cesty zadané na
příkazové řádce mají přednost před konfigurací; adresář, ve kterém některé cesty z paths leží, se ale
zúží jen na ně, viz Příkazová řádka.
excludePaths naopak cesty vynechává a jen přidává: k výchozímu seznamu (vendor,
node_modules, temp, tmp, log a všechny adresáře začínající tečkou)
přidá vaše, a totéž udělá každé rozšíření. Nikdo nemůže vrátit zpátky to, co jiný vyloučil, takže se nestane,
že by rozšíření omylem zapnulo kontrolu vendor.
paths:
- src
- tests
excludePaths:
- tests/fixtures
- '*.generated.php'
Vzor s lomítkem je ukotvený ke kořeni, takže tests/fixtures je právě ten jeden adresář. Vzor bez lomítka
odpovídá jménu souboru nebo adresáře v jakékoli hloubce, takže fixtures vynechá každý adresář toho
jména. Hvězdička zastupuje cokoli kromě lomítka, dvě hvězdičky i lomítka, takže tests/**.phpt jsou
všechny testy v libovolné hloubce.
Jednotlivé pravidlo vypnete jen pro některé cesty přepisem s hodnotou
keep; zbytek pravidel takový soubor zkontroluje normálně:
overrides:
- paths: [legacy]
rules: {dresscode/strict-comparison: keep}
fileExtensions říká, které přípony se berou jako PHP (výchozí je jen php); projekt s testy
Nette Testeru přidá phpt. Soubor podle jeho obsahu, třeba generovaný kód podle hlavičky, vynechá
skipWhen, kterému předáte callback jako entitu:
skipWhen: App\CodeStyle\GeneratedFilter::isGenerated(...)
Callback dostane obsah souboru a jeho cestu a vrátí true, když se má soubor přeskočit. Filtr může
přinést i rozšíření; soubor se pak přeskočí, když ho přeskočí kterýkoli z nich.
Rozšíření
Klíč extensions vyjmenuje třídy, které do projektu něco přinášejí. Rozšíření (extension) je
to, co má pro projekt balíček: pravidla a presety pod jmény, analýzy, vyloučené cesty a filtr souborů. Takhle se do
DressCode zapojuje Nette Coding Standard:
extensions:
- Nette\CodingStandard\Extension
presets:
- dresscode/nette
- nette/clean-code
Rozšíření o tom, jak se kód píše, nerozhoduje: nezapne preset ani pravidlo a nenastaví styl. To je vždycky
rozhodnutí projektu, a proto ho vždycky přečtete v jeho vlastním souboru. Rozšíření jen zpřístupní jména, takže
nette/clean-code v ukázce si vybral projekt.
V klíči extensions může stát i třída pravidla nebo presetu. Tím dostane své jméno: pravidlo pak
zapnete jménem v rules, na jeden běh v --rule a potlačíte ho v komentáři
dresscode:ignore, preset zapnete jménem v presets, obojí v konfiguraci i v přepisu. Jak
rozšíření napsat, popisuje Vlastní preset a
rozšíření.
Balíček může své rozšíření ohlásit i sám, ve svém composer.json pod klíčem
extra.dresscode.extension. DressCode ho pak po instalaci najde v vendor/composer/installed.json a do
extensions ho psát nemusíte. Stejně najde soubor deprecations.neon, který knihovna uvede pod
extra.dresscode.deprecations a ve kterém stojí, co její verze přejmenovaly, viz Aktualizace knihoven. Ani jedno přitom žádné pravidlo nezapne:
pravidla z balíčku jen dostanou svá jména a data se uplatní jen v pravidlech, která jste zapnuli sami, ať jménem, nebo
skupinou deprecations. Živý příklad nese nette/forms: po jeho instalaci ví
dresscode/no-deprecated-classes, že se z Nette\Forms\IControl stalo Nette\Forms\Control, a
vy jste neudělali nic než to pravidlo zapnuli.
Objekty a callbacky
Kde zápis v PHP předává objekt nebo callback, napíše se v NEONu entita. Vypadá jako volání v PHP a znáte ji třeba z konfigurace Nette DI:
App\CodeStyle\Filter(8.1, strict: true)vytvoří objekt; argumenty mohou být pojmenované,App\CodeStyle\Filter::create(8.1)zavolá statickou metodu a použije, co vrátí,App\CodeStyle\Filter::isGenerated(...)předá samotnou metodu jako callback,App\CodeStyle\Filter(8.1)::withLimit(100)zavolá metodu na tom, co vrátil předchozí článek řetězu.
Argumentem může být i další entita. Entitu přijímají čtyři klíče, rules včetně pravidel
v přepisech:
extensions:
- App\CodeStyle\Extension(strict: true)
skipWhen: App\CodeStyle\GeneratedFilter::isGenerated(...)
rules:
App\CodeStyle\CacheKeyRule: App\CodeStyle\CacheKeyRule(App\CodeStyle\Keys::load())
analyses:
- App\CodeStyle\Analyses\Imports
App\CodeStyle\Analyses\Calls: App\CodeStyle\Analyses\Calls::create(...)
V PHP je to totéž, jen napsané jako kód:
return new Config(
extensions: [new App\CodeStyle\Extension(strict: true)],
rules: [
App\CodeStyle\CacheKeyRule::class => fn() => new App\CodeStyle\CacheKeyRule(App\CodeStyle\Keys::load()),
],
skipWhen: App\CodeStyle\GeneratedFilter::isGenerated(...),
analyses: [
App\CodeStyle\Analyses\Imports::class,
App\CodeStyle\Analyses\Calls::class => App\CodeStyle\Analyses\Calls::create(...),
],
);
Rozšíření, skipWhen a továrna analýzy se vyhodnotí hned při načtení konfigurace. U pravidla je entita
recept: pravidlo s vlastními závislostmi se podle něj postaví pokaždé, když ho DressCode potřebuje, třeba zvlášť pro
soubory každého přepisu. Při načtení se jen ověří, že třída nebo metoda existuje, takže překlep je chyba konfigurace
hned, ne až během kontroly.
Příkazová řádka
Přepínače --preset, --group a --rule jsou nejvyšší vrstva: leží nad konfigurací
i nad všemi přepisy, takže --rule dresscode/line-length=off vypne pravidlo pro jeden běh opravdu všude.
Přepínač --only běh zúží na jmenovaná pravidla, presety a skupiny a --fix-risky dovolí všechny
rizikové opravy. Klíči konfiguračního souboru nejsou: jsou to rozhodnutí jednoho běhu, ne projektu. Všechny přepínače
popisuje stránka Příkazová řádka.
Další klíče
baseline: soubor se soupisem porušení, která zatím opravit nejde a nemají se hlásit; jak vzniká a kdy se hodí, popisuje Potlačení pravidel a baseline.cacheDir: kam si DressCode ukládá, které soubory už prošly čistě; výchozí je systémový dočasný adresář.analyses: registrace vlastní analýzy pro vlastní pravidla; analýza, kterou jádro samo nepostaví, dostane továrnu jako entitu. Analýza stejné třídy z konfigurace má přednost před tou z rozšíření.
Co z toho všeho nakonec platí, ukáže dresscode config: u každého pravidla, které běží, volby
s hodnotou, vrstvou, která ji nastavila, a s tím, co přebila, a u pravidla, které neběží, důvod. S --file
totéž pro jeden soubor, i s přepisy, které pro něj platí. dresscode rules vypíše všechna známá pravidla,
hvězdičkou označí ta, která v aktuální konfiguraci platí, a u každého uvede jména pravidel jiných nástrojů, která
pokrývá.