Skip to content

Commit

Permalink
feat(transformer): 父类方法阻止事件冒泡,close #1596
Browse files Browse the repository at this point in the history
  • Loading branch information
yuche committed Jan 9, 2019
1 parent 81d615d commit eb362a7
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 53 deletions.
65 changes: 16 additions & 49 deletions packages/taro-transformer-wx/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import traverse, { Binding, NodePath } from 'babel-traverse'
import generate from 'babel-generator'
import * as fs from 'fs'
import { prettyPrint } from 'html'
import { transform as parse } from 'babel-core'
import * as ts from 'typescript'
import { Transformer } from './class'
import { setting, findFirstIdentifierFromMemberExpression, isContainJSXElement, codeFrameError, isArrayMapCallExpression, pathResolver } from './utils'
import { setting, findFirstIdentifierFromMemberExpression, isContainJSXElement, codeFrameError, isArrayMapCallExpression, getSuperClassCode } from './utils'
import * as t from 'babel-types'
import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID } from './constant'
import { Adapters, setAdapter, Adapter } from './adapter'
import { Options, setTransformOptions } from './options'
import { Options, setTransformOptions, babelTransformOptions } from './options'
import { get as safeGet } from 'lodash'
import { eslintValidation } from './eslint'

const template = require('babel-template')

Expand Down Expand Up @@ -163,29 +161,7 @@ export default function transform (options: Options): TransformResult {
// 导致 Path#getSource|buildCodeFrameError 都无法直接使用
// 原因大概是 babylon.parse 没有生成 File 实例导致 scope 和 path 原型上都没有 `file`
// 将来升级到 babel@7 可以直接用 parse 而不是 transform
const ast = parse(code, {
parserOpts: {
sourceType: 'module',
plugins: [
'classProperties',
'jsx',
'flow',
'flowComment',
'trailingFunctionCommas',
'asyncFunctions',
'exponentiationOperator',
'asyncGenerators',
'objectRestSpread',
'decorators',
'dynamicImport'
] as any[]
},
plugins: [
require('babel-plugin-transform-flow-strip-types'),
[require('babel-plugin-transform-define').default, options.env]
].concat(process.env.ESLINT === 'false' || options.isNormal || options.isTyped ? [] : eslintValidation)
.concat((process.env.NODE_ENV === 'test') ? [] : require('babel-plugin-minify-dead-code'))
}).ast as t.File
const ast = parse(code, babelTransformOptions).ast as t.File
if (options.isNormal) {
return { ast } as any
}
Expand Down Expand Up @@ -233,28 +209,19 @@ export default function transform (options: Options): TransformResult {
},
ClassDeclaration (path) {
mainClass = path
const superClass = path.node.superClass
if (t.isIdentifier(superClass)) {
const binding = path.scope.getBinding(superClass.name)
if (binding && binding.kind === 'module') {
const bindingPath = binding.path.parentPath
if (bindingPath.isImportDeclaration()) {
const source = bindingPath.node.source
try {
const p = pathResolver(source.value, options.sourcePath) + (options.isTyped ? '.js' : '.js')
const code = fs.readFileSync(p, 'utf8')
componentProperies = transform({
isRoot: false,
isApp: false,
code,
isTyped: true,
sourcePath: source.value,
outputPath: source.value
}).componentProperies
} catch (error) {
//
}
}
const superClass = getSuperClassCode(path)
if (superClass) {
try {
componentProperies = transform({
isRoot: false,
isApp: false,
code: superClass.code,
isTyped: true,
sourcePath: superClass.sourcePath,
outputPath: superClass.sourcePath
}).componentProperies
} catch (error) {
//
}
}
},
Expand Down
26 changes: 26 additions & 0 deletions packages/taro-transformer-wx/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Adapters } from './adapter'
import { eslintValidation } from './eslint'
import { TransformOptions } from 'babel-core'

export interface Options {
isRoot?: boolean,
Expand All @@ -21,3 +23,27 @@ export const setTransformOptions = (options: Options) => {
}
}
}

export const babelTransformOptions: TransformOptions = {
parserOpts: {
sourceType: 'module',
plugins: [
'classProperties',
'jsx',
'flow',
'flowComment',
'trailingFunctionCommas',
'asyncFunctions',
'exponentiationOperator',
'asyncGenerators',
'objectRestSpread',
'decorators',
'dynamicImport'
] as any[]
},
plugins: [
require('babel-plugin-transform-flow-strip-types'),
[require('babel-plugin-transform-define').default, transformOptions.env]
].concat(process.env.ESLINT === 'false' || transformOptions.isNormal || transformOptions.isTyped ? [] : eslintValidation)
.concat((process.env.NODE_ENV === 'test') ? [] : require('babel-plugin-minify-dead-code'))
}
33 changes: 30 additions & 3 deletions packages/taro-transformer-wx/src/render.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NodePath, Scope, Visitor } from 'babel-traverse'
import traverse, { NodePath, Scope, Visitor } from 'babel-traverse'
import * as t from 'babel-types'
import { transform as parse } from 'babel-core'
import {
newJSXIfAttr,
reverseBoolean,
Expand All @@ -20,7 +21,8 @@ import {
isVarName,
setParentCondition,
isContainJSXElement,
getSlotName
getSlotName,
getSuperClassCode
} from './utils'
import { difference, get as safeGet, cloneDeep } from 'lodash'
import {
Expand All @@ -40,7 +42,7 @@ import {
ALIPAY_BUBBLE_EVENTS
} from './constant'
import { Adapter, Adapters } from './adapter'
import { transformOptions } from './options'
import { transformOptions, babelTransformOptions } from './options'
import generate from 'babel-generator'
import { LoopRef } from './interface'
const template = require('babel-template')
Expand Down Expand Up @@ -785,6 +787,7 @@ export class RenderParser {
const methodName = findMethodName(value.expression)
methodName && this.usedEvents.add(methodName)
const method = this.methods.get(methodName)
const classDecl = path.findParent(p => p.isClassDeclaration())
const componentName = jsxElementPath.node.openingElement.name
// if (method && t.isIdentifier(method.node.key)) {
// this.usedEvents.add(methodName)
Expand All @@ -797,6 +800,30 @@ export class RenderParser {
if (this.methods.has(methodName)) {
eventShouldBeCatched = isContainStopPropagation(method)
}
if (classDecl && classDecl.isClassDeclaration()) {
const superClass = getSuperClassCode(classDecl)
if (superClass) {
try {
const ast = parse(superClass.code, babelTransformOptions).ast as t.File
traverse(ast, {
ClassMethod (p) {
if (!p.get('key').isIdentifier({ name: methodName })) {
return
}
eventShouldBeCatched = isContainStopPropagation(method)
},
ClassProperty (p) {
if (!p.get('key').isIdentifier({ name: methodName })) {
return
}
eventShouldBeCatched = isContainStopPropagation(method)
}
})
} catch (error) {
//
}
}
}
if (t.isJSXIdentifier(componentName) && !DEFAULT_Component_SET.has(componentName.name)) {
const element = path.parent as t.JSXOpeningElement
if (process.env.NODE_ENV !== 'test' && Adapter.type !== Adapters.alipay) {
Expand Down
29 changes: 28 additions & 1 deletion packages/taro-transformer-wx/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,46 @@ import * as t from 'babel-types'
import generate from 'babel-generator'
import { codeFrameColumns } from '@babel/code-frame'
import { NodePath, Scope } from 'babel-traverse'
import { LOOP_STATE } from './constant'
import { LOOP_STATE, TARO_PACKAGE_NAME } from './constant'
import { cloneDeep } from 'lodash'
import * as fs from 'fs'
import * as path from 'path'
import { buildBlockElement } from './jsx'
import { Adapter } from './adapter'
import { transformOptions } from './options'
const template = require('babel-template')

export const incrementId = () => {
let id = 0
return () => id++
}

export function getSuperClassCode (path: NodePath<t.ClassDeclaration>) {
const superClass = path.node.superClass
if (t.isIdentifier(superClass)) {
const binding = path.scope.getBinding(superClass.name)
if (binding && binding.kind === 'module') {
const bindingPath = binding.path.parentPath
if (bindingPath.isImportDeclaration()) {
const source = bindingPath.node.source
if (source.value === TARO_PACKAGE_NAME) {
return
}
try {
const p = pathResolver(source.value, transformOptions.sourcePath) + (transformOptions.isTyped ? '.tsx' : '.js')
const code = fs.readFileSync(p, 'utf8')
return {
code,
sourcePath: source.value
}
} catch (error) {
return
}
}
}
}
}

export function decodeUnicode (s: string) {
return unescape(s.replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1'))
}
Expand Down

1 comment on commit eb362a7

@mengqingshen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
这块儿是不是有问题,本来是要读取父类模块的代码吧,但 pathResolver 返回的并不是绝对路径,fs.readFileSync 直接读取的话,会找不到文件报错。由于被 try..catch 了,所以没报错,应该一直在报错。

Please sign in to comment.