Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

preprocessor to replace javascript keywords

Tags:

javascript

I am using the Angular version of the $q library however this would also be relevant for the original q library.

Usage example:

$q
  .when(someFunction)
  .then(function(){
    // ..
  })
  .catch(function(){
    // ..
  })
  .finally(function(){
    // ..
  });

Unfortunately some function names (e.g. finally) conflict with javascript keywords.
From the Angular reference:

"Because finally is a reserved word in JavaScript and reserved keywords are not supported as property names by ES3, you'll need to invoke the method like promise['finally'](callback) to make your code IE8 and Android 2.x compatible."

ECMA-262, the official standard, available at http://www.ecma-international.org/publications/standards/Ecma-262.htm, states:

7.6.1.1 Keywords

The following tokens are ECMAScript keywords and may not be used as Identifiers in ECMAScript programs.

break           do              instanceof      typeof  
case            else            new             var 
catch           finally         return          void 
continue        for             switch          while 
debugger        function        this            with 
default         if              throw            
delete          in              try

This means that the first example has to be changed into the following code to get it working with IE8:

$q
  .when(someFunction)
  .then(function(){
    // ..
  })
  ['catch'](function(){
    // ..
  })
  ['finally'](function(){
    // ..
  });

As this code is harder to maintain I am looking for a javascript preprocessor (maybe a grunt task) which turns the first example into the IE8 compatible version.

Is there such a preprocessor?

like image 706
jantimon Avatar asked Jul 16 '14 15:07

jantimon


1 Answers

Your friendly neighborhood Stef Panner created such a tool just for that a few months ago. It's called es3-safe-recast. There is also a grunt task for it.

Let's go through what it does. First it requires the Esprima package for JS syntax tree analysis and recast on top of it that is built for these conversions:

'use strict';
var esprima = require('esprima');
var recast = require('recast');
var Visitor = recast.Visitor;
var types = recast.types;
var namedTypes = types.namedTypes;
var builders = types.builders;

Then it contains a big map of all the identifiers - just like your list:

identifierToLiteral.finally = true; // here is `finally` for example

Here is how it parses the tree and replaces it with a visitor:

var ES6Safe = Visitor.extend({
  visitProperty: function(node) { // go through all properties
    // check if need to replace name with literal
    if (namedTypes.Identifier.check(node.key) && identifierToLiteral[node.key.name]) {
      node.key = builders.literal(node.key.name);
    }

    return this.genericVisit(node);
  },

  visitMemberExpression: function(node) { // and all member expressions
    var property = node.property;
    var newNode;
    // check if need to replace name with literal
    if (namedTypes.Identifier.check(property) && identifierToLiteral[property.name]) {
      newNode = builders.memberExpression(node.object, builders.literal(property.name), true);
    } else {
      newNode = node;
    }
    return this.genericVisit(newNode);
  }
});

Finally, it runs the code through recast:

ast = recast.parse(source, { esprima: esprima } );
new ES6Safe().visit(ast);
code = recast.print(ast).code;

Producing the safe version of the above code.

like image 186
Benjamin Gruenbaum Avatar answered Oct 18 '22 17:10

Benjamin Gruenbaum