UNPKG

4.87 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21var __importDefault = (this && this.__importDefault) || function (mod) {
22 return (mod && mod.__esModule) ? mod : { "default": mod };
23};
24Object.defineProperty(exports, "__esModule", { value: true });
25const parser_1 = require("@babel/parser");
26const babel_walk_1 = require("babel-walk");
27const t = __importStar(require("@babel/types"));
28const globals_1 = __importDefault(require("./globals"));
29const parseOptions = {
30 allowReturnOutsideFunction: true,
31 allowImportExportEverywhere: true,
32};
33/**
34 * Mimic `with` as far as possible but at compile time
35 *
36 * @param obj The object part of a with expression
37 * @param src The body of the with expression
38 * @param exclude A list of variable names to explicitly exclude
39 */
40function addWith(obj, src, exclude = []) {
41 // tslint:disable-next-line: no-parameter-reassignment
42 obj = obj + '';
43 // tslint:disable-next-line: no-parameter-reassignment
44 src = src + '';
45 let ast;
46 try {
47 ast = parser_1.parse(src, parseOptions);
48 }
49 catch (e) {
50 throw Object.assign(new Error('Error parsing body of the with expression'), {
51 component: 'src',
52 babylonError: e,
53 });
54 }
55 let objAst;
56 try {
57 objAst = parser_1.parse(obj, parseOptions);
58 }
59 catch (e) {
60 throw Object.assign(new Error('Error parsing object part of the with expression'), {
61 component: 'obj',
62 babylonError: e,
63 });
64 }
65 const excludeSet = new Set([
66 'undefined',
67 'this',
68 ...exclude,
69 ...globals_1.default(objAst).map((g) => g.name),
70 ]);
71 const vars = new Set(globals_1.default(ast)
72 .map((global) => global.name)
73 .filter((v) => !excludeSet.has(v)));
74 if (vars.size === 0)
75 return src;
76 let declareLocal = '';
77 let local = 'locals_for_with';
78 let result = 'result_of_with';
79 if (t.isValidIdentifier(obj)) {
80 local = obj;
81 }
82 else {
83 while (vars.has(local) || excludeSet.has(local)) {
84 local += '_';
85 }
86 declareLocal = `var ${local} = (${obj});`;
87 }
88 while (vars.has(result) || excludeSet.has(result)) {
89 result += '_';
90 }
91 const args = [
92 'this',
93 ...Array.from(vars).map((v) => `${JSON.stringify(v)} in ${local} ?
94 ${local}.${v} :
95 typeof ${v} !== 'undefined' ? ${v} : undefined`),
96 ];
97 const unwrapped = unwrapReturns(ast, src, result);
98 return `;
99 ${declareLocal}
100 ${unwrapped.before}
101 (function (${Array.from(vars).join(', ')}) {
102 ${unwrapped.body}
103 }.call(${args.join(', ')}));
104 ${unwrapped.after};`;
105}
106exports.default = addWith;
107const unwrapReturnsVisitors = babel_walk_1.recursive({
108 Function(_node, _state, _c) {
109 // returns in these functions are not applicable
110 },
111 ReturnStatement(node, state) {
112 state.hasReturn = true;
113 let value = '';
114 if (node.argument) {
115 value = `value: (${state.source(node.argument)})`;
116 }
117 state.replace(node, `return {${value}};`);
118 },
119});
120/**
121 * Take a self calling function, and unwrap it such that return inside the function
122 * results in return outside the function
123 *
124 * @param src Some JavaScript code representing a self-calling function
125 * @param result A temporary variable to store the result in
126 */
127function unwrapReturns(ast, src, result) {
128 const charArray = src.split('');
129 const state = {
130 hasReturn: false,
131 source(node) {
132 return src.slice(node.start, node.end);
133 },
134 replace(node, str) {
135 charArray.fill('', node.start, node.end);
136 charArray[node.start] = str;
137 },
138 };
139 unwrapReturnsVisitors(ast, state);
140 return {
141 before: state.hasReturn ? `var ${result} = ` : '',
142 body: charArray.join(''),
143 after: state.hasReturn ? `;if (${result}) return ${result}.value` : '',
144 };
145}
146module.exports = addWith;
147module.exports.default = addWith;
148//# sourceMappingURL=index.js.map
\No newline at end of file