Skip to content

Commit 62c2ed7

Browse files
vicbjelbourn
authored andcommitted
feat(HtmlParser): better error message when a void tag has content
1 parent 9c6b929 commit 62c2ed7

2 files changed

Lines changed: 47 additions & 7 deletions

File tree

modules/angular2/src/compiler/html_parser.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,21 @@ class TreeBuilder {
128128
attrs.push(this._consumeAttr(this._advance()));
129129
}
130130
var fullName = getElementFullName(prefix, name, this._getParentElement());
131-
var voidElement = false;
131+
var selfClosing = false;
132132
// Note: There could have been a tokenizer error
133133
// so that we don't get a token for the end tag...
134134
if (this.peek.type === HtmlTokenType.TAG_OPEN_END_VOID) {
135135
this._advance();
136-
voidElement = true;
136+
selfClosing = true;
137137
} else if (this.peek.type === HtmlTokenType.TAG_OPEN_END) {
138138
this._advance();
139-
voidElement = false;
139+
selfClosing = false;
140140
}
141141
var end = this.peek.sourceSpan.start;
142142
var el = new HtmlElementAst(fullName, attrs, [],
143143
new ParseSourceSpan(startTagToken.sourceSpan.start, end));
144144
this._pushElement(el);
145-
if (voidElement) {
145+
if (selfClosing) {
146146
this._popElement(fullName);
147147
}
148148
}
@@ -172,18 +172,27 @@ class TreeBuilder {
172172
var fullName =
173173
getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
174174
if (!this._popElement(fullName)) {
175-
this.errors.push(HtmlTreeError.create(fullName, endTagToken.sourceSpan.start,
176-
`Unexpected closing tag "${endTagToken.parts[1]}"`));
175+
let msg;
176+
177+
if (getHtmlTagDefinition(fullName).isVoid) {
178+
msg =
179+
`Void elements do not have end tags (they can not have content) "${endTagToken.parts[1]}"`;
180+
} else {
181+
msg = `Unexpected closing tag "${endTagToken.parts[1]}"`;
182+
}
183+
184+
this.errors.push(HtmlTreeError.create(fullName, endTagToken.sourceSpan.start, msg));
177185
}
178186
}
179187

180188
private _popElement(fullName: string): boolean {
181189
for (let stackIndex = this.elementStack.length - 1; stackIndex >= 0; stackIndex--) {
182-
var el = this.elementStack[stackIndex];
190+
let el = this.elementStack[stackIndex];
183191
if (el.name.toLowerCase() == fullName.toLowerCase()) {
184192
ListWrapper.splice(this.elementStack, stackIndex, this.elementStack.length - stackIndex);
185193
return true;
186194
}
195+
187196
if (!getHtmlTagDefinition(el.name).closedByParent) {
188197
return false;
189198
}

modules/angular2/test/compiler/html_parser_spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ export function main() {
8585
]);
8686
});
8787

88+
it('should tolerate end tags for void elements when they have no content', () => {
89+
expect(humanizeDom(parser.parse('<ng-content></ng-content>', 'TestComp')))
90+
.toEqual([[HtmlElementAst, 'ng-content', 0]]);
91+
});
92+
8893
it('should support optional end tags', () => {
8994
expect(humanizeDom(parser.parse('<div><p>1<p>2</div>', 'TestComp')))
9095
.toEqual([
@@ -209,6 +214,32 @@ export function main() {
209214
expect(humanizeErrors(errors)).toEqual([['p', 'Unexpected closing tag "p"', '0:5']]);
210215
});
211216

217+
it('should report text content in void elements', () => {
218+
let errors = parser.parse('<ng-content>content</ng-content>', 'TestComp').errors;
219+
expect(errors.length).toEqual(1);
220+
expect(humanizeErrors(errors))
221+
.toEqual([
222+
[
223+
'ng-content',
224+
'Void elements do not have end tags (they can not have content) "ng-content"',
225+
'0:19'
226+
]
227+
]);
228+
});
229+
230+
it('should report html content in void elements', () => {
231+
let errors = parser.parse('<ng-content><p></p></ng-content>', 'TestComp').errors;
232+
expect(errors.length).toEqual(1);
233+
expect(humanizeErrors(errors))
234+
.toEqual([
235+
[
236+
'ng-content',
237+
'Void elements do not have end tags (they can not have content) "ng-content"',
238+
'0:19'
239+
]
240+
]);
241+
});
242+
212243
it('should also report lexer errors', () => {
213244
let errors = parser.parse('<!-err--><div></p></div>', 'TestComp').errors;
214245
expect(errors.length).toEqual(2);

0 commit comments

Comments
 (0)