Skip to content

Commit

Permalink
fix(alita): 修复 函数组件文件转化错误的bug
Browse files Browse the repository at this point in the history
  • Loading branch information
ykforerlang committed Nov 6, 2019
1 parent d199d96 commit 668bc3e
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 111 deletions.
5 changes: 1 addition & 4 deletions src/basetran/handleMisc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,9 @@ export default function (ast, {isFuncComp}) {
* const x = 1
* export default x
*
* 函数式组件在后续会被处理为class组件,这里不需要处理
*
*/

if (!isFuncComp
&& path.type === 'ExportDefaultDeclaration'
if (path.type === 'ExportDefaultDeclaration'
&& path.node.declaration
&& path.node.declaration.type === 'AssignmentExpression'
&& path.node.declaration.left.type === 'Identifier'
Expand Down
193 changes: 119 additions & 74 deletions src/tran/funcCompToClassComp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
*/

import traverse from "@babel/traverse";
import * as t from "@babel/types";
import {miscNameToJSName} from '../util/util'
Expand All @@ -14,7 +14,7 @@ const npath = require('path')


/**
* 把函数声明的组件, 转化为class
* 把函数声明的组件, 转化为FuncComponent 组件
*
* 1. export default () => {}
*
Expand All @@ -33,96 +33,141 @@ const npath = require('path')
*
*
* @param ast
* @param info
* @returns {*}
*/
export default function (ast, info) {
let compName = npath.basename(miscNameToJSName(info.filepath), '.js')
compName = compName.substring(0, 1).toUpperCase() + compName.substring(1)
export default function funcCompToClassComp(ast, info) {

let funcPath = null
let hasJSXElement = false

traverse(ast, {
enter: path => {
// function x {}
if (path.type === 'FunctionDeclaration' && path.parentPath.type === 'Program') {
funcPath = path
hasJSXElement = false
}

// const x = () => {}
if (path.type === 'ArrowFunctionExpression'
&& path.parentPath.type === 'VariableDeclarator'
&& path.parentPath.parentPath.parentPath.type === 'Program'
) {
funcPath = path
hasJSXElement = false
}

// export const x = () => {}
if (path.type === 'ArrowFunctionExpression'
&& path.parentPath.type === 'VariableDeclarator'
&& path.parentPath.parentPath.parentPath.type === 'ExportNamedDeclaration'
) {
funcPath = path
hasJSXElement = false
}

// const b = function (){}
if (path.type === 'FunctionExpression'
&& path.parentPath.type === 'VariableDeclarator'
&& path.parentPath.parentPath.parentPath.type === 'Program'
) {
funcPath = path
hasJSXElement = false
}

// export const b = function (){}
if (path.type === 'FunctionExpression'
&& path.parentPath.type === 'VariableDeclarator'
&& path.parentPath.parentPath.parentPath.type === 'ExportNamedDeclaration'
) {
funcPath = path
hasJSXElement = false
}

// export default () => {}
if (path.type === 'ArrowFunctionExpression'
&& path.parentPath.type === 'ExportDefaultDeclaration'
) {
funcPath = path
hasJSXElement = false
}

// export default function () {}
if (path.type === 'FunctionDeclaration'
&& path.parentPath.type === 'ExportDefaultDeclaration'
) {
funcPath = path
hasJSXElement = false
}

// export default (function () {})
if (path.type === 'FunctionExpression'
&& path.parentPath.type === 'ExportDefaultDeclaration'
) {
funcPath = path
hasJSXElement = false
}

if (path.type === 'JSXOpeningElement') {
hasJSXElement = true
}
},

exit: path => {
if (path.type === 'ExportDefaultDeclaration') {
const declaration = path.node.declaration
if (path.type === 'ClassDeclaration' || path.type === 'ClassExpression') {
// 下面的path.replaceWith 将导致exit 在执行一次
return
}

if (path === funcPath && hasJSXElement) {
const funcPathNode = funcPath.node

if (funcPathNode.body.type !== 'BlockStatement') {
funcPathNode.body = t.blockStatement([
t.returnStatement(funcPathNode.body)
])
}

let renderBody = getRenderBody(declaration)
path.node.declaration = t.classDeclaration(
t.identifier(compName),
const propsVar = funcPathNode.params[0]
if (propsVar) {
const propDec = t.variableDeclaration('const', [
t.variableDeclarator(propsVar, t.memberExpression(t.thisExpression(), t.identifier('props')))
])

funcPathNode.body.body.unshift(propDec)
}

const contextVar = funcPathNode.params[1]
if (contextVar) {
const contextDec = t.variableDeclaration('const', [
t.variableDeclarator(contextVar, t.memberExpression(t.thisExpression(), t.identifier('context')))
])

funcPathNode.body.body.unshift(contextDec)
}


const classDec = t.classExpression(
path.node.id,
t.memberExpression(t.identifier('React'), t.identifier('FuncComponent')),
t.classBody([
t.classMethod(
'method',
t.identifier('render'),
[],
t.blockStatement(renderBody)
funcPathNode.body
)
])
)

if (funcPathNode.type === 'FunctionDeclaration') {
classDec.type = 'ClassDeclaration'
}

path.replaceWith(classDec)
}
}
})

return ast
}


function getRenderBody(declaration) {
let renderBody = null
let params = null
if (declaration.type === 'AssignmentExpression') {
const { operator, right} = declaration
if (operator === '=' && (right.type === 'ArrowFunctionExpression' || right.type === 'FunctionExpression')) {

params = right.params

if (right.body.body) {
renderBody = [...right.body.body]
} else {
renderBody = [
t.returnStatement(right.body)
]
}
}
}

if (declaration.type === 'ArrowFunctionExpression') {
const func = declaration
params = func.params
if (func.body.body) {
renderBody = [...func.body.body]
} else {
renderBody = [
t.returnStatement(func.body)
]
}
}

if (declaration.type === 'FunctionDeclaration') {
const func = declaration
params = func.params
renderBody = [
...func.body.body
]
}


const propsVar = params[0]
if (propsVar) {
const propDec = t.variableDeclaration('const', [
t.variableDeclarator(propsVar, t.memberExpression(t.thisExpression(), t.identifier('props')))
])

renderBody.unshift(propDec)
}

const contextVar = params[1]
if (contextVar) {
const contextDec = t.variableDeclaration('const', [
t.variableDeclarator(contextVar, t.memberExpression(t.thisExpression(), t.identifier('context')))
])

renderBody.unshift(contextDec)
}

return renderBody
}
6 changes: 3 additions & 3 deletions test/help/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
*/

import {parseCode, geneCode} from '../../src/util/uast'
import {parseCode, geneJSXCode} from '../../src/util/uast'

/**
* 通过trans把code转化为newCode
Expand All @@ -17,13 +17,13 @@ import {parseCode, geneCode} from '../../src/util/uast'
*/
export function getNewCode(code, info, ...trans) {

let ast = parseCode(code)
let ast = parseCode(code, '.js')
for(let i = 0; i < trans.length; i ++) {
const tranFunc = trans[i]
ast = tranFunc.call(null, ast, info)
}

return geneCode(ast)
return geneJSXCode(ast)
}

export function expectNewCode(code, expectCode, info, ...trans) {
Expand Down

0 comments on commit 668bc3e

Please sign in to comment.