UNPKG

125 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const babel_traverse_1 = require("babel-traverse");
4const t = require("babel-types");
5const babel_core_1 = require("babel-core");
6const utils_1 = require("./utils");
7const lodash_1 = require("lodash");
8const jsx_1 = require("./jsx");
9const constant_1 = require("./constant");
10const adapter_1 = require("./adapter");
11const options_1 = require("./options");
12const babel_generator_1 = require("babel-generator");
13const env_1 = require("./env");
14const functional_1 = require("./functional");
15const template = require('babel-template');
16function findParents(path, predicates) {
17 const parents = [];
18 // tslint:disable-next-line:no-conditional-assignment
19 while (path = path.parentPath) {
20 if (predicates(path)) {
21 parents.push(path);
22 }
23 }
24 return parents;
25}
26function isClassDcl(p) {
27 return p.isClassExpression() || p.isClassDeclaration();
28}
29function isChildrenOfJSXAttr(p) {
30 return !!p.findParent(p => p.isJSXAttribute());
31}
32function buildAssignState(pendingState) {
33 return t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), [
34 t.memberExpression(t.thisExpression(), t.identifier('state')),
35 pendingState
36 ]));
37}
38const incrementCalleeId = utils_1.incrementId();
39const incrementLoopArrayId = utils_1.incrementId();
40class RenderParser {
41 /**
42 *
43 * @param renderPath
44 * @param referencedIdentifiers
45 * 这三个属性是需要单独传入的
46 */
47 constructor(renderPath, methods, initState, referencedIdentifiers, usedState, customComponentNames, componentProperies, loopRefs, refObjExpr, methodName) {
48 this.classProperties = new Set();
49 this.templates = new Map();
50 this.jsxDeclarations = new Set();
51 this.loopScopes = new Set();
52 this.returnedPaths = [];
53 this.usedThisState = new Set();
54 this.loopComponents = new Map();
55 this.loopComponentNames = new Map();
56 this.loopRefIdentifiers = new Map();
57 this.reserveStateWords = new Set(functional_1.Status.isSFC ? [] : ['state', 'props']);
58 this.topLevelIfStatement = new Set();
59 this.usedEvents = new Set();
60 this.loopCalleeId = new Set();
61 this.usedThisProperties = new Set();
62 this.incrementCalleeId = env_1.isTestEnv ? utils_1.incrementId() : incrementCalleeId;
63 this.loopArrayId = env_1.isTestEnv ? utils_1.incrementId() : incrementLoopArrayId;
64 this.classComputedState = new Set();
65 this.propsSettingExpressions = new Map();
66 this.genCompidExprs = new Set();
67 this.loopCallees = new Set();
68 this.loopIfStemComponentMap = new Map();
69 this.hasNoReturnLoopStem = false;
70 this.isDefaultRender = false;
71 // private renderArg: t.Identifier | t.ObjectPattern | null = null
72 this.renderMethodName = '';
73 this.deferedHandleClosureJSXFunc = [];
74 this.ancestorConditions = new Set();
75 this.handleJSXElement = (jsxElementPath, func) => {
76 const parentNode = jsxElementPath.parent;
77 const parentPath = jsxElementPath.parentPath;
78 const isJSXChildren = t.isJSXElement(parentNode);
79 if (!isJSXChildren) {
80 let statementParent = jsxElementPath.getStatementParent();
81 const isReturnStatement = statementParent.isReturnStatement();
82 const isIfStemInLoop = this.isIfStemInLoop(jsxElementPath);
83 const isFinalReturn = statementParent.getFunctionParent().isClassMethod();
84 if (!(statementParent.isVariableDeclaration() ||
85 statementParent.isExpressionStatement())) {
86 statementParent = statementParent.findParent(s => s.isVariableDeclaration() || s.isExpressionStatement());
87 }
88 if (t.isVariableDeclarator(parentNode)) {
89 if (statementParent) {
90 const name = utils_1.findIdentifierFromStatement(statementParent.node);
91 // setTemplate(name, path, templates)
92 name && this.templates.set(name, jsxElementPath.node);
93 }
94 }
95 func({ parentNode, parentPath, statementParent, isReturnStatement, isFinalReturn, isIfStemInLoop });
96 }
97 };
98 this.isIfStemInLoop = (p) => {
99 const ifStem = p.findParent(p => p.isIfStatement());
100 if (ifStem && ifStem.isIfStatement()) {
101 const loopStem = ifStem.findParent(p => p.isCallExpression());
102 if (loopStem && utils_1.isArrayMapCallExpression(loopStem)) {
103 return true;
104 }
105 }
106 return false;
107 };
108 this.isLiteralOrUndefined = (node) => t.isLiteral(node) || t.isIdentifier(node, { name: 'undefined' });
109 this.replaceIdWithTemplate = (handleRefId = false) => (path) => {
110 if (!t.isJSXAttribute(path.parent)) {
111 path.traverse({
112 Identifier: (path) => {
113 const parentPath = path.parentPath;
114 if (parentPath.isConditionalExpression() ||
115 parentPath.isLogicalExpression() ||
116 path.isReferencedIdentifier()) {
117 const name = path.node.name;
118 if (handleRefId && Object.keys(this.renderScope.getAllBindings()).includes(name)) {
119 this.addRefIdentifier(path, path.node);
120 // referencedIdentifiers.add(path.node)
121 }
122 if (this.templates.has(name)) {
123 path.replaceWith(this.templates.get(name));
124 }
125 }
126 }
127 });
128 }
129 };
130 this.hasStateOrProps = (key) => (p) => t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === key;
131 this.returnedifStemJSX = new Set();
132 this.loopComponentVisitor = {
133 VariableDeclarator: (path) => {
134 const id = path.get('id');
135 const init = path.get('init');
136 const parentPath = path.parentPath;
137 if (id.isObjectPattern() &&
138 init.isThisExpression() &&
139 parentPath.isVariableDeclaration()) {
140 const { properties } = id.node;
141 this.destructStateOrProps('state', path, properties, parentPath);
142 this.destructStateOrProps('props', path, properties, parentPath);
143 }
144 },
145 JSXElement: {
146 enter: (jsxElementPath) => {
147 this.handleJSXElement(jsxElementPath, (options) => {
148 this.handleConditionExpr(options, jsxElementPath);
149 if (this.isIfStemInLoop(jsxElementPath)) {
150 this.handleJSXInIfStatement(jsxElementPath, options);
151 this.removeJSXStatement();
152 }
153 if (options.parentPath.isReturnStatement() && this.returnedifStemJSX.has(options.parentPath.scope)) {
154 const block = jsx_1.buildBlockElement();
155 jsx_1.setJSXAttr(block, adapter_1.Adapter.else);
156 block.children = [jsxElementPath.node];
157 jsxElementPath.replaceWith(block);
158 this.returnedifStemJSX.delete(options.parentPath.scope);
159 }
160 });
161 },
162 exit: (jsxElementPath) => {
163 this.handleJSXElement(jsxElementPath, ({ parentNode, parentPath, statementParent, isFinalReturn }) => {
164 if (statementParent && statementParent.findParent(p => p === this.renderPath)) {
165 this.jsxDeclarations.add(statementParent);
166 }
167 if (t.isReturnStatement(parentNode)) {
168 if (!isFinalReturn) {
169 const callExpr = parentPath.findParent(p => p.isCallExpression());
170 if (callExpr && callExpr.isCallExpression()) {
171 const callee = callExpr.node.callee;
172 if (this.loopComponents.has(callExpr)) {
173 return;
174 }
175 if (t.isMemberExpression(callee) &&
176 t.isIdentifier(callee.property) &&
177 callee.property.name === 'map') {
178 let ary = callee.object;
179 if (t.isCallExpression(ary) || utils_1.isContainFunction(callExpr.get('callee').get('object'))) {
180 this.loopCallees.add(ary);
181 const variableName = `${constant_1.LOOP_CALLEE}_${this.incrementCalleeId()}`;
182 callExpr.getStatementParent().insertBefore(utils_1.buildConstVariableDeclaration(variableName, utils_1.setParentCondition(jsxElementPath, ary, true)));
183 ary = t.identifier(variableName);
184 }
185 if (t.isMemberExpression(ary)) {
186 const id = utils_1.findFirstIdentifierFromMemberExpression(ary);
187 if (t.isIdentifier(id)) {
188 this.referencedIdentifiers.add(id);
189 }
190 }
191 else if (t.isIdentifier(ary)) {
192 const parentCallExpr = callExpr.find(p => p.isCallExpression());
193 if (!utils_1.isArrayMapCallExpression(parentCallExpr) && parentCallExpr !== callExpr) {
194 this.referencedIdentifiers.add(ary);
195 }
196 }
197 const block = jsx_1.buildBlockElement();
198 const hasIfAttr = jsxElementPath.node.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.if);
199 const needWrapper = "swan" /* swan */ === adapter_1.Adapter.type && hasIfAttr;
200 if (needWrapper) {
201 block.children = [jsxElementPath.node];
202 jsxElementPath.replaceWith(block);
203 }
204 jsx_1.setJSXAttr(needWrapper ? block : jsxElementPath.node, adapter_1.Adapter.for, t.jSXExpressionContainer(ary));
205 this.loopCalleeId.add(utils_1.findFirstIdentifierFromMemberExpression(callee));
206 const [func] = callExpr.node.arguments;
207 if (t.isFunctionExpression(func) ||
208 t.isArrowFunctionExpression(func)) {
209 const [item, index] = func.params;
210 let itemName = '';
211 let indexName = '';
212 if (t.isIdentifier(item)) {
213 if ("quickapp" /* quickapp */ !== adapter_1.Adapter.type) {
214 jsx_1.setJSXAttr(needWrapper ? block : jsxElementPath.node, adapter_1.Adapter.forItem, t.stringLiteral(item.name));
215 }
216 else {
217 itemName = item.name;
218 }
219 this.loopScopes.add(item.name);
220 }
221 else if (t.isObjectPattern(item)) {
222 throw utils_1.codeFrameError(item.loc, 'JSX map 循环参数暂时不支持使用 Object pattern 解构。');
223 }
224 else {
225 jsx_1.setJSXAttr(needWrapper ? block : jsxElementPath.node, adapter_1.Adapter.forItem, t.stringLiteral('__item'));
226 func.params[0] = t.identifier('__item');
227 }
228 if (t.isIdentifier(index)) {
229 if ("quickapp" /* quickapp */ !== adapter_1.Adapter.type) {
230 jsx_1.setJSXAttr(needWrapper ? block : jsxElementPath.node, adapter_1.Adapter.forIndex, t.stringLiteral(index.name));
231 }
232 else {
233 indexName = index.name;
234 }
235 this.loopScopes.add(index.name);
236 // tslint:disable-next-line: strict-type-predicates
237 }
238 else if (index === undefined) {
239 if (process.env.NODE_ENV !== 'test') {
240 const uid = this.renderScope.generateUid('anonIdx');
241 func.params[1] = t.identifier(uid);
242 jsx_1.setJSXAttr(needWrapper ? block : jsxElementPath.node, adapter_1.Adapter.forIndex, t.stringLiteral(this.renderScope.generateUid('anonIdx')));
243 }
244 }
245 else {
246 throw utils_1.codeFrameError(index, '包含 JSX 的 map 循环第二个参数只能是一个普通标识符');
247 }
248 if ("quickapp" /* quickapp */ === adapter_1.Adapter.type) {
249 if (itemName || indexName) {
250 const code = jsx_1.generateJSXAttr(ary);
251 let forExpr;
252 if (itemName && !indexName) {
253 forExpr = `${itemName} in ${code}`;
254 }
255 else {
256 forExpr = `(${indexName}, ${itemName}) in ${code}`;
257 }
258 jsx_1.setJSXAttr(jsxElementPath.node, adapter_1.Adapter.for, t.stringLiteral(`{{${forExpr}}}`));
259 }
260 // if (itemName && !indexName) {
261 // const forExpr = gene
262 // }
263 }
264 this.loopComponents.set(callExpr, jsxElementPath);
265 let loopComponentName;
266 const parentCallee = callExpr.findParent(c => utils_1.isArrayMapCallExpression(c));
267 if (utils_1.isArrayMapCallExpression(parentCallee)) {
268 loopComponentName = `${constant_1.LOOP_CALLEE}_${this.incrementCalleeId()}`;
269 }
270 else {
271 loopComponentName = 'loopArray' + this.loopArrayId();
272 }
273 this.loopComponentNames.set(callExpr, loopComponentName);
274 // caller.replaceWith(jsxElementPath.node)
275 if (statementParent) {
276 const name = utils_1.findIdentifierFromStatement(statementParent.node);
277 // setTemplate(name, path, templates)
278 name && this.templates.set(name, jsxElementPath.node);
279 }
280 }
281 }
282 }
283 }
284 }
285 else if (t.isArrowFunctionExpression(parentNode)) {
286 parentPath.replaceWith(t.arrowFunctionExpression(parentNode.params, t.blockStatement([
287 t.returnStatement(jsxElementPath.node)
288 ])));
289 }
290 });
291 }
292 }
293 };
294 this.renameIfScopeVaribale = (blockStatement) => {
295 return {
296 VariableDeclarator: (path) => {
297 const { id, init } = path.node;
298 const ifStem = path.parentPath.parentPath.parentPath;
299 if (!ifStem.isIfStatement() || utils_1.isContainJSXElement(path)) {
300 return;
301 }
302 if (t.isIdentifier(id)) {
303 if (id.name.startsWith('loopArray') || id.name.startsWith(constant_1.LOOP_CALLEE)) {
304 this.renderPath.node.body.body.unshift(t.variableDeclaration('let', [t.variableDeclarator(t.identifier(id.name))]));
305 path.parentPath.replaceWith(template('ID = INIT;')({ ID: t.identifier(id.name), INIT: init }));
306 }
307 else if (id.name.startsWith('$props__')) {
308 path.skip();
309 }
310 else {
311 const newId = this.renderScope.generateDeclaredUidIdentifier('$' + id.name);
312 blockStatement.scope.rename(id.name, newId.name);
313 path.parentPath.replaceWith(template('ID = INIT;')({ ID: newId, INIT: init || t.identifier('undefined') }));
314 }
315 }
316 },
317 JSXElement: (jsxElementPath) => {
318 this.handleJSXElement(jsxElementPath, (options) => {
319 this.handleConditionExpr(options, jsxElementPath);
320 });
321 },
322 JSXExpressionContainer: this.replaceIdWithTemplate(true)
323 };
324 };
325 this.findParallelIfStem = (p) => {
326 const exprs = new Set();
327 let expr = p.parentPath;
328 while (expr.isIfStatement()) {
329 exprs.add(expr);
330 expr = expr.parentPath;
331 }
332 return exprs;
333 };
334 this.insertElseBlock = (block, jsx, test) => {
335 if (this.isEmptyBlock(block)) {
336 return;
337 }
338 for (const child of block.children) {
339 if (!t.isJSXElement(child)) {
340 continue;
341 }
342 const ifAttr = child.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.if);
343 const ifElseAttr = child.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.elseif);
344 if ((ifAttr && t.isJSXExpressionContainer(ifAttr.value, { expression: test }))
345 ||
346 (ifElseAttr && t.isJSXExpressionContainer(ifElseAttr.value, { expression: test }))) {
347 block.children.push(jsx);
348 break;
349 }
350 else {
351 this.insertElseBlock(child, jsx, test);
352 }
353 }
354 };
355 this.handleNestedIfStatement = (block, jsx, test, hasNest, isElse) => {
356 if (this.isEmptyBlock(block)) {
357 return;
358 }
359 for (const [index, child] of block.children.entries()) {
360 if (!t.isJSXElement(child)) {
361 continue;
362 }
363 const ifAttr = child.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.if);
364 const ifElseAttr = child.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.elseif);
365 if ((ifAttr && t.isJSXExpressionContainer(ifAttr.value, { expression: test }))
366 ||
367 (ifElseAttr && t.isJSXExpressionContainer(ifElseAttr.value, { expression: test }))) {
368 if (isElse) {
369 const nextChild = block.children[index + 1];
370 if (t.isJSXElement(nextChild)) {
371 nextChild.children.push(jsx);
372 }
373 }
374 else {
375 child.children.push(jsx);
376 }
377 hasNest = true;
378 break;
379 }
380 else {
381 this.handleNestedIfStatement(child, jsx, test, hasNest, isElse);
382 }
383 }
384 };
385 this.isEmptyBlock = ((block) => block.children.length === 0 && block.openingElement.attributes.length === 0);
386 this.prefixExpr = () => this.isDefaultRender ? t.identifier('__prefix') : t.identifier(constant_1.CLASS_COMPONENT_UID);
387 this.propsDecls = new Map();
388 this.isInternalComponent = (element) => {
389 return t.isJSXIdentifier(element.name) &&
390 !constant_1.DEFAULT_Component_SET.has(element.name.name) &&
391 !constant_1.DEFAULT_Component_SET_COPY.has(element.name.name) &&
392 /[A-Z]/.test(element.name.name.charAt(0));
393 };
394 this.jsxElementVisitor = {
395 JSXElement: (jsxElementPath) => {
396 this.handleJSXElement(jsxElementPath, (options) => {
397 this.handleConditionExpr(options, jsxElementPath);
398 this.handleJSXInIfStatement(jsxElementPath, options);
399 });
400 // handle jsx attrs
401 jsxElementPath.traverse(this.jsxAttrVisitor);
402 }
403 };
404 this.jsxAttrVisitor = {
405 JSXExpressionContainer: (path) => {
406 if (!isChildrenOfJSXAttr(path)) {
407 return;
408 }
409 const expression = path.get('expression');
410 if (expression.isStringLiteral()) {
411 path.replaceWith(expression);
412 }
413 else if (expression.isCallExpression()) {
414 const node = expression.node;
415 if (t.isMemberExpression(node.callee) &&
416 t.isIdentifier(node.callee.property) &&
417 node.callee.property.name === 'bind') {
418 const JSXElement = path.findParent(p => p.isJSXElement())
419 .node;
420 const componentName = JSXElement.openingElement.name;
421 if (adapter_1.isNewPropsSystem() &&
422 t.isJSXIdentifier(componentName)) {
423 if (constant_1.THIRD_PARTY_COMPONENTS.has(componentName.name)) {
424 //
425 }
426 else if (!constant_1.DEFAULT_Component_SET.has(componentName.name)) {
427 return;
428 }
429 }
430 // const JSXAttribute = path.findParent(p => p.isJSXAttribute())
431 let bindCalleeName = null;
432 if (t.isIdentifier(node.callee.object)) {
433 bindCalleeName = node.callee.object.name;
434 }
435 else if (t.isMemberExpression(node.callee.object)) {
436 if (t.isIdentifier(node.callee.object.property)) {
437 bindCalleeName = node.callee.object.property.name;
438 }
439 }
440 if (bindCalleeName !== null) {
441 const attr = path.parentPath.node;
442 let bindEventName = attr.name.name;
443 bindEventName = bindEventName.replace(/^bind|^catch/, '');
444 const args = expression.get('arguments');
445 args.forEach((arg, index) => {
446 const node = arg.node;
447 const argName = babel_generator_1.default(node).code;
448 if (index === 0) {
449 jsx_1.setJSXAttr(JSXElement, `data-e-${bindEventName}-so`, t.stringLiteral(argName));
450 }
451 else {
452 let expr = null;
453 if (t.isIdentifier(node) && path.scope.hasBinding(argName)) {
454 this.addRefIdentifier(path, node);
455 expr = t.jSXExpressionContainer(node);
456 }
457 else if (t.isMemberExpression(node)) {
458 const id = utils_1.findFirstIdentifierFromMemberExpression(node);
459 this.addRefIdentifier(path, id);
460 expr = t.jSXExpressionContainer(node);
461 }
462 else if (node.type === 'NumericLiteral' || t.isStringLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node)) {
463 expr = t.jSXExpressionContainer(node);
464 }
465 else if (utils_1.hasComplexExpression(arg)) {
466 const isCookedLoop = JSXElement.openingElement.attributes.some(attr => attr.name.name === adapter_1.Adapter.for);
467 if (isCookedLoop) {
468 throw utils_1.codeFrameError(arg.node, '在循环中使用 bind 时,需要声明将此复杂表达式声明为一个变量再放入 bind 参数中。');
469 }
470 else {
471 const id = utils_1.generateAnonymousState(this.renderScope, arg, this.referencedIdentifiers);
472 expr = t.jSXExpressionContainer(id);
473 }
474 }
475 else {
476 expr = t.jSXExpressionContainer(t.identifier(argName));
477 }
478 jsx_1.setJSXAttr(JSXElement, `data-e-${bindEventName}-a-${utils_1.toLetters(index)}`, expr);
479 }
480 });
481 expression.replaceWith(t.stringLiteral(`${bindCalleeName}`));
482 }
483 }
484 }
485 },
486 JSXAttribute: (path) => {
487 const { name, value } = path.node;
488 let eventShouldBeCatched = false;
489 const jsxElementPath = path.parentPath.parentPath;
490 if (t.isJSXIdentifier(name) && jsxElementPath.isJSXElement()) {
491 const componentName = jsxElementPath.node.openingElement.name.name;
492 const isThirdPartyKey = name.name === 'taroKey';
493 if (name.name === 'key' || isThirdPartyKey) {
494 if (constant_1.THIRD_PARTY_COMPONENTS.has(componentName) && !isThirdPartyKey) {
495 return;
496 }
497 const jsx = path.findParent(p => p.isJSXElement());
498 const loopBlock = jsx.findParent(p => {
499 if (p.isJSXElement()) {
500 const element = p.get('openingElement');
501 if (element.get('name').isJSXIdentifier({ name: 'block' })) {
502 const attrs = element.node.attributes;
503 const hasWXForLoop = attrs.some(attr => t.isJSXIdentifier(attr.name, { name: adapter_1.Adapter.for }));
504 const hasWXKey = attrs.some(attr => t.isJSXIdentifier(attr.name, { name: adapter_1.Adapter.key }));
505 return hasWXForLoop && !hasWXKey;
506 }
507 }
508 return false;
509 });
510 if (loopBlock) {
511 jsx_1.setJSXAttr(loopBlock.node, adapter_1.Adapter.key, value);
512 path.remove();
513 }
514 else {
515 path.get('name').replaceWith(t.jSXIdentifier(adapter_1.Adapter.key));
516 }
517 }
518 else if (name.name.startsWith('on')) {
519 if (t.isJSXExpressionContainer(value)) {
520 const methodName = utils_1.findMethodName(value.expression);
521 methodName && this.usedEvents.add(methodName);
522 const method = this.methods.get(methodName);
523 const classDecl = path.findParent(p => p.isClassDeclaration());
524 const componentName = jsxElementPath.node.openingElement.name;
525 // if (method && t.isIdentifier(method.node.key)) {
526 // this.usedEvents.add(methodName)
527 // } else if (method === null) {
528 // this.usedEvents.add(methodName)
529 // }
530 if (!babel_generator_1.default(value.expression).code.includes('.bind') &&
531 (!adapter_1.isNewPropsSystem() ||
532 (t.isJSXIdentifier(componentName) && constant_1.DEFAULT_Component_SET.has(componentName.name)))) {
533 path.node.value = t.stringLiteral(`${methodName}`);
534 }
535 if (this.methods.has(methodName)) {
536 eventShouldBeCatched = utils_1.isContainStopPropagation(method);
537 }
538 if (classDecl && classDecl.isClassDeclaration()) {
539 const superClass = utils_1.getSuperClassCode(classDecl);
540 if (superClass) {
541 try {
542 const ast = babel_core_1.transform(superClass.code, options_1.buildBabelTransformOptions()).ast;
543 babel_traverse_1.default(ast, {
544 ClassMethod(p) {
545 if (!p.get('key').isIdentifier({ name: methodName })) {
546 return;
547 }
548 eventShouldBeCatched = utils_1.isContainStopPropagation(method);
549 },
550 ClassProperty(p) {
551 if (!p.get('key').isIdentifier({ name: methodName })) {
552 return;
553 }
554 eventShouldBeCatched = utils_1.isContainStopPropagation(method);
555 }
556 });
557 }
558 catch (error) {
559 //
560 }
561 }
562 }
563 if (t.isJSXIdentifier(componentName) && !constant_1.DEFAULT_Component_SET.has(componentName.name)) {
564 const element = path.parent;
565 if (process.env.NODE_ENV !== 'test' && adapter_1.Adapter.type !== "alipay" /* alipay */) {
566 const fnName = `${constant_1.FN_PREFIX}${name.name}`;
567 element.attributes = element.attributes.concat([t.jSXAttribute(t.jSXIdentifier(fnName))]);
568 }
569 }
570 }
571 if (t.isJSXIdentifier(jsxElementPath.node.openingElement.name)) {
572 const componentName = jsxElementPath.node.openingElement.name.name;
573 if (adapter_1.Adapter.type === "alipay" /* alipay */) {
574 let transformName = name.name;
575 if (constant_1.DEFAULT_Component_SET.has(componentName) && constant_1.ALIPAY_BUBBLE_EVENTS.has(name.name)) {
576 if (name.name === 'onClick') {
577 transformName = eventShouldBeCatched ? 'catchTap' : 'onTap';
578 }
579 else {
580 transformName = `${eventShouldBeCatched ? 'catch' : 'on'}${name.name.slice(2)}`;
581 }
582 }
583 path.node.name = t.jSXIdentifier(transformName);
584 }
585 else if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
586 const transformName = name.name;
587 path.node.name = t.jSXIdentifier(transformName);
588 }
589 else if (constant_1.DEFAULT_Component_SET.has(componentName)) {
590 let transformName = `${eventShouldBeCatched ? 'catch' : 'bind'}`
591 + name.name.slice(2).toLowerCase();
592 if (name.name === 'onClick') {
593 transformName = eventShouldBeCatched ? 'catchtap' : 'bindtap';
594 }
595 path.node.name = t.jSXIdentifier(transformName);
596 }
597 else if (constant_1.THIRD_PARTY_COMPONENTS.has(componentName)) {
598 path.node.name = t.jSXIdentifier('bind' + name.name[2].toLowerCase() + name.name.slice(3));
599 }
600 else {
601 path.node.name = t.jSXIdentifier('bind' + name.name.toLowerCase());
602 }
603 }
604 // let transformName = `${eventShouldBeCatched ? 'catch' : 'bind'}` + name.name.slice(2, name.name.length)
605 // transformName = eventShouldBeCatched
606 // ? CATCH_EVENT_MAP.get(name.name)!
607 // : BIND_EVENT_MAP.get(name.name)!
608 }
609 else if (/^render[A-Z]/.test(name.name) && !constant_1.DEFAULT_Component_SET.has(componentName)) {
610 if (!t.isJSXExpressionContainer(value)) {
611 throw utils_1.codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。');
612 }
613 const expression = value.expression;
614 if (!t.isJSXElement(expression)) {
615 throw utils_1.codeFrameError(value, '以 render 开头的 props 只能传入包含一个 JSX 元素的 JSX 表达式。');
616 }
617 const slotName = utils_1.getSlotName(name.name);
618 const slot = lodash_1.cloneDeep(expression);
619 const view = t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('View'), []), t.jSXClosingElement(t.jSXIdentifier('View')), []);
620 view.children.push(slot);
621 jsx_1.setJSXAttr(view, 'slot', t.stringLiteral(slotName));
622 jsxElementPath.node.children.push(view);
623 path.remove();
624 }
625 }
626 },
627 Identifier: (path) => {
628 if (!isChildrenOfJSXAttr(path)) {
629 return;
630 }
631 if (!path.isReferencedIdentifier()) {
632 return;
633 }
634 const parentPath = path.parentPath;
635 if (parentPath.isConditionalExpression() ||
636 parentPath.isLogicalExpression() ||
637 parentPath.isJSXExpressionContainer() ||
638 parentPath.isBinaryExpression() ||
639 this.renderScope.hasOwnBinding(path.node.name)) {
640 this.addRefIdentifier(path, path.node);
641 }
642 },
643 MemberExpression: {
644 exit: (path) => {
645 const { object, property } = path.node;
646 if (!path.isReferencedMemberExpression()) {
647 return;
648 }
649 if (!t.isThisExpression(object)) {
650 return;
651 }
652 const reserves = new Set([
653 'state',
654 'props',
655 ...this.methods.keys()
656 ]);
657 if (t.isIdentifier(property) || t.isMemberExpression(property)) {
658 const id = t.isIdentifier(property) ? property : utils_1.findFirstIdentifierFromMemberExpression(property);
659 if (reserves.has(id.name)) {
660 return;
661 }
662 const jsxAttr = path.findParent(p => p.isJSXAttribute());
663 if (jsxAttr && t.isJSXIdentifier(jsxAttr.node.name) && jsxAttr.node.name.name.startsWith('on')) {
664 return;
665 }
666 if (t.isIdentifier(id) && !(id.name.startsWith('_create') && id.name.endsWith('Data'))) {
667 this.referencedIdentifiers.add(id);
668 this.usedThisProperties.add(id.name);
669 }
670 }
671 },
672 enter: (path) => {
673 if (!isChildrenOfJSXAttr(path)) {
674 return;
675 }
676 if (!path.isReferencedMemberExpression() || path.parentPath.isMemberExpression()) {
677 return;
678 }
679 const { object, property } = path.node;
680 if (t.isMemberExpression(object) &&
681 t.isThisExpression(object.object) &&
682 t.isIdentifier(object.property, { name: 'state' })) {
683 if (t.isIdentifier(property)) {
684 this.usedThisState.add(property.name);
685 }
686 else if (t.isMemberExpression(property)) {
687 const id = utils_1.findFirstIdentifierFromMemberExpression(property);
688 if (id && this.renderScope.hasBinding(id.name)) {
689 this.usedThisState.add(id.name);
690 }
691 }
692 return;
693 }
694 const code = babel_generator_1.default(path.node).code;
695 if (code.includes('this.$router.params') && t.isIdentifier(property)) {
696 const name = this.renderScope.generateUid(property.name);
697 const dcl = utils_1.buildConstVariableDeclaration(name, path.node);
698 this.renderPath.node.body.body.unshift(dcl);
699 path.replaceWith(t.identifier(name));
700 }
701 const parentPath = path.parentPath;
702 const id = utils_1.findFirstIdentifierFromMemberExpression(path.node);
703 if (t.isThisExpression(id)) {
704 return;
705 }
706 if (parentPath.isConditionalExpression() ||
707 parentPath.isLogicalExpression() ||
708 parentPath.isJSXExpressionContainer() ||
709 parentPath.isBinaryExpression() ||
710 (this.renderScope.hasOwnBinding(id.name))) {
711 this.addRefIdentifier(path, id);
712 }
713 }
714 },
715 ArrowFunctionExpression: (path) => {
716 if (!isChildrenOfJSXAttr(path)) {
717 return;
718 }
719 const uid = path.scope.generateUid('_anonymous_function_');
720 const c = t.classProperty(t.identifier(uid), path.node);
721 this.classProperties.add(c);
722 }
723 };
724 this.visitors = Object.assign(Object.assign({ MemberExpression: (path) => {
725 const { object, property } = path.node;
726 if (t.isThisExpression(object) && t.isIdentifier(property) && property.name.startsWith('renderClosure')) {
727 const parentPath = path.parentPath;
728 if (parentPath.isVariableDeclarator()) {
729 const id = parentPath.node.id;
730 if (t.isIdentifier(id) && id.name.startsWith('renderClosure')) {
731 this.deferedHandleClosureJSXFunc.push(() => {
732 const classMethod = this.methods.get(id.name);
733 if (classMethod && classMethod.isClassMethod()) {
734 path.replaceWith(t.arrowFunctionExpression([t.identifier(constant_1.CLASS_COMPONENT_UID)], t.blockStatement([
735 t.returnStatement(t.arrowFunctionExpression(classMethod.node.params, classMethod.node.body))
736 ])));
737 // classMethod.node.body.body = []
738 }
739 });
740 }
741 }
742 }
743 if (t.isThisExpression(object) && t.isIdentifier(property) && /^render[A-Z]/.test(this.renderMethodName)) {
744 const s = new Set(['state', 'props']);
745 if (s.has(property.name) && path.parentPath.isMemberExpression()) {
746 const p = path.parentPath.node.property;
747 let id = { name: 'example' };
748 if (t.isIdentifier(p)) {
749 id = p;
750 }
751 else if (t.isMemberExpression(p)) {
752 id = utils_1.findFirstIdentifierFromMemberExpression(p);
753 }
754 // tslint:disable-next-line: no-console
755 console.warn(utils_1.codeFrameError(path.parentPath.node, `\n 在形如以 render 开头的 ${this.renderMethodName}() 类函数中,请先把 this.${property.name} 解构出来才进行使用。\n 例如: const { ${id.name} } = this.${property.name}`).message);
756 }
757 }
758 }, VariableDeclarator: (path) => {
759 const init = path.get('init');
760 const id = path.get('id');
761 const ifStem = init.findParent(p => p.isIfStatement());
762 // tslint:disable-next-line: strict-type-predicates
763 if (ifStem && init.node === null) {
764 init.replaceWith(t.identifier('undefined'));
765 }
766 let isDerivedFromState = false;
767 if (init.isMemberExpression()) {
768 const object = init.get('object');
769 if (object.isMemberExpression() && object.get('object').isThisExpression() && object.get('property').isIdentifier({ name: 'state' })) {
770 isDerivedFromState = true;
771 }
772 if (object.isThisExpression() && init.get('property').isIdentifier({ name: 'state' })) {
773 isDerivedFromState = true;
774 }
775 }
776 if (!isDerivedFromState) {
777 const errMsg = 'Warning: render 函数定义一个不从 this.state 解构或赋值而来的变量,此变量又与 this.state 下的变量重名可能会导致无法渲染。';
778 if (id.isIdentifier()) {
779 const name = id.node.name;
780 if (this.initState.has(name)) {
781 // tslint:disable-next-line
782 console.log(utils_1.codeFrameError(id.node, errMsg).message);
783 }
784 }
785 if (id.isObjectPattern()) {
786 const { properties } = id.node;
787 for (const p of properties) {
788 if (t.isIdentifier(p)) {
789 if (this.initState.has(p.name)) {
790 // tslint:disable-next-line
791 console.log(utils_1.codeFrameError(id.node, errMsg).message);
792 }
793 }
794 if (t.isSpreadProperty(p) && t.isIdentifier(p.argument)) {
795 if (this.initState.has(p.argument.name)) {
796 // tslint:disable-next-line
797 console.log(utils_1.codeFrameError(id.node, errMsg).message);
798 }
799 }
800 }
801 }
802 }
803 }, JSXEmptyExpression(path) {
804 const parent = path.parentPath;
805 if (path.parentPath.isJSXExpressionContainer()) {
806 parent.remove();
807 }
808 },
809 NullLiteral(path) {
810 const statementParent = path.getStatementParent();
811 const callExprs = findParents(path, p => p.isCallExpression());
812 if (callExprs.some(callExpr => callExpr && t.isIdentifier(callExpr.node.callee) && /^use[A-Z]/.test(callExpr.node.callee.name))) {
813 return;
814 }
815 if (statementParent && statementParent.isReturnStatement() && !t.isBinaryExpression(path.parent) && !isChildrenOfJSXAttr(path)) {
816 path.replaceWith(t.jSXElement(t.jSXOpeningElement(t.jSXIdentifier('View'), []), undefined, [], true));
817 }
818 }, ReturnStatement: (path) => {
819 const parentPath = path.parentPath;
820 if (parentPath.parentPath.isClassMethod() ||
821 (parentPath.parentPath.isIfStatement() && parentPath.parentPath.parentPath.isClassMethod())) {
822 this.replaceIdWithTemplate()(path);
823 }
824 } }, this.jsxElementVisitor), { JSXExpressionContainer: this.replaceIdWithTemplate(true) });
825 this.quickappVistor = {
826 JSXExpressionContainer(path) {
827 if (path.parentPath.isJSXAttribute() || utils_1.isContainJSXElement(path)) {
828 return;
829 }
830 utils_1.replaceJSXTextWithTextComponent(path);
831 }
832 };
833 this.isEmptyProps = (attrs) => attrs.filter(a => {
834 if (t.isJSXSpreadAttribute(a))
835 return true;
836 const list = [adapter_1.Adapter.for, adapter_1.Adapter.forIndex, adapter_1.Adapter.forItem, 'id'];
837 adapter_1.Adapter.type === "weapp" /* weapp */ && list.push('extraProps');
838 return !list.includes(a.name.name);
839 }).length === 0;
840 /**
841 * jsxDeclarations,
842 * renderScope,
843 * methods,
844 * loopScopes,
845 * initState,
846 * templates
847 */
848 this.handleLoopComponents = () => {
849 const replaceQueue = [];
850 let hasLoopRef = false;
851 this.loopComponents.forEach((component, callee) => {
852 if (!callee.isCallExpression()) {
853 return;
854 }
855 if (this.loopIfStemComponentMap.has(callee)) {
856 const block = this.loopIfStemComponentMap.get(callee);
857 const attrs = component.node.openingElement.attributes;
858 const wxForDirectives = new Set([adapter_1.Adapter.for, adapter_1.Adapter.forIndex, adapter_1.Adapter.forItem]);
859 const ifAttrs = attrs.filter(a => wxForDirectives.has(a.name.name));
860 if (ifAttrs.length) {
861 block.openingElement.attributes.push(...ifAttrs);
862 component.node.openingElement.attributes = attrs.filter(a => !wxForDirectives.has(a.name.name));
863 }
864 jsx_1.setJSXAttr(component.node, adapter_1.Adapter.else);
865 block.children.push(component.node);
866 component.replaceWith(block);
867 }
868 for (const dcl of this.jsxDeclarations) {
869 const isChildren = dcl && dcl.findParent(d => d === callee);
870 if (isChildren) {
871 this.jsxDeclarations.delete(dcl);
872 dcl.remove();
873 }
874 }
875 const blockStatementPath = component.findParent(p => p.isBlockStatement());
876 const body = blockStatementPath.node.body;
877 let loopRefComponent = null;
878 this.loopRefs.forEach((ref, jsx) => {
879 if (ref.component.findParent(p => p === component)) {
880 loopRefComponent = jsx;
881 }
882 });
883 const [func] = callee.node.arguments;
884 let indexId = null;
885 let itemId = null;
886 if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) {
887 const params = func.params;
888 if (Array.isArray(params)) {
889 indexId = params[1];
890 itemId = params[0];
891 }
892 }
893 if (this.loopRefs.has(component.node) || loopRefComponent) {
894 hasLoopRef = true;
895 const ref = this.loopRefs.get(component.node) || this.loopRefs.get(loopRefComponent);
896 if (indexId === null || !t.isIdentifier(indexId)) {
897 throw utils_1.codeFrameError(component.node, '在循环中使用 ref 必须暴露循环的第二个参数 `index`');
898 }
899 const id = typeof ref.id === 'string' ? t.binaryExpression('+', t.stringLiteral(ref.id), indexId) : ref.id;
900 const args = [
901 t.identifier('__scope'),
902 t.binaryExpression('+', t.stringLiteral('#'), id)
903 ];
904 if (ref.type === 'component') {
905 args.push(t.stringLiteral('component'));
906 }
907 else {
908 args.push(t.stringLiteral('dom'));
909 }
910 args.push(ref.fn);
911 const callHandleLoopRef = t.callExpression(t.identifier(constant_1.HANDLE_LOOP_REF), args);
912 const loopRefStatement = t.expressionStatement(t.logicalExpression('&&', t.logicalExpression('&&', t.identifier('__scope'), t.identifier('__isRunloopRef')), callHandleLoopRef));
913 body.splice(body.length - 1, 0, !env_1.isTestEnv ? loopRefStatement : t.expressionStatement(callHandleLoopRef));
914 }
915 if (adapter_1.isNewPropsSystem()) {
916 const loopIndices = this.findParentIndices(callee, indexId);
917 const deferCallBack = [];
918 blockStatementPath.traverse({
919 CallExpression(path) {
920 const pathCallee = path.node.callee;
921 if (t.isMemberExpression(pathCallee) &&
922 t.isThisExpression(pathCallee.object) &&
923 t.isIdentifier(pathCallee.property) &&
924 pathCallee.property.name.startsWith('_create') &&
925 pathCallee.property.name.endsWith('Data')) {
926 const arg = path.node.arguments[0];
927 if (t.isBinaryExpression(arg)) {
928 deferCallBack.push(() => {
929 path.node.arguments = [
930 t.binaryExpression('+', arg, t.templateLiteral([
931 t.templateElement({ raw: '' }),
932 ...loopIndices.map(() => t.templateElement({ raw: '' }))
933 ], loopIndices.map(l => t.identifier(l))))
934 ];
935 });
936 }
937 }
938 },
939 JSXElement: path => {
940 const element = path.node.openingElement;
941 if (this.isInternalComponent(element)) {
942 if (this.isEmptyProps(element.attributes)) {
943 return;
944 }
945 // createData 函数里加入 compid 相关逻辑
946 const compid = utils_1.genCompid();
947 const prevVariableName = `${constant_1.PREV_COMPID}__${compid}`;
948 const variableName = `${constant_1.COMPID}__${compid}`;
949 const tpmlExprs = [];
950 for (let index = 0; index < loopIndices.length; index++) {
951 const element = loopIndices[index];
952 tpmlExprs.push(t.identifier(element));
953 if (loopIndices[index + 1]) {
954 tpmlExprs.push(t.stringLiteral('-'));
955 }
956 }
957 const compidTempDecl = t.variableDeclaration('const', [
958 t.variableDeclarator(t.arrayPattern([t.identifier(prevVariableName), t.identifier(variableName)]), t.callExpression(t.identifier(constant_1.GEN_COMP_ID), [t.templateLiteral([
959 t.templateElement({ raw: '' }),
960 t.templateElement({ raw: utils_1.createRandomLetters(10) }),
961 ...tpmlExprs.map(() => t.templateElement({ raw: '' }))
962 ], [
963 this.prefixExpr(),
964 ...tpmlExprs
965 ]), t.booleanLiteral(true)]))
966 ]);
967 const properties = this.getPropsFromAttrs(element);
968 const propsSettingExpr = this.genPropsSettingExpression(properties, t.identifier(variableName), t.identifier(prevVariableName));
969 const expr = utils_1.setAncestorCondition(path, propsSettingExpr);
970 this.ancestorConditions.add(expr);
971 body.splice(body.length - 1, 0, compidTempDecl, t.expressionStatement(expr));
972 // wxml 组件打上 compid
973 const [func] = callee.node.arguments;
974 let forItem = null;
975 if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) {
976 forItem = func.params[0];
977 }
978 if (forItem === null || !t.isIdentifier(forItem)) {
979 throw utils_1.codeFrameError(callee.node, '在循环中使用自定义组件时必须暴露循环的第一个参数 `item`');
980 }
981 element.attributes.push(t.jSXAttribute(t.jSXIdentifier('compid'), t.jSXExpressionContainer(t.memberExpression(forItem, t.identifier(variableName)))));
982 }
983 }
984 });
985 deferCallBack.forEach(cb => cb());
986 }
987 let stateToBeAssign = new Set(lodash_1.difference(Object.keys(blockStatementPath.scope.getAllBindings()), Object.keys(this.renderScope.getAllBindings())).filter(i => {
988 return !this.methods.has(i);
989 })
990 .filter(i => !this.loopScopes.has(i))
991 .filter(i => !this.initState.has(i))
992 .filter(i => !this.templates.has(i))
993 .filter(i => !i.includes('.'))
994 .filter(i => i !== constant_1.MAP_CALL_ITERATOR));
995 if (body.length > 1) {
996 const [func] = callee.node.arguments;
997 if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) {
998 const [item, indexParam] = func.params;
999 const parents = findParents(callee, (p) => utils_1.isArrayMapCallExpression(p));
1000 const iterators = new Set([item.name, ...parents
1001 .map((p) => lodash_1.get(p, 'node.arguments[0].params[0].name', ''))
1002 .filter(Boolean)]);
1003 for (const [index, statement] of body.entries()) {
1004 if (t.isVariableDeclaration(statement)) {
1005 for (const dcl of statement.declarations) {
1006 if (t.isIdentifier(dcl.id)) {
1007 const name = dcl.id.name;
1008 if (name.startsWith(constant_1.LOOP_STATE) ||
1009 name.startsWith(constant_1.LOOP_CALLEE) ||
1010 name.startsWith(constant_1.COMPID) ||
1011 name.startsWith('_$indexKey')) {
1012 stateToBeAssign.add(name);
1013 dcl.id = t.identifier(name);
1014 }
1015 }
1016 else if (t.isArrayPattern(dcl.id)) {
1017 dcl.id.elements.forEach(stm => {
1018 if (t.isIdentifier(stm)) {
1019 const name = stm.name;
1020 if (name.startsWith(constant_1.LOOP_STATE) ||
1021 name.startsWith(constant_1.LOOP_CALLEE) ||
1022 name.startsWith(constant_1.COMPID) ||
1023 name.startsWith('_$indexKey')) {
1024 stateToBeAssign.add(name);
1025 }
1026 }
1027 });
1028 }
1029 }
1030 }
1031 if (t.isReturnStatement(statement)) {
1032 body.splice(index, 1);
1033 }
1034 }
1035 stateToBeAssign.forEach(s => this.loopRefIdentifiers.set(s, callee));
1036 const properties = Array.from(stateToBeAssign).map(state => t.objectProperty(t.identifier(state), t.identifier(state)));
1037 // tslint:disable-next-line:no-inner-declarations
1038 function replaceOriginal(path, parent, name) {
1039 if ((path.isReferencedIdentifier() || t.isAssignmentExpression(parent)) &&
1040 iterators.has(name) &&
1041 !(t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: constant_1.LOOP_ORIGINAL })) &&
1042 !(t.isMemberExpression(parent) && t.isIdentifier(parent.property) && (parent.property.name.startsWith(constant_1.LOOP_STATE) || parent.property.name.startsWith(constant_1.LOOP_CALLEE) || parent.property.name.startsWith(constant_1.COMPID)))) {
1043 path.replaceWith(t.memberExpression(t.identifier(name), t.identifier(constant_1.LOOP_ORIGINAL)));
1044 }
1045 }
1046 const bodyPath = callee.get('arguments')[0].get('body');
1047 bodyPath.traverse({
1048 Identifier(path) {
1049 const name = path.node.name;
1050 const parent = path.parent;
1051 replaceOriginal(path, parent, name);
1052 }
1053 });
1054 const replacements = new Set();
1055 component.traverse({
1056 JSXAttribute: !t.isIdentifier(indexParam) ? utils_1.noop : (path) => {
1057 const { value } = path.node;
1058 if (t.isJSXExpressionContainer(value) && t.isJSXIdentifier(path.node.name, { name: 'key' }) && t.isIdentifier(value.expression, { name: indexParam.name })) {
1059 if (process.env.TERM_PROGRAM || env_1.isTestEnv) { // 无法找到 cli 名称的工具(例如 idea/webstorm)显示这个报错可能会乱码
1060 // tslint:disable-next-line:no-console
1061 console.log(utils_1.codeFrameError(value.expression, '建议修改:使用循环的 index 变量作为 key 是一种反优化。参考:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md').message);
1062 }
1063 }
1064 },
1065 JSXExpressionContainer: this.replaceIdWithTemplate(),
1066 Identifier: (path) => {
1067 const name = path.node.name;
1068 const parent = path.parent;
1069 const parentCallExpr = path.findParent(p => p.isCallExpression());
1070 if (replacements.has(parent) || (this.renderScope.hasOwnBinding(name) &&
1071 (this.loopCalleeId.has(path.node) || parentCallExpr && this.loopCalleeId.has(parentCallExpr.node)))) {
1072 return;
1073 }
1074 if (stateToBeAssign.has(name) && path.isReferencedIdentifier()) {
1075 if (t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: 'map' })) {
1076 const grandParentPath = path.parentPath.parentPath;
1077 if (grandParentPath.isCallExpression() && this.loopComponents.has(grandParentPath)) {
1078 return;
1079 }
1080 }
1081 if (path.findParent(p => this.loopCallees.has(p.node))) {
1082 return;
1083 }
1084 const parentCondition = path.findParent(p => p.isConditionalExpression() || p.isLogicalExpression());
1085 if (parentCondition) {
1086 const varDecl = parentCondition.findParent(p => p.isVariableDeclarator());
1087 if (varDecl && varDecl.isVariableDeclarator()) {
1088 const init = varDecl.node.id;
1089 if (t.isIdentifier(init) && init.name.startsWith(constant_1.LOOP_STATE)) {
1090 return;
1091 }
1092 }
1093 if (path.findParent(p => this.ancestorConditions.has(p.node))) {
1094 return;
1095 }
1096 }
1097 const replacement = t.memberExpression(t.identifier(item.name), path.node);
1098 path.replaceWith(replacement);
1099 replacements.add(replacement);
1100 }
1101 else {
1102 replaceOriginal(path, parent, name);
1103 }
1104 },
1105 MemberExpression(path) {
1106 const { object, property } = path.node;
1107 if (t.isThisExpression(object) && t.isIdentifier(property)) {
1108 if (property.name === 'state' && path.parentPath.isMemberExpression() && path.parentPath.parentPath.isMemberExpression()) {
1109 // tslint:disable-next-line
1110 console.warn(utils_1.codeFrameError(path.parentPath.parentPath.node, `在循环中使用 this.state.xx.xx 可能会存在问题,请给 xx 起一个别名,例如 const { xx } = this.state`));
1111 }
1112 }
1113 }
1114 });
1115 const originalProp = t.objectProperty(t.identifier(constant_1.LOOP_ORIGINAL), t.memberExpression(t.identifier(item.name), t.identifier(constant_1.LOOP_ORIGINAL)));
1116 properties.push(originalProp);
1117 body.unshift(t.expressionStatement(t.assignmentExpression('=', t.identifier(item.name), t.objectExpression([
1118 t.objectProperty(t.identifier(constant_1.LOOP_ORIGINAL), t.callExpression(t.identifier(constant_1.INTERNAL_GET_ORIGNAL), [t.identifier(item.name)]))
1119 ]))));
1120 const returnStatement = t.returnStatement(properties.length ? t.objectExpression(properties) : item);
1121 const parentCallee = callee.findParent(c => utils_1.isArrayMapCallExpression(c));
1122 if (utils_1.isArrayMapCallExpression(parentCallee)) {
1123 const [func] = parentCallee.node.arguments;
1124 const { object } = callee.node.callee;
1125 if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) {
1126 const funcBody = func.body;
1127 if (t.isBlockStatement(funcBody)) {
1128 if (t.isIdentifier(object) || t.isMemberExpression(object)) {
1129 const variableName = this.loopComponentNames.get(callee);
1130 funcBody.body.splice(funcBody.body.length - 1, 0, utils_1.buildConstVariableDeclaration(variableName, utils_1.setParentCondition(component, callee.node, true)));
1131 const iterator = func.params[0];
1132 component.node.openingElement.attributes.forEach(attr => {
1133 if (attr.name.name === adapter_1.Adapter.for && t.isIdentifier(iterator)) {
1134 attr.value = t.jSXExpressionContainer(t.memberExpression(iterator, t.identifier(variableName)));
1135 }
1136 });
1137 }
1138 else {
1139 throw utils_1.codeFrameError(object.loc, '多层循环中循环的数组只能是一个变量或成员表达式,可以尝试把该表达式赋值给循环内部的一个新变量。');
1140 }
1141 }
1142 }
1143 body.push(returnStatement);
1144 }
1145 else {
1146 body.push(returnStatement);
1147 const stateName = this.loopComponentNames.get(callee);
1148 // setJSXAttr(returned, Adapter.for, t.identifier(stateName))
1149 this.addRefIdentifier(callee, t.identifier(stateName));
1150 // this.referencedIdentifiers.add(t.identifier(stateName))
1151 if ("quickapp" /* quickapp */ === adapter_1.Adapter.type) {
1152 let itemName = itemId.name;
1153 let indexName = indexId.name;
1154 if (itemName || indexName) {
1155 let forExpr;
1156 if (itemName && !indexName) {
1157 forExpr = `${itemName} in ${stateName}`;
1158 }
1159 else {
1160 forExpr = `(${indexName}, ${itemName}) in ${stateName}`;
1161 }
1162 jsx_1.setJSXAttr(component.node, adapter_1.Adapter.for, t.stringLiteral(`{{${forExpr}}}`));
1163 }
1164 }
1165 else {
1166 jsx_1.setJSXAttr(component.node, adapter_1.Adapter.for, t.jSXExpressionContainer(t.identifier(stateName)));
1167 }
1168 const returnBody = this.renderPath.node.body.body;
1169 const ifStem = callee.findParent(p => p.isIfStatement());
1170 // @TEST
1171 if (ifStem && ifStem.isIfStatement()) {
1172 const consequent = ifStem.get('consequent');
1173 if (consequent.isBlockStatement()) {
1174 const assignment = t.expressionStatement(t.assignmentExpression('=', t.identifier(stateName), utils_1.setParentCondition(component, callee.node, true)));
1175 returnBody.unshift(t.variableDeclaration('let', [t.variableDeclarator(t.identifier(stateName))]));
1176 if (callee.findParent(p => p === consequent)) {
1177 consequent.node.body.push(assignment);
1178 }
1179 else {
1180 const alternate = ifStem.get('alternate');
1181 if (alternate.isBlockStatement()) {
1182 alternate.node.body.push(assignment);
1183 }
1184 else {
1185 consequent.node.body.push(assignment);
1186 }
1187 }
1188 }
1189 }
1190 else {
1191 const decl = utils_1.buildConstVariableDeclaration(stateName, utils_1.setParentCondition(component, callee.node, true));
1192 returnBody.push(decl);
1193 }
1194 }
1195 }
1196 }
1197 replaceQueue.push(() => {
1198 const statement = component.getStatementParent();
1199 callee.replaceWith(statement.isReturnStatement()
1200 ? statement.get('argument').node
1201 : component.node);
1202 });
1203 });
1204 if (hasLoopRef) {
1205 const scopeDecl = template('const __scope = this.$scope')();
1206 this.renderPath.node.body.body.unshift(scopeDecl);
1207 }
1208 replaceQueue.forEach(func => func());
1209 };
1210 this.setReserveWord = (word) => {
1211 const binding = this.renderScope.getOwnBinding(word);
1212 let hasStateId = false;
1213 if (binding) {
1214 const path = binding.path;
1215 const id = path.get('id');
1216 const init = path.get('init');
1217 if (init.isThisExpression()) {
1218 return hasStateId;
1219 }
1220 if (id.isObjectPattern()) {
1221 hasStateId = id.node.properties.some(p => {
1222 return (t.isObjectProperty(p) && t.isIdentifier(p.key, { name: word }))
1223 || (t.isRestProperty(p) && t.isIdentifier(p.argument, { name: word }));
1224 });
1225 }
1226 else if (id.isIdentifier({ name: word })) {
1227 hasStateId = true;
1228 }
1229 if (hasStateId) {
1230 this.referencedIdentifiers.add(t.identifier(word));
1231 }
1232 }
1233 if (hasStateId) {
1234 this.reserveStateWords.delete(word);
1235 }
1236 };
1237 this.getCreateJSXMethodName = (name) => `_create${name.slice(6)}Data`;
1238 this.renderPath = renderPath;
1239 this.methods = methods;
1240 this.initState = initState;
1241 this.referencedIdentifiers = referencedIdentifiers;
1242 this.usedState = usedState;
1243 this.customComponentNames = customComponentNames;
1244 this.componentProperies = componentProperies;
1245 this.loopRefs = loopRefs;
1246 this.refObjExpr = refObjExpr;
1247 const renderBody = renderPath.get('body');
1248 this.renderScope = renderBody.scope;
1249 this.isDefaultRender = methodName === 'render';
1250 this.upperCaseComponentProps = new Set(Array.from(this.componentProperies).filter(p => /[A-Z]/.test(p) && !p.startsWith('on')));
1251 const [, error] = renderPath.node.body.body.filter(s => t.isReturnStatement(s));
1252 if (error) {
1253 throw utils_1.codeFrameError(error.loc, 'render 函数顶级作用域暂时只支持一个 return');
1254 }
1255 if (t.isIdentifier(this.renderPath.node.key)) {
1256 this.renderMethodName = this.renderPath.node.key.name;
1257 }
1258 else {
1259 throw utils_1.codeFrameError(this.renderPath.node, '类函数对象必须指明函数名');
1260 }
1261 this.handleQuickappProps();
1262 renderBody.traverse(this.loopComponentVisitor);
1263 if (this.hasNoReturnLoopStem) {
1264 renderBody.traverse({
1265 JSXElement: this.loopComponentVisitor.JSXElement.exit[0]
1266 });
1267 }
1268 this.handleLoopComponents();
1269 if (adapter_1.isNewPropsSystem()) {
1270 this.handleComponents(renderBody);
1271 }
1272 renderBody.traverse(this.visitors);
1273 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
1274 renderBody.traverse(this.quickappVistor);
1275 }
1276 if (t.isIdentifier(this.renderPath.node.key)) {
1277 this.renderPath.node.key.name = this.getCreateJSXMethodName(this.renderMethodName);
1278 }
1279 this.setOutputTemplate();
1280 this.checkDuplicateName();
1281 this.removeJSXStatement();
1282 this.setUsedState();
1283 this.setPendingState();
1284 this.setCustomEvent();
1285 this.createData();
1286 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
1287 this.setProperies();
1288 }
1289 this.setLoopRefFlag();
1290 this.handleClosureComp();
1291 }
1292 handleConditionExpr({ parentNode, parentPath, statementParent }, jsxElementPath) {
1293 if (parentPath.isObjectProperty()) {
1294 const value = parentPath.get('value');
1295 if (value !== jsxElementPath) {
1296 return;
1297 }
1298 if (!parentPath.parentPath.isObjectExpression()) {
1299 return;
1300 }
1301 const properties = parentPath.parentPath.get('properties');
1302 if (!parentPath.parentPath.parentPath.isMemberExpression()) {
1303 return;
1304 }
1305 const rval = parentPath.parentPath.parentPath.get('property');
1306 if (!rval || !rval.node || !Array.isArray(properties)) {
1307 return;
1308 }
1309 const children = properties.map(p => p.node).map((p, index) => {
1310 const block = jsx_1.buildBlockElement();
1311 const leftExpression = p.key;
1312 const tester = t.binaryExpression('===', leftExpression, rval.node);
1313 block.children = [t.jSXExpressionContainer(p.value)];
1314 if (index === 0) {
1315 utils_1.newJSXIfAttr(block, tester);
1316 }
1317 else {
1318 jsx_1.setJSXAttr(block, adapter_1.Adapter.elseif, t.jSXExpressionContainer(tester));
1319 }
1320 return block;
1321 });
1322 const block = jsx_1.buildBlockElement();
1323 block.children = children;
1324 parentPath.parentPath.parentPath.replaceWith(block);
1325 }
1326 else if (t.isLogicalExpression(parentNode)) {
1327 const { left, operator, right } = parentNode;
1328 const leftExpression = parentPath.get('left');
1329 if (operator === '&&' && t.isExpression(left)) {
1330 if (utils_1.hasComplexExpression(leftExpression)) {
1331 utils_1.generateAnonymousState(this.renderScope, leftExpression, this.referencedIdentifiers, true);
1332 }
1333 const block = jsx_1.buildBlockElement();
1334 utils_1.newJSXIfAttr(block, leftExpression.node);
1335 block.children = [jsxElementPath.node];
1336 parentPath.replaceWith(block);
1337 if (statementParent) {
1338 const name = utils_1.findIdentifierFromStatement(statementParent.node);
1339 utils_1.setTemplate(name, jsxElementPath, this.templates);
1340 // name && templates.set(name, path.node)
1341 }
1342 }
1343 if (operator === '||' && t.isExpression(left)) {
1344 const newNode = t.conditionalExpression(left, left, right);
1345 parentPath.replaceWith(newNode);
1346 // this.handleConditionExpr({ parentNode: newNode, parentPath, statementParent }, jsxElementPath)
1347 }
1348 }
1349 else if (t.isConditionalExpression(parentNode)) {
1350 const { consequent, alternate } = parentNode;
1351 const testExpression = parentPath.get('test');
1352 const block = jsx_1.buildBlockElement();
1353 if (utils_1.hasComplexExpression(testExpression)) {
1354 utils_1.generateAnonymousState(parentPath.scope, testExpression, this.referencedIdentifiers, true);
1355 }
1356 const test = testExpression.node;
1357 if (t.isJSXElement(consequent) && this.isLiteralOrUndefined(alternate)) {
1358 const { value, confident } = parentPath.get('alternate').evaluate();
1359 if (confident && !value || t.isIdentifier({ name: 'undefined' })) {
1360 utils_1.newJSXIfAttr(block, test);
1361 block.children = [jsxElementPath.node];
1362 // newJSXIfAttr(jsxElementPath.node, test)
1363 parentPath.replaceWith(block);
1364 }
1365 else {
1366 const block2 = jsx_1.buildBlockElement();
1367 block.children = [consequent];
1368 utils_1.newJSXIfAttr(block, test);
1369 jsx_1.setJSXAttr(block2, adapter_1.Adapter.else);
1370 block2.children = [t.jSXExpressionContainer(alternate)];
1371 const parentBlock = jsx_1.buildBlockElement();
1372 parentBlock.children = [block, block2];
1373 parentPath.replaceWith(parentBlock);
1374 }
1375 if (statementParent) {
1376 const name = utils_1.findIdentifierFromStatement(statementParent.node);
1377 utils_1.setTemplate(name, jsxElementPath, this.templates);
1378 // name && templates.set(name, path.node)
1379 }
1380 }
1381 else if (this.isLiteralOrUndefined(consequent) && t.isJSXElement(alternate)) {
1382 const { value, confident } = parentPath.get('consequent').evaluate();
1383 if (confident && !value || t.isIdentifier({ name: 'undefined' })) {
1384 utils_1.newJSXIfAttr(block, utils_1.reverseBoolean(test));
1385 block.children = [jsxElementPath.node];
1386 // newJSXIfAttr(jsxElementPath.node, test)
1387 parentPath.replaceWith(block);
1388 }
1389 else {
1390 const block2 = jsx_1.buildBlockElement();
1391 block.children = [t.jSXExpressionContainer(consequent)];
1392 utils_1.newJSXIfAttr(block, test);
1393 jsx_1.setJSXAttr(block2, adapter_1.Adapter.else);
1394 block2.children = [alternate];
1395 const parentBlock = jsx_1.buildBlockElement();
1396 parentBlock.children = [block, block2];
1397 parentPath.replaceWith(parentBlock);
1398 }
1399 if (statementParent) {
1400 const name = utils_1.findIdentifierFromStatement(statementParent.node);
1401 utils_1.setTemplate(name, jsxElementPath, this.templates);
1402 // name && templates.set(name, path.node)
1403 }
1404 }
1405 else if (t.isJSXElement(consequent) && t.isJSXElement(alternate)) {
1406 const block2 = jsx_1.buildBlockElement();
1407 block.children = [consequent];
1408 utils_1.newJSXIfAttr(block, test);
1409 jsx_1.setJSXAttr(block2, adapter_1.Adapter.else);
1410 block2.children = [alternate];
1411 const parentBlock = jsx_1.buildBlockElement();
1412 parentBlock.children = [block, block2];
1413 parentPath.replaceWith(parentBlock);
1414 if (statementParent) {
1415 const name = utils_1.findIdentifierFromStatement(statementParent.node);
1416 utils_1.setTemplate(name, jsxElementPath, this.templates);
1417 }
1418 }
1419 else if (t.isJSXElement(consequent) && t.isCallExpression(alternate) && !utils_1.isArrayMapCallExpression(parentPath.get('alternate'))) {
1420 const id = utils_1.generateAnonymousState(this.renderScope, parentPath.get('alternate'), this.referencedIdentifiers, true);
1421 parentPath.get('alternate').replaceWith(id);
1422 //
1423 }
1424 else if (t.isJSXElement(alternate) && t.isCallExpression(consequent) && !utils_1.isArrayMapCallExpression(parentPath.get('consequent'))) {
1425 const id = utils_1.generateAnonymousState(this.renderScope, parentPath.get('consequent'), this.referencedIdentifiers, true);
1426 parentPath.get('consequent').replaceWith(id);
1427 }
1428 else if (t.isJSXElement(alternate) && utils_1.isArrayMapCallExpression(parentPath.get('consequent'))) {
1429 //
1430 }
1431 else if (t.isJSXElement(consequent) && utils_1.isArrayMapCallExpression(parentPath.get('alternate'))) {
1432 //
1433 }
1434 else {
1435 block.children = [t.jSXExpressionContainer(consequent)];
1436 utils_1.newJSXIfAttr(block, test);
1437 const block2 = jsx_1.buildBlockElement();
1438 jsx_1.setJSXAttr(block2, adapter_1.Adapter.else);
1439 block2.children = [t.jSXExpressionContainer(alternate)];
1440 const parentBlock = jsx_1.buildBlockElement();
1441 parentBlock.children = [block, block2];
1442 parentPath.replaceWith(parentBlock);
1443 if (statementParent) {
1444 const name = utils_1.findIdentifierFromStatement(statementParent.node);
1445 utils_1.setTemplate(name, jsxElementPath, this.templates);
1446 }
1447 }
1448 }
1449 }
1450 setProperies() {
1451 if (!this.isDefaultRender) {
1452 return;
1453 }
1454 const properties = [];
1455 this.componentProperies.forEach((propName) => {
1456 const p = "quickapp" /* quickapp */ === "quickapp" /* quickapp */ && this.upperCaseComponentProps.has(propName) && !propName.startsWith('prv-fn') ? lodash_1.snakeCase(propName) : propName;
1457 properties.push(t.objectProperty(t.stringLiteral(p), t.objectExpression([
1458 t.objectProperty(t.stringLiteral('type'), t.nullLiteral()),
1459 t.objectProperty(t.stringLiteral('value'), t.nullLiteral())
1460 ])));
1461 });
1462 let classProp = t.classProperty(t.identifier('properties'), t.objectExpression(properties));
1463 classProp.static = true;
1464 const classPath = this.renderPath.findParent(isClassDcl);
1465 adapter_1.Adapter.type !== "alipay" /* alipay */ && classPath.node.body.body.unshift(classProp);
1466 }
1467 setLoopRefFlag() {
1468 if (this.loopRefs.size) {
1469 const classPath = this.renderPath.findParent(isClassDcl);
1470 classPath.node.body.body.unshift(t.classProperty(t.identifier('$$hasLoopRef'), t.booleanLiteral(true)));
1471 }
1472 }
1473 destructStateOrProps(key, path, properties, parentPath) {
1474 const hasStateOrProps = properties.filter(p => t.isObjectProperty(p) && t.isIdentifier(p.key) && key === p.key.name);
1475 if (hasStateOrProps.length === 0) {
1476 return;
1477 }
1478 if (hasStateOrProps.length !== properties.length) {
1479 throw utils_1.codeFrameError(path.node, 'state 或 props 只能单独从 this 中解构');
1480 }
1481 const declareState = template(`const ${key} = this.${key};`)();
1482 if (properties.length > 1) {
1483 const index = properties.findIndex(p => t.isObjectProperty(p) && t.isIdentifier(p.key, { name: key }));
1484 properties.splice(index, 1);
1485 parentPath.insertAfter(declareState);
1486 }
1487 else {
1488 parentPath.insertAfter(declareState);
1489 parentPath.remove();
1490 }
1491 }
1492 handleJSXInIfStatement(jsxElementPath, { parentNode, parentPath, isFinalReturn, isIfStemInLoop }) {
1493 if (t.isReturnStatement(parentNode)) {
1494 if (!isFinalReturn && !isIfStemInLoop) {
1495 return;
1496 }
1497 else {
1498 const ifStatement = parentPath.findParent(p => p.isIfStatement());
1499 const blockStatement = parentPath.findParent(p => p.isBlockStatement() && (p.parentPath === ifStatement));
1500 const loopCallExpr = jsxElementPath.findParent(p => utils_1.isArrayMapCallExpression(p));
1501 if (loopCallExpr && loopCallExpr.findParent(p => p.isIfStatement())) {
1502 throw utils_1.codeFrameError(loopCallExpr.node, '在循环的上级和内部都有 if-else 的情况,需要把循环的内部 if-else return 的 JSX 设置为一个变量,保证单个 return 语句。\n 示例:https://gist.github.com/yuche/f6a0933df2537407abe0f426f774f670');
1503 }
1504 if (blockStatement && blockStatement.isBlockStatement()) {
1505 blockStatement.traverse(this.renameIfScopeVaribale(blockStatement));
1506 }
1507 const blockAttrs = [];
1508 if ((adapter_1.isNewPropsSystem()) && !this.finalReturnElement && process.env.NODE_ENV !== 'test') {
1509 if (this.isDefaultRender && adapter_1.Adapter.type !== "swan" /* swan */) {
1510 blockAttrs.push(t.jSXAttribute(t.jSXIdentifier(adapter_1.Adapter.if), t.jSXExpressionContainer(t.jSXIdentifier(constant_1.IS_TARO_READY))));
1511 }
1512 }
1513 const block = this.finalReturnElement || jsx_1.buildBlockElement(blockAttrs);
1514 if (utils_1.isBlockIfStatement(ifStatement, blockStatement)) {
1515 let { test, alternate, consequent } = ifStatement.node;
1516 if (utils_1.hasComplexExpression(ifStatement.get('test'))) {
1517 ifStatement.node.test = test = utils_1.generateAnonymousState(blockStatement.scope, ifStatement.get('test'), this.referencedIdentifiers, true);
1518 }
1519 // blockStatement.node.body.push(t.returnStatement(
1520 // t.memberExpression(t.thisExpression(), t.identifier('state'))
1521 // ))
1522 if (alternate === blockStatement.node) {
1523 throw utils_1.codeFrameError(parentNode.loc, '不必要的 else 分支,请遵从 ESLint consistent-return: https://eslint.org/docs/rules/consistent-return');
1524 }
1525 else if (consequent === blockStatement.node) {
1526 const parentIfStatement = ifStatement.findParent(p => p.isIfStatement());
1527 if (parentIfStatement) {
1528 jsx_1.setJSXAttr(jsxElementPath.node, adapter_1.Adapter.elseif, t.jSXExpressionContainer(test), jsxElementPath);
1529 if (loopCallExpr && this.loopIfStemComponentMap.has(loopCallExpr)) {
1530 const block = this.loopIfStemComponentMap.get(loopCallExpr);
1531 block.children.push(jsxElementPath.node);
1532 }
1533 }
1534 else {
1535 if (isIfStemInLoop && loopCallExpr && loopCallExpr.isCallExpression()) {
1536 if (this.loopIfStemComponentMap.has(loopCallExpr)) {
1537 const component = this.loopIfStemComponentMap.get(loopCallExpr);
1538 utils_1.newJSXIfAttr(jsxElementPath.node, test, jsxElementPath);
1539 component.children.push(jsxElementPath.node);
1540 }
1541 else {
1542 utils_1.newJSXIfAttr(jsxElementPath.node, test, jsxElementPath);
1543 this.loopIfStemComponentMap.set(loopCallExpr, block);
1544 const arrowFunc = loopCallExpr.node.arguments[0];
1545 if (t.isArrowFunctionExpression(arrowFunc) && t.isBlockStatement(arrowFunc.body) && !arrowFunc.body.body.some(s => t.isReturnStatement(s))) {
1546 arrowFunc.body.body.push(t.returnStatement(jsx_1.buildBlockElement()));
1547 this.hasNoReturnLoopStem = true;
1548 }
1549 }
1550 let scope;
1551 try {
1552 scope = loopCallExpr.get('arguments')[0].get('body').scope;
1553 }
1554 catch (error) {
1555 //
1556 }
1557 if (scope) {
1558 this.returnedifStemJSX.add(scope);
1559 }
1560 }
1561 else {
1562 if (this.topLevelIfStatement.size > 0) {
1563 jsx_1.setJSXAttr(jsxElementPath.node, adapter_1.Adapter.elseif, t.jSXExpressionContainer(test), jsxElementPath);
1564 }
1565 else {
1566 utils_1.newJSXIfAttr(jsxElementPath.node, test, jsxElementPath);
1567 this.topLevelIfStatement.add(ifStatement);
1568 }
1569 }
1570 }
1571 }
1572 }
1573 else if (block.children.length !== 0) {
1574 if (this.topLevelIfStatement.size > 0) {
1575 jsx_1.setJSXAttr(jsxElementPath.node, adapter_1.Adapter.else);
1576 }
1577 }
1578 block.children.push(jsxElementPath.node);
1579 if (!this.loopIfStemComponentMap.has(loopCallExpr)) {
1580 this.finalReturnElement = block;
1581 }
1582 this.returnedPaths.push(parentPath);
1583 }
1584 }
1585 else if (t.isArrowFunctionExpression(parentNode)) {
1586 // console.log('arrow')
1587 }
1588 else if (t.isAssignmentExpression(parentNode)) {
1589 const ifStatement = parentPath.findParent(p => p.isIfStatement());
1590 const blockStatement = parentPath.findParent(p => p.isBlockStatement() && (p.parentPath === ifStatement));
1591 if (blockStatement && blockStatement.isBlockStatement()) {
1592 blockStatement.traverse(this.renameIfScopeVaribale(blockStatement));
1593 }
1594 if (t.isIdentifier(parentNode.left)) {
1595 const assignmentName = parentNode.left.name;
1596 const renderScope = isIfStemInLoop ? jsxElementPath.findParent(p => utils_1.isArrayMapCallExpression(p)).get('arguments')[0].get('body').scope : this.renderScope;
1597 const bindingNode = renderScope.getOwnBinding(assignmentName).path.node;
1598 // tslint:disable-next-line
1599 const parallelIfStems = this.findParallelIfStem(ifStatement);
1600 const parentIfStatement = ifStatement.findParent(p => p.isIfStatement() && !parallelIfStems.has(p));
1601 // @TODO: 重构 this.templates 为基于作用域的 HashMap,现在仍然可能会存在重复的情况
1602 let block = this.templates.get(assignmentName) || jsx_1.buildBlockElement();
1603 let isElse = false;
1604 if (utils_1.isEmptyDeclarator(bindingNode)) {
1605 const blockStatement = parentPath.findParent(p => p.isBlockStatement());
1606 if (utils_1.isBlockIfStatement(ifStatement, blockStatement)) {
1607 const { test, alternate, consequent } = ifStatement.node;
1608 if (alternate === blockStatement.node) {
1609 const newBlock = jsx_1.buildBlockElement();
1610 jsx_1.setJSXAttr(newBlock, adapter_1.Adapter.else);
1611 newBlock.children = [jsxElementPath.node];
1612 jsxElementPath.node = newBlock;
1613 }
1614 else if (consequent === blockStatement.node) {
1615 const parentIfStatement = ifStatement.findParent(p => p.isIfStatement());
1616 const assignments = [];
1617 let isAssignedBefore = false;
1618 // @TODO: 重构这两种循环为通用模块
1619 // 如果这个 JSX assigmnent 的作用域中有其他的 if block 曾经赋值过,它应该是 else-if
1620 if (blockStatement && blockStatement.isBlockStatement()) {
1621 for (const parentStatement of blockStatement.node.body) {
1622 if (t.isIfStatement(parentStatement) && t.isBlockStatement(parentStatement.consequent)) {
1623 const statements = parentStatement.consequent.body;
1624 for (const statement of statements) {
1625 if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression) && t.isIdentifier(statement.expression.left, { name: assignmentName })) {
1626 isAssignedBefore = true;
1627 }
1628 }
1629 }
1630 }
1631 }
1632 // 如果这个 JSX assigmnent 的的父级作用域中的 prev sibling 有相同的赋值,它应该是 else-if
1633 if (parentIfStatement) {
1634 const { consequent } = parentIfStatement.node;
1635 if (t.isBlockStatement(consequent)) {
1636 const body = consequent.body;
1637 for (const parentStatement of body) {
1638 if (t.isIfStatement(parentStatement) && t.isBlockStatement(parentStatement.consequent)) {
1639 const statements = parentStatement.consequent.body;
1640 for (const statement of statements) {
1641 if (t.isExpressionStatement(statement) && t.isAssignmentExpression(statement.expression) && t.isIdentifier(statement.expression.left, { name: assignmentName })) {
1642 assignments.push(statement.expression);
1643 }
1644 }
1645 }
1646 }
1647 }
1648 }
1649 if ((parentIfStatement &&
1650 (parentIfStatement.get('alternate') === ifStatement ||
1651 assignments.findIndex(a => a === parentNode) > 0))
1652 ||
1653 isAssignedBefore) {
1654 jsx_1.setJSXAttr(jsxElementPath.node, adapter_1.Adapter.elseif, t.jSXExpressionContainer(test), jsxElementPath);
1655 }
1656 else {
1657 if (parentIfStatement) {
1658 if (this.isEmptyBlock(block)) {
1659 utils_1.newJSXIfAttr(block, parentIfStatement.node.test, jsxElementPath);
1660 }
1661 else if (parentIfStatement.node.alternate === ifStatement.parent) {
1662 const newBlock = jsx_1.buildBlockElement();
1663 jsx_1.setJSXAttr(newBlock, adapter_1.Adapter.else);
1664 this.insertElseBlock(block, newBlock, parentIfStatement.node.test);
1665 isElse = true;
1666 }
1667 else {
1668 const newBlock = jsx_1.buildBlockElement();
1669 jsx_1.setJSXAttr(newBlock, adapter_1.Adapter.elseif, t.jSXExpressionContainer(parentIfStatement.node.test), jsxElementPath);
1670 block.children.push(newBlock);
1671 }
1672 }
1673 utils_1.newJSXIfAttr(jsxElementPath.node, test, jsxElementPath);
1674 }
1675 }
1676 const ifAttr = block.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.if);
1677 if (ifAttr && t.isJSXExpressionContainer(ifAttr.value, { expression: test })) {
1678 const newBlock = jsx_1.buildBlockElement();
1679 newBlock.children = [block, jsxElementPath.node];
1680 block = newBlock;
1681 }
1682 else if (parentIfStatement && ifStatement.parentPath !== parentIfStatement) {
1683 let hasNest = false;
1684 this.handleNestedIfStatement(block, jsxElementPath.node, parentIfStatement.node.test, hasNest, isElse || !!ifStatement.findParent(p => p.node === parentIfStatement.node.alternate));
1685 if (!hasNest && parentIfStatement.get('alternate') !== ifStatement) {
1686 const ifAttr = block.openingElement.attributes.find(a => t.isJSXIdentifier(a.name) && a.name.name === adapter_1.Adapter.if);
1687 if (ifAttr && t.isJSXExpressionContainer(ifAttr.value, { expression: parentIfStatement.node.test })) {
1688 const newBlock = jsx_1.buildBlockElement();
1689 block.children.push(jsxElementPath.node);
1690 newBlock.children = [block];
1691 block = newBlock;
1692 }
1693 }
1694 }
1695 else {
1696 block.children.push(jsxElementPath.node);
1697 }
1698 // setTemplate(name, path, templates)
1699 assignmentName && this.templates.set(assignmentName, block);
1700 if (isIfStemInLoop) {
1701 this.replaceIdWithTemplate()(renderScope.path);
1702 this.returnedPaths.push(parentPath);
1703 }
1704 }
1705 }
1706 else {
1707 throw utils_1.codeFrameError(jsxElementPath.node.loc, '请将 JSX 赋值表达式初始化为 null,然后再进行 if 条件表达式赋值。');
1708 }
1709 }
1710 }
1711 else if (!t.isJSXElement(parentNode)) {
1712 // throwError(path, '考虑只对 JSX 元素赋值一次。')
1713 }
1714 }
1715 genPropsSettingExpression(properties, id, previd) {
1716 return t.callExpression(t.memberExpression(t.identifier(constant_1.PROPS_MANAGER), t.identifier('set')), [Array.isArray(properties) ? t.objectExpression(properties) : properties, id, previd]);
1717 }
1718 getPropsFromAttrs(openingElement) {
1719 const attrs = openingElement.attributes;
1720 const properties = [];
1721 openingElement.attributes = attrs.filter(attr => {
1722 if (t.isJSXSpreadAttribute(attr)) {
1723 properties.push(t.spreadProperty(attr.argument));
1724 return false;
1725 }
1726 else if (t.isJSXAttribute(attr)) {
1727 const { name, value } = attr;
1728 if (t.isJSXIdentifier(name)
1729 && name.name !== 'key'
1730 && name.name !== 'id'
1731 && !(name.name === 'extraProps' && adapter_1.Adapter.type === "weapp" /* weapp */)
1732 && name.name !== adapter_1.Adapter.for
1733 && name.name !== adapter_1.Adapter.forItem
1734 && name.name !== adapter_1.Adapter.forIndex
1735 && name.name.indexOf('render') !== 0
1736 && !t.isJSXElement(value)
1737 && !name.name.includes('-')) {
1738 // tslint:disable-next-line: strict-type-predicates
1739 const v = value === null
1740 ? t.booleanLiteral(true)
1741 : (t.isJSXExpressionContainer(value)
1742 ? value.expression
1743 : value);
1744 v && properties.push(t.objectProperty(t.stringLiteral(name.name), v));
1745 return false;
1746 }
1747 return true;
1748 }
1749 });
1750 return properties;
1751 }
1752 addIdToElement(jsxElementPath) {
1753 const openingElement = jsxElementPath.node.openingElement;
1754 if (openingElement.attributes.find(attr => {
1755 return t.isJSXAttribute(attr) && attr.name.name === 'compid';
1756 })) {
1757 return;
1758 }
1759 if (this.isInternalComponent(openingElement)) {
1760 if (this.isEmptyProps(openingElement.attributes) && adapter_1.Adapter.type !== "swan" /* swan */) {
1761 return;
1762 }
1763 const compId = utils_1.genCompid();
1764 const prevName = `${constant_1.PREV_COMPID}__${compId}`;
1765 const name = `${constant_1.COMPID}__${compId}`;
1766 const variableName = t.identifier(name);
1767 this.referencedIdentifiers.add(variableName);
1768 const idExpr = t.variableDeclaration('const', [
1769 t.variableDeclarator(t.arrayPattern([t.identifier(prevName), variableName]), t.callExpression(t.identifier(constant_1.GEN_COMP_ID), [
1770 t.binaryExpression('+', this.prefixExpr(), t.stringLiteral(name))
1771 ]))
1772 ]);
1773 // createData 中设置 props
1774 const properties = this.getPropsFromAttrs(openingElement);
1775 const propsId = `$props__${compId}`;
1776 const collectedProps = utils_1.buildConstVariableDeclaration(propsId, t.objectExpression(properties));
1777 const result = jsxElementPath.getStatementParent().insertBefore(collectedProps);
1778 this.propsDecls.set(propsId, result[0]);
1779 const propsSettingExpr = this.genPropsSettingExpression(t.identifier(propsId), variableName, t.identifier(prevName));
1780 this.genCompidExprs.add(idExpr);
1781 const expr = utils_1.setAncestorCondition(jsxElementPath, propsSettingExpr);
1782 this.ancestorConditions.add(expr);
1783 const ifStatement = jsxElementPath.findParent(p => p.isIfStatement());
1784 const blockStatement = jsxElementPath.findParent(p => p.isBlockStatement());
1785 let blockStem = this.renderPath.node.body;
1786 if (ifStatement && blockStatement) {
1787 const consequent = ifStatement.get('consequent');
1788 const alternate = ifStatement.get('alternate');
1789 if (blockStatement === consequent || blockStatement === alternate) {
1790 blockStem = blockStatement.node;
1791 }
1792 }
1793 const funcs = this.propsSettingExpressions.get(blockStem);
1794 const func = () => t.expressionStatement(expr);
1795 this.propsSettingExpressions.set(blockStem, funcs ? [...funcs, func] : [func]);
1796 // xml 中打上组件 ID
1797 jsx_1.setJSXAttr(jsxElementPath.node, 'compid', t.jSXExpressionContainer(variableName));
1798 }
1799 }
1800 handleComponents(renderBody) {
1801 renderBody.traverse({
1802 JSXElement: jsxElementPath => this.addIdToElement(jsxElementPath)
1803 });
1804 }
1805 handleQuickappProps() {
1806 if (adapter_1.Adapter.type !== "quickapp" /* quickapp */) {
1807 return;
1808 }
1809 this.renderPath.traverse({
1810 Identifier: (path) => {
1811 if (!this.upperCaseComponentProps.has(path.node.name)) {
1812 return;
1813 }
1814 if (utils_1.isDerivedFromProps(this.renderScope, path.node.name)) {
1815 this.renderScope.rename(path.node.name, lodash_1.snakeCase(path.node.name));
1816 path.replaceWith(t.identifier(lodash_1.snakeCase(path.node.name)));
1817 }
1818 const sibling = path.getSibling('object');
1819 if (sibling && sibling.isMemberExpression() && sibling.get('object').isThisExpression() && sibling.get('property').isIdentifier({ name: 'props' })) {
1820 path.replaceWith(t.identifier(lodash_1.snakeCase(path.node.name)));
1821 }
1822 }
1823 });
1824 }
1825 handleClosureComp() {
1826 this.deferedHandleClosureJSXFunc.forEach(func => func());
1827 }
1828 checkDuplicateData() {
1829 this.initState.forEach((stateName) => {
1830 if (this.templates.has(stateName)) {
1831 throw utils_1.codeFrameError(this.templates.get(stateName), `自定义变量组件名: \`${stateName}\` 和已有 this.state.${stateName} 重复。请使用另一个变量名。`);
1832 }
1833 });
1834 this.componentProperies.forEach((componentName) => {
1835 if (this.componentProperies.has(componentName)) {
1836 throw utils_1.codeFrameError(this.renderPath.node, `state: \`${componentName}\` 和已有 this.props.${componentName} 重复。请使用另一个变量名。`);
1837 }
1838 if (this.templates.has(componentName)) {
1839 throw utils_1.codeFrameError(this.templates.get(componentName), `自定义变量组件名: \`${componentName}\` 和已有 this.props.${componentName} 重复。请使用另一个变量名。`);
1840 }
1841 });
1842 }
1843 addRefIdentifier(path, id) {
1844 const arrayMap = path.findParent(p => utils_1.isArrayMapCallExpression(p));
1845 if (arrayMap && arrayMap.isCallExpression()) {
1846 this.loopRefIdentifiers.set(id.name, arrayMap);
1847 }
1848 else {
1849 id && this.referencedIdentifiers.add(id);
1850 }
1851 }
1852 findParentIndices(callee, indexId) {
1853 const loopIndices = [];
1854 const loops = t.arrayExpression([]);
1855 utils_1.findParentLoops(callee, this.loopComponentNames, loops);
1856 for (const el of loops.elements) {
1857 if (t.isObjectExpression(el)) {
1858 for (const prop of el.properties) {
1859 if (t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: 'indexId' }) && t.isIdentifier(prop.value)) {
1860 loopIndices.push(prop.value.name);
1861 }
1862 }
1863 }
1864 }
1865 if (loopIndices.length === 0) {
1866 if (t.isIdentifier(indexId)) {
1867 loopIndices.push(indexId.name);
1868 }
1869 else {
1870 throw utils_1.codeFrameError(callee.node, '循环中使用自定义组件需要暴露循环的 index');
1871 }
1872 }
1873 return loopIndices;
1874 }
1875 setOutputTemplate() {
1876 if (adapter_1.Adapter.type === "quickapp" /* quickapp */ && options_1.transformOptions.rootProps && options_1.transformOptions.isRoot) {
1877 const attrs = [];
1878 for (const key in options_1.transformOptions.rootProps) {
1879 if (options_1.transformOptions.rootProps.hasOwnProperty(key)) {
1880 const value = options_1.transformOptions.rootProps[key];
1881 const keyName = key + '__temp';
1882 const decl = utils_1.buildConstVariableDeclaration(keyName, t.identifier(JSON.stringify(value)));
1883 this.referencedIdentifiers.add(t.identifier(keyName));
1884 this.renderPath.node.body.body.push(decl);
1885 attrs.push(t.jSXAttribute(t.jSXIdentifier(key), t.jSXExpressionContainer(t.identifier(keyName))));
1886 }
1887 }
1888 this.finalReturnElement.openingElement.attributes.push(...attrs);
1889 }
1890 if (!this.finalReturnElement) {
1891 throw utils_1.codeFrameError(this.renderPath.node, '没有找到返回的 JSX 元素,你是不是忘记 return 了?');
1892 }
1893 this.outputTemplate = jsx_1.parseJSXElement(this.finalReturnElement, true);
1894 if (!this.isDefaultRender) {
1895 this.outputTemplate = `<template name="${this.renderMethodName}">${this.outputTemplate}</template>`;
1896 }
1897 }
1898 removeJSXStatement() {
1899 this.jsxDeclarations.forEach(d => d && !d.removed && utils_1.isContainJSXElement(d) && d.remove());
1900 this.returnedPaths.forEach((p) => {
1901 if (p.removed) {
1902 return;
1903 }
1904 const ifStem = p.findParent(_ => _.isIfStatement());
1905 if (ifStem) {
1906 const node = p.node;
1907 if (!node) {
1908 return;
1909 }
1910 if (t.isJSXElement(node.argument)) {
1911 const jsx = node.argument;
1912 if (jsx.children.length === 0 && jsx.openingElement.attributes.length === 0 && !this.isIfStemInLoop(p.get('argument'))) {
1913 node.argument = t.nullLiteral();
1914 }
1915 else {
1916 p.remove();
1917 }
1918 }
1919 else {
1920 const isValid = p.get('argument').evaluateTruthy();
1921 if (isValid === false) {
1922 node.argument = t.nullLiteral();
1923 }
1924 else {
1925 p.remove();
1926 }
1927 }
1928 }
1929 else {
1930 p.remove();
1931 }
1932 });
1933 }
1934 setCustomEvent() {
1935 const classPath = this.renderPath.findParent(isClassDcl);
1936 const eventPropName = adapter_1.Adapter.type === "quickapp" /* quickapp */ ? 'privateTaroEvent' : '$$events';
1937 const body = classPath.node.body.body.find(b => t.isClassProperty(b) && b.key.name === eventPropName);
1938 const usedEvents = Array.from(this.usedEvents).map(s => t.stringLiteral(s));
1939 if (body && t.isArrayExpression(body.value)) {
1940 body.value = t.arrayExpression(lodash_1.uniq(body.value.elements.concat(usedEvents)));
1941 }
1942 else {
1943 let classProp = t.classProperty(t.identifier(eventPropName), t.arrayExpression(usedEvents)); // babel 6 typing 没有 static
1944 classProp.static = true;
1945 classPath.node.body.body.unshift(classProp);
1946 }
1947 }
1948 setUsedState() {
1949 if (!this.isDefaultRender) {
1950 return;
1951 }
1952 for (const [key, method] of this.methods) {
1953 if (method) {
1954 if (method.isClassMethod()) {
1955 const kind = method.node.kind;
1956 if (kind === 'get') {
1957 this.classComputedState.add(key);
1958 }
1959 }
1960 }
1961 }
1962 let componentProperies = lodash_1.cloneDeep(this.componentProperies);
1963 componentProperies.forEach(s => {
1964 if (s.startsWith(constant_1.FN_PREFIX)) {
1965 const eventName = s.slice(5);
1966 if (componentProperies.has(eventName)) {
1967 componentProperies.delete(s);
1968 componentProperies.delete(eventName);
1969 }
1970 }
1971 });
1972 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
1973 componentProperies = new Set(Array.from(componentProperies).map(p => this.upperCaseComponentProps.has(p) && !p.startsWith('on') && !p.startsWith('prv-fn') ? lodash_1.snakeCase(p) : p));
1974 }
1975 Array.from(this.reserveStateWords).forEach(this.setReserveWord);
1976 let usedState = Array.from(new Set(Array.from(this.referencedIdentifiers)
1977 .map(i => i.name)
1978 .concat([...this.initState, ...this.usedThisState, ...componentProperies, ...this.classComputedState])))
1979 .concat(...this.usedState)
1980 // .filter(i => {
1981 // return !methods.has(i)
1982 // })
1983 .filter(i => !this.loopScopes.has(i))
1984 .filter(i => !this.templates.has(i))
1985 .filter(Boolean);
1986 if (adapter_1.Adapter.type === "quickapp" /* quickapp */) {
1987 usedState = usedState
1988 .filter(i => !new Set([...this.upperCaseComponentProps].map(i => i.toLowerCase())).has(i))
1989 .filter(i => !this.upperCaseComponentProps.has(i));
1990 }
1991 const classPath = this.renderPath.findParent(isClassDcl);
1992 classPath.node.body.body.unshift(t.classProperty(t.identifier('$usedState'), t.arrayExpression([...new Set(usedState
1993 .filter(s => !this.loopScopes.has(s.split('.')[0]))
1994 .filter(i => i !== constant_1.MAP_CALL_ITERATOR && !this.reserveStateWords.has(i))
1995 .filter(i => utils_1.isVarName(i))
1996 .filter(i => !this.loopRefIdentifiers.has(i))
1997 .concat(Array.from(this.customComponentNames)))]
1998 .map(s => t.stringLiteral(s)))));
1999 }
2000 checkDuplicateName() {
2001 this.loopScopes.forEach(s => {
2002 if (s.includes('anonIdx')) {
2003 return;
2004 }
2005 if (this.renderPath.scope.hasBinding(s)) {
2006 const err = utils_1.codeFrameError(this.renderPath.scope.getBinding(s).path.node, '此变量声明与循环变量冲突,可能会造成问题。');
2007 // tslint:disable-next-line: no-console
2008 console.warn('Warning: ', err.message);
2009 this.loopScopes.delete(s);
2010 }
2011 });
2012 }
2013 setPendingState() {
2014 let propertyKeys = Array.from(new Set(Array.from(this.referencedIdentifiers)
2015 .map(i => i.name)))
2016 .filter(i => {
2017 const method = this.methods.get(i);
2018 let isGet = false;
2019 if (method) {
2020 if (method.isClassMethod()) {
2021 const kind = method.node.kind;
2022 if (kind === 'get') {
2023 isGet = true;
2024 }
2025 }
2026 }
2027 return !this.methods.has(i) || isGet;
2028 })
2029 .filter(i => !this.loopScopes.has(i))
2030 .filter(i => !this.templates.has(i))
2031 .filter(i => utils_1.isVarName(i))
2032 .filter(i => i !== constant_1.MAP_CALL_ITERATOR && !this.reserveStateWords.has(i))
2033 .filter(i => !i.startsWith('$$'))
2034 .filter(i => !i.startsWith('_$indexKey'))
2035 .filter(i => !this.loopRefIdentifiers.has(i));
2036 if (this.isDefaultRender) {
2037 propertyKeys = propertyKeys.filter(i => !this.initState.has(i));
2038 }
2039 let properties = propertyKeys.map(i => t.objectProperty(t.identifier(i), t.identifier(i)));
2040 const pendingState = t.objectExpression(properties.concat(Array.from(this.classComputedState).filter(i => {
2041 return !propertyKeys.includes(i);
2042 }).map(i => {
2043 return t.objectProperty(t.identifier(i), t.memberExpression(t.thisExpression(), t.identifier(i)));
2044 })));
2045 this.propsSettingExpressions.forEach((exprs, stem) => {
2046 stem.body.push(...exprs.map(e => e()));
2047 });
2048 this.renderPath.node.body.body.unshift(...Array.from(this.genCompidExprs));
2049 if (this.isDefaultRender) {
2050 if (this.refObjExpr && this.refObjExpr.length) {
2051 this.renderPath.node.body.body.push(t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('$$refs')), t.identifier('pushRefs')), [t.arrayExpression(this.refObjExpr)])));
2052 }
2053 this.renderPath.node.body.body = this.renderPath.node.body.body.concat(
2054 // ...propsStatement,
2055 buildAssignState(pendingState), t.returnStatement(t.memberExpression(t.thisExpression(), t.identifier('state'))));
2056 }
2057 else {
2058 const usedState = Array.from(this.usedThisState).map(s => t.objectProperty(t.identifier(s), t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('state')), t.identifier(s))));
2059 this.renderPath.node.body.body.push(
2060 // ...propsStatement,
2061 t.returnStatement(t.objectExpression(pendingState.properties.concat(usedState))));
2062 const { async, body, params } = this.renderPath.node;
2063 this.renderPath.replaceWith(t.classMethod('method', t.identifier(`_create${this.renderMethodName.slice(6)}Data`), [t.identifier(constant_1.CLASS_COMPONENT_UID)], t.blockStatement([
2064 t.returnStatement(t.arrowFunctionExpression(params, body, async))
2065 ])));
2066 }
2067 this.renderPath.traverse({
2068 Identifier: (path) => {
2069 if (this.propsDecls.has(path.node.name) && path.parentPath.isCallExpression()) {
2070 const { callee } = path.parentPath.node;
2071 if (t.isMemberExpression(callee) && t.isIdentifier(callee.object, { name: constant_1.PROPS_MANAGER }) && t.isIdentifier(callee.property, { name: 'set' })) {
2072 const decl = this.propsDecls.get(path.node.name);
2073 path.replaceWith(decl.node.declarations[0].init);
2074 this.propsDecls.delete(path.node.name);
2075 !decl.removed && decl.remove();
2076 }
2077 }
2078 }
2079 });
2080 }
2081 createData() {
2082 if (!this.isDefaultRender) {
2083 return;
2084 }
2085 const renderBody = this.renderPath.get('body');
2086 renderBody.traverse({
2087 ThisExpression(path) {
2088 const property = path.getSibling('property');
2089 if (property.isIdentifier({ name: 'state' })) {
2090 property.replaceWith(t.identifier('__state'));
2091 }
2092 if (property.isIdentifier({ name: 'props' })) {
2093 property.replaceWith(t.identifier('__props'));
2094 }
2095 }
2096 });
2097 this.usedThisProperties.forEach(prop => {
2098 if (this.renderScope.hasBinding(prop)) {
2099 const binding = this.renderScope.getBinding(prop);
2100 throw utils_1.codeFrameError(binding.path.node, `此变量声明与 this.${prop} 的声明冲突,请更改其中一个变量名。详情见:https://github.com/NervJS/taro/issues/822`);
2101 }
2102 });
2103 this.renderPath.node.body.body.unshift(template(`this.__state = arguments[0] || this.state || {};`)(), template(`this.__props = arguments[1] || this.props || {};`)(), template(`const __isRunloopRef = arguments[2];`)(), template(`const __prefix = this.$prefix`)(), this.usedThisProperties.size
2104 ? t.variableDeclaration('const', [
2105 t.variableDeclarator(t.objectPattern(Array.from(this.usedThisProperties).map(p => t.objectProperty(t.identifier(p), t.identifier(p)))), t.thisExpression())
2106 ])
2107 : t.emptyStatement());
2108 if (t.isIdentifier(this.renderPath.node.key)) {
2109 this.renderPath.node.key.name = '_createData';
2110 }
2111 }
2112}
2113exports.RenderParser = RenderParser;
2114//# sourceMappingURL=render.js.map
\No newline at end of file