1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const utils_1 = require("./utils");
|
4 | const t = require("babel-types");
|
5 | const lodash_1 = require("lodash");
|
6 | const babel_generator_1 = require("babel-generator");
|
7 | const constant_1 = require("./constant");
|
8 | const render_props_1 = require("./render-props");
|
9 | const options_1 = require("./options");
|
10 | function initialIsCapital(word) {
|
11 | return word[0] !== word[0].toLowerCase();
|
12 | }
|
13 | exports.Status = {
|
14 | isSFC: false
|
15 | };
|
16 | exports.functionalComponent = () => {
|
17 | return {
|
18 | visitor: {
|
19 | JSXElement(path) {
|
20 | const arrowFuncExpr = path.findParent(p => p.isArrowFunctionExpression());
|
21 | const funcExpr = path.findParent(p => p.isFunctionExpression());
|
22 | if (funcExpr && funcExpr.isFunctionExpression() && funcExpr.parentPath.isVariableDeclarator()) {
|
23 | const { params, body, async } = funcExpr.node;
|
24 | funcExpr.replaceWith(t.arrowFunctionExpression(params, body, async));
|
25 | return;
|
26 | }
|
27 | if (arrowFuncExpr && arrowFuncExpr.isArrowFunctionExpression()) {
|
28 | if (arrowFuncExpr.parentPath.isVariableDeclarator()) {
|
29 | const valDecl = arrowFuncExpr.parentPath.parentPath;
|
30 | if (!valDecl.isVariableDeclaration() && !valDecl.isFunctionDeclaration()) {
|
31 | throw utils_1.codeFrameError(valDecl.node, '函数式组件不能同时定义多个值');
|
32 | }
|
33 | const id = arrowFuncExpr.parentPath.node.id;
|
34 | if (!t.isIdentifier(id)) {
|
35 | throw utils_1.codeFrameError(id, '函数式组件只能使用普通标识符定义');
|
36 | }
|
37 | if (!initialIsCapital(id.name)) {
|
38 | return;
|
39 | }
|
40 | const hasClassDecl = arrowFuncExpr.findParent(p => p.isClassDeclaration());
|
41 | if (hasClassDecl) {
|
42 |
|
43 | return;
|
44 | }
|
45 | const { body } = arrowFuncExpr.node;
|
46 | if (t.isBlockStatement(body)) {
|
47 | valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params, body));
|
48 | }
|
49 | else {
|
50 | valDecl.replaceWith(t.functionDeclaration(id, arrowFuncExpr.node.params, t.blockStatement([
|
51 | t.returnStatement(body)
|
52 | ])));
|
53 | }
|
54 | return;
|
55 | }
|
56 | else if (arrowFuncExpr.parentPath.isExportDefaultDeclaration()) {
|
57 | const { body, params } = arrowFuncExpr.node;
|
58 | const func = t.functionDeclaration(t.identifier('AnonymousSFC'), params, t.isBlockStatement(body) ? body : t.blockStatement([
|
59 | t.returnStatement(body)
|
60 | ]));
|
61 | arrowFuncExpr.parentPath.insertAfter(t.exportDefaultDeclaration(t.identifier('AnonymousSFC')));
|
62 | arrowFuncExpr.parentPath.replaceWith(func);
|
63 | return;
|
64 | }
|
65 | }
|
66 | const functionDecl = path.findParent(p => p.isFunctionDeclaration());
|
67 | if (functionDecl && functionDecl.isFunctionDeclaration()) {
|
68 | const hasClassDecl = path.findParent(p => p.isClassDeclaration() || p.isClassExpression());
|
69 | if (hasClassDecl) {
|
70 |
|
71 | return;
|
72 | }
|
73 | let { id, body, params } = functionDecl.node;
|
74 | let arg = null;
|
75 |
|
76 | if (id === null) {
|
77 | functionDecl.node.id = t.identifier('YourShouldGiveTheComponentAName');
|
78 | id = functionDecl.node.id;
|
79 | }
|
80 | if (params.length > 1) {
|
81 | throw utils_1.codeFrameError(id, '函数式组件的参数最多只能传入一个');
|
82 | }
|
83 | else if (params.length === 1) {
|
84 | arg = params[0];
|
85 | }
|
86 | const cloneBody = lodash_1.cloneDeep(body);
|
87 | if (!initialIsCapital(id.name)) {
|
88 | throw utils_1.codeFrameError(id, `普通函数式组件命名规则请遵守帕斯卡命名法(Pascal Case), 如果是在函数内声明闭包组件,则需要使用函数表达式的写法。
|
89 | 形如:
|
90 | const ${id.name} = ${babel_generator_1.default(t.arrowFunctionExpression(params, body)).code}
|
91 | `);
|
92 | }
|
93 | if (arg) {
|
94 | if (t.isIdentifier(arg)) {
|
95 | cloneBody.body.unshift(utils_1.buildConstVariableDeclaration(arg.name, t.memberExpression(t.thisExpression(), t.identifier('props'))));
|
96 | }
|
97 | else if (t.isObjectPattern(arg)) {
|
98 | let hasChildren = false;
|
99 | for (const [index, p] of arg.properties.entries()) {
|
100 | if (t.isObjectProperty(p) && t.isIdentifier(p.key, { name: 'children' })) {
|
101 | hasChildren = true;
|
102 | arg.properties.splice(index, 1);
|
103 | }
|
104 | }
|
105 | cloneBody.body.unshift(t.variableDeclaration('const', [
|
106 | t.variableDeclarator(arg, t.memberExpression(t.thisExpression(), t.identifier('props')))
|
107 | ]));
|
108 | if (hasChildren) {
|
109 | cloneBody.body.unshift(t.variableDeclaration('const', [
|
110 | t.variableDeclarator(t.objectPattern([
|
111 | t.objectProperty(t.identifier('children'), t.identifier('children'))
|
112 | ]), t.memberExpression(t.thisExpression(), t.identifier('props')))
|
113 | ]));
|
114 | }
|
115 | }
|
116 | else if (t.isAssignmentPattern(arg)) {
|
117 | throw utils_1.codeFrameError(arg, '给函数式组件的第一个参数设置默认参数是没有意义的,因为 props 永远都有值(不传 props 的时候是个空对象),所以默认参数永远都不会执行。');
|
118 | }
|
119 | else {
|
120 | throw utils_1.codeFrameError(arg, '函数式组件只支持传入一个简单标识符或使用对象结构');
|
121 | }
|
122 | }
|
123 | exports.Status.isSFC = true;
|
124 | const classDecl = t.classDeclaration(id, t.memberExpression(t.identifier('Taro'), t.identifier('Component')), t.classBody([
|
125 | t.classMethod('method', t.identifier('render'), [], cloneBody)
|
126 | ]), []);
|
127 | functionDecl.replaceWith(classDecl);
|
128 | }
|
129 | },
|
130 | JSXAttribute(path) {
|
131 | const { name, value } = path.node;
|
132 | const jsxElementPath = path.parentPath.parentPath;
|
133 | if (t.isJSXIdentifier(name) && jsxElementPath.isJSXElement() && options_1.transformOptions.isNormal !== true) {
|
134 | const componentName = jsxElementPath.node.openingElement.name.name;
|
135 | if (/^render[A-Z]/.test(name.name) && !constant_1.DEFAULT_Component_SET.has(componentName)) {
|
136 | if (!t.isJSXExpressionContainer(value)) {
|
137 | throw utils_1.codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。');
|
138 | }
|
139 | const expression = value.expression;
|
140 | if (t.isArrowFunctionExpression(expression)) {
|
141 | render_props_1.injectRenderPropsListener(path, name.name, expression, componentName);
|
142 | }
|
143 | }
|
144 | }
|
145 | }
|
146 | }
|
147 | };
|
148 | };
|
149 |
|
\ | No newline at end of file |