fixes #5919: [html] Angular 2 directives break HTML syntax highlighting

This commit is contained in:
Martin Aeschlimann
2016-05-10 17:07:30 +02:00
parent be5a691a36
commit 3505aa37bd
2 changed files with 54 additions and 18 deletions
+25 -13
View File
@@ -85,10 +85,14 @@ export class State extends AbstractState {
return false;
}
private nextName(stream:Modes.IStream):string {
private nextElementName(stream:Modes.IStream):string {
return stream.advanceIfRegExp(/^[_:\w][_:\w-.\d]*/).toLowerCase();
}
private nextAttributeName(stream:Modes.IStream):string {
return stream.advanceIfRegExp(/^[^\s"'>/=\x00-\x0F\x7F\x80-\x9F]*/).toLowerCase();
}
public tokenize(stream:Modes.IStream) : Modes.ITokenizationResult {
switch(this.kind){
@@ -133,7 +137,7 @@ export class State extends AbstractState {
break;
case States.OpeningEndTag:
var tagName = this.nextName(stream);
var tagName = this.nextElementName(stream);
if (tagName.length > 0){
return {
type: State.escapeTagName(tagName),
@@ -149,7 +153,7 @@ export class State extends AbstractState {
}
case States.OpeningStartTag:
this.lastTagName = this.nextName(stream);
this.lastTagName = this.nextElementName(stream);
if (this.lastTagName.length > 0) {
this.lastAttributeName = null;
if ('script' === this.lastTagName || 'style' === this.lastTagName) {
@@ -165,18 +169,22 @@ export class State extends AbstractState {
case States.WithinTag:
if (stream.skipWhitespace2() || stream.eos()) {
this.lastAttributeName = ''; // remember that we have seen a whitespace
return { type: '' };
} else {
var name:string = this.nextName(stream);
if (name.length > 0) {
this.lastAttributeName = name;
this.kind = States.AttributeName;
return { type: htmlTokenTypes.ATTRIB_NAME };
} else if (stream.advanceIfString2('/>')) {
this.kind = States.Content;
return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true };
} if (stream.advanceIfCharCode2('>'.charCodeAt(0))) {
if (this.lastAttributeName === '') {
var name = this.nextAttributeName(stream);
if (name.length > 0) {
this.lastAttributeName = name;
this.kind = States.AttributeName;
return { type: htmlTokenTypes.ATTRIB_NAME };
}
}
if (stream.advanceIfString2('/>')) {
this.kind = States.Content;
return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true };
}
if (stream.advanceIfCharCode2('>'.charCodeAt(0))) {
if (tagsEmbeddingContent.indexOf(this.lastTagName) !== -1) {
this.kind = States.WithinEmbeddedContent;
return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true };
@@ -200,6 +208,7 @@ export class State extends AbstractState {
return { type: htmlTokenTypes.DELIM_ASSIGN };
} else {
this.kind = States.WithinTag;
this.lastAttributeName = '';
return this.tokenize(stream); // no advance yet - jump to WithinTag
}
@@ -231,6 +240,7 @@ export class State extends AbstractState {
this.kind = States.WithinTag;
this.attributeValue = '';
this.attributeValueQuote = '';
this.lastAttributeName = null;
} else {
var part = stream.next();
this.attributeValue += part;
@@ -241,6 +251,7 @@ export class State extends AbstractState {
let attributeValue = stream.advanceIfRegExp(/^[^\s"'`=<>]+/);
if (attributeValue.length > 0) {
this.kind = States.WithinTag;
this.lastAttributeName = null;
return { type: htmlTokenTypes.ATTRIB_VALUE };
}
var ch = stream.peek();
@@ -251,6 +262,7 @@ export class State extends AbstractState {
return { type: htmlTokenTypes.ATTRIB_VALUE };
} else {
this.kind = States.WithinTag;
this.lastAttributeName = null;
return this.tokenize(stream); // no advance yet - jump to WithinTag
}
}
+29 -5
View File
@@ -466,7 +466,7 @@ suite('Colorizing - HTML', () => {
]);
});
test('Tag with empty atrributes', () => {
test('Tag with empty attributes', () => {
modesUtil.assertTokenization(tokenizationSupport, [{
line: '<abc foo="">',
tokens: [
@@ -580,7 +580,7 @@ suite('Colorizing - HTML', () => {
]);
});
test('Tag with Invalid Attribute Name', () => {
test('Tag with Interesting Attribute Name', () => {
modesUtil.assertTokenization(tokenizationSupport, [{
line: '<abc foo!@#="bar">',
tokens: [
@@ -588,14 +588,38 @@ suite('Colorizing - HTML', () => {
{ startIndex:1, type: getTag('abc') },
{ startIndex:4, type: '' },
{ startIndex:5, type: ATTRIB_NAME },
{ startIndex:8, type: '' },
{ startIndex:13, type: ATTRIB_NAME },
{ startIndex:16, type: '' },
{ startIndex:11, type: DELIM_ASSIGN },
{ startIndex:12, type: ATTRIB_VALUE },
{ startIndex:17, type: DELIM_START }
]}
]);
});
test('Tag with Angular Attribute Name', () => {
modesUtil.assertTokenization(tokenizationSupport, [{
line: '<abc #myinput (click)="bar" [value]="someProperty" *ngIf="someCondition">',
tokens: [
{ startIndex:0, type: DELIM_START },
{ startIndex:1, type: getTag('abc') },
{ startIndex:4, type: '' },
{ startIndex:5, type: ATTRIB_NAME },
{ startIndex:13, type: '' },
{ startIndex:14, type: ATTRIB_NAME },
{ startIndex:21, type: DELIM_ASSIGN },
{ startIndex:22, type: ATTRIB_VALUE },
{ startIndex:27, type: '' },
{ startIndex:28, type: ATTRIB_NAME },
{ startIndex:35, type: DELIM_ASSIGN },
{ startIndex:36, type: ATTRIB_VALUE },
{ startIndex:50, type: '' },
{ startIndex:51, type: ATTRIB_NAME },
{ startIndex:56, type: DELIM_ASSIGN },
{ startIndex:57, type: ATTRIB_VALUE },
{ startIndex:72, type: DELIM_START }
]}
]);
});
test('Tag with Invalid Attribute Value', () => {
modesUtil.assertTokenization(tokenizationSupport, [{
line: '<abc foo=">',