UNPKG

8.57 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const utils_1 = require("./utils");
4const t = require("babel-types");
5const lodash_1 = require("lodash");
6const babel_generator_1 = require("babel-generator");
7const constant_1 = require("./constant");
8const render_props_1 = require("./render-props");
9const options_1 = require("./options");
10function initialIsCapital(word) {
11 return word[0] !== word[0].toLowerCase();
12}
13exports.Status = {
14 isSFC: false
15};
16exports.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 // @TODO: 加上链接
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 // @TODO: 加上链接
71 return;
72 }
73 let { id, body, params } = functionDecl.node;
74 let arg = null;
75 // tslint:disable-next-line: strict-type-predicates
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形如:
90const ${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//# sourceMappingURL=functional.js.map
\No newline at end of file