expressions.js 1.5 KB
module.exports = function Expressions() {
  var expressions = [];

  var findEnd = function(data, start) {
    var end = start + 'expression'.length;
    var level = 0;
    var quoted = false;

    while(true) {
      var next = data[end++];

      if (quoted) {
        quoted = next != '\'' && next != '"';
      } else {
        quoted = next == '\'' || next == '"';

        if (next == '(')
          level++;
        if (next == ')')
          level--;
      }

      if (level === 0 || !next)
        break;
    }

    return end;
  };

  return {
    // Escapes expressions by replacing them by the __EXPRESSION__
    // marker for further restoring. It's done via string scanning
    // instead of regexps to speed up the process.
    escape: function(data) {
      var nextStart = 0;
      var nextEnd = 0;
      var cursor = 0;
      var tempData = [];

      for (; nextEnd < data.length; ) {
        nextStart = data.indexOf('expression(', nextEnd);
        if (nextStart == -1)
          break;

        nextEnd = findEnd(data, nextStart);

        tempData.push(data.substring(cursor, nextStart));
        tempData.push('__EXPRESSION__');
        expressions.push(data.substring(nextStart, nextEnd));
        cursor = nextEnd;
      }

      return tempData.length > 0 ?
        tempData.join('') + data.substring(cursor, data.length) :
        data;
    },

    restore: function(data) {
      return data.replace(/__EXPRESSION__/g, function() {
        return expressions.shift();
      });
    }
  };
};