source: trip-planner-front/node_modules/regenerator-transform/src/hoist.js@ 76712b2

Last change on this file since 76712b2 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 4.7 KB
Line 
1/**
2 * Copyright (c) 2014-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import * as util from "./util";
9let hasOwn = Object.prototype.hasOwnProperty;
10
11// The hoist function takes a FunctionExpression or FunctionDeclaration
12// and replaces any Declaration nodes in its body with assignments, then
13// returns a VariableDeclaration containing just the names of the removed
14// declarations.
15exports.hoist = function(funPath) {
16 const t = util.getTypes();
17 t.assertFunction(funPath.node);
18
19 let vars = {};
20
21 function varDeclToExpr({ node: vdec, scope }, includeIdentifiers) {
22 t.assertVariableDeclaration(vdec);
23 // TODO assert.equal(vdec.kind, "var");
24 let exprs = [];
25
26 vdec.declarations.forEach(function(dec) {
27 // Note: We duplicate 'dec.id' here to ensure that the variable declaration IDs don't
28 // have the same 'loc' value, since that can make sourcemaps and retainLines behave poorly.
29 vars[dec.id.name] = t.identifier(dec.id.name);
30
31 // Remove the binding, to avoid "duplicate declaration" errors when it will
32 // be injected again.
33 scope.removeBinding(dec.id.name);
34
35 if (dec.init) {
36 exprs.push(t.assignmentExpression(
37 "=", dec.id, dec.init
38 ));
39 } else if (includeIdentifiers) {
40 exprs.push(dec.id);
41 }
42 });
43
44 if (exprs.length === 0)
45 return null;
46
47 if (exprs.length === 1)
48 return exprs[0];
49
50 return t.sequenceExpression(exprs);
51 }
52
53 funPath.get("body").traverse({
54 VariableDeclaration: {
55 exit: function(path) {
56 let expr = varDeclToExpr(path, false);
57 if (expr === null) {
58 path.remove();
59 } else {
60 // We don't need to traverse this expression any further because
61 // there can't be any new declarations inside an expression.
62 util.replaceWithOrRemove(path, t.expressionStatement(expr));
63 }
64
65 // Since the original node has been either removed or replaced,
66 // avoid traversing it any further.
67 path.skip();
68 }
69 },
70
71 ForStatement: function(path) {
72 let init = path.get("init");
73 if (init.isVariableDeclaration()) {
74 util.replaceWithOrRemove(init, varDeclToExpr(init, false));
75 }
76 },
77
78 ForXStatement: function(path) {
79 let left = path.get("left");
80 if (left.isVariableDeclaration()) {
81 util.replaceWithOrRemove(left, varDeclToExpr(left, true));
82 }
83 },
84
85 FunctionDeclaration: function(path) {
86 let node = path.node;
87 vars[node.id.name] = node.id;
88
89 let assignment = t.expressionStatement(
90 t.assignmentExpression(
91 "=",
92 t.clone(node.id),
93 t.functionExpression(
94 path.scope.generateUidIdentifierBasedOnNode(node),
95 node.params,
96 node.body,
97 node.generator,
98 node.expression
99 )
100 )
101 );
102
103 if (path.parentPath.isBlockStatement()) {
104 // Insert the assignment form before the first statement in the
105 // enclosing block.
106 path.parentPath.unshiftContainer("body", assignment);
107
108 // Remove the function declaration now that we've inserted the
109 // equivalent assignment form at the beginning of the block.
110 path.remove();
111 } else {
112 // If the parent node is not a block statement, then we can just
113 // replace the declaration with the equivalent assignment form
114 // without worrying about hoisting it.
115 util.replaceWithOrRemove(path, assignment);
116 }
117
118 // Remove the binding, to avoid "duplicate declaration" errors when it will
119 // be injected again.
120 path.scope.removeBinding(node.id.name);
121
122 // Don't hoist variables out of inner functions.
123 path.skip();
124 },
125
126 FunctionExpression: function(path) {
127 // Don't descend into nested function expressions.
128 path.skip();
129 },
130
131 ArrowFunctionExpression: function(path) {
132 // Don't descend into nested function expressions.
133 path.skip();
134 }
135 });
136
137 let paramNames = {};
138 funPath.get("params").forEach(function(paramPath) {
139 let param = paramPath.node;
140 if (t.isIdentifier(param)) {
141 paramNames[param.name] = param;
142 } else {
143 // Variables declared by destructuring parameter patterns will be
144 // harmlessly re-declared.
145 }
146 });
147
148 let declarations = [];
149
150 Object.keys(vars).forEach(function(name) {
151 if (!hasOwn.call(paramNames, name)) {
152 declarations.push(t.variableDeclarator(vars[name], null));
153 }
154 });
155
156 if (declarations.length === 0) {
157 return null; // Be sure to handle this case!
158 }
159
160 return t.variableDeclaration("var", declarations);
161};
Note: See TracBrowser for help on using the repository browser.