mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
[html] add endTagStart to Node
This commit is contained in:
parent
49dfae7e00
commit
06727ce174
|
@ -11,10 +11,12 @@ import { isEmptyElement, isSameTag } from './htmlTags';
|
|||
export class Node {
|
||||
public tag: string;
|
||||
public closed: boolean;
|
||||
public endTagStart: number;
|
||||
constructor(public start: number, public end: number, public children: Node[], public parent: Node) {
|
||||
this.closed = false;
|
||||
|
||||
}
|
||||
private get lastChild(): Node { return this.children.length ? this.children[this.children.length - 1] : void 0; }
|
||||
public get firstChild(): Node { return this.children[0]; }
|
||||
public get lastChild(): Node { return this.children.length ? this.children[this.children.length - 1] : void 0; }
|
||||
|
||||
public findNodeBefore(offset:number) : Node {
|
||||
let idx = findFirst(this.children, c => offset <= c.start) - 1;
|
||||
|
@ -33,11 +35,23 @@ export class Node {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public findNodeAt(offset:number) : Node {
|
||||
let idx = findFirst(this.children, c => offset <= c.start) - 1;
|
||||
if (idx >= 0) {
|
||||
let child = this.children[idx];
|
||||
if (offset > child.start && offset <= child.end) {
|
||||
return child.findNodeBefore(offset);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export interface HTMLDocument {
|
||||
roots: Node[];
|
||||
findNodeBefore(offset:number) : Node;
|
||||
findNodeAt(offset:number) : Node;
|
||||
}
|
||||
|
||||
export function parse(text: string) : HTMLDocument {
|
||||
|
@ -76,13 +90,16 @@ export function parse(text: string) : HTMLDocument {
|
|||
}
|
||||
if (curr !== htmlDocument) {
|
||||
curr.closed = true;
|
||||
curr.endTagStart = endTagStart;
|
||||
}
|
||||
break;
|
||||
case TokenType.StartTagSelfClose:
|
||||
if (curr !== htmlDocument) {
|
||||
curr.closed = true;
|
||||
curr.end = scanner.getTokenEnd();
|
||||
curr = curr.parent;
|
||||
}
|
||||
// fallthrough
|
||||
break;
|
||||
case TokenType.EndTagClose:
|
||||
if (curr !== htmlDocument) {
|
||||
curr.end = scanner.getTokenEnd();
|
||||
|
@ -94,13 +111,13 @@ export function parse(text: string) : HTMLDocument {
|
|||
}
|
||||
while (curr !== htmlDocument) {
|
||||
curr.end = text.length;
|
||||
curr.closed = false;
|
||||
curr = curr.parent;
|
||||
}
|
||||
return {
|
||||
roots: htmlDocument.children,
|
||||
findNodeBefore: (offset:number) => {
|
||||
return htmlDocument.findNodeBefore(offset);
|
||||
}
|
||||
findNodeBefore: htmlDocument.findNodeBefore.bind(htmlDocument),
|
||||
findNodeAt: htmlDocument.findNodeAt.bind(htmlDocument)
|
||||
};
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ import {Node, HTMLDocument, parse} from '../parser/htmlParser';
|
|||
suite('HTML Parser', () => {
|
||||
|
||||
function toJSON(node: Node): any {
|
||||
return { tag: node.tag, start: node.start, end: node.end, closed: node.closed, children: node.children.map(toJSON) };
|
||||
return { tag: node.tag, start: node.start, end: node.end, endTagStart: node.endTagStart, closed: node.closed, children: node.children.map(toJSON) };
|
||||
}
|
||||
|
||||
function assertDocument(input: string, expected: any) {
|
||||
|
@ -25,29 +25,29 @@ suite('HTML Parser', () => {
|
|||
}
|
||||
|
||||
test('Simple', () => {
|
||||
assertDocument('<html></html>', [ { tag: 'html', start: 0, end: 13, closed: true, children: []}] );
|
||||
assertDocument('<html><body></body></html>', [ { tag: 'html', start: 0, end: 26, closed: true, children: [ { tag: 'body', start: 6, end: 19, closed: true, children: [] }]}] );
|
||||
assertDocument('<html><head></head><body></body></html>', [ { tag: 'html', start: 0, end: 39, closed: true, children: [ { tag: 'head', start: 6, end: 19, closed: true, children: [] }, { tag: 'body', start: 19, end: 32, closed: true, children: [] }]}] );
|
||||
assertDocument('<html></html>', [ { tag: 'html', start: 0, end: 13, endTagStart: 6, closed: true, children: []}] );
|
||||
assertDocument('<html><body></body></html>', [ { tag: 'html', start: 0, end: 26, endTagStart: 19, closed: true, children: [ { tag: 'body', start: 6, end: 19, endTagStart: 12, closed: true, children: [] }]}] );
|
||||
assertDocument('<html><head></head><body></body></html>', [ { tag: 'html', start: 0, end: 39, endTagStart: 32, closed: true, children: [ { tag: 'head', start: 6, end: 19, endTagStart: 12, closed: true, children: [] }, { tag: 'body', start: 19, end: 32, endTagStart: 25, closed: true, children: [] }]}] );
|
||||
});
|
||||
|
||||
test('SelfClose', () => {
|
||||
assertDocument('<br/>', [ { tag: 'br', start: 0, end: 5, closed: true, children: []}] );
|
||||
assertDocument('<div><br/><span></span></div>', [ { tag: 'div', start: 0, end: 29, closed: true, children: [{ tag: 'br', start: 5, end: 10, closed: true, children: [] }, { tag: 'span', start: 10, end: 23, closed: true, children: [] }]}] );
|
||||
assertDocument('<br/>', [ { tag: 'br', start: 0, end: 5, endTagStart: void 0, closed: true, children: []}] );
|
||||
assertDocument('<div><br/><span></span></div>', [ { tag: 'div', start: 0, end: 29, endTagStart: 23, closed: true, children: [{ tag: 'br', start: 5, end: 10, endTagStart: void 0, closed: true, children: [] }, { tag: 'span', start: 10, end: 23, endTagStart: 16, closed: true, children: [] }]}] );
|
||||
});
|
||||
|
||||
test('EmptyTag', () => {
|
||||
assertDocument('<meta>', [ { tag: 'meta', start: 0, end: 6, closed: true, children: []}] );
|
||||
assertDocument('<div><input type="button"><span><br><br></span></div>', [ { tag: 'div', start: 0, end: 53, closed: true, children: [
|
||||
{ tag: 'input', start: 5, end: 26, closed: true, children: [] },
|
||||
{ tag: 'span', start: 26, end: 47, closed: true, children: [{ tag: 'br', start: 32, end: 36, closed: true, children: [] }, { tag: 'br', start: 36, end: 40, closed: true, children: [] }] }
|
||||
assertDocument('<meta>', [ { tag: 'meta', start: 0, end: 6, endTagStart: void 0, closed: true, children: []}] );
|
||||
assertDocument('<div><input type="button"><span><br><br></span></div>', [ { tag: 'div', start: 0, end: 53, endTagStart: 47, closed: true, children: [
|
||||
{ tag: 'input', start: 5, end: 26, endTagStart: void 0, closed: true, children: [] },
|
||||
{ tag: 'span', start: 26, end: 47, endTagStart: 40, closed: true, children: [{ tag: 'br', start: 32, end: 36, endTagStart: void 0, closed: true, children: [] }, { tag: 'br', start: 36, end: 40, endTagStart: void 0, closed: true, children: [] }] }
|
||||
]}] );
|
||||
});
|
||||
test('MissingTags', () => {
|
||||
assertDocument('</meta>', [] );
|
||||
assertDocument('<div></div></div>', [ { tag: 'div', start: 0, end: 11, closed: true, children: [] }] );
|
||||
assertDocument('<div><div></div>', [ { tag: 'div', start: 0, end: 16, closed: false, children: [ { tag: 'div', start: 5, end: 16, closed: true, children: [] } ] }] );
|
||||
assertDocument('<title><div></title>', [ { tag: 'title', start: 0, end: 20, closed: true, children: [ { tag: 'div', start: 7, end: 12, closed: false, children: [] } ] }] );
|
||||
assertDocument('<h1><div><span></h1>', [ { tag: 'h1', start: 0, end: 20, closed: true, children: [ { tag: 'div', start: 4, end: 15, closed: false, children: [ { tag: 'span', start: 9, end: 15, closed: false, children: [] }] } ] }] );
|
||||
assertDocument('<div></div></div>', [ { tag: 'div', start: 0, end: 11, endTagStart: 5, closed: true, children: [] }] );
|
||||
assertDocument('<div><div></div>', [ { tag: 'div', start: 0, end: 16, endTagStart: void 0, closed: false, children: [ { tag: 'div', start: 5, end: 16, endTagStart: 10, closed: true, children: [] } ] }] );
|
||||
assertDocument('<title><div></title>', [ { tag: 'title', start: 0, end: 20, endTagStart: 12, closed: true, children: [ { tag: 'div', start: 7, end: 12, endTagStart: void 0, closed: false, children: [] } ] }] );
|
||||
assertDocument('<h1><div><span></h1>', [ { tag: 'h1', start: 0, end: 20, endTagStart: 15, closed: true, children: [ { tag: 'div', start: 4, end: 15, endTagStart: void 0, closed: false, children: [ { tag: 'span', start: 9, end: 15, endTagStart: void 0, closed: false, children: [] }] } ] }] );
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue