qooxdoo supports a set of compiler hints (in other environments sometimes called pragmas) that instruct the Generator when creating an application. Characteristic of compiler hints is that they are embedded in the class source code, usually in a comment towards the top of the class file. In that, compiler hints have a sort of syntax and semantics that are hidden from the “normal” language (JavaScript) inside comments.
The Generator would then use these hints to include resources and classes into a build that it wouldn’t otherwise. Likewise, the Generator could be instructed to not care about a certain name reference in the code, e.g. when that name belonged to a separate JS library which would only be available at runtime, or is a dependency that should not be included in a build.
#-Hints
So far, compiler hints were given in a block comment starting with a # (hash or pound) sign. Then a keyword ensued, like asset, ignore or require, and then some sort of parameters, usually enclosed in parens. All this was wrapped in a JavaScript block comment. Here is an example of such a comment block:
/* *********************************** #asset(custom/*) #require(qx.dev.unit.TestCase) #ignore(Dygraph) *************************************/
@-Hints
Over the years we also adopted a variant of the JSDoc standard for documenting classes and methods within qooxdoo. These are again specially crafted JS comment blocks that have a certain inner structure, or syntax. Each such comment block allows you to describe e.g. the method at hand in a free text.
But JSDoc also provides you with special keyed entries – JSDoc calls them “documentation tags” – that can be used to describe certain aspects of the method more formally, like the type and meaning of its formal parameters or its return value (I will use the terms “tag”, “attribute” and “hint” here interchangeably). Due to their formal structure JSDoc comments can be processed programmatically, be extracted, analyzed and transformed, one result of which you can see in our Apiviewer.
Over time, along with the standard tags like @param or @return we established special tags that we found helpful in working with the code an its documentation. Different parts of qooxdoo would use these additional tags, such as the Lint checker (@lint) or the Demobrowser (@tag). A full reference for the tags we support is given in the manual.
So effectively we had to maintain two different types of special JavaScript comments, with two different parsers (however simple), two places to look up things, etc., when one of them would actually suffice.
One Syntax to Rule them All
It seemed natural and efficient to normalize everything into JSDoc comments and extend the set of recognized attributes with those utilized by the Generator at compile time. We did that, and with the next qooxdoo release #-hints will be deprecated in favor of the corresponding @-hints. It’s mostly a one-to-one replacement, with an occasional tweak. The migration guide for the upcoming version has all the details.
Special Case: @ignore
Particularly, the @ignore hint introduces some novelties over its #ignore sibling. Like all @-hints it is capable of variadic arguments. So instead of writing
#ignore(foo) #ignore(bar)
you can write
@ignore(foo, bar)
to the same effect. (Of course you can still have two separate @ignore entries if you prefer that).
Double Relevance
More importantly, @ignore has relevance both as a compiler hint, but also for the lint checker, and in that supersedes the equally deprecated @lint ignoreUndefined() hint. I.e. using @ignore means
- don’t warn about this symbol if you cannot resolve it (for the lint checker)
- don’t include this symbol and its dependencies in the build (whether it is known or not – for the compiler. There was a blog post recently about issues around implementing this functionality.)
Name Globbing
As one more detail, @ignore is more strict about globbing. Already the old #ignore supported globs like #ignore(foo.*) to ignore entire namespaces, but also did some automatic globbing when it thought that foo was actually a class and not a namespace. The effect was that #ignore(foo) would also ignore foo.getBar when this looked like an attribute reference on a class object. (As you can imagine the problem lies in the term “looked like”. This decision could be safely made for known classes but not for unknown symbols. In an unknown “foo.bar”, is “bar” a nested namespace or a class attribute?!).
@ignore(foo) will ignore foo and only foo. If you also want foo.getBar be ignored either list it explicitly (as in @ignore(foo, foo.getBar)) or use a wildcard (as in @ignore(foo.*)) which will ignore both
Scoped Application
But most importantly, @ignore is lexically scoped. This was a major requirement, and one reason to integrate compiler hints with the JSDoc system. When people used an unknown symbol in one method, they wanted to ignore that specifically for that method and not globally for the whole file. As a consequence, using the same symbol in a sibling method you would again get an “Unknown global symbol” warning, which was desired. This was not available with the old #ignore.
So if an unknown name is found in a particular line of code, a lookup happens to the next enclosing lexical scope if this name should be ignored. If there is no such information in the enclosing JSDoc comment the search is repeated upwards, e.g. in the JSDoc preceding the class definition. If necessary this is repeated all the way up to the top-most JSDoc, which effectively takes the place of the old #ignore hint. So the old functionality is covered by a simple replacement of the different comment blocks, but the new system also allows a much finer control.
This scoped look up is not the case for other compiler hints like @require or @use which still scope over the entire class file.
So, all in all the new @-hints should be drop-in replacements for the old #-hints while being in line with the established JSDoc syntax, and being more versatile in some cases.