diff --git a/src/parse/read/directives.ts b/src/parse/read/directives.ts index a3ff94c68c..c9c79a85c3 100644 --- a/src/parse/read/directives.ts +++ b/src/parse/read/directives.ts @@ -4,53 +4,52 @@ import { Parser } from '../index'; const DIRECTIVES = { Ref: { - names: [ 'ref' ], + names: ['ref'], attribute(start, end, type, name) { return { start, end, type, name }; - } + }, + allowedExpressionTypes: [], + error: 'ref directives cannot have a value' }, EventHandler: { - names: [ 'on' ], - allowedExpressionTypes: [ 'CallExpression' ], + names: ['on'], + attribute(start, end, type, name, expression) { + return { start, end, type, name, expression }; + }, + allowedExpressionTypes: ['CallExpression'], + error: 'Expected a method call' }, Binding: { - names: [ '', 'bind' ], - allowedExpressionTypes: [ 'Identifier', 'MemberExpression' ], - attribute(start, end, type, name, expression, directiveName) { - let value; - - // :foo is shorthand for foo='{{foo}}' - if (!directiveName) { - const valueStart = start + 1; - const valueEnd = start + name.length; - type = 'Attribute'; - value = getShorthandValue(start + 1, name); - } else { - value = expression || { + names: ['bind'], + attribute(start, end, type, name, expression) { + return { + start, end, type, name, + value: expression || { type: 'Identifier', start: start + 5, end, name, - }; - } - - return { start, end, type, name, value }; + } + }; }, + allowedExpressionTypes: ['Identifier', 'MemberExpression'], + error: 'Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)' }, Transition: { - names: [ 'in', 'out', 'transition' ], - allowedExpressionTypes: [ 'ObjectExpression' ], + names: ['in', 'out', 'transition'], attribute(start, end, type, name, expression, directiveName) { return { start, end, type, name, expression, intro: directiveName === 'in' || directiveName === 'transition', outro: directiveName === 'out' || directiveName === 'transition', - } + }; }, - }, + allowedExpressionTypes: ['ObjectExpression'], + error: 'Transition argument must be an object literal, e.g. `{ duration: 400 }`' + } }; @@ -83,7 +82,7 @@ function readExpression(parser: Parser, start: number, quoteMark: string|null) { } else { str += char; } - } else if (/[\s\r\n\/>]/.test(char)) { + } else if (/[\s\/>]/.test(char)) { break; } else { str += char; @@ -106,12 +105,23 @@ export function readDirective( start: number, attrName: string ) { - const [ directiveName, name ] = attrName.split(':'); + const [directiveName, name] = attrName.split(':'); if (name === undefined) return; // No colon in the name - + + if (directiveName === '') { + // not a directive — :foo is short for foo={{foo}} + return { + start: start, + end: start + name.length + 1, + type: 'Attribute', + name, + value: getShorthandValue(start + 1, name) + }; + } + const type = lookupByName[directiveName]; if (!type) return; // not a registered directive - + const directive = DIRECTIVES[type]; let expression = null; @@ -133,21 +143,11 @@ export function readDirective( expression = readExpression(parser, expressionStart, quoteMark); if (directive.allowedExpressionTypes.indexOf(expression.type) === -1) { - parser.error(`Expected ${directive.allowedExpressionTypes.join(' or ')}`, expressionStart); + parser.error(directive.error, expressionStart); } } - if (directive.attribute) { - return directive.attribute(start, parser.index, type, name, expression, directiveName); - } else { - return { - start, - end: parser.index, - type: type, - name, - expression, - }; - } + return directive.attribute(start, parser.index, type, name, expression, directiveName); } diff --git a/test/parser/samples/error-binding-rvalue/error.json b/test/parser/samples/error-binding-rvalue/error.json index 2f25dbef0d..63f6711cd1 100644 --- a/test/parser/samples/error-binding-rvalue/error.json +++ b/test/parser/samples/error-binding-rvalue/error.json @@ -1,5 +1,5 @@ { - "message": "Expected Identifier or MemberExpression", + "message": "Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)", "pos": 19, "loc": { "line": 1, diff --git a/test/parser/samples/error-event-handler/error.json b/test/parser/samples/error-event-handler/error.json index 45032c2707..f5e603b06a 100644 --- a/test/parser/samples/error-event-handler/error.json +++ b/test/parser/samples/error-event-handler/error.json @@ -1,5 +1,5 @@ { - "message": "Expected CallExpression", + "message": "Expected a method call", "loc": { "line": 1, "column": 15 diff --git a/test/parser/samples/error-ref-value/error.json b/test/parser/samples/error-ref-value/error.json new file mode 100644 index 0000000000..963c4656eb --- /dev/null +++ b/test/parser/samples/error-ref-value/error.json @@ -0,0 +1,8 @@ +{ + "message": "ref directives cannot have a value", + "loc": { + "line": 1, + "column": 14 + }, + "pos": 14 +} \ No newline at end of file diff --git a/test/parser/samples/error-ref-value/input.html b/test/parser/samples/error-ref-value/input.html new file mode 100644 index 0000000000..8ad19958e3 --- /dev/null +++ b/test/parser/samples/error-ref-value/input.html @@ -0,0 +1 @@ +
\ No newline at end of file