Skip to content

Commit 270e1d1

Browse files
authored
Merge pull request #1245 from sveltejs/gh-1242-followup
don't treat :foo as a directive
2 parents 6f866bb + 39694c3 commit 270e1d1

File tree

5 files changed

+52
-43
lines changed

5 files changed

+52
-43
lines changed

src/parse/read/directives.ts

+41-41
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,52 @@ import { Parser } from '../index';
44

55
const DIRECTIVES = {
66
Ref: {
7-
names: [ 'ref' ],
7+
names: ['ref'],
88
attribute(start, end, type, name) {
99
return { start, end, type, name };
10-
}
10+
},
11+
allowedExpressionTypes: [],
12+
error: 'ref directives cannot have a value'
1113
},
1214

1315
EventHandler: {
14-
names: [ 'on' ],
15-
allowedExpressionTypes: [ 'CallExpression' ],
16+
names: ['on'],
17+
attribute(start, end, type, name, expression) {
18+
return { start, end, type, name, expression };
19+
},
20+
allowedExpressionTypes: ['CallExpression'],
21+
error: 'Expected a method call'
1622
},
1723

1824
Binding: {
19-
names: [ '', 'bind' ],
20-
allowedExpressionTypes: [ 'Identifier', 'MemberExpression' ],
21-
attribute(start, end, type, name, expression, directiveName) {
22-
let value;
23-
24-
// :foo is shorthand for foo='{{foo}}'
25-
if (!directiveName) {
26-
const valueStart = start + 1;
27-
const valueEnd = start + name.length;
28-
type = 'Attribute';
29-
value = getShorthandValue(start + 1, name);
30-
} else {
31-
value = expression || {
25+
names: ['bind'],
26+
attribute(start, end, type, name, expression) {
27+
return {
28+
start, end, type, name,
29+
value: expression || {
3230
type: 'Identifier',
3331
start: start + 5,
3432
end,
3533
name,
36-
};
37-
}
38-
39-
return { start, end, type, name, value };
34+
}
35+
};
4036
},
37+
allowedExpressionTypes: ['Identifier', 'MemberExpression'],
38+
error: 'Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)'
4139
},
4240

4341
Transition: {
44-
names: [ 'in', 'out', 'transition' ],
45-
allowedExpressionTypes: [ 'ObjectExpression' ],
42+
names: ['in', 'out', 'transition'],
4643
attribute(start, end, type, name, expression, directiveName) {
4744
return {
4845
start, end, type, name, expression,
4946
intro: directiveName === 'in' || directiveName === 'transition',
5047
outro: directiveName === 'out' || directiveName === 'transition',
51-
}
48+
};
5249
},
53-
},
50+
allowedExpressionTypes: ['ObjectExpression'],
51+
error: 'Transition argument must be an object literal, e.g. `{ duration: 400 }`'
52+
}
5453
};
5554

5655

@@ -83,7 +82,7 @@ function readExpression(parser: Parser, start: number, quoteMark: string|null) {
8382
} else {
8483
str += char;
8584
}
86-
} else if (/[\s\r\n\/>]/.test(char)) {
85+
} else if (/[\s\/>]/.test(char)) {
8786
break;
8887
} else {
8988
str += char;
@@ -106,12 +105,23 @@ export function readDirective(
106105
start: number,
107106
attrName: string
108107
) {
109-
const [ directiveName, name ] = attrName.split(':');
108+
const [directiveName, name] = attrName.split(':');
110109
if (name === undefined) return; // No colon in the name
111-
110+
111+
if (directiveName === '') {
112+
// not a directive — :foo is short for foo={{foo}}
113+
return {
114+
start: start,
115+
end: start + name.length + 1,
116+
type: 'Attribute',
117+
name,
118+
value: getShorthandValue(start + 1, name)
119+
};
120+
}
121+
112122
const type = lookupByName[directiveName];
113123
if (!type) return; // not a registered directive
114-
124+
115125
const directive = DIRECTIVES[type];
116126
let expression = null;
117127

@@ -133,21 +143,11 @@ export function readDirective(
133143

134144
expression = readExpression(parser, expressionStart, quoteMark);
135145
if (directive.allowedExpressionTypes.indexOf(expression.type) === -1) {
136-
parser.error(`Expected ${directive.allowedExpressionTypes.join(' or ')}`, expressionStart);
146+
parser.error(directive.error, expressionStart);
137147
}
138148
}
139149

140-
if (directive.attribute) {
141-
return directive.attribute(start, parser.index, type, name, expression, directiveName);
142-
} else {
143-
return {
144-
start,
145-
end: parser.index,
146-
type: type,
147-
name,
148-
expression,
149-
};
150-
}
150+
return directive.attribute(start, parser.index, type, name, expression, directiveName);
151151
}
152152

153153

test/parser/samples/error-binding-rvalue/error.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"message": "Expected Identifier or MemberExpression",
2+
"message": "Can only bind to an identifier (e.g. `foo`) or a member expression (e.g. `foo.bar` or `foo[baz]`)",
33
"pos": 19,
44
"loc": {
55
"line": 1,

test/parser/samples/error-event-handler/error.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"message": "Expected CallExpression",
2+
"message": "Expected a method call",
33
"loc": {
44
"line": 1,
55
"column": 15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"message": "ref directives cannot have a value",
3+
"loc": {
4+
"line": 1,
5+
"column": 14
6+
},
7+
"pos": 14
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div ref:foo='bar'></div>

0 commit comments

Comments
 (0)