Tombstone
JavaScriptPro
Aug 2007 โ Feb 2008 ยท age 25โ26
What it was
A JavaScript minifier and obfuscator for one web application, written in C# in a single day on top of an ANTLR 3 grammar drafted six months earlier. It stripped comments while keeping line numbers intact, parsed the file into an AST, and printed it back twice. The first pass hoisted every top-level function and declaration so that everything was declared before anything ran. The second pass re-parsed that output and renamed every local variable to _N, where N counts the names already visible in all enclosing scopes, so nothing could ever collide. Any name nobody declared, like window or the application's own globals, fell off the top of the scope chain and passed through untouched, with no reserved-word list at all. It ran once against the real file, and the grammar rejected every classic for loop in it.
Wins, for the age
- At twenty-five, in one sitting, Jeff arrived at collision-free scope-relative renaming with globals passing through, finding on its own what Dojo ShrinkSafe (2005) had already found. The shape was right on the first try.
- Made the printer the transform: one printer, two modes, and re-parsing its own output to chain passes.
- Kept line numbers alive through comment stripping so parse errors still pointed at the original source.
- Threw away an ANTLR 2 grammar and rewrote it smaller in ANTLR 3, which takes a humility most primates ration carefully.
What it taught
- Alternatives that start with the same token need a syntactic predicate. The error log was forty lines of "expecting 'in'".
- A parameterized printer is a transform, and re-parsing output is a cheap pipeline.
- The hard part of minification is reserved names; passing unknown names through sidesteps it.
- Keep the input that broke the parser. It is a test fixture waiting to happen.
Genealogy
Ancestors: none on record. A grammar drafted alone, then used in a day. Descendants: HUROX Compilers: a parser that hoists and renames locals for hurox.com.
Epitaph
Here lies JavaScriptPro. Six months to draft the grammar, one day to write the tool, one run on the real file. The scope renamer was right; the
forloop was not.