-
Notifications
You must be signed in to change notification settings - Fork 0
/
return.macro.js
67 lines (55 loc) · 2.11 KB
/
return.macro.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
const { createMacro } = require("babel-plugin-macros")
function assert(condition, message) {
if (!condition) throw new Error(message)
}
module.exports = createMacro(({ references, babel }) => {
const { types: t } = babel
const isNull = key => t.binaryExpression("==", key, t.nullLiteral())
references.default.forEach(referencePath => {
const callPath = referencePath.parentPath
assert(t.isCallExpression(callPath.node), "return() must be called as a function.")
const nullishPath = callPath.parentPath
assert(
t.isLogicalExpression(nullishPath.node, { operator: "??" }),
"return() must be assigned to a LogicalExpression using ??, got " +
nullishPath.node.type
)
const declPath = nullishPath.parentPath
const declNode = declPath.node
assert(
t.isVariableDeclarator(declNode) ||
(t.isAssignmentExpression(declNode) && t.isIdentifier(declNode.left)),
"return() must be assigned to a VariableDeclarator or AssignmentExpression, got " +
declNode.type
)
const id = t.isVariableDeclarator(declNode) ? declNode.id : declNode.left
assert(
t.isIdentifier(id) ||
(t.isObjectPattern(id) && id.properties.every(t.isObjectProperty)) ||
(t.isArrayPattern(id) && id.elements.every(t.isIdentifier)),
"return() must be assigned to an Identifier or an ObjectPattern or ArrayPattern with no RestElement, got " +
id.type
)
const checkNulls = list =>
list.reduce(
(accum, key) =>
accum ? t.logicalExpression("||", accum, isNull(key)) : isNull(key),
null
)
const condition = t.isIdentifier(id)
? isNull(id)
: t.isObjectPattern(id)
? checkNulls(id.properties.map(x => x.value))
: t.isArrayPattern(id)
? checkNulls(id.elements)
: null
if (t.isVariableDeclarator(declNode)) {
declNode.init = declNode.init.left
} else if (t.isAssignmentExpression(declNode)) {
declNode.right = declNode.right.left
}
declPath.parentPath.insertAfter(
t.ifStatement(condition, t.returnStatement(callPath.node.arguments[0]))
)
})
})