1import type { TAG_ID } from './html.js'; 2 3export enum TokenType { 4 CHARACTER, 5 NULL_CHARACTER, 6 WHITESPACE_CHARACTER, 7 START_TAG, 8 END_TAG, 9 COMMENT, 10 DOCTYPE, 11 EOF, 12 HIBERNATION, 13} 14 15export interface Location { 16 /** One-based line index of the first character. */ 17 startLine: number; 18 /** One-based column index of the first character. */ 19 startCol: number; 20 /** Zero-based first character index. */ 21 startOffset: number; 22 /** One-based line index of the last character. */ 23 endLine: number; 24 /** One-based column index of the last character. Points directly *after* the last character. */ 25 endCol: number; 26 /** Zero-based last character index. Points directly *after* the last character. */ 27 endOffset: number; 28} 29 30export interface LocationWithAttributes extends Location { 31 /** Start tag attributes' location info. */ 32 attrs?: Record<string, Location>; 33 line?: number; 34 col?: number; 35} 36 37export interface ElementLocation extends LocationWithAttributes { 38 /** Element's start tag location info. */ 39 startTag?: Location; 40 /** 41 * Element's end tag location info. 42 * This property is undefined, if the element has no closing tag. 43 */ 44 endTag?: Location; 45} 46 47interface TokenBase { 48 readonly type: TokenType; 49 location: Location | null; 50} 51 52export interface DoctypeToken extends TokenBase { 53 readonly type: TokenType.DOCTYPE; 54 name: string | null; 55 forceQuirks: boolean; 56 publicId: string | null; 57 systemId: string | null; 58} 59 60export interface Attribute { 61 /** The name of the attribute. */ 62 name: string; 63 /** The namespace of the attribute. */ 64 namespace?: string; 65 /** The namespace-related prefix of the attribute. */ 66 prefix?: string; 67 /** The value of the attribute. */ 68 value: string; 69} 70 71export interface TagToken extends TokenBase { 72 readonly type: TokenType.START_TAG | TokenType.END_TAG; 73 tagName: string; 74 /** Used to cache the ID of the tag name. */ 75 tagID: TAG_ID; 76 selfClosing: boolean; 77 ackSelfClosing: boolean; 78 attrs: Attribute[]; 79 location: LocationWithAttributes | null; 80} 81 82export function getTokenAttr(token: TagToken, attrName: string): string | null { 83 for (let i = token.attrs.length - 1; i >= 0; i--) { 84 if (token.attrs[i].name === attrName) { 85 return token.attrs[i].value; 86 } 87 } 88 89 return null; 90} 91 92export interface CommentToken extends TokenBase { 93 readonly type: TokenType.COMMENT; 94 data: string; 95} 96 97export interface EOFToken extends TokenBase { 98 readonly type: TokenType.EOF; 99} 100 101export interface CharacterToken extends TokenBase { 102 type: TokenType.CHARACTER | TokenType.NULL_CHARACTER | TokenType.WHITESPACE_CHARACTER; 103 chars: string; 104} 105 106export type Token = DoctypeToken | TagToken | CommentToken | EOFToken | CharacterToken; 107