Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80540 views
1
/**
2
* Copyright 2013 Facebook, Inc.
3
*
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
7
*
8
* http://www.apache.org/licenses/LICENSE-2.0
9
*
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
15
*/
16
17
/*global exports:true*/
18
19
/**
20
* Desugars ES6 Arrow functions to ES3 function expressions.
21
* If the function contains `this` expression -- automatically
22
* binds the function to current value of `this`.
23
*
24
* Single parameter, simple expression:
25
*
26
* [1, 2, 3].map(x => x * x);
27
*
28
* [1, 2, 3].map(function(x) { return x * x; });
29
*
30
* Several parameters, complex block:
31
*
32
* this.users.forEach((user, idx) => {
33
* return this.isActive(idx) && this.send(user);
34
* });
35
*
36
* this.users.forEach(function(user, idx) {
37
* return this.isActive(idx) && this.send(user);
38
* }.bind(this));
39
*
40
*/
41
var restParamVisitors = require('./es6-rest-param-visitors');
42
var destructuringVisitors = require('./es6-destructuring-visitors');
43
44
var Syntax = require('esprima-fb').Syntax;
45
var utils = require('../src/utils');
46
47
/**
48
* @public
49
*/
50
function visitArrowFunction(traverse, node, path, state) {
51
var notInExpression = (path[0].type === Syntax.ExpressionStatement);
52
53
// Wrap a function into a grouping operator, if it's not
54
// in the expression position.
55
if (notInExpression) {
56
utils.append('(', state);
57
}
58
59
utils.append('function', state);
60
renderParams(traverse, node, path, state);
61
62
// Skip arrow.
63
utils.catchupWhiteSpace(node.body.range[0], state);
64
65
var renderBody = node.body.type == Syntax.BlockStatement
66
? renderStatementBody
67
: renderExpressionBody;
68
69
path.unshift(node);
70
renderBody(traverse, node, path, state);
71
path.shift();
72
73
// Bind the function only if `this` value is used
74
// inside it or inside any sub-expression.
75
var containsBindingSyntax =
76
utils.containsChildMatching(node.body, function(node) {
77
return node.type === Syntax.ThisExpression
78
|| (node.type === Syntax.Identifier
79
&& node.name === "super");
80
});
81
82
if (containsBindingSyntax) {
83
utils.append('.bind(this)', state);
84
}
85
86
utils.catchupWhiteSpace(node.range[1], state);
87
88
// Close wrapper if not in the expression.
89
if (notInExpression) {
90
utils.append(')', state);
91
}
92
93
return false;
94
}
95
96
function renderParams(traverse, node, path, state) {
97
// To preserve inline typechecking directives, we
98
// distinguish between parens-free and paranthesized single param.
99
if (isParensFreeSingleParam(node, state) || !node.params.length) {
100
utils.append('(', state);
101
}
102
if (node.params.length !== 0) {
103
path.unshift(node);
104
traverse(node.params, path, state);
105
path.unshift();
106
}
107
utils.append(')', state);
108
}
109
110
function isParensFreeSingleParam(node, state) {
111
return node.params.length === 1 &&
112
state.g.source[state.g.position] !== '(';
113
}
114
115
function renderExpressionBody(traverse, node, path, state) {
116
// Wrap simple expression bodies into a block
117
// with explicit return statement.
118
utils.append('{', state);
119
120
// Special handling of rest param.
121
if (node.rest) {
122
utils.append(
123
restParamVisitors.renderRestParamSetup(node, state),
124
state
125
);
126
}
127
128
// Special handling of destructured params.
129
destructuringVisitors.renderDestructuredComponents(
130
node,
131
utils.updateState(state, {
132
localScope: {
133
parentNode: state.parentNode,
134
parentScope: state.parentScope,
135
identifiers: state.identifiers,
136
tempVarIndex: 0
137
}
138
})
139
);
140
141
utils.append('return ', state);
142
renderStatementBody(traverse, node, path, state);
143
utils.append(';}', state);
144
}
145
146
function renderStatementBody(traverse, node, path, state) {
147
traverse(node.body, path, state);
148
utils.catchup(node.body.range[1], state);
149
}
150
151
visitArrowFunction.test = function(node, path, state) {
152
return node.type === Syntax.ArrowFunctionExpression;
153
};
154
155
exports.visitorList = [
156
visitArrowFunction
157
];
158
159
160