Rozšiřování DressCode
Vlastní pravidlo pro váš tým, preset pro všechny vaše projekty, plugin, který je rozdá jako balíček, analýza pro víc pravidel, nebo data, se kterými si uživatelé vaší knihovny přepíšou kód na její novou verzi: kdy sáhnout po kterém z pěti rozšíření DressCode a na které jeho třídy se dá spolehnout jako na veřejné API.
Pět míst, kam se dá sáhnout
Pravidlo je odpověď na „chci hlídat ještě tohle“. Ohlásí rozhodnutí, která vynucuje, a buď
jako NodeRule řekne, které uzly ho zajímají, položí otázku a případně opraví, nebo jako
GapRule vysloví nárok na bílé znaky mezi tokeny. Uživatel pak píše jeho rozhodnutí stejně jako rozhodnutí
jádra: pravidla projektu v sekci project, pravidla pluginu v sekci pojmenované po pluginu. Napíšete ho za
odpoledne: Jak napsat vlastní pravidlo.
Preset je odpověď na „chci tenhle styl na všech projektech“. Soubor NEON ve tvaru konfigurace, který nese rozhodnutí, může vycházet z jiného presetu a dá se použít pro celý projekt i jen pro jeho část. Viz Vlastní preset a plugin.
Plugin je odpověď na „chci to rozdávat jako balíček“. Třída s rozhraním DressCode\Plugin,
jejíž jediná metoda getManifest() vrátí PluginManifest: pravidla balíčku, sekci jejich
rozhodnutí, rozhodnutí sdílená víc pravidly, presety se jmény, pluginy, na kterých staví, analýzy, vyloučené cesty,
filtr souborů a adresu stránek pravidel. Projekt ho uvede v klíči use vedle presetů, a to třídou nebo jménem
balíčku, který ho ohlásí v extra.dresscode.plugin svého composer.json; plugin, který je jen
nainstalovaný, se nenačte, protože přináší kód, který běží při každé kontrole. Jak má kód vypadat, plugin
nerozhoduje: rozhodnutí napíše projekt nebo preset. Viz Vlastní preset
a plugin.
Analýza je odpověď na „tuhle informaci o souboru potřebuje víc pravidel“. Obyčejná třída postavená nad
stromem, kterou si pravidla vyžádají; jádro ji vytvoří jednou a po každé změně stromu zahodí, jen analýza
s rozhraním PassAnalysis vydrží celý průchod. Vestavěné jsou NameResolver a Scope, PhpDoc, PhpSymbols s
PhpSignatures (co deklaruje samo PHP) a Types (typy kódu z PHPStanu projektu). Viz Pravidlo do detailu.
Data pro upgrade jsou odpověď na „nová verze mé knihovny přejmenovala API a uživatelé to mají opravit“.
Nejsou to pravidla, ale soubory NEON v adresáři, který balíček ohlásí v extra.dresscode.upgrading-dir, a
plní mapy jádra jako upgrading.api.replacedClasses nebo mapy pravidel pluginů. Viz Mapy náhrad.
Co rozšířit nejde, je parser. Je to samostatná knihovna PhpSyntax, jeho
gramatikou je PHP a nic jiného a strom, který z něj vzejde, je pro všechna pravidla stejný. Právě proto se dají pravidla
skládat, aniž by o sobě musela navzájem vědět. A nejde ani přidat vlastní formát výstupu: výstup je samostatná
smlouva, a kdo chce výsledky zpracovat jinde, přečte JSON z dresscode check --format json.
Co je veřejné API
Na tyhle třídy se plugin může spolehnout mezi minoritními verzemi:
- psaní pravidla:
Rules potomkyNodeRuleaGapRule,RuleInfo,RuleContext,Claim,Space,Line,Gap,Styles podobou importůImportStyle,Violationa výčtyStage,Severity,TristateaRisk; - rozhodnutí:
Decision,Domains obory vDomains\(Words,Shapes,Count,Flag,Names,Text,GrammarEntry,Map), hodnotyValuesaValues vrstvou, která hodnotu určila (Config\Layer,Config\LayerKind), a katalogConfig\Catalogue; - konfigurace:
Config,Profile,Override,PluginaPluginManifest; presety jsou soubory NEON a jejich jména; - pomocníci pravidel:
GlobalCalls(kterou globální funkci volání volá),CodeWriter(kód zapsaný v podobě, jakou soubor má),QualifiedNames(dvě poloviny plně kvalifikovaného jména) a gramatika map vUpgrading\(MemberMap,MemberMapGrammar,MemberPattern,MemberMapMatch,ArgumentPattern,ArgumentPatternItem,ArgumentBindings,FunctionPattern); vestavěná pravidla vRules\jen jménem a jmenným prostorem třídy, aby je šlo jmenovat v konfiguraci, jejich metody veřejné nejsou; - analýzy a testování: všechno v
Analyses\kroměRegistry,PhpStan,PhpSymbolsDataaPhpSignaturesData, dáleTesting\RuleTesteraTesting\UpgradingTesteri s jejich výjimkouTesting\TestFailurea výsledek souboruFileResult, který vracíUpgradingTester::runSample(); - příkazová řádka:
Console\ApplicationaConsole\UsageExceptionpro program, který chce běh vložit do sebe; - výjimky:
ConfigurationException,RuleException,ConvergenceException; - z knihovny PhpSyntax všechno, co není označené
@internal:Parser,Lexer,Printer,Node,Token,Trivia, uzly, analýzy,Style,Indentation, výčty aParseException.
Co je označené @internal, se může změnit kdykoli: jádro, načítání a řešení konfigurace, výstupní
formáty a pomocníci, které si vestavěná pravidla sdílejí jen mezi sebou. Program, který chce DressCode spustit, ho proto
spouští z příkazové řádky. Oba seznamy hlídá test, takže kvůli třídě, která není ani v jednom, testy selžou,
místo aby se nedopatřením stala veřejným API. A protože s novou syntaxí PHP může v minoritní verzi přibýt nový
uzel stromu, potřebuje každý match přes třídy uzlů větev default.
Některé veřejné třídy vytváří jen jádro: FileResult, ImportStyle, LineSplits
nebo MemberMapMatch pravidlo čte, ale nevytváří, a jejich konstruktor je proto @internal. Co se smí
mezi verzemi změnit a co ne, shrnuje stránka Zpětná kompatibilita
DressCode.
Pojmenování rozhodnutí
Co uživatel píše a čte, je cesta rozhodnutí, a tak na jejím jménu záleží nejvíc. Cesta jmenuje věc v kódu, ne
krok, který dělá oprava: acme.exceptionMessagePeriod: required, ne acme.addPeriod: true. Hodnota pak
říká, jak se ta věc píše, a vestavěný katalog na to má ustálená slova: forbidden a required
pro to, co v kódu být nesmí, nebo musí (v sekci upgrading i pro konstrukci novějšího PHP a náhradu
zavrženého API), sameLine a nextLine pro polohu tokenu, ukázku kódu v uvozovkách pro tvar, počet
pro prázdné řádky. Kde má věc víc míst, dostane každé svůj klíč (braces.position.class,
braces.position.function), a parametr, který jen upřesňuje, nese jméno toho, co upřesňuje
(mistakes.debugOutputFunctions). Cesty se píšou v camelCase.
Třída pravidla nese podle konvence příponu Rule a jméno stavu, který vynucuje, takže
ExceptionMessagePeriodRule vynucuje acme.exceptionMessagePeriod. Z tohoto jména bez přípony,
s malým prvním písmenem, skládá ruleUrl adresu stránky pravidla. Jméno presetu má tvar
vendor/name a sekce pluginu jméno pluginu. Je to konvence vestavěného katalogu a plugin, který se jí drží, do
něj zapadne.