SonarTS, a strange beast

by carlo bottiglieri|

    Embarking on the creation of a new language analyzer is often a complex decision, with many variables to consider, most of them hard to quantify. For TypeScript it was not so: we knew we wanted to create SonarTS, but the difficult questions came later. In the end, we went down a path that is very unusual for us, but has great potential.

    Our Parser or the TypeScript Parser?

    In general we prefer to write our own parsers for languages, to make sure that we have full control of the information we expose in the syntax tree. When you have to build many code-model layers on top of a syntax, you want to be sure that you master your foundations. When we started looking at the Microsoft TypeScript compiler though, we found that instead of being a closed product with the unique goal of transpiling from TS to JS, it was written as an inclusive language front-end library, that third parties are expected to leverage fully.

    Moreover, the TypeScript compiler API goes beyond syntax and provides semantic information, with cross-file type-inference.

    Finally, it is open-source and, while we would have liked a more rounded documentation on the syntax tree, the code is reasonably easy to understand.

    The decision to use the Microsoft TS compiler also put us in a place we have often wanted to be: in the position of developing an analyzer in the language of the users of the analyzer. Except for the SonarQube integration, SonarTS is written in TypeScript. This means we have become TypeScript developers and that has already proven very valuable, both for generating ideas for new rules, and for guaranteeing that we'll support the TypeScript developer's tool chain in the best possible way.

    While the use of the Microsoft TS compiler has many benefits, it's not without its drawbacks. Using it makes for an overall more fragile solution: the Java-to-TypeScript boundary of the plugin will need continuous refinement and, while it’s great to be able to analyze your project with the same compiler that you are using to transpile to JS, it will take additional time and effort to support each possible TypeScript (or multi-language) project layout.

    To Lint or not to Lint?

    TSLint seems to be the mainstream linter in the TypeScript world, and we are a natural competitor.

    We know we can develop interesting rules that understand the code more deeply than the average TSLint rule, but on the other hand, we probably don’t want to spend time writing dozens of style rules for an ever-growing number of frameworks, and it's not practical to use both a command line linter and a SonarQube analyzer at the same time, so TypeScript users would have to make a choice between the broader and the deeper analysis.

    That choice intrinsically lowers the overall value a TypeScript developer can get out of his linting setup. Do we really have to compete by forcing that choice? What if we could deliver value to SonarQube users AND to TSLint users in one stroke?

    A quick look at TSLint showed that it wouldn't take much to respect its API and have all our rules work in TSLint as well. This meant that we could create useful rules, based on more advanced code models than the TS compiler provides in its API, and provide them both as a TSLint extension and as a classic SonarQube plugin.

    This doesn’t mean that you get exactly the same feature-set out of the TSLint extension that you do from the SonarQube plugin: right now we can’t write a SonarQube plugin that supports third-party TSLint extensions so that necessarily narrows the available scope of analysis, and on the other hand the TSLint command-line does not offer a UI that allows us to report secondary issue locations, project metrics and all the goodness that we can offer when integrating with SonarQube.

    These differences will still allow the largest possible number of users to benefit from the lion's share of the value SonarTS has to offer. SonarTS is indeed a strange beast, but a generous one, with two faces and one brain. A bit like the ancient Roman god: Two-faced Janus.