| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 | 'use strict';var detect = require('acorn-globals');var acorn = require('acorn');var walk = require('acorn/dist/walk');// hacky fix for https://github.com/marijnh/acorn/issues/227function reallyParse(source) {  return acorn.parse(source, {    ecmaVersion: 6,    allowReturnOutsideFunction: true  });}module.exports = addWith/** * Mimic `with` as far as possible but at compile time * * @param {String} obj The object part of a with expression * @param {String} src The body of the with expression * @param {Array.<String>} exclude A list of variable names to explicitly exclude */function addWith(obj, src, exclude) {  obj = obj + ''  src = src + ''  exclude = exclude || []  exclude = exclude.concat(detect(obj).map(function (global) { return global.name; }))  var vars = detect(src).map(function (global) { return global.name; })    .filter(function (v) {      return exclude.indexOf(v) === -1        && v !== 'undefined'        && v !== 'this'    })  if (vars.length === 0) return src  var declareLocal = ''  var local = 'locals_for_with'  var result = 'result_of_with'  if (/^[a-zA-Z0-9$_]+$/.test(obj)) {    local = obj  } else {    while (vars.indexOf(local) != -1 || exclude.indexOf(local) != -1) {      local += '_'    }    declareLocal = 'var ' + local + ' = (' + obj + ')'  }  while (vars.indexOf(result) != -1 || exclude.indexOf(result) != -1) {    result += '_'  }  var inputVars = vars.map(function (v) {    return JSON.stringify(v) + ' in ' + local + '?' +      local + '.' + v + ':' +      'typeof ' + v + '!=="undefined"?' + v + ':undefined'  })  src = '(function (' + vars.join(', ') + ') {' +    src +    '}.call(this' + inputVars.map(function (v) { return ',' + v; }).join('') + '))'  return ';' + declareLocal + ';' + unwrapReturns(src, result) + ';'}/** * Take a self calling function, and unwrap it such that return inside the function * results in return outside the function * * @param {String} src    Some JavaScript code representing a self-calling function * @param {String} result A temporary variable to store the result in */function unwrapReturns(src, result) {  var originalSource = src  var hasReturn = false  var ast = reallyParse(src)  var ref  src = src.split('')  // get a reference to the function that was inserted to add an inner context  if ((ref = ast.body).length !== 1   || (ref = ref[0]).type !== 'ExpressionStatement'   || (ref = ref.expression).type !== 'CallExpression'   || (ref = ref.callee).type !== 'MemberExpression' || ref.computed !== false || ref.property.name !== 'call'   || (ref = ref.object).type !== 'FunctionExpression')    throw new Error('AST does not seem to represent a self-calling function')  var fn = ref  walk.recursive(ast, null, {    Function: function (node, st, c) {      if (node === fn) {        c(node.body, st, "ScopeBody");      }    },    ReturnStatement: function (node) {      hasReturn = true;      replace(node, 'return {value: (' + (node.argument ? source(node.argument) : 'undefined') + ')};');    }  });  function source(node) {    return src.slice(node.start, node.end).join('')  }  function replace(node, str) {    for (var i = node.start; i < node.end; i++) {      src[i] = ''    }    src[node.start] = str  }  if (!hasReturn) return originalSource  else return 'var ' + result + '=' + src.join('') + ';if (' + result + ') return ' + result + '.value'}
 |