nwex.de/html/tokenizer/token.ts

61 lines
1.9 KiB
TypeScript
Raw Normal View History

export const enum Type {
DOCTYPE = 'DOCTYPE',
StartTag = 'start tag',
EndTag = 'end tag',
Comment = 'comment',
Character = 'character',
EndOfFile = 'end-of-file'
}
export type Attribute = { name: NonNullable<string>, value: NonNullable<string> };
export class AttributeList {
private attributes: Array<Attribute>;
public constructor() {
this.attributes = new Array<Attribute>();
}
public get current(): Attribute {
return this.attributes[this.attributes.length - 1];
}
public get list(): Array<Attribute> {
return this.attributes;
}
public nonEmpty(): boolean {
return this.list.length !== 0;
}
public append(attribute: Attribute): void {
this.attributes.push(attribute);
}
}
export type Token = { type: Type.DOCTYPE, name?: string, publicIdentifier?: string, systemIdentifier?: string, forceQuirks?: true } |
{ type: Type.StartTag, name: NonNullable<string>, selfClosing?: true, attributes: AttributeList } |
{ type: Type.EndTag, name: NonNullable<string>, selfClosing?: true, attributes: AttributeList } |
{ type: Type.Comment, data: NonNullable<string> } |
{ type: Type.Character, data: NonNullable<string> } |
{ type: Type.EndOfFile };
export function stringify(token: Token): string {
switch (token.type) {
case Type.Character: return token.data;
case Type.Comment: return `<!--${token.data}-->`;
case Type.DOCTYPE: return `<!DOCTYPE ${token.name}>`;
case Type.EndOfFile: return 'EOF';
case Type.EndTag: return `</${token.name}>`;
case Type.StartTag: {
let string = `<${token.name}`;
for (const attribute of token.attributes.list)
string += ` ${attribute.name}="${attribute.value}"`;
if (token.selfClosing) return `${string} />`;
return `${string}>`;
};
}
}