Skip to content

Commit

Permalink
feat(wx-to-taro): 解析 Page 页面
Browse files Browse the repository at this point in the history
  • Loading branch information
yuche authored and luckyadam committed Nov 19, 2018
1 parent 857bea1 commit 053e605
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 14 deletions.
1 change: 1 addition & 0 deletions packages/wx-to-taro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"author": "yuche",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"babel-core": "^6.26.3",
"babel-generator": "^6.26.1",
"babel-template": "^6.26.0",
Expand Down
29 changes: 29 additions & 0 deletions packages/wx-to-taro/src/lifecycle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const enum Lifecycle {
constructor = 'constructor',
componentWillMount = 'componentWillMount',
componentDidMount = 'componentDidMount',
componentWillUpdate = 'componentWillUpdate',
componentDidUpdate = 'componentDidUpdate',
componentWillUnmount = 'componentWillUnmount',
componentDidCatch = 'componentDidCatch',
componentDidShow = 'componentDidShow',
componentDidHide = 'componentDidHide',
componentDidAttached = 'componentDidAttached',
componentDidMoved = 'componentDidMoved',
shouldComponentUpdate = 'shouldComponentUpdate',
componentWillReceiveProps = 'componentWillReceiveProps'
}

export const PageLifecycle = new Map<string, string>()
PageLifecycle.set('onLoad', Lifecycle.componentWillMount)
PageLifecycle.set('onShow', Lifecycle.componentDidShow)
PageLifecycle.set('onReady ', Lifecycle.componentDidMount)
PageLifecycle.set('onHide ', Lifecycle.componentDidHide)
PageLifecycle.set('onUnload', Lifecycle.componentWillUnmount)

export const ComponentLifeCycle = new Map<string, string>()
ComponentLifeCycle.set('created', Lifecycle.componentWillMount)
ComponentLifeCycle.set('created', Lifecycle.componentWillMount)
ComponentLifeCycle.set('created', Lifecycle.componentWillMount)
ComponentLifeCycle.set('created', Lifecycle.componentWillMount)
ComponentLifeCycle.set('created', Lifecycle.componentWillMount)
74 changes: 60 additions & 14 deletions packages/wx-to-taro/src/script.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as t from 'babel-types'
import traverse, { NodePath } from 'babel-traverse'
import { transform } from 'babel-core'
import { buildImportStatement } from './utils'
import { buildImportStatement, codeFrameError } from './utils'
import { usedComponents } from './wxml'
import { PageLifecycle } from './lifecycle'

function parseScript (script: string) {
export function parseScript (script: string) {
const { ast } = transform(script, {
parserOpts: {
sourceType: 'module',
Expand All @@ -22,32 +23,77 @@ function parseScript (script: string) {
'dynamicImport'
]
}
})
}) as { ast: t.File }
let classDecl!: t.ClassDeclaration
traverse(ast, {
Program (path) {
path.scope.rename('wx', 'Taro')
},
CallExpression (path) {
const callee = path.get('callee')
if (callee.isIdentifier({ name: 'Page' })) {
parsePage(path)
classDecl = parsePage(path)!
path.insertAfter(classDecl)
path.remove()
path.stop()
}
}
})

const taroComponentsImport = buildImportStatement('@tarojs/components', [...usedComponents])
const taroImport = buildImportStatement('@tarojs/taro', [], 'Taro')
ast.program.body.unshift(taroComponentsImport, taroImport)
}

const defaultClassName = 'C'

function parsePage (path: NodePath<t.CallExpression>) {
}
const arg = path.get('arguments')[0]
if (!arg || !arg.isObjectExpression()) {
return
}
const props = arg.get('properties')
const properties = props.filter(p => !p.isSpreadProperty()) as NodePath<t.ObjectProperty | t.ObjectMethod>[]
if (properties.length !== props.length) {
throw new Error('不支持编译在 Page 对象中使用解构(`...` spread property)语法')
}

function renameSetData (path: NodePath<t.CallExpression>, guard?: (node: NodePath<t.Node>) => node is NodePath<t.Identifier>) {
const callee = path.get('callee')
if (callee.isMemberExpression() && callee.get('property').isIdentifier({ name: 'setData' })) {
const obj = callee.get('object')
const property = callee.get('property')
if (obj.isThisExpression()) {
property.replaceWith(t.identifier('setState'))
return
const classBody = properties.map(prop => {
const key = prop.get('key')
const value = prop.get('value')
if (!key.isIdentifier()) {
throw codeFrameError(key.node, 'Page 对象的键值只能是字符串')
}
}
const name = key.node.name
if (name === 'data') {
return t.classProperty(t.identifier('state'), value.node)
}
if (PageLifecycle.has(name)) {
const lifecycle = PageLifecycle.get(name)!
return t.classMethod('method', t.identifier(lifecycle), [], value.node as any)
}
if (prop.isObjectMethod()) {
const body = prop.get('body')
return t.classProperty(t.identifier(name), t.arrowFunctionExpression([], body.node))
}
return t.classProperty(t.identifier(name), value.isFunctionExpression() ? t.arrowFunctionExpression(value.node.params, value.node.body) : value.node)
})

return t.classDeclaration(
t.identifier(defaultClassName),
t.memberExpression(t.identifier('Taro'), t.identifier('Component')),
t.classBody(classBody)
)
}

// function renameSetData (path: NodePath<t.CallExpression>, guard?: (node: NodePath<t.Node>) => node is NodePath<t.Identifier>) {
// const callee = path.get('callee')
// if (callee.isMemberExpression() && callee.get('property').isIdentifier({ name: 'setData' })) {
// const obj = callee.get('object')
// const property = callee.get('property')
// if (obj.isThisExpression()) {
// property.replaceWith(t.identifier('setState'))
// return
// }
// }
// }
17 changes: 17 additions & 0 deletions packages/wx-to-taro/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as template from 'babel-template'
import * as t from 'babel-types'
import { codeFrameColumns } from '@babel/code-frame'

export const buildTemplate = (str: string) => template(str)().expression as t.Expression

Expand All @@ -15,6 +16,22 @@ export function buildImportStatement (source: string, specifiers: string[] = [],
)
}

export function codeFrameError (node, msg: string) {
let errMsg = ''
try {
errMsg = codeFrameColumns(setting.sourceCode, node && node.type && node.loc ? node.loc : node)
} catch (error) {
errMsg = 'failed to locate source'
}
return new Error(`${msg}
-----
${errMsg}`)
}

export const setting = {
sourceCode: ''
}

// tslint:disable-next-line
export const DEFAULT_Component_SET = new Set<string>([
'View',
Expand Down
14 changes: 14 additions & 0 deletions packages/wx-to-taro/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
# yarn lockfile v1


"@babel/code-frame@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
dependencies:
"@babel/highlight" "^7.0.0"

"@babel/code-frame@^7.0.0-beta.35":
version "7.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-rc.2.tgz#12b6daeb408238360744649d16c0e9fa7ab3859e"
Expand All @@ -16,6 +22,14 @@
esutils "^2.0.2"
js-tokens "^4.0.0"

"@babel/highlight@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
dependencies:
chalk "^2.0.0"
esutils "^2.0.2"
js-tokens "^4.0.0"

"@types/babel-generator@^6.25.2":
version "6.25.2"
resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.2.tgz#fa13653ec2d34a4037be9c34dec32ae75bea04cc"
Expand Down

0 comments on commit 053e605

Please sign in to comment.