diff --git a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js index 71c08eb11b84d1d65a498b21c8490c6afbe3d133..7238037e808bf9ac48d39eaf995f71a264743665 100644 --- a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js +++ b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js @@ -584,7 +584,12 @@ describe('mp:compiler-extra', () => { `` ) }) - it('generate event ', () => { + it('generate event ', () => { + assertCodegen( + ``, + `` + ) + assertCodegen( `{{item.title}}`, `{{item.title}}` diff --git a/packages/uni-template-compiler/__tests__/demo.js b/packages/uni-template-compiler/__tests__/demo.js index cfca7bbdc6798af3c887323f1b7ce7eb02a79382..7ead891078114e8cafa93cfb04a25e33fc90f5fb 100644 --- a/packages/uni-template-compiler/__tests__/demo.js +++ b/packages/uni-template-compiler/__tests__/demo.js @@ -2,7 +2,7 @@ const compiler = require('../lib') const res = compiler.compile( ` - + `, { resourcePath: '/User/fxy/Documents/test.wxml', mp: { diff --git a/packages/uni-template-compiler/lib/index.js b/packages/uni-template-compiler/lib/index.js index 9e6b3cd5e442dc08dbf808c53679e7fcb90a01c0..084a219726b34d494ef21c575b60330f2d483172 100644 --- a/packages/uni-template-compiler/lib/index.js +++ b/packages/uni-template-compiler/lib/index.js @@ -55,10 +55,18 @@ module.exports = { } // console.log(`function render(){${res.render}}`) const ast = parser.parse(`function render(){${res.render}}`) - - res.render = generateScript(traverseScript(ast, state), state) - - let template = generateTemplate(traverseTemplate(ast, state), state) + let template = '' + + try { + res.render = generateScript(traverseScript(ast, state), state) + template = generateTemplate(traverseTemplate(ast, state), state) + } catch (e) { + console.error(e) + throw new Error('Compile failed at ' + options.resourcePath.replace( + path.extname(options.resourcePath), + '.vue' + )) + } res.specialMethods = state.options.specialMethods || new Set() delete state.options.specialMethods diff --git a/packages/uni-template-compiler/lib/script/traverse/data/event.js b/packages/uni-template-compiler/lib/script/traverse/data/event.js index 22ec016c584cf90780417d629f5fe469ff97f179..8efef87e721aed53bf09e2294987c6f1d8afaa3e 100644 --- a/packages/uni-template-compiler/lib/script/traverse/data/event.js +++ b/packages/uni-template-compiler/lib/script/traverse/data/event.js @@ -167,7 +167,7 @@ function getMethodName (methodName) { return methodName === '__HOLDER__' ? '' : methodName } -function parseEventByCallExpression (callExpr, methods) { +function parseEventByCallExpression (callExpr, methods) { let methodName = callExpr.callee.name if (methodName === '$set') { methodName = INTERNAL_SET_SYNC @@ -197,12 +197,12 @@ function parseEventByCallExpression (callExpr, methods) { arrayExpression.push(t.arrayExpression(argsExpression)) } } - methods.push(t.arrayExpression(arrayExpression)) + methods.push(t.arrayExpression(arrayExpression)) } function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, tagName, ret) { const key = keyPath.node - let type = key.value || key.name + let type = key.value || key.name || '' const isCustom = isComponent && !isNativeOn @@ -211,124 +211,126 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, let isPassive = false let isOnce = false - isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive - type = isPassive ? type.slice(1) : type + let methods = [] - isOnce = type.charAt(0) === VUE_EVENT_MODIFIERS.once // Prefixed last, checked first - type = isOnce ? type.slice(1) : type + if (type) { + isPassive = type.charAt(0) === VUE_EVENT_MODIFIERS.passive + type = isPassive ? type.slice(1) : type - isCapture = type.charAt(0) === VUE_EVENT_MODIFIERS.capture - type = isCapture ? type.slice(1) : type + isOnce = type.charAt(0) === VUE_EVENT_MODIFIERS.once // Prefixed last, checked first + type = isOnce ? type.slice(1) : type - const specialEvents = state.options.platform.specialEvents - const isSpecialEvent = specialEvents[tagName] && Object.keys(specialEvents[tagName]).includes(type) + isCapture = type.charAt(0) === VUE_EVENT_MODIFIERS.capture + type = isCapture ? type.slice(1) : type - let methods = [] + const specialEvents = state.options.platform.specialEvents + const isSpecialEvent = specialEvents[tagName] && Object.keys(specialEvents[tagName]).includes(type) - if (!valuePath.isArrayExpression()) { - valuePath = [valuePath] - } else { - valuePath = valuePath.get('elements') - } + if (!valuePath.isArrayExpression()) { + valuePath = [valuePath] + } else { + valuePath = valuePath.get('elements') + } - valuePath.forEach(funcPath => { - if ( // wxs event - funcPath.isMemberExpression() && - t.isIdentifier(funcPath.node.object) && - state.options.filterModules.includes(funcPath.node.object.name) - ) { - const { - getEventType, - formatEventType - } = state.options.platform - const wxsEventType = formatEventType(getEventType(type)) - if (key.value) { - key.value = wxsEventType - } else { - key.name = wxsEventType - } - } else if (funcPath.isIdentifier()) { // on:{click:handle} - if (!isSpecialEvent) { - const arrayExpression = [t.stringLiteral(getMethodName(funcPath.node.name))] - if (!isCustom) { // native events - arrayExpression.push(defaultArgs) + valuePath.forEach(funcPath => { + if ( // wxs event + funcPath.isMemberExpression() && + t.isIdentifier(funcPath.node.object) && + state.options.filterModules.includes(funcPath.node.object.name) + ) { + const { + getEventType, + formatEventType + } = state.options.platform + const wxsEventType = formatEventType(getEventType(type)) + if (key.value) { + key.value = wxsEventType + } else { + key.name = wxsEventType } - methods.push(t.arrayExpression(arrayExpression)) - } else { - if (!state.options.specialMethods) { - state.options.specialMethods = new Set() + } else if (funcPath.isIdentifier()) { // on:{click:handle} + if (!isSpecialEvent) { + const arrayExpression = [t.stringLiteral(getMethodName(funcPath.node.name))] + if (!isCustom) { // native events + arrayExpression.push(defaultArgs) + } + methods.push(t.arrayExpression(arrayExpression)) + } else { + if (!state.options.specialMethods) { + state.options.specialMethods = new Set() + } + state.options.specialMethods.add(funcPath.node.name) } - state.options.specialMethods.add(funcPath.node.name) - } - } else if (isSpecialEvent) { - state.errors.add( - `${tagName} 组件 ${type} 事件仅支持 @${type}="methodName" 方式绑定` - ) - } else if (funcPath.isArrowFunctionExpression()) { // e=>count++ - methods.push(addEventExpressionStatement(funcPath, state, isCustom)) - } else { - let anonymous = true + } else if (isSpecialEvent) { + state.errors.add( + `${tagName} 组件 ${type} 事件仅支持 @${type}="methodName" 方式绑定` + ) + } else if (funcPath.isArrowFunctionExpression()) { // e=>count++ + methods.push(addEventExpressionStatement(funcPath, state, isCustom)) + } else { + let anonymous = true - // "click":function($event) {click1(item);click2(item);} - const body = funcPath.node.body.body - if (body.length) { - const exprStatements = body.filter(node => { - return t.isExpressionStatement(node) && t.isCallExpression(node.expression) - }) - if (exprStatements.length === body.length) { - anonymous = false - exprStatements.forEach(exprStatement => { - parseEventByCallExpression(exprStatement.expression, methods) + // "click":function($event) {click1(item);click2(item);} + const body = funcPath.node.body.body + if (body.length) { + const exprStatements = body.filter(node => { + return t.isExpressionStatement(node) && t.isCallExpression(node.expression) }) - } - } - - anonymous && funcPath.traverse({ - noScope: true, - MemberExpression (path) { - if (path.node.object.name === '$event' && path.node.property.name === - 'stopPropagation') { - isCatch = true - path.stop() - } - }, - AssignmentExpression (path) { // "update:title": function($event) {title = $event} - const left = path.node.left - const right = path.node.right - // v-bind:title.sync="title" - if (t.isIdentifier(left) && - t.isIdentifier(right) && - right.name === '$event' && - type.indexOf('update:') === 0) { - methods.push(t.arrayExpression( // ['$set',['title','$event']] - [ - t.stringLiteral(INTERNAL_SET_SYNC), - t.arrayExpression([ - t.identifier(left.name), - t.stringLiteral(left.name), - t.stringLiteral('$event') - ]) - ] - )) + if (exprStatements.length === body.length) { anonymous = false - path.stop() + exprStatements.forEach(exprStatement => { + parseEventByCallExpression(exprStatement.expression, methods) + }) } - }, - ReturnStatement (path) { - const argument = path.node.argument - if (t.isCallExpression(argument)) { - if (t.isIdentifier(argument.callee)) { + } + + anonymous && funcPath.traverse({ + noScope: true, + MemberExpression (path) { + if (path.node.object.name === '$event' && path.node.property.name === + 'stopPropagation') { + isCatch = true + path.stop() + } + }, + AssignmentExpression (path) { // "update:title": function($event) {title = $event} + const left = path.node.left + const right = path.node.right + // v-bind:title.sync="title" + if (t.isIdentifier(left) && + t.isIdentifier(right) && + right.name === '$event' && + type.indexOf('update:') === 0) { + methods.push(t.arrayExpression( // ['$set',['title','$event']] + [ + t.stringLiteral(INTERNAL_SET_SYNC), + t.arrayExpression([ + t.identifier(left.name), + t.stringLiteral(left.name), + t.stringLiteral('$event') + ]) + ] + )) anonymous = false - parseEventByCallExpression(argument, methods) + path.stop() + } + }, + ReturnStatement (path) { + const argument = path.node.argument + if (t.isCallExpression(argument)) { + if (t.isIdentifier(argument.callee)) { + anonymous = false + parseEventByCallExpression(argument, methods) + } } } + }) + if (anonymous) { + methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn)) } - }) - if (anonymous) { - methods.push(addEventExpressionStatement(funcPath, state, isComponent, isNativeOn)) } - } - }) + }) + } return { type, @@ -345,6 +347,10 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, function _processEvent (path, state, isComponent, isNativeOn = false, tagName, ret) { const opts = [] + // remove invalid event + path.node.value.properties = path.node.value.properties.filter(property => { + return property.key.value || property.key.name + }) const len = path.node.value.properties.length for (let i = 0; i < len; i++) { const propertyPath = path.get(`value.properties.${i}`) @@ -439,4 +445,4 @@ module.exports = function processEvent (paths, path, state, isComponent, tagName ) return ret -} +}