diff --git a/src/parse/read/directives.js b/src/parse/read/directives.js index 28adc3078a..9cc09392d7 100644 --- a/src/parse/read/directives.js +++ b/src/parse/read/directives.js @@ -1,19 +1,11 @@ -import { parse, parseExpressionAt } from 'acorn'; +import { parseExpressionAt } from 'acorn'; import spaces from '../../utils/spaces.js'; -export function readEventHandlerDirective ( parser, start, name ) { - const quoteMark = ( - parser.eat( `'` ) ? `'` : - parser.eat( `"` ) ? `"` : - null - ); - - const expressionStart = parser.index; - +function readExpression ( parser, start, quoteMark ) { let str = ''; let escaped = false; - for ( let i = expressionStart; i < parser.template.length; i += 1 ) { + for ( let i = start; i < parser.template.length; i += 1 ) { const char = parser.template[i]; if ( quoteMark ) { @@ -21,7 +13,6 @@ export function readEventHandlerDirective ( parser, start, name ) { if ( escaped ) { str += quoteMark; } else { - parser.index = i + 1; break; } } else if ( escaped ) { @@ -35,7 +26,6 @@ export function readEventHandlerDirective ( parser, start, name ) { } else if ( /\s/.test( char ) ) { - parser.index = i; break; } @@ -44,13 +34,25 @@ export function readEventHandlerDirective ( parser, start, name ) { } } - const ast = parse( spaces( expressionStart ) + str ); + const expression = parseExpressionAt( spaces( start ) + str, start ); + parser.index = expression.end; - if ( ast.body.length > 1 ) { - parser.error( `Event handler should be a single call expression`, ast.body[1].start ); - } + parser.allowWhitespace(); + if ( quoteMark ) parser.eat( quoteMark, true ); - const expression = ast.body[0].expression; + return expression; +} + +export function readEventHandlerDirective ( parser, start, name ) { + const quoteMark = ( + parser.eat( `'` ) ? `'` : + parser.eat( `"` ) ? `"` : + null + ); + + const expressionStart = parser.index; + + const expression = readExpression( parser, expressionStart, quoteMark ); if ( expression.type !== 'CallExpression' ) { parser.error( `Expected call expression`, expressionStart ); @@ -127,3 +129,29 @@ export function readBindingDirective ( parser, start, name ) { value }; } + +export function readTransitionDirective ( parser, start, name, type ) { + const quoteMark = ( + parser.eat( `'` ) ? `'` : + parser.eat( `"` ) ? `"` : + null + ); + + const expressionStart = parser.index; + + const expression = readExpression( parser, expressionStart, quoteMark ); + + if ( expression.type !== 'ObjectExpression' ) { + parser.error( `Expected object expression`, expressionStart ); + } + + return { + start, + end: parser.index, + type: 'Transition', + name, + intro: type === 'in' || type === 'transition', + outro: type === 'out' || type === 'transition', + expression + }; +} \ No newline at end of file diff --git a/src/parse/state/tag.js b/src/parse/state/tag.js index 48e8cd197e..901b250833 100644 --- a/src/parse/state/tag.js +++ b/src/parse/state/tag.js @@ -1,7 +1,7 @@ import readExpression from '../read/expression.js'; import readScript from '../read/script.js'; import readStyle from '../read/style.js'; -import { readEventHandlerDirective, readBindingDirective } from '../read/directives.js'; +import { readEventHandlerDirective, readBindingDirective, readTransitionDirective } from '../read/directives.js'; import { trimStart, trimEnd } from '../../utils/trim.js'; import { decodeCharacterReferences } from '../utils/html.js'; import isVoidElementName from '../../utils/isVoidElementName.js'; @@ -253,6 +253,12 @@ function readAttribute ( parser, uniqueNames ) { }; } + const match = /^(in|out|transition):/.exec( name ); + if ( match ) { + parser.eat( '=', true ); + return readTransitionDirective( parser, start, name.slice( match[0].length ), match[1] ); + } + let value; // :foo is shorthand for foo='{{foo}}' diff --git a/test/parser/samples/transition-intro/input.html b/test/parser/samples/transition-intro/input.html new file mode 100644 index 0000000000..db14cfcb2f --- /dev/null +++ b/test/parser/samples/transition-intro/input.html @@ -0,0 +1 @@ +