-
Notifications
You must be signed in to change notification settings - Fork 1
/
pure-component-to-class.js
102 lines (81 loc) · 2.51 KB
/
pure-component-to-class.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
'use strict';
module.exports = function (file, api, options) {
const printOptions = options.printOptions || {
quote: 'single',
trailingComma: true,
};
const j = api.jscodeshift;
function createComponentBody(body) {
body = j.BlockStatement.check(body)
? body
: j.blockStatement([j.returnStatement(body)]);
j(body)
.find(j.Identifier, {name: 'props'})
.replaceWith(() => j.memberExpression(j.thisExpression(), j.identifier('props')));
return body;
}
const createPropsDecl = param => {
if (!j.ObjectPattern.check(param) && param.name === 'props') {
return null;
}
return j.variableDeclaration('const', [
j.variableDeclarator(
param,
j.memberExpression(j.thisExpression(), j.identifier('props'))
),
]);
};
const areValidArguments = args => {
const hasOneArgumentMax = args.length <= 1;
const argumentIsIdentifierOrObjectPattern =
!args[0] || j.Identifier.check(args[0]) || j.ObjectPattern.check(args[0]);
return hasOneArgumentMax && argumentIsIdentifierOrObjectPattern;
};
function hasJSXElement(ast) {
return j(ast).find(j.JSXElement).size() > 0;
}
const canBeReplaced = path => {
const isFunc = [
j.FunctionDeclaration,
j.FunctionExpression,
j.ArrowFunctionExpression
].some(x => x.check(path));
const isJSX = hasJSXElement(path) || j.JSXElement.check(path);
return isFunc && areValidArguments(path.params) && isJSX;
};
function toClassComponent(name, p) {
if (!canBeReplaced(p)){
return;
}
const param = p.params[0];
const body = createComponentBody(p.body);
if (param) {
const propsDecl = createPropsDecl(param);
if (propsDecl) {
body.body.unshift(createPropsDecl(param));
}
}
return j.classDeclaration(
name,
j.classBody([
j.methodDefinition('method',
j.identifier('render'),
j.functionExpression(null, [], body))
]),
j.memberExpression(
j.identifier('React'),
j.identifier('Component'),
false
)
);
}
const path = j(file.source);
path
.find(j.ExportDefaultDeclaration)
.replaceWith(p => j.exportDefaultDeclaration(toClassComponent(null, p.value.declaration) || p.value));
path
.find(j.VariableDeclaration)
.filter(p => p.value.declarations.length === 1)
.replaceWith(p => toClassComponent(p.value.declarations[0].id, p.value.declarations[0].init) || p.value);
return path.toSource(printOptions);
};