Futurice logo

Tech Pick of the Week: jsstana


This week's tech pick is a small JavaScript library, made for a very specific purpose by yours truly: jsstana. The homepage states “Find code inside your code! Pattern matching for Mozilla Parser AST, produced e.g. by esprima.” This might need a bit of explanation. I hope that the following examples will tell the story best.

Portrait of Oleg Grenrus
Oleg Grenrus

Software Developer

Pattern matching

Consider you have to check whether a piece of text contains exactly three exclamation marks. There are many ways to tackle a problem even as simple as this one.

    int has3exclmarks(const char *str, int len) {
        int count = 0;
        int len4 = len - 4;
        int i = 0;
        for (; i < len4 && count <= 3; i += 4) {
            uint32_t j = *((uint32_t *) (str + i));
            count += (j & (0xff)) == '!';
            count += (j & (0xff) << 8) == '!' << 8;
            count += (j & (0xff) << 16) == '!' << 16;
            count += (j & (0xff) << 24) == '!' << 24;
        for (; i < len; i++) {
            count += str[i] == '!';
        return count == 3;
    hasThreeExclamationMarks = (3==) . length . filter ('!'==)
    sub has3exclmarks {
        @_[0] =~ /^[^!]*![^!]*![^!]*![^!]*$/;

The first example is written in an imperative way. It's probably very fast (though I didn't check if it's really faster than a more trivial for loop, C compilers can work magic nowadays). On the other hand it's also very explicit about how it finds the answer. The functional example, the second one is very terse, and yet not obfuscated. There we combine even more primitive functions to get our job done. You can argue whether it's still how, or if it is already close to the executed definition, what. The last example is by no means close to obfuscated. However, the regular expression shows exactly what we are searching for: three exclamation marks surrounded by anything else. That is very declarative.

But wait, what if the requirement changes? Say, now we still need to check whether a piece of text contains three exclamation marks but only if two of them are next to each other, “like in this sentence! ni!!”. Updating the above examples is left as an exercise for the reader.

Searching for pieces of code

Sometimes, actually pretty often when refactoring, you have to find a particular piece of code. With trivial needles like

new Error grep is probably sufficient, assuming your code style is consistent and there is only ever one space between new and Error (of course you could use grep -E 'new\s+Error', couldn’t you?)

From time to time, you might want to find more complicated patterns, for example the return of the sum of two expressions, like return (a*b) + c;. Perhaps if you are writing rules for eslint, or trying to do some static analysis for the quality assurance of your JavaScript codebase by other means. With plain grep it will be painful (and you cannot really use it with eslint). Luckily there are JavaScript parsers, like esprima or acorn, which parse JavaScript source code into an Abstract Syntax Tree (AST). On the other hand it's more complicated to work with an AST, but on the other it's very precise.

Traversing and searching for patterns inside an AST without any helpers is very verbose:

    function isReturnOfSum(node) {
        return node.type === "ReturnStatement" &&
            node.argument.type === "BinaryExpression" &&
            node.argument.operator === "+";

With more complex patterns it's very easy to “blow up” the code. Of course you should use helpers, or some kind of a library to help you.

jsstana goes further and provides a way to write patterns for matching within an AST.

    var isReturnOfSum = jsstana.match("(return (+ ?lhs ?rhs))");

About jsstana

jsstana is a very young project, still already quite powerful. It can match everything we needed to match in our current project and a bit more. Fortunately it's extensible, so you can add more rators as you like, without having to go through me. Actually, you can try out jsstana on its homepage. Try to hover over matches on the right, or change different patterns at the bottom. Or you can install the npm package, and use the jsgrep tool bundled with it. Nowadays I use it daily in project work, it's an easy substitute for plain grep, just two additional characters in the name.

Why lispy s-expressions?

This is the most frequent question asked about jsstana. I'm not trying to trick everyone into using ClojureScript. It just felt natural to use s-expressions for this need. And it took a quarter of an hour to write the parser and get to the fun part.

You could use css selectors, as you could for any tree structure. Or you could use JavaScript syntax itself. But both approaches are limiting, e.g. how to match returns with anything but the sum? With lispy s-expressions it's easy:

    var isReturnOfNotSum = jsstana.match("(return (not (+ ? ?)))");

However, you can try out graspjs, which is a relatively new project as well. Maybe it will include s-expression support by jsstana. Maybe I'll borrow ideas from it. Time will tell.

I would like to hear feedback about jsstana. If you have any question, ideas or bug reports, please tell me, via Twitter or GitHub.

  • About
  • Services
  • Case Studies
  • Blog
  • Contact
  • Join us


© 2021 Futurice. All Rights Reserved | Privacy policy | Impressum

Futurice logo

Future. Co-created.