You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.8 KiB
148 lines
4.8 KiB
"use strict"; |
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
|
}) : (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
o[k2] = m[k]; |
|
})); |
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
}) : function(o, v) { |
|
o["default"] = v; |
|
}); |
|
var __importStar = (this && this.__importStar) || function (mod) { |
|
if (mod && mod.__esModule) return mod; |
|
var result = {}; |
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
__setModuleDefault(result, mod); |
|
return result; |
|
}; |
|
var __importDefault = (this && this.__importDefault) || function (mod) { |
|
return (mod && mod.__esModule) ? mod : { "default": mod }; |
|
}; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
const parser_1 = require("@babel/parser"); |
|
const babel_walk_1 = require("babel-walk"); |
|
const t = __importStar(require("@babel/types")); |
|
const globals_1 = __importDefault(require("./globals")); |
|
const parseOptions = { |
|
allowReturnOutsideFunction: true, |
|
allowImportExportEverywhere: true, |
|
}; |
|
/** |
|
* Mimic `with` as far as possible but at compile time |
|
* |
|
* @param obj The object part of a with expression |
|
* @param src The body of the with expression |
|
* @param exclude A list of variable names to explicitly exclude |
|
*/ |
|
function addWith(obj, src, exclude = []) { |
|
// tslint:disable-next-line: no-parameter-reassignment |
|
obj = obj + ''; |
|
// tslint:disable-next-line: no-parameter-reassignment |
|
src = src + ''; |
|
let ast; |
|
try { |
|
ast = parser_1.parse(src, parseOptions); |
|
} |
|
catch (e) { |
|
throw Object.assign(new Error('Error parsing body of the with expression'), { |
|
component: 'src', |
|
babylonError: e, |
|
}); |
|
} |
|
let objAst; |
|
try { |
|
objAst = parser_1.parse(obj, parseOptions); |
|
} |
|
catch (e) { |
|
throw Object.assign(new Error('Error parsing object part of the with expression'), { |
|
component: 'obj', |
|
babylonError: e, |
|
}); |
|
} |
|
const excludeSet = new Set([ |
|
'undefined', |
|
'this', |
|
...exclude, |
|
...globals_1.default(objAst).map((g) => g.name), |
|
]); |
|
const vars = new Set(globals_1.default(ast) |
|
.map((global) => global.name) |
|
.filter((v) => !excludeSet.has(v))); |
|
if (vars.size === 0) |
|
return src; |
|
let declareLocal = ''; |
|
let local = 'locals_for_with'; |
|
let result = 'result_of_with'; |
|
if (t.isValidIdentifier(obj)) { |
|
local = obj; |
|
} |
|
else { |
|
while (vars.has(local) || excludeSet.has(local)) { |
|
local += '_'; |
|
} |
|
declareLocal = `var ${local} = (${obj});`; |
|
} |
|
while (vars.has(result) || excludeSet.has(result)) { |
|
result += '_'; |
|
} |
|
const args = [ |
|
'this', |
|
...Array.from(vars).map((v) => `${JSON.stringify(v)} in ${local} ? |
|
${local}.${v} : |
|
typeof ${v} !== 'undefined' ? ${v} : undefined`), |
|
]; |
|
const unwrapped = unwrapReturns(ast, src, result); |
|
return `; |
|
${declareLocal} |
|
${unwrapped.before} |
|
(function (${Array.from(vars).join(', ')}) { |
|
${unwrapped.body} |
|
}.call(${args.join(', ')})); |
|
${unwrapped.after};`; |
|
} |
|
exports.default = addWith; |
|
const unwrapReturnsVisitors = babel_walk_1.recursive({ |
|
Function(_node, _state, _c) { |
|
// returns in these functions are not applicable |
|
}, |
|
ReturnStatement(node, state) { |
|
state.hasReturn = true; |
|
let value = ''; |
|
if (node.argument) { |
|
value = `value: (${state.source(node.argument)})`; |
|
} |
|
state.replace(node, `return {${value}};`); |
|
}, |
|
}); |
|
/** |
|
* Take a self calling function, and unwrap it such that return inside the function |
|
* results in return outside the function |
|
* |
|
* @param src Some JavaScript code representing a self-calling function |
|
* @param result A temporary variable to store the result in |
|
*/ |
|
function unwrapReturns(ast, src, result) { |
|
const charArray = src.split(''); |
|
const state = { |
|
hasReturn: false, |
|
source(node) { |
|
return src.slice(node.start, node.end); |
|
}, |
|
replace(node, str) { |
|
charArray.fill('', node.start, node.end); |
|
charArray[node.start] = str; |
|
}, |
|
}; |
|
unwrapReturnsVisitors(ast, state); |
|
return { |
|
before: state.hasReturn ? `var ${result} = ` : '', |
|
body: charArray.join(''), |
|
after: state.hasReturn ? `;if (${result}) return ${result}.value` : '', |
|
}; |
|
} |
|
module.exports = addWith; |
|
module.exports.default = addWith; |
|
//# sourceMappingURL=index.js.map
|