Codequalität in TYPO3-Projekten
Vor einiger Zeit schrieb ich (ursprünglich als Teil eines größeren Artikels für das t3n-Magazin) ein kleines Tool zur Analyse der Codequalität in TypoScript-Dateien, welches sich auch nach einigen Jahren noch einer gewissen Beliebtheit erfreut. Aus diesem Grund gibt es hier noch einmal eine kurze Zusammenfassung und einen Überblick über die Benutzung.
Was ist ein Linter?
Der Begriff des “Lintings” geht auf das betagte Unix-Tool lint zurück. Dieses diente ursprünglich dazu, Programmierfehler in C-Quelltexten zu finden. Mittlerweile versteht man unter einem “Linter” ein Tool, das Fehler (einschließlich stilistischer Fehler) in Programmquelltexten erkennt und meldet (Quelle: Wikipedia). Linter helfen Entwicklern, in Projekten einen einheitlichen Programmierstil einzuhalten, und mögliche Fehler möglichst früh durch statische Codeanalyse zu erkennen.
Linter gibt es für alle möglichen Programmiersprachen; Web-Entwickler kennen womöglich JSLint, CSSLint oder HTMLLint. In diese Liste reiht sich nun auch TypoScript Lint ein, welches ähnliche Funktionen für das in TYPO3-Projekten gebräuchliche TypoScript anbietet. Als kleines Beispiel sei folgender TypoScript-Quelltext betrachtet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
page = PAGE
page {
10 = FLUIDTEMPLATE
10 {
templateName = Default
templateRootPaths.10 = fileadmin/templates
templateRootPaths.20 = EXT:mysite/Resources/Private/Templates
layoutRootPaths {
}
}
}
#page.includeJS.main = fileadmin/js/app.js
page.includeJS.main = fileadmin/js/app.min.js
page.10.templateRootPaths.10 = fileadmin/templates2
In diesem Code-Abschnitt gibt es einige offensichtliche stilistische Punkte zu bemängeln (sortiert nach Schwere):
- In Zeile 6 wird die Eigenschaft
page.10.templateRootPaths.10
zugewiesen. Allerdings wird genau diese Eigenschaft in Zeile 17 wieder überschrieben. Dies ist eine gefährliche Falle: Ein unbedachter Entwickler könnte nun im guten Glauben Zeile 6 verändern, ohne dass dies irgendeine Auswirkung hätte – ein Fehler, den zu debuggen dann im Anschluss wertvolle Zeit kosten würde. - Nachdem der erste Zuweisungsblock zu
page
geschlossen wurde, folgt noch eine zweite Zuweisung zu einem Unterobjekt vonpage
. Dies könnte überraschen, da ein Leser des Quelltextes nicht unbedingt damit rechnet, dass nach dem Zuweisungsblock noch einzelne Unterattribute despage
-Objekts zugewiesen werden. - Die Kommentarzeile in Zeile 14 enthält offensichtlich auskommentierten Code. Dieser stört die Lesbarkeit und sollte komplett entfernt werden. Dafür gibt es ja schließlich Versionsverwaltung!
- Die Einrückung der Datei ist nicht konsistent. Die
10
in den Zeilen 3 und 4 sollten gleich weit eingerückt sein, sind es aber nicht. Gleiches gilt in Zeile 7. Gerade in größeren Dateien können solche Einrückungsfehler der Lesbarkeit des Quelltextes enorm schaden. - Die Zuweisungen zu
templateRootPaths
in den Zeilen 6 und 7 beginnen mit demselben Pfad-Segment. Zur besseren Lesbarkeit könnten diese beiden Zuweisungen in einen Block ausgelagert werden. - Die Zuweisung zu
layoutRootPaths
ist komplett leer.
Und tatsächlich generiert der TypoScript-Linter bei einer Eingabedatei mit obigem Inhalt folgende Ausgabe, welche alle oben angemerkten Fehler (und sogar noch ein paar mehr) ankreidet:
Completed with 8 issues
CHECKSTYLE REPORT
=> /Users/mhelmich/Git/Github/typo3-ci-example/test.typoscript.
2 Accessor should be followed by single space.
4 Expected indent of 2 spaces.
6 Value of object "page.10.templateRootPaths.10" is overwritten in line 17.
6 Common path prefix "templateRootPaths" with assignment to "templateRootPaths.20" in line 7. Consider merging them into a nested assignment.
7 Expected indent of 4 spaces.
7 Common path prefix "templateRootPaths" with assignment to "templateRootPaths.10" in line 6. Consider merging them into a nested assignment.
9 Empty assignment block
14 Found commented code (page.includeJS.main = fileadmin/js/app.js).
15 Assignment to value "page.includeJS.main", altough nested statement for path "page" exists at line 2.
17 Assignment to value "page.10.templateRootPaths.10", altough nested statement for path "page" exists at line 2.
17 Common path prefix "page" with assignment to "page.includeJS.main" in line 15. Consider merging them into a nested assignment.
SUMMARY
12 issues in total. (11 warnings, 1 infos)
Eine vollständige Liste aller vom TypoScript-Linter erkannten Fehler findet sich in der README des Projekts.
Installation
Der Typoscript-Linter wird per Composer installiert. Das funktioniert natürlich am besten, wenn das TYPO3-Projekt, in dem der Linter genutzt werden soll, selbst ebenfalls mit Composer verwaltet wird (zum Setup von TYPO3 mit Composer sei auf die zugehörige README verwiesen). In diesem Fall reicht ein einfaches composer require --dev
im Projektverzeichnis:
Das --dev
-Flag stellt sicher, dass der Linter nicht mit installiert wird, wenn das Projekt auf einem Produktivsystem installiert wird. Der Linter steht im Anschluss im Verzeichnis vendor/bin
zur Verfügung und kann mit vendor/bin/typoscript-lint
aufgerufen werden.
Falls euer TYPO3-Projekt nicht mit Composer verwaltet wird, kann auch der composer global
-Befehl genutzt werden, um den Linter global zu installieren. In diesem Fall steht der Linter dann nicht im Projektverzeichnis, sondern im Home-Verzeichnis eures Nutzers unter $HOME/.composer/vendor/bin/typoscript-lint
zur Verfügung (wenn ihr das Verzeichnis $HOME/.composer/vendor/bin
in euren Suchpfad eintragt, reicht anschließend auch ein einfaches typoscript-lint
zum Aufruf).
Nutzung
Nach der Installation kann typoscript-lint
auf beliebige Typoscript-Dateien aufgerufen werden. Die Dateien werden analyisiert, und das Tool wird euch auf Stilfehler (und auch echte Fehler) im Quelltext hinweisen. Die Ausgabe des Tools könnte beispielsweise aussehen wie folgt:
Mit den Optionen -f xml
und -o ausgabedatei.xml
kann auch eine XML-Ausgabedatei generiert werden, die dem verbreiteten Checkstyle-Format folgt. Auf diese Weise kann der Typoscript-Linter bequem in Continuous Integration-Umgebungen wie etwa Jenkins integriert werden (für das ein Plugin für Checkstyle existiert).
Konfiguration
Stilfragen in Programmiersprachen ist häufig subjektiv und abhängig von persönlichen Vorlieben. Bestes Beispiel ist wahrscheinlich die “Tabs oder Spaces?”-Frage. Natürlich kann der TypoScript-Linter an derartige Präferenzen angepasst werden. Hierzu muss im Projektverzeichnis eine Konfigurationsdatei typoscript-lint.yml
hinterlegt werden (frühere Versionen des Linters benutzten tslint.yml
als Dateiname für die Konfigurationsdatei, was allerdings zu einigen offensichtlichen Konflikten führte). Hier kann beispielsweise die Einrückung konfiguriert werden (hier etwa für die Einrückung mit Tabs statt Spaces):
1
2
3
4
5
sniffs:
- class: Indentation
parameters:
useSpaces: false
indentPerLevel: 1
Auch das Deaktivieren einzelner Überprüfungen ist möglich. Wenn euch beispielsweise die Empfehlungen für das Verschachteln von Statements nerven, kann diese Überprüfung einfach deaktiviert werden:
1
2
3
sniffs:
- class: NestingConsistency
disabled: true
Fragen & Feedback?
Der TypoScript-Linter ist auf GitHub verfügbar und steht unter der MIT-Lizenz zur Verfügung. Fällt euch bei der Nutzung des Linters ein Fehler auf, nutzt gerne den Bugtracker auf GitHub. Auch Verbesserungsvorschläge in Form von Pull Requests sind stets willkommen.