A while ago I wrote a small tool for analyzing code quality in TypoScript files (originally as part of a larger article for the t3n magazine) that since then has achieved a bit of popularity in the TYPO3 community. This article contains an updated write-up on the tool and a short guide on how to use it.
What is a linter?
The term “linting” dates back to the UNIX tool lint, which was originally intended find programming errors in C source code. By now, a “linter” is commonly understood as a tool to detect and report errors (including stylistic errors) in program source codes (source: Wikipedia). Linters help developers to keep a consistent coding style in projects and to find potential errors as early as possible using static code analysis.
There are linters for lots of different programming languages; web developers may have stumbled upon JSLint, CSSLint or HTMLLint. A new addition to this list is now TypoScript Lint that offers similar features for TypoScript, a language customarily used in TYPO3 projects. As a small example, let’s have a look at the following TypoScript snippet:
There are some obvious stylistic errors in this code snipped (ordered by severity):
- The property
page.10.templateRootPaths.10is assigned in line 6. However, the exact same property is overwritten in line 17. This is a dangerous pitfall: an unsuspecting developer might now change line 6 in good faith, without this having any effect - an error that will cost a lot of valuable time to debug.
- After the first assignment block to
pagehas been closed, there are subsequent assignments to sub-properties of
pagein lines 15 and 17. These might be surprising, since someone reading the source code might not expect these assignments after the initial assignment block.
- The comment in line 14 apparently contains source code that was commented out. This obstructs readability and should be removed completely. This is what version control is for!
- Indentation is not consistent. The
10s in lines 3 and 4 should be indented equally, but aren’t. Same goes for line 7. Especially in larger files, inconsistent indentation can reduce code readability hugely.
- The assignments to
templateRootPathsin lines 6 and 7 start with the same path segment. For better readability, these two assignments could be grouped in a single assignment block.
- The assignment to
layoutRootPathsin line 9 and 10 is completely empty.
And indeed, when passed an input file with the content seen above, the TypoScript linter generates the following output, that admonished all stated errors (and even a few more):
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)
A complete list of coding errors that are detected by the TypoScript linter can be found in the project’s README file.
The TypoScript linter is installed via Composer. Of course, this works best if the TYPO3 project in which the linter should be used is itself also managed with Composer (for setting up TYPO3 with Composer, I’ll just link to the respective README file). In this case, a simple
composer require --dev command in the project directory is sufficient:
--dev flag asserts that the linter is not installed when the project is deployed on a production system. After installation, the linter is available in the
vendor/bin directory and can be called with
If your TYPO3 project is not managed with Composer, you can use the
composer global command to install the linter globally. In this case, the linter is available not in your project directory, but in your user’s home directory; more precisely,
$HOME/.composer/vendor/bin/typoscript-lint (if you add the
$HOME/.composer/vendor/bin directory to your shell’s search path, a simple
typoscript-lint will be sufficient for calling the linter).
After the installation,
typoscript-lint can be called on arbitraty TypoScript files. These files will be analyzed and the linter will point out coding and style errors in the source code. The tool’s output might look as follows:
Using the options
-f xml and
-o outputfile.xml, you can create an XML output file that is compatible to the popular Checkstyle format. This way, you can easily integrate the TypoScript linter in Continuous Integration environments like Jenkins (for which there exists a plugin for Checkstyle).
Style in programming languages is often subjective and a matter of personal taste (best example probably being the “Tabs or Spaces?” question). Of course, the TypoScript linter can be adjusted to these kinds of preferences. For this, a configuration file called
tslint.yml needs to be created in your project directory. In this file, you can for example configure the indentation (here, for using tabs for indentation instead of spaces):
You can also deactivate individual checks. For example, if the recommendations for nesting assignments annoy you, they can be easily disabled:
Questions & feedback?
The TypoScript linter is available on GitHub and licensed under the MIT license. If you should notice errors while using the linter, feel free to use the issue tracker on GitHub or open up a Pull Request if you want to fix a bug or make a change to the linter by yourself.