UNPKG

saven

Version:
226 lines 13.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const t = require("babel-types"); const utils_1 = require("./utils"); const jsx_1 = require("./jsx"); const constant_1 = require("./constant"); // @TODO // 重构 parseRender 和 parseLoop 失败 // 尚不清楚 babel 的 state 和 context 传参机制 // 目前先写两份代码,有时间看看 babel 具体对 state 和 context 做了什么导致传参失败 function parseLoopBody(body, jsxDeclarations, // @TODO // 把 templates 换成 Map 可以支持 shalow variables declared // 现在先用 ESLint 的 no-shalow 顶着 templates, loopScopes, finalReturnElement, returnedPaths) { const bodyScope = body.scope; body.traverse({ JSXElement(jsxElementPath) { const parentNode = jsxElementPath.parent; const parentPath = jsxElementPath.parentPath; const isFinalReturn = jsxElementPath.getFunctionParent().isClassMethod(); const isJSXChildren = t.isJSXElement(parentNode); if (!isJSXChildren) { let statementParent = jsxElementPath.getStatementParent(); if (!(statementParent.isVariableDeclaration() || statementParent.isExpressionStatement())) { statementParent = statementParent.findParent(s => s.isVariableDeclaration() || s.isExpressionStatement()); } jsxDeclarations.add(statementParent); if (t.isVariableDeclarator(parentNode)) { if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); // setTemplate(name, path, templates) name && templates.set(name, jsxElementPath.node); } } else if (t.isLogicalExpression(parentNode)) { const { left, operator } = parentNode; if (operator === '&&') { if (t.isExpression(left)) { utils_1.newJSXIfAttr(jsxElementPath.node, left); parentPath.replaceWith(jsxElementPath.node); if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); utils_1.setTemplate(name, jsxElementPath, templates); // name && templates.set(name, path.node) } } } } else if (t.isConditionalExpression(parentNode)) { const { test, consequent, alternate } = parentNode; const block = jsx_1.buildBlockElement(); if (t.isJSXElement(consequent) && t.isLiteral(alternate)) { const { value, confident } = parentPath.get('alternate').evaluate(); if (confident && !value) { utils_1.newJSXIfAttr(block, test); block.children = [jsxElementPath.node]; // newJSXIfAttr(jsxElementPath.node, test) parentPath.replaceWith(block); if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); utils_1.setTemplate(name, jsxElementPath, templates); // name && templates.set(name, path.node) } } } else if (t.isLiteral(consequent) && t.isJSXElement(consequent)) { if (t.isNullLiteral(consequent)) { utils_1.newJSXIfAttr(block, utils_1.reverseBoolean(test)); // newJSXIfAttr(jsxElementPath.node, reverseBoolean(test)) parentPath.replaceWith(block); if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); utils_1.setTemplate(name, jsxElementPath, templates); // name && templates.set(name, path.node) } } } else if (t.isJSXElement(consequent) && t.isJSXElement(alternate)) { const block2 = jsx_1.buildBlockElement(); block.children = [consequent]; utils_1.newJSXIfAttr(block, test); jsx_1.setJSXAttr(block2, 'wx:else'); block2.children = [alternate]; const parentBlock = jsx_1.buildBlockElement(); parentBlock.children = [block, block2]; parentPath.replaceWith(parentBlock); if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); utils_1.setTemplate(name, jsxElementPath, templates); } } else { // console.log('todo') } } else if (t.isReturnStatement(parentNode)) { if (!isFinalReturn) { const caller = parentPath.findParent(p => p.isCallExpression()); if (caller.isCallExpression()) { const callee = caller.node.callee; if (t.isMemberExpression(callee) && t.isIdentifier(callee.property) && callee.property.name === 'map') { let ary = callee.object; const blockStatementPath = parentPath.findParent(p => p.isBlockStatement()); const body = blockStatementPath.node.body; let stateToBeAssign = new Set(); for (const statement of body) { if (t.isVariableDeclaration(statement)) { for (const dcl of statement.declarations) { if (t.isIdentifier(dcl.id)) { const scope = blockStatementPath.scope; const stateName = scope.generateUid(constant_1.LOOP_STATE); stateToBeAssign.add(stateName); blockStatementPath.scope.rename(dcl.id.name, stateName); } } } } if (t.isCallExpression(ary) || utils_1.isContainFunction(caller.get('callee').get('object'))) { const variableName = `anonymousState_${bodyScope.generateUid()}`; caller.getStatementParent().insertBefore(utils_1.buildConstVariableDeclaration(variableName, ary)); ary = t.identifier(variableName); } jsx_1.setJSXAttr(jsxElementPath.node, 'wx:for', t.jSXExpressionContainer(ary)); const [func] = caller.node.arguments; if (t.isFunctionExpression(func) || t.isArrowFunctionExpression(func)) { const [item, index] = func.params; if (t.isIdentifier(item)) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:for-item', t.stringLiteral(item.name)); loopScopes.add(item.name); } else { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:for-item', t.stringLiteral('__item')); } if (t.isIdentifier(index)) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:for-index', t.stringLiteral(index.name)); loopScopes.add(index.name); } caller.replaceWith(jsxElementPath.node); if (statementParent) { const name = utils_1.findIdentifierFromStatement(statementParent.node); // setTemplate(name, path, templates) name && templates.set(name, jsxElementPath.node); } } } } } else { const ifStatement = parentPath.findParent(p => p.isIfStatement()); const blockStatement = parentPath.findParent(p => p.isBlockStatement()); const block = finalReturnElement || jsx_1.buildBlockElement(); if (utils_1.isBlockIfStatement(ifStatement, blockStatement)) { const { test, alternate, consequent } = ifStatement.node; if (alternate === blockStatement.node) { throw utils_1.codeFrameError(parentNode.loc, '不必要的 else 分支,请遵从 ESLint consistent-return: https://eslint.org/docs/rules/consistent-return'); } else if (consequent === blockStatement.node) { const parentIfStatement = ifStatement.findParent(p => p.isIfStatement()); if (parentIfStatement) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:elif', t.jSXExpressionContainer(test)); } else { utils_1.newJSXIfAttr(jsxElementPath.node, test); } } } else if (block.children.length !== 0) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:else'); } block.children.push(jsxElementPath.node); finalReturnElement = block; returnedPaths.push(parentPath); } } else if (t.isArrowFunctionExpression(parentNode)) { // } else if (t.isAssignmentExpression(parentNode)) { if (t.isIdentifier(parentNode.left)) { const name = parentNode.left.name; const bindingNode = bodyScope.getOwnBinding(name).path.node; const block = templates.get(name) || jsx_1.buildBlockElement(); if (utils_1.isEmptyDeclarator(bindingNode)) { const ifStatement = parentPath.findParent(p => p.isIfStatement()); const blockStatement = parentPath.findParent(p => p.isBlockStatement()); if (utils_1.isBlockIfStatement(ifStatement, blockStatement)) { const { test, alternate, consequent } = ifStatement.node; if (alternate === blockStatement.node) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:else'); } else if (consequent === blockStatement.node) { const parentIfStatement = ifStatement.findParent(p => p.isIfStatement()); if (parentIfStatement && parentIfStatement.get('alternate') === ifStatement) { jsx_1.setJSXAttr(jsxElementPath.node, 'wx:elif', t.jSXExpressionContainer(test)); } else { if (parentIfStatement) { utils_1.newJSXIfAttr(block, parentIfStatement.node.test); } utils_1.newJSXIfAttr(jsxElementPath.node, test); } } block.children.push(jsxElementPath.node); // setTemplate(name, path, templates) name && templates.set(name, block); } } else { throw utils_1.codeFrameError(jsxElementPath.node.loc, '请将 JSX 赋值表达式初始化为 null,然后再进行 if 条件表达式赋值。'); } } } else if (!t.isJSXElement(parentNode)) { // throwError(path, '考虑只对 JSX 元素赋值一次。') } } } }); } exports.parseLoopBody = parseLoopBody; //# sourceMappingURL=loop-component.js.map