angular-html-parser
Advanced tools
+583
| //#endregion | ||
| //#region ../compiler/src/ml_parser/tags.d.ts | ||
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| declare enum TagContentType { | ||
| RAW_TEXT = 0, | ||
| ESCAPABLE_RAW_TEXT = 1, | ||
| PARSABLE_DATA = 2, | ||
| } | ||
| interface TagDefinition { | ||
| closedByParent: boolean; | ||
| implicitNamespacePrefix: string | null; | ||
| isVoid: boolean; | ||
| ignoreFirstLf: boolean; | ||
| canSelfClose: boolean; | ||
| preventNamespaceInheritance: boolean; | ||
| isClosedByChild(name: string): boolean; | ||
| getContentType(prefix?: string): TagContentType; | ||
| } | ||
| //#endregion | ||
| //#region ../compiler/src/parse_util.d.ts | ||
| declare class ParseLocation { | ||
| file: ParseSourceFile; | ||
| offset: number; | ||
| line: number; | ||
| col: number; | ||
| constructor(file: ParseSourceFile, offset: number, line: number, col: number); | ||
| toString(): string; | ||
| moveBy(delta: number): ParseLocation; | ||
| getContext(maxChars: number, maxLines: number): { | ||
| before: string; | ||
| after: string; | ||
| } | null; | ||
| } | ||
| declare class ParseSourceFile { | ||
| content: string; | ||
| url: string; | ||
| constructor(content: string, url: string); | ||
| } | ||
| declare class ParseSourceSpan { | ||
| start: ParseLocation; | ||
| end: ParseLocation; | ||
| fullStart: ParseLocation; | ||
| details: string | null; | ||
| /** | ||
| * Create an object that holds information about spans of tokens/nodes captured during | ||
| * lexing/parsing of text. | ||
| * | ||
| * @param start | ||
| * The location of the start of the span (having skipped leading trivia). | ||
| * Skipping leading trivia makes source-spans more "user friendly", since things like HTML | ||
| * elements will appear to begin at the start of the opening tag, rather than at the start of any | ||
| * leading trivia, which could include newlines. | ||
| * | ||
| * @param end | ||
| * The location of the end of the span. | ||
| * | ||
| * @param fullStart | ||
| * The start of the token without skipping the leading trivia. | ||
| * This is used by tooling that splits tokens further, such as extracting Angular interpolations | ||
| * from text tokens. Such tooling creates new source-spans relative to the original token's | ||
| * source-span. If leading trivia characters have been skipped then the new source-spans may be | ||
| * incorrectly offset. | ||
| * | ||
| * @param details | ||
| * Additional information (such as identifier names) that should be associated with the span. | ||
| */ | ||
| constructor(start: ParseLocation, end: ParseLocation, fullStart?: ParseLocation, details?: string | null); | ||
| toString(): string; | ||
| } | ||
| declare enum ParseErrorLevel { | ||
| WARNING = 0, | ||
| ERROR = 1, | ||
| } | ||
| declare class ParseError extends Error { | ||
| /** Location of the error. */ | ||
| readonly span: ParseSourceSpan; | ||
| /** Error message. */ | ||
| readonly msg: string; | ||
| /** Severity level of the error. */ | ||
| readonly level: ParseErrorLevel; | ||
| /** | ||
| * Error that caused the error to be surfaced. For example, an error in a sub-expression that | ||
| * couldn't be parsed. Not guaranteed to be defined, but can be used to provide more context. | ||
| */ | ||
| readonly relatedError?: unknown; | ||
| constructor(/** Location of the error. */ | ||
| span: ParseSourceSpan, /** Error message. */ | ||
| msg: string, /** Severity level of the error. */ | ||
| level?: ParseErrorLevel, | ||
| /** | ||
| * Error that caused the error to be surfaced. For example, an error in a sub-expression that | ||
| * couldn't be parsed. Not guaranteed to be defined, but can be used to provide more context. | ||
| */ | ||
| relatedError?: unknown); | ||
| contextualMessage(): string; | ||
| toString(): string; | ||
| } | ||
| //#endregion | ||
| //#region ../compiler/src/i18n/i18n_ast.d.ts | ||
| /** | ||
| * Describes the text contents of a placeholder as it appears in an ICU expression, including its | ||
| * source span information. | ||
| */ | ||
| interface MessagePlaceholder { | ||
| /** The text contents of the placeholder */ | ||
| text: string; | ||
| /** The source span of the placeholder */ | ||
| sourceSpan: ParseSourceSpan; | ||
| } | ||
| declare class Message { | ||
| nodes: Node$1[]; | ||
| placeholders: { | ||
| [phName: string]: MessagePlaceholder; | ||
| }; | ||
| placeholderToMessage: { | ||
| [phName: string]: Message; | ||
| }; | ||
| meaning: string; | ||
| description: string; | ||
| customId: string; | ||
| sources: MessageSpan[]; | ||
| id: string; | ||
| /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ | ||
| legacyIds: string[]; | ||
| messageString: string; | ||
| /** | ||
| * @param nodes message AST | ||
| * @param placeholders maps placeholder names to static content and their source spans | ||
| * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) | ||
| * @param meaning | ||
| * @param description | ||
| * @param customId | ||
| */ | ||
| constructor(nodes: Node$1[], placeholders: { | ||
| [phName: string]: MessagePlaceholder; | ||
| }, placeholderToMessage: { | ||
| [phName: string]: Message; | ||
| }, meaning: string, description: string, customId: string); | ||
| } | ||
| interface MessageSpan { | ||
| filePath: string; | ||
| startLine: number; | ||
| startCol: number; | ||
| endLine: number; | ||
| endCol: number; | ||
| } | ||
| interface Node$1 { | ||
| sourceSpan: ParseSourceSpan; | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class Text$1 implements Node$1 { | ||
| value: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class Container implements Node$1 { | ||
| children: Node$1[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(children: Node$1[], sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class Icu implements Node$1 { | ||
| expression: string; | ||
| type: string; | ||
| cases: { | ||
| [k: string]: Node$1; | ||
| }; | ||
| sourceSpan: ParseSourceSpan; | ||
| expressionPlaceholder?: string; | ||
| constructor(expression: string, type: string, cases: { | ||
| [k: string]: Node$1; | ||
| }, sourceSpan: ParseSourceSpan, expressionPlaceholder?: string); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class TagPlaceholder implements Node$1 { | ||
| tag: string; | ||
| attrs: { | ||
| [k: string]: string; | ||
| }; | ||
| startName: string; | ||
| closeName: string; | ||
| children: Node$1[]; | ||
| isVoid: boolean; | ||
| sourceSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan | null; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(tag: string, attrs: { | ||
| [k: string]: string; | ||
| }, startName: string, closeName: string, children: Node$1[], isVoid: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan | null, endSourceSpan: ParseSourceSpan | null); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class Placeholder implements Node$1 { | ||
| value: string; | ||
| name: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string, name: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class IcuPlaceholder implements Node$1 { | ||
| value: Icu; | ||
| name: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| /** Used to capture a message computed from a previous processing pass (see `setI18nRefs()`). */ | ||
| previousMessage?: Message; | ||
| constructor(value: Icu, name: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| declare class BlockPlaceholder implements Node$1 { | ||
| name: string; | ||
| parameters: string[]; | ||
| startName: string; | ||
| closeName: string; | ||
| children: Node$1[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan | null; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, parameters: string[], startName: string, closeName: string, children: Node$1[], sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan | null, endSourceSpan: ParseSourceSpan | null); | ||
| visit(visitor: Visitor$1, context?: any): any; | ||
| } | ||
| /** | ||
| * Each HTML node that is affect by an i18n tag will also have an `i18n` property that is of type | ||
| * `I18nMeta`. | ||
| * This information is either a `Message`, which indicates it is the root of an i18n message, or a | ||
| * `Node`, which indicates is it part of a containing `Message`. | ||
| */ | ||
| type I18nMeta = Message | Node$1; | ||
| interface Visitor$1 { | ||
| visitText(text: Text$1, context?: any): any; | ||
| visitContainer(container: Container, context?: any): any; | ||
| visitIcu(icu: Icu, context?: any): any; | ||
| visitTagPlaceholder(ph: TagPlaceholder, context?: any): any; | ||
| visitPlaceholder(ph: Placeholder, context?: any): any; | ||
| visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): any; | ||
| visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): any; | ||
| } | ||
| //#endregion | ||
| //#region ../compiler/src/ml_parser/tokens.d.ts | ||
| declare const enum TokenType { | ||
| TAG_OPEN_START = 0, | ||
| TAG_OPEN_END = 1, | ||
| TAG_OPEN_END_VOID = 2, | ||
| TAG_CLOSE = 3, | ||
| INCOMPLETE_TAG_OPEN = 4, | ||
| TEXT = 5, | ||
| ESCAPABLE_RAW_TEXT = 6, | ||
| RAW_TEXT = 7, | ||
| INTERPOLATION = 8, | ||
| ENCODED_ENTITY = 9, | ||
| COMMENT_START = 10, | ||
| COMMENT_END = 11, | ||
| CDATA_START = 12, | ||
| CDATA_END = 13, | ||
| ATTR_NAME = 14, | ||
| ATTR_QUOTE = 15, | ||
| ATTR_VALUE_TEXT = 16, | ||
| ATTR_VALUE_INTERPOLATION = 17, | ||
| DOC_TYPE_START = 18, | ||
| DOC_TYPE_END = 19, | ||
| EXPANSION_FORM_START = 20, | ||
| EXPANSION_CASE_VALUE = 21, | ||
| EXPANSION_CASE_EXP_START = 22, | ||
| EXPANSION_CASE_EXP_END = 23, | ||
| EXPANSION_FORM_END = 24, | ||
| BLOCK_OPEN_START = 25, | ||
| BLOCK_OPEN_END = 26, | ||
| BLOCK_CLOSE = 27, | ||
| BLOCK_PARAMETER = 28, | ||
| INCOMPLETE_BLOCK_OPEN = 29, | ||
| LET_START = 30, | ||
| LET_VALUE = 31, | ||
| LET_END = 32, | ||
| INCOMPLETE_LET = 33, | ||
| COMPONENT_OPEN_START = 34, | ||
| COMPONENT_OPEN_END = 35, | ||
| COMPONENT_OPEN_END_VOID = 36, | ||
| COMPONENT_CLOSE = 37, | ||
| INCOMPLETE_COMPONENT_OPEN = 38, | ||
| DIRECTIVE_NAME = 39, | ||
| DIRECTIVE_OPEN = 40, | ||
| DIRECTIVE_CLOSE = 41, | ||
| EOF = 42, | ||
| } | ||
| type InterpolatedTextToken = TextToken | InterpolationToken | EncodedEntityToken; | ||
| type InterpolatedAttributeToken = AttributeValueTextToken | AttributeValueInterpolationToken | EncodedEntityToken; | ||
| interface TokenBase { | ||
| type: TokenType; | ||
| parts: string[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| } | ||
| interface TextToken extends TokenBase { | ||
| type: TokenType.TEXT | TokenType.ESCAPABLE_RAW_TEXT | TokenType.RAW_TEXT; | ||
| parts: [text: string]; | ||
| } | ||
| interface InterpolationToken extends TokenBase { | ||
| type: TokenType.INTERPOLATION; | ||
| parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
| } | ||
| interface EncodedEntityToken extends TokenBase { | ||
| type: TokenType.ENCODED_ENTITY; | ||
| parts: [decoded: string, encoded: string]; | ||
| } | ||
| interface AttributeValueTextToken extends TokenBase { | ||
| type: TokenType.ATTR_VALUE_TEXT; | ||
| parts: [value: string]; | ||
| } | ||
| interface AttributeValueInterpolationToken extends TokenBase { | ||
| type: TokenType.ATTR_VALUE_INTERPOLATION; | ||
| parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
| } | ||
| declare namespace ast_d_exports { | ||
| export { Attribute, Block, BlockParameter, CDATA, Comment, Component, Directive, DocType, Element, Expansion, ExpansionCase, LetDeclaration, Node, NodeWithI18n, RecursiveVisitor, Text, Visitor, visitAll }; | ||
| } | ||
| interface BaseNode { | ||
| sourceSpan: ParseSourceSpan; | ||
| visit(visitor: Visitor, context: any): any; | ||
| } | ||
| type Node = Attribute | CDATA | Comment | DocType | Element | Expansion | ExpansionCase | Text | Block | BlockParameter | LetDeclaration | Component | Directive; | ||
| declare abstract class NodeWithI18n implements BaseNode { | ||
| sourceSpan: ParseSourceSpan; | ||
| i18n?: I18nMeta; | ||
| constructor(sourceSpan: ParseSourceSpan, i18n?: I18nMeta); | ||
| abstract visit(visitor: Visitor, context: any): any; | ||
| } | ||
| declare class Text extends NodeWithI18n { | ||
| value: string; | ||
| tokens: InterpolatedTextToken[]; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan, tokens: InterpolatedTextToken[], i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "text"; | ||
| } | ||
| declare class CDATA extends NodeWithI18n { | ||
| value: string; | ||
| tokens: InterpolatedTextToken[]; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan, tokens: InterpolatedTextToken[], i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "cdata"; | ||
| } | ||
| declare class Expansion extends NodeWithI18n { | ||
| switchValue: string; | ||
| type: string; | ||
| cases: ExpansionCase[]; | ||
| switchValueSourceSpan: ParseSourceSpan; | ||
| constructor(switchValue: string, type: string, cases: ExpansionCase[], sourceSpan: ParseSourceSpan, switchValueSourceSpan: ParseSourceSpan, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "expansion"; | ||
| } | ||
| declare class ExpansionCase implements BaseNode { | ||
| value: string; | ||
| expression: Node[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| valueSourceSpan: ParseSourceSpan; | ||
| expSourceSpan: ParseSourceSpan; | ||
| constructor(value: string, expression: Node[], sourceSpan: ParseSourceSpan, valueSourceSpan: ParseSourceSpan, expSourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "expansionCase"; | ||
| } | ||
| declare class Attribute extends NodeWithI18n { | ||
| name: string; | ||
| value: string; | ||
| readonly keySpan: ParseSourceSpan | undefined; | ||
| valueSpan: ParseSourceSpan | undefined; | ||
| valueTokens: InterpolatedAttributeToken[] | undefined; | ||
| constructor(name: string, value: string, sourceSpan: ParseSourceSpan, keySpan: ParseSourceSpan | undefined, valueSpan: ParseSourceSpan | undefined, valueTokens: InterpolatedAttributeToken[] | undefined, i18n: I18nMeta | undefined); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "attribute"; | ||
| get nameSpan(): ParseSourceSpan; | ||
| } | ||
| declare class Element extends NodeWithI18n { | ||
| name: string; | ||
| attrs: Attribute[]; | ||
| readonly directives: Directive[]; | ||
| children: Node[]; | ||
| readonly isSelfClosing: boolean; | ||
| startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| nameSpan: ParseSourceSpan | null; | ||
| readonly isVoid: boolean; | ||
| constructor(name: string, attrs: Attribute[], directives: Directive[], children: Node[], isSelfClosing: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan: ParseSourceSpan | null, nameSpan: ParseSourceSpan | null, isVoid: boolean, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "element"; | ||
| } | ||
| declare class Comment implements BaseNode { | ||
| value: string | null; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string | null, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "comment"; | ||
| } | ||
| declare class DocType implements BaseNode { | ||
| value: string | null; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string | null, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "docType"; | ||
| } | ||
| declare class Block extends NodeWithI18n { | ||
| name: string; | ||
| parameters: BlockParameter[]; | ||
| children: Node[]; | ||
| nameSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, parameters: BlockParameter[], children: Node[], sourceSpan: ParseSourceSpan, nameSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "block"; | ||
| } | ||
| declare class Component extends NodeWithI18n { | ||
| readonly componentName: string; | ||
| readonly tagName: string | null; | ||
| readonly fullName: string; | ||
| attrs: Attribute[]; | ||
| readonly directives: Directive[]; | ||
| readonly children: Node[]; | ||
| readonly isSelfClosing: boolean; | ||
| readonly startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(componentName: string, tagName: string | null, fullName: string, attrs: Attribute[], directives: Directive[], children: Node[], isSelfClosing: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "component"; | ||
| } | ||
| declare class Directive implements BaseNode { | ||
| readonly name: string; | ||
| readonly attrs: Attribute[]; | ||
| readonly sourceSpan: ParseSourceSpan; | ||
| readonly startSourceSpan: ParseSourceSpan; | ||
| readonly endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, attrs: Attribute[], sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "directive"; | ||
| } | ||
| declare class BlockParameter implements BaseNode { | ||
| expression: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(expression: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "blockParameter"; | ||
| readonly startSourceSpan: null; | ||
| readonly endSourceSpan: null; | ||
| } | ||
| declare class LetDeclaration implements BaseNode { | ||
| name: string; | ||
| value: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| readonly nameSpan: ParseSourceSpan; | ||
| valueSpan: ParseSourceSpan; | ||
| constructor(name: string, value: string, sourceSpan: ParseSourceSpan, nameSpan: ParseSourceSpan, valueSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly kind = "letDeclaration"; | ||
| readonly startSourceSpan: null; | ||
| readonly endSourceSpan: null; | ||
| } | ||
| interface Visitor { | ||
| visit?(node: Node, context: any): any; | ||
| visitElement(element: Element, context: any): any; | ||
| visitAttribute(attribute: Attribute, context: any): any; | ||
| visitText(text: Text, context: any): any; | ||
| visitCdata(text: CDATA, context: any): any; | ||
| visitComment(comment: Comment, context: any): any; | ||
| visitDocType(docType: DocType, context: any): any; | ||
| visitExpansion(expansion: Expansion, context: any): any; | ||
| visitExpansionCase(expansionCase: ExpansionCase, context: any): any; | ||
| visitBlock(block: Block, context: any): any; | ||
| visitBlockParameter(parameter: BlockParameter, context: any): any; | ||
| visitLetDeclaration(decl: LetDeclaration, context: any): any; | ||
| visitComponent(component: Component, context: any): any; | ||
| visitDirective(directive: Directive, context: any): any; | ||
| } | ||
| declare function visitAll(visitor: Visitor, nodes: Node[], context?: any): any[]; | ||
| declare class RecursiveVisitor implements Visitor { | ||
| constructor(); | ||
| visitElement(ast: Element, context: any): any; | ||
| visitAttribute(ast: Attribute, context: any): any; | ||
| visitText(ast: Text, context: any): any; | ||
| visitCdata(ast: CDATA, context: any): any; | ||
| visitComment(ast: Comment, context: any): any; | ||
| visitDocType(ast: DocType, context: any): any; | ||
| visitExpansion(ast: Expansion, context: any): any; | ||
| visitExpansionCase(ast: ExpansionCase, context: any): any; | ||
| visitBlock(block: Block, context: any): any; | ||
| visitBlockParameter(ast: BlockParameter, context: any): any; | ||
| visitLetDeclaration(decl: LetDeclaration, context: any): void; | ||
| visitComponent(component: Component, context: any): void; | ||
| visitDirective(directive: Directive, context: any): void; | ||
| private visitChildren; | ||
| } | ||
| //#endregion | ||
| //#region ../compiler/src/ml_parser/parser.d.ts | ||
| declare class ParseTreeResult { | ||
| rootNodes: Node[]; | ||
| errors: ParseError[]; | ||
| constructor(rootNodes: Node[], errors: ParseError[]); | ||
| } | ||
| //#endregion | ||
| //#region ../compiler/src/ml_parser/html_tags.d.ts | ||
| declare class HtmlTagDefinition implements TagDefinition { | ||
| private closedByChildren; | ||
| private contentType; | ||
| closedByParent: boolean; | ||
| implicitNamespacePrefix: string | null; | ||
| isVoid: boolean; | ||
| ignoreFirstLf: boolean; | ||
| canSelfClose: boolean; | ||
| preventNamespaceInheritance: boolean; | ||
| constructor({ | ||
| closedByChildren, | ||
| implicitNamespacePrefix, | ||
| contentType, | ||
| closedByParent, | ||
| isVoid, | ||
| ignoreFirstLf, | ||
| preventNamespaceInheritance, | ||
| canSelfClose | ||
| }?: { | ||
| closedByChildren?: string[]; | ||
| closedByParent?: boolean; | ||
| implicitNamespacePrefix?: string; | ||
| contentType?: TagContentType | { | ||
| default: TagContentType; | ||
| [namespace: string]: TagContentType; | ||
| }; | ||
| isVoid?: boolean; | ||
| ignoreFirstLf?: boolean; | ||
| preventNamespaceInheritance?: boolean; | ||
| canSelfClose?: boolean; | ||
| }); | ||
| isClosedByChild(name: string): boolean; | ||
| getContentType(prefix?: string): TagContentType; | ||
| } | ||
| declare function getHtmlTagDefinition(tagName: string): HtmlTagDefinition; | ||
| //#endregion | ||
| //#region src/index.d.ts | ||
| interface ParseOptions { | ||
| /** | ||
| * any element can self close | ||
| * | ||
| * defaults to false | ||
| */ | ||
| canSelfClose?: boolean; | ||
| /** | ||
| * support [`htm`](https://github.com/developit/htm) component closing tags (`<//>`) | ||
| * | ||
| * defaults to false | ||
| */ | ||
| allowHtmComponentClosingTags?: boolean; | ||
| /** | ||
| * do not lowercase tag names before querying their tag definitions | ||
| * | ||
| * defaults to false | ||
| */ | ||
| isTagNameCaseSensitive?: boolean; | ||
| /** | ||
| * customize tag content type | ||
| * | ||
| * defaults to the content type defined in the HTML spec | ||
| */ | ||
| getTagContentType?: (tagName: string, prefix: string, hasParent: boolean, attrs: Array<{ | ||
| prefix: string; | ||
| name: string; | ||
| value?: string; | ||
| }>) => void | TagContentType; | ||
| /** | ||
| * tokenize angular control flow block syntax | ||
| */ | ||
| tokenizeAngularBlocks?: boolean; | ||
| /** | ||
| * tokenize angular let declaration syntax | ||
| */ | ||
| tokenizeAngularLetDeclaration?: boolean; | ||
| /** | ||
| * enable angular selectorless syntax | ||
| */ | ||
| enableAngularSelectorlessSyntax?: boolean; | ||
| } | ||
| declare function parse(input: string, options?: ParseOptions): ParseTreeResult; | ||
| //#endregion | ||
| export { type ast_d_exports as Ast, ParseLocation, ParseOptions, ParseSourceFile, ParseSourceSpan, type ParseTreeResult, RecursiveVisitor, TagContentType, getHtmlTagDefinition, parse, visitAll }; |
Sorry, the diff of this file is too big to display
+9
-16
| { | ||
| "name": "angular-html-parser", | ||
| "version": "9.3.0", | ||
| "version": "10.0.0", | ||
| "description": "A HTML parser extracted from Angular with some modifications", | ||
@@ -14,4 +14,4 @@ "repository": "https://github.com/prettier/angular-html-parser/blob/HEAD/packages/angular-html-parser", | ||
| ".": { | ||
| "types": "./lib/angular-html-parser/src/index.d.ts", | ||
| "default": "./lib/angular-html-parser/src/index.js" | ||
| "types": "./dist/index.d.ts", | ||
| "default": "./dist/index.js" | ||
| }, | ||
@@ -23,6 +23,3 @@ "./*": "./*" | ||
| "prepublish": "yarn run build", | ||
| "build": "yarn clean && yarn build-lib && yarn codemod", | ||
| "clean": "del-cli ./lib", | ||
| "build-lib": "tsc -p tsconfig.build.json", | ||
| "codemod": "node ./node_modules/jscodeshift/bin/jscodeshift.js -t postbuild-codemod.ts lib --extensions=js,ts --parser=ts", | ||
| "build": "tsdown", | ||
| "test": "vitest", | ||
@@ -34,13 +31,9 @@ "release": "release-it", | ||
| "devDependencies": { | ||
| "@types/node": "24.3.0", | ||
| "@types/node": "24.7.1", | ||
| "@vitest/coverage-v8": "3.2.4", | ||
| "del-cli": "6.0.0", | ||
| "jasmine": "5.10.0", | ||
| "jscodeshift": "17.3.0", | ||
| "prettier": "3.6.2", | ||
| "release-it": "19.0.4", | ||
| "standard-version": "9.5.0", | ||
| "ts-node": "10.9.2", | ||
| "release-it": "19.0.5", | ||
| "tsconfig-paths": "4.2.0", | ||
| "typescript": "5.9.2", | ||
| "tsdown": "0.15.6", | ||
| "typescript": "5.9.3", | ||
| "vitest": "3.2.4" | ||
@@ -52,3 +45,3 @@ }, | ||
| "files": [ | ||
| "lib", | ||
| "dist", | ||
| "ThirdPartyNoticeText.txt" | ||
@@ -55,0 +48,0 @@ ], |
| import { TagContentType } from "../../compiler/src/ml_parser/tags.js"; | ||
| import { ParseTreeResult } from "../../compiler/src/ml_parser/parser.js"; | ||
| export interface ParseOptions { | ||
| /** | ||
| * any element can self close | ||
| * | ||
| * defaults to false | ||
| */ | ||
| canSelfClose?: boolean; | ||
| /** | ||
| * support [`htm`](https://github.com/developit/htm) component closing tags (`<//>`) | ||
| * | ||
| * defaults to false | ||
| */ | ||
| allowHtmComponentClosingTags?: boolean; | ||
| /** | ||
| * do not lowercase tag names before querying their tag definitions | ||
| * | ||
| * defaults to false | ||
| */ | ||
| isTagNameCaseSensitive?: boolean; | ||
| /** | ||
| * customize tag content type | ||
| * | ||
| * defaults to the content type defined in the HTML spec | ||
| */ | ||
| getTagContentType?: (tagName: string, prefix: string, hasParent: boolean, attrs: Array<{ | ||
| prefix: string; | ||
| name: string; | ||
| value?: string; | ||
| }>) => void | TagContentType; | ||
| /** | ||
| * tokenize angular control flow block syntax | ||
| */ | ||
| tokenizeAngularBlocks?: boolean; | ||
| /** | ||
| * tokenize angular let declaration syntax | ||
| */ | ||
| tokenizeAngularLetDeclaration?: boolean; | ||
| /** | ||
| * enable angular selectorless syntax | ||
| */ | ||
| enableAngularSelectorlessSyntax?: boolean; | ||
| } | ||
| export declare function parse(input: string, options?: ParseOptions): ParseTreeResult; | ||
| export { TagContentType }; | ||
| export { RecursiveVisitor, visitAll, } from "../../compiler/src/ml_parser/ast.js"; | ||
| export { ParseSourceSpan, ParseLocation, ParseSourceFile, } from "../../compiler/src/parse_util.js"; | ||
| export { getHtmlTagDefinition } from "../../compiler/src/ml_parser/html_tags.js"; |
| import { HtmlParser } from "../../compiler/src/ml_parser/html_parser.js"; | ||
| import { TagContentType } from "../../compiler/src/ml_parser/tags.js"; | ||
| let parser = null; | ||
| const getParser = () => { | ||
| if (!parser) { | ||
| parser = new HtmlParser(); | ||
| } | ||
| return parser; | ||
| }; | ||
| export function parse(input, options = {}) { | ||
| const { canSelfClose = false, allowHtmComponentClosingTags = false, isTagNameCaseSensitive = false, getTagContentType, tokenizeAngularBlocks = false, tokenizeAngularLetDeclaration = false, enableAngularSelectorlessSyntax = false, } = options; | ||
| return getParser().parse(input, "angular-html-parser", { | ||
| tokenizeExpansionForms: tokenizeAngularBlocks, | ||
| interpolationConfig: undefined, | ||
| canSelfClose, | ||
| allowHtmComponentClosingTags, | ||
| tokenizeBlocks: tokenizeAngularBlocks, | ||
| tokenizeLet: tokenizeAngularLetDeclaration, | ||
| selectorlessEnabled: enableAngularSelectorlessSyntax, | ||
| }, isTagNameCaseSensitive, getTagContentType); | ||
| } | ||
| // For prettier | ||
| export { TagContentType }; | ||
| export { RecursiveVisitor, visitAll, } from "../../compiler/src/ml_parser/ast.js"; | ||
| export { ParseSourceSpan, ParseLocation, ParseSourceFile, } from "../../compiler/src/parse_util.js"; | ||
| export { getHtmlTagDefinition } from "../../compiler/src/ml_parser/html_tags.js"; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare function assertInterpolationSymbols(identifier: string, value: any): void; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| const UNUSABLE_INTERPOLATION_REGEXPS = [ | ||
| /@/, // control flow reserved symbol | ||
| /^\s*$/, // empty | ||
| /[<>]/, // html tag | ||
| /^[{}]$/, // i18n expansion | ||
| /&(#|[a-z])/i, // character reference, | ||
| /^\/\//, // comment | ||
| ]; | ||
| export function assertInterpolationSymbols(identifier, value) { | ||
| if (value != null && !(Array.isArray(value) && value.length == 2)) { | ||
| throw new Error(`Expected '${identifier}' to be an array, [start, end].`); | ||
| } | ||
| else if (value != null) { | ||
| const start = value[0]; | ||
| const end = value[1]; | ||
| // Check for unusable interpolation symbols | ||
| UNUSABLE_INTERPOLATION_REGEXPS.forEach((regexp) => { | ||
| if (regexp.test(start) || regexp.test(end)) { | ||
| throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`); | ||
| } | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare const $EOF = 0; | ||
| export declare const $BSPACE = 8; | ||
| export declare const $TAB = 9; | ||
| export declare const $LF = 10; | ||
| export declare const $VTAB = 11; | ||
| export declare const $FF = 12; | ||
| export declare const $CR = 13; | ||
| export declare const $SPACE = 32; | ||
| export declare const $BANG = 33; | ||
| export declare const $DQ = 34; | ||
| export declare const $HASH = 35; | ||
| export declare const $$ = 36; | ||
| export declare const $PERCENT = 37; | ||
| export declare const $AMPERSAND = 38; | ||
| export declare const $SQ = 39; | ||
| export declare const $LPAREN = 40; | ||
| export declare const $RPAREN = 41; | ||
| export declare const $STAR = 42; | ||
| export declare const $PLUS = 43; | ||
| export declare const $COMMA = 44; | ||
| export declare const $MINUS = 45; | ||
| export declare const $PERIOD = 46; | ||
| export declare const $SLASH = 47; | ||
| export declare const $COLON = 58; | ||
| export declare const $SEMICOLON = 59; | ||
| export declare const $LT = 60; | ||
| export declare const $EQ = 61; | ||
| export declare const $GT = 62; | ||
| export declare const $QUESTION = 63; | ||
| export declare const $0 = 48; | ||
| export declare const $7 = 55; | ||
| export declare const $9 = 57; | ||
| export declare const $A = 65; | ||
| export declare const $E = 69; | ||
| export declare const $F = 70; | ||
| export declare const $X = 88; | ||
| export declare const $Z = 90; | ||
| export declare const $LBRACKET = 91; | ||
| export declare const $BACKSLASH = 92; | ||
| export declare const $RBRACKET = 93; | ||
| export declare const $CARET = 94; | ||
| export declare const $_ = 95; | ||
| export declare const $a = 97; | ||
| export declare const $b = 98; | ||
| export declare const $e = 101; | ||
| export declare const $f = 102; | ||
| export declare const $n = 110; | ||
| export declare const $r = 114; | ||
| export declare const $t = 116; | ||
| export declare const $u = 117; | ||
| export declare const $v = 118; | ||
| export declare const $x = 120; | ||
| export declare const $z = 122; | ||
| export declare const $LBRACE = 123; | ||
| export declare const $BAR = 124; | ||
| export declare const $RBRACE = 125; | ||
| export declare const $NBSP = 160; | ||
| export declare const $PIPE = 124; | ||
| export declare const $TILDA = 126; | ||
| export declare const $AT = 64; | ||
| export declare const $BT = 96; | ||
| export declare function isWhitespace(code: number): boolean; | ||
| export declare function isDigit(code: number): boolean; | ||
| export declare function isAsciiLetter(code: number): boolean; | ||
| export declare function isAsciiHexDigit(code: number): boolean; | ||
| export declare function isNewLine(code: number): boolean; | ||
| export declare function isOctalDigit(code: number): boolean; | ||
| export declare function isQuote(code: number): boolean; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export const $EOF = 0; | ||
| export const $BSPACE = 8; | ||
| export const $TAB = 9; | ||
| export const $LF = 10; | ||
| export const $VTAB = 11; | ||
| export const $FF = 12; | ||
| export const $CR = 13; | ||
| export const $SPACE = 32; | ||
| export const $BANG = 33; | ||
| export const $DQ = 34; | ||
| export const $HASH = 35; | ||
| export const $$ = 36; | ||
| export const $PERCENT = 37; | ||
| export const $AMPERSAND = 38; | ||
| export const $SQ = 39; | ||
| export const $LPAREN = 40; | ||
| export const $RPAREN = 41; | ||
| export const $STAR = 42; | ||
| export const $PLUS = 43; | ||
| export const $COMMA = 44; | ||
| export const $MINUS = 45; | ||
| export const $PERIOD = 46; | ||
| export const $SLASH = 47; | ||
| export const $COLON = 58; | ||
| export const $SEMICOLON = 59; | ||
| export const $LT = 60; | ||
| export const $EQ = 61; | ||
| export const $GT = 62; | ||
| export const $QUESTION = 63; | ||
| export const $0 = 48; | ||
| export const $7 = 55; | ||
| export const $9 = 57; | ||
| export const $A = 65; | ||
| export const $E = 69; | ||
| export const $F = 70; | ||
| export const $X = 88; | ||
| export const $Z = 90; | ||
| export const $LBRACKET = 91; | ||
| export const $BACKSLASH = 92; | ||
| export const $RBRACKET = 93; | ||
| export const $CARET = 94; | ||
| export const $_ = 95; | ||
| export const $a = 97; | ||
| export const $b = 98; | ||
| export const $e = 101; | ||
| export const $f = 102; | ||
| export const $n = 110; | ||
| export const $r = 114; | ||
| export const $t = 116; | ||
| export const $u = 117; | ||
| export const $v = 118; | ||
| export const $x = 120; | ||
| export const $z = 122; | ||
| export const $LBRACE = 123; | ||
| export const $BAR = 124; | ||
| export const $RBRACE = 125; | ||
| export const $NBSP = 160; | ||
| export const $PIPE = 124; | ||
| export const $TILDA = 126; | ||
| export const $AT = 64; | ||
| export const $BT = 96; | ||
| export function isWhitespace(code) { | ||
| return (code >= $TAB && code <= $SPACE) || code == $NBSP; | ||
| } | ||
| export function isDigit(code) { | ||
| return $0 <= code && code <= $9; | ||
| } | ||
| export function isAsciiLetter(code) { | ||
| return (code >= $a && code <= $z) || (code >= $A && code <= $Z); | ||
| } | ||
| export function isAsciiHexDigit(code) { | ||
| return (code >= $a && code <= $f) || (code >= $A && code <= $F) || isDigit(code); | ||
| } | ||
| export function isNewLine(code) { | ||
| return code === $LF || code === $CR; | ||
| } | ||
| export function isOctalDigit(code) { | ||
| return $0 <= code && code <= $7; | ||
| } | ||
| export function isQuote(code) { | ||
| return code === $SQ || code === $DQ || code === $BT; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare const emitDistinctChangesOnlyDefaultValue = true; | ||
| export declare enum ViewEncapsulation { | ||
| Emulated = 0, | ||
| None = 2, | ||
| ShadowDom = 3, | ||
| IsolatedShadowDom = 4 | ||
| } | ||
| export declare enum ChangeDetectionStrategy { | ||
| OnPush = 0, | ||
| Default = 1 | ||
| } | ||
| export interface Input { | ||
| alias?: string; | ||
| required?: boolean; | ||
| transform?: (value: any) => any; | ||
| isSignal: boolean; | ||
| } | ||
| /** Flags describing an input for a directive. */ | ||
| export declare enum InputFlags { | ||
| None = 0, | ||
| SignalBased = 1, | ||
| HasDecoratorInputTransform = 2 | ||
| } | ||
| export interface Output { | ||
| alias?: string; | ||
| } | ||
| export interface HostBinding { | ||
| hostPropertyName?: string; | ||
| } | ||
| export interface HostListener { | ||
| eventName?: string; | ||
| args?: string[]; | ||
| } | ||
| export interface SchemaMetadata { | ||
| name: string; | ||
| } | ||
| export declare const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata; | ||
| export declare const NO_ERRORS_SCHEMA: SchemaMetadata; | ||
| export interface Type extends Function { | ||
| new (...args: any[]): any; | ||
| } | ||
| export declare const Type: FunctionConstructor; | ||
| export declare enum SecurityContext { | ||
| NONE = 0, | ||
| HTML = 1, | ||
| STYLE = 2, | ||
| SCRIPT = 3, | ||
| URL = 4, | ||
| RESOURCE_URL = 5 | ||
| } | ||
| /** | ||
| * Injection flags for DI. | ||
| */ | ||
| export declare const enum InjectFlags { | ||
| Default = 0, | ||
| /** | ||
| * Specifies that an injector should retrieve a dependency from any injector until reaching the | ||
| * host element of the current component. (Only used with Element Injector) | ||
| */ | ||
| Host = 1, | ||
| /** Don't descend into ancestors of the node requesting injection. */ | ||
| Self = 2, | ||
| /** Skip the node that is requesting injection. */ | ||
| SkipSelf = 4, | ||
| /** Inject `defaultValue` instead if token not found. */ | ||
| Optional = 8, | ||
| /** | ||
| * This token is being injected into a pipe. | ||
| * @internal | ||
| */ | ||
| ForPipe = 16 | ||
| } | ||
| export declare enum MissingTranslationStrategy { | ||
| Error = 0, | ||
| Warning = 1, | ||
| Ignore = 2 | ||
| } | ||
| /** | ||
| * Flags used to generate R3-style CSS Selectors. They are pasted from | ||
| * core/src/render3/projection.ts because they cannot be referenced directly. | ||
| */ | ||
| export declare const enum SelectorFlags { | ||
| /** Indicates this is the beginning of a new negative selector */ | ||
| NOT = 1, | ||
| /** Mode for matching attributes */ | ||
| ATTRIBUTE = 2, | ||
| /** Mode for matching tag names */ | ||
| ELEMENT = 4, | ||
| /** Mode for matching class names */ | ||
| CLASS = 8 | ||
| } | ||
| export type R3CssSelector = (string | SelectorFlags)[]; | ||
| export type R3CssSelectorList = R3CssSelector[]; | ||
| export declare function parseSelectorToR3Selector(selector: string | null): R3CssSelectorList; | ||
| /** | ||
| * Flags passed into template functions to determine which blocks (i.e. creation, update) | ||
| * should be executed. | ||
| * | ||
| * Typically, a template runs both the creation block and the update block on initialization and | ||
| * subsequent runs only execute the update block. However, dynamically created views require that | ||
| * the creation block be executed separately from the update block (for backwards compat). | ||
| */ | ||
| export declare const enum RenderFlags { | ||
| Create = 1, | ||
| Update = 2 | ||
| } | ||
| /** | ||
| * A set of marker values to be used in the attributes arrays. These markers indicate that some | ||
| * items are not regular attributes and the processing should be adapted accordingly. | ||
| */ | ||
| export declare const enum AttributeMarker { | ||
| /** | ||
| * Marker indicates that the following 3 values in the attributes array are: | ||
| * namespaceUri, attributeName, attributeValue | ||
| * in that order. | ||
| */ | ||
| NamespaceURI = 0, | ||
| /** | ||
| * Signals class declaration. | ||
| * | ||
| * Each value following `Classes` designates a class name to include on the element. | ||
| * ## Example: | ||
| * | ||
| * Given: | ||
| * ```html | ||
| * <div class="foo bar baz">...</div> | ||
| * ``` | ||
| * | ||
| * the generated code is: | ||
| * ```ts | ||
| * var _c1 = [AttributeMarker.Classes, 'foo', 'bar', 'baz']; | ||
| * ``` | ||
| */ | ||
| Classes = 1, | ||
| /** | ||
| * Signals style declaration. | ||
| * | ||
| * Each pair of values following `Styles` designates a style name and value to include on the | ||
| * element. | ||
| * ## Example: | ||
| * | ||
| * Given: | ||
| * ```html | ||
| * <div style="width:100px; height:200px; color:red">...</div> | ||
| * ``` | ||
| * | ||
| * the generated code is: | ||
| * ```ts | ||
| * var _c1 = [AttributeMarker.Styles, 'width', '100px', 'height'. '200px', 'color', 'red']; | ||
| * ``` | ||
| */ | ||
| Styles = 2, | ||
| /** | ||
| * Signals that the following attribute names were extracted from input or output bindings. | ||
| * | ||
| * For example, given the following HTML: | ||
| * | ||
| * ```html | ||
| * <div moo="car" [foo]="exp" (bar)="doSth()"> | ||
| * ``` | ||
| * | ||
| * the generated code is: | ||
| * | ||
| * ```ts | ||
| * var _c1 = ['moo', 'car', AttributeMarker.Bindings, 'foo', 'bar']; | ||
| * ``` | ||
| */ | ||
| Bindings = 3, | ||
| /** | ||
| * Signals that the following attribute names were hoisted from an inline-template declaration. | ||
| * | ||
| * For example, given the following HTML: | ||
| * | ||
| * ```html | ||
| * <div *ngFor="let value of values; trackBy:trackBy" dirA [dirB]="value"> | ||
| * ``` | ||
| * | ||
| * the generated code for the `template()` instruction would include: | ||
| * | ||
| * ``` | ||
| * ['dirA', '', AttributeMarker.Bindings, 'dirB', AttributeMarker.Template, 'ngFor', 'ngForOf', | ||
| * 'ngForTrackBy', 'let-value'] | ||
| * ``` | ||
| * | ||
| * while the generated code for the `element()` instruction inside the template function would | ||
| * include: | ||
| * | ||
| * ``` | ||
| * ['dirA', '', AttributeMarker.Bindings, 'dirB'] | ||
| * ``` | ||
| */ | ||
| Template = 4, | ||
| /** | ||
| * Signals that the following attribute is `ngProjectAs` and its value is a parsed `CssSelector`. | ||
| * | ||
| * For example, given the following HTML: | ||
| * | ||
| * ```html | ||
| * <h1 attr="value" ngProjectAs="[title]"> | ||
| * ``` | ||
| * | ||
| * the generated code for the `element()` instruction would include: | ||
| * | ||
| * ``` | ||
| * ['attr', 'value', AttributeMarker.ProjectAs, ['', 'title', '']] | ||
| * ``` | ||
| */ | ||
| ProjectAs = 5, | ||
| /** | ||
| * Signals that the following attribute will be translated by runtime i18n | ||
| * | ||
| * For example, given the following HTML: | ||
| * | ||
| * ```html | ||
| * <div moo="car" foo="value" i18n-foo [bar]="binding" i18n-bar> | ||
| * ``` | ||
| * | ||
| * the generated code is: | ||
| * | ||
| * ```ts | ||
| * var _c1 = ['moo', 'car', AttributeMarker.I18n, 'foo', 'bar']; | ||
| * ``` | ||
| */ | ||
| I18n = 6 | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| // Attention: | ||
| // This file duplicates types and values from @angular/core | ||
| // so that we are able to make @angular/compiler independent of @angular/core. | ||
| // This is important to prevent a build cycle, as @angular/core needs to | ||
| // be compiled with the compiler. | ||
| import { CssSelector } from "./directive_matching.js"; | ||
| // Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not | ||
| // explicitly set. | ||
| export const emitDistinctChangesOnlyDefaultValue = true; | ||
| export var ViewEncapsulation; | ||
| (function (ViewEncapsulation) { | ||
| ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated"; | ||
| // Historically the 1 value was for `Native` encapsulation which has been removed as of v11. | ||
| ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None"; | ||
| ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom"; | ||
| ViewEncapsulation[ViewEncapsulation["IsolatedShadowDom"] = 4] = "IsolatedShadowDom"; | ||
| })(ViewEncapsulation || (ViewEncapsulation = {})); | ||
| export var ChangeDetectionStrategy; | ||
| (function (ChangeDetectionStrategy) { | ||
| ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush"; | ||
| ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default"; | ||
| })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {})); | ||
| /** Flags describing an input for a directive. */ | ||
| export var InputFlags; | ||
| (function (InputFlags) { | ||
| InputFlags[InputFlags["None"] = 0] = "None"; | ||
| InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased"; | ||
| InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform"; | ||
| })(InputFlags || (InputFlags = {})); | ||
| export const CUSTOM_ELEMENTS_SCHEMA = { | ||
| name: 'custom-elements', | ||
| }; | ||
| export const NO_ERRORS_SCHEMA = { | ||
| name: 'no-errors-schema', | ||
| }; | ||
| export const Type = Function; | ||
| export var SecurityContext; | ||
| (function (SecurityContext) { | ||
| SecurityContext[SecurityContext["NONE"] = 0] = "NONE"; | ||
| SecurityContext[SecurityContext["HTML"] = 1] = "HTML"; | ||
| SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE"; | ||
| SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT"; | ||
| SecurityContext[SecurityContext["URL"] = 4] = "URL"; | ||
| SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL"; | ||
| })(SecurityContext || (SecurityContext = {})); | ||
| export var MissingTranslationStrategy; | ||
| (function (MissingTranslationStrategy) { | ||
| MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error"; | ||
| MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning"; | ||
| MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore"; | ||
| })(MissingTranslationStrategy || (MissingTranslationStrategy = {})); | ||
| function parserSelectorToSimpleSelector(selector) { | ||
| const classes = selector.classNames && selector.classNames.length | ||
| ? [8 /* SelectorFlags.CLASS */, ...selector.classNames] | ||
| : []; | ||
| const elementName = selector.element && selector.element !== '*' ? selector.element : ''; | ||
| return [elementName, ...selector.attrs, ...classes]; | ||
| } | ||
| function parserSelectorToNegativeSelector(selector) { | ||
| const classes = selector.classNames && selector.classNames.length | ||
| ? [8 /* SelectorFlags.CLASS */, ...selector.classNames] | ||
| : []; | ||
| if (selector.element) { | ||
| return [ | ||
| 1 /* SelectorFlags.NOT */ | 4 /* SelectorFlags.ELEMENT */, | ||
| selector.element, | ||
| ...selector.attrs, | ||
| ...classes, | ||
| ]; | ||
| } | ||
| else if (selector.attrs.length) { | ||
| return [1 /* SelectorFlags.NOT */ | 2 /* SelectorFlags.ATTRIBUTE */, ...selector.attrs, ...classes]; | ||
| } | ||
| else { | ||
| return selector.classNames && selector.classNames.length | ||
| ? [1 /* SelectorFlags.NOT */ | 8 /* SelectorFlags.CLASS */, ...selector.classNames] | ||
| : []; | ||
| } | ||
| } | ||
| function parserSelectorToR3Selector(selector) { | ||
| const positive = parserSelectorToSimpleSelector(selector); | ||
| const negative = selector.notSelectors && selector.notSelectors.length | ||
| ? selector.notSelectors.map((notSelector) => parserSelectorToNegativeSelector(notSelector)) | ||
| : []; | ||
| return positive.concat(...negative); | ||
| } | ||
| export function parseSelectorToR3Selector(selector) { | ||
| return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : []; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| /** | ||
| * A css selector contains an element name, | ||
| * css classes and attribute/value pairs with the purpose | ||
| * of selecting subsets out of them. | ||
| */ | ||
| export declare class CssSelector { | ||
| element: string | null; | ||
| classNames: string[]; | ||
| /** | ||
| * The selectors are encoded in pairs where: | ||
| * - even locations are attribute names | ||
| * - odd locations are attribute values. | ||
| * | ||
| * Example: | ||
| * Selector: `[key1=value1][key2]` would parse to: | ||
| * ``` | ||
| * ['key1', 'value1', 'key2', ''] | ||
| * ``` | ||
| */ | ||
| attrs: string[]; | ||
| notSelectors: CssSelector[]; | ||
| static parse(selector: string): CssSelector[]; | ||
| /** | ||
| * Unescape `\$` sequences from the CSS attribute selector. | ||
| * | ||
| * This is needed because `$` can have a special meaning in CSS selectors, | ||
| * but we might want to match an attribute that contains `$`. | ||
| * [MDN web link for more | ||
| * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). | ||
| * @param attr the attribute to unescape. | ||
| * @returns the unescaped string. | ||
| */ | ||
| unescapeAttribute(attr: string): string; | ||
| /** | ||
| * Escape `$` sequences from the CSS attribute selector. | ||
| * | ||
| * This is needed because `$` can have a special meaning in CSS selectors, | ||
| * with this method we are escaping `$` with `\$'. | ||
| * [MDN web link for more | ||
| * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). | ||
| * @param attr the attribute to escape. | ||
| * @returns the escaped string. | ||
| */ | ||
| escapeAttribute(attr: string): string; | ||
| isElementSelector(): boolean; | ||
| hasElementSelector(): boolean; | ||
| setElement(element?: string | null): void; | ||
| getAttrs(): string[]; | ||
| addAttribute(name: string, value?: string): void; | ||
| addClassName(name: string): void; | ||
| toString(): string; | ||
| } | ||
| /** | ||
| * Reads a list of CssSelectors and allows to calculate which ones | ||
| * are contained in a given CssSelector. | ||
| */ | ||
| export declare class SelectorMatcher<T = any> { | ||
| static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher<null>; | ||
| private _elementMap; | ||
| private _elementPartialMap; | ||
| private _classMap; | ||
| private _classPartialMap; | ||
| private _attrValueMap; | ||
| private _attrValuePartialMap; | ||
| private _listContexts; | ||
| addSelectables(cssSelectors: CssSelector[], callbackCtxt?: T): void; | ||
| /** | ||
| * Add an object that can be found later on by calling `match`. | ||
| * @param cssSelector A css selector | ||
| * @param callbackCtxt An opaque object that will be given to the callback of the `match` function | ||
| */ | ||
| private _addSelectable; | ||
| private _addTerminal; | ||
| private _addPartial; | ||
| /** | ||
| * Find the objects that have been added via `addSelectable` | ||
| * whose css selector is contained in the given css selector. | ||
| * @param cssSelector A css selector | ||
| * @param matchedCallback This callback will be called with the object handed into `addSelectable` | ||
| * @return boolean true if a match was found | ||
| */ | ||
| match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: T) => void) | null): boolean; | ||
| /** @internal */ | ||
| _matchTerminal(map: Map<string, SelectorContext<T>[]>, name: string, cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: any) => void) | null): boolean; | ||
| /** @internal */ | ||
| _matchPartial(map: Map<string, SelectorMatcher<T>>, name: string, cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: any) => void) | null): boolean; | ||
| } | ||
| export declare class SelectorListContext { | ||
| selectors: CssSelector[]; | ||
| alreadyMatched: boolean; | ||
| constructor(selectors: CssSelector[]); | ||
| } | ||
| export declare class SelectorContext<T = any> { | ||
| selector: CssSelector; | ||
| cbContext: T; | ||
| listContext: SelectorListContext; | ||
| notSelectors: CssSelector[]; | ||
| constructor(selector: CssSelector, cbContext: T, listContext: SelectorListContext); | ||
| finalize(cssSelector: CssSelector, callback: ((c: CssSelector, a: T) => void) | null): boolean; | ||
| } | ||
| export declare class SelectorlessMatcher<T = unknown> { | ||
| private registry; | ||
| constructor(registry: Map<string, T[]>); | ||
| match(name: string): T[]; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not(" | ||
| '(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#"; | ||
| // "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range | ||
| // 4: attribute; 5: attribute_string; 6: attribute_value | ||
| '(?:\\[([-.\\w*\\\\$]+)(?:=(["\']?)([^\\]"\']*)\\5)?\\])|' + // "[name]", "[name=value]", | ||
| // "[name="value"]", | ||
| // "[name='value']" | ||
| '(\\))|' + // 7: ")" | ||
| '(\\s*,\\s*)', // 8: "," | ||
| 'g'); | ||
| /** | ||
| * A css selector contains an element name, | ||
| * css classes and attribute/value pairs with the purpose | ||
| * of selecting subsets out of them. | ||
| */ | ||
| export class CssSelector { | ||
| constructor() { | ||
| this.element = null; | ||
| this.classNames = []; | ||
| /** | ||
| * The selectors are encoded in pairs where: | ||
| * - even locations are attribute names | ||
| * - odd locations are attribute values. | ||
| * | ||
| * Example: | ||
| * Selector: `[key1=value1][key2]` would parse to: | ||
| * ``` | ||
| * ['key1', 'value1', 'key2', ''] | ||
| * ``` | ||
| */ | ||
| this.attrs = []; | ||
| this.notSelectors = []; | ||
| } | ||
| static parse(selector) { | ||
| const results = []; | ||
| const _addResult = (res, cssSel) => { | ||
| if (cssSel.notSelectors.length > 0 && | ||
| !cssSel.element && | ||
| cssSel.classNames.length == 0 && | ||
| cssSel.attrs.length == 0) { | ||
| cssSel.element = '*'; | ||
| } | ||
| res.push(cssSel); | ||
| }; | ||
| let cssSelector = new CssSelector(); | ||
| let match; | ||
| let current = cssSelector; | ||
| let inNot = false; | ||
| _SELECTOR_REGEXP.lastIndex = 0; | ||
| while ((match = _SELECTOR_REGEXP.exec(selector))) { | ||
| if (match[1 /* SelectorRegexp.NOT */]) { | ||
| if (inNot) { | ||
| throw new Error('Nesting :not in a selector is not allowed'); | ||
| } | ||
| inNot = true; | ||
| current = new CssSelector(); | ||
| cssSelector.notSelectors.push(current); | ||
| } | ||
| const tag = match[2 /* SelectorRegexp.TAG */]; | ||
| if (tag) { | ||
| const prefix = match[3 /* SelectorRegexp.PREFIX */]; | ||
| if (prefix === '#') { | ||
| // #hash | ||
| current.addAttribute('id', tag.slice(1)); | ||
| } | ||
| else if (prefix === '.') { | ||
| // Class | ||
| current.addClassName(tag.slice(1)); | ||
| } | ||
| else { | ||
| // Element | ||
| current.setElement(tag); | ||
| } | ||
| } | ||
| const attribute = match[4 /* SelectorRegexp.ATTRIBUTE */]; | ||
| if (attribute) { | ||
| current.addAttribute(current.unescapeAttribute(attribute), match[6 /* SelectorRegexp.ATTRIBUTE_VALUE */]); | ||
| } | ||
| if (match[7 /* SelectorRegexp.NOT_END */]) { | ||
| inNot = false; | ||
| current = cssSelector; | ||
| } | ||
| if (match[8 /* SelectorRegexp.SEPARATOR */]) { | ||
| if (inNot) { | ||
| throw new Error('Multiple selectors in :not are not supported'); | ||
| } | ||
| _addResult(results, cssSelector); | ||
| cssSelector = current = new CssSelector(); | ||
| } | ||
| } | ||
| _addResult(results, cssSelector); | ||
| return results; | ||
| } | ||
| /** | ||
| * Unescape `\$` sequences from the CSS attribute selector. | ||
| * | ||
| * This is needed because `$` can have a special meaning in CSS selectors, | ||
| * but we might want to match an attribute that contains `$`. | ||
| * [MDN web link for more | ||
| * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). | ||
| * @param attr the attribute to unescape. | ||
| * @returns the unescaped string. | ||
| */ | ||
| unescapeAttribute(attr) { | ||
| let result = ''; | ||
| let escaping = false; | ||
| for (let i = 0; i < attr.length; i++) { | ||
| const char = attr.charAt(i); | ||
| if (char === '\\') { | ||
| escaping = true; | ||
| continue; | ||
| } | ||
| if (char === '$' && !escaping) { | ||
| throw new Error(`Error in attribute selector "${attr}". ` + | ||
| `Unescaped "$" is not supported. Please escape with "\\$".`); | ||
| } | ||
| escaping = false; | ||
| result += char; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Escape `$` sequences from the CSS attribute selector. | ||
| * | ||
| * This is needed because `$` can have a special meaning in CSS selectors, | ||
| * with this method we are escaping `$` with `\$'. | ||
| * [MDN web link for more | ||
| * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). | ||
| * @param attr the attribute to escape. | ||
| * @returns the escaped string. | ||
| */ | ||
| escapeAttribute(attr) { | ||
| return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$'); | ||
| } | ||
| isElementSelector() { | ||
| return (this.hasElementSelector() && | ||
| this.classNames.length == 0 && | ||
| this.attrs.length == 0 && | ||
| this.notSelectors.length === 0); | ||
| } | ||
| hasElementSelector() { | ||
| return !!this.element; | ||
| } | ||
| setElement(element = null) { | ||
| this.element = element; | ||
| } | ||
| getAttrs() { | ||
| const result = []; | ||
| if (this.classNames.length > 0) { | ||
| result.push('class', this.classNames.join(' ')); | ||
| } | ||
| return result.concat(this.attrs); | ||
| } | ||
| addAttribute(name, value = '') { | ||
| this.attrs.push(name, (value && value.toLowerCase()) || ''); | ||
| } | ||
| addClassName(name) { | ||
| this.classNames.push(name.toLowerCase()); | ||
| } | ||
| toString() { | ||
| let res = this.element || ''; | ||
| if (this.classNames) { | ||
| this.classNames.forEach((klass) => (res += `.${klass}`)); | ||
| } | ||
| if (this.attrs) { | ||
| for (let i = 0; i < this.attrs.length; i += 2) { | ||
| const name = this.escapeAttribute(this.attrs[i]); | ||
| const value = this.attrs[i + 1]; | ||
| res += `[${name}${value ? '=' + value : ''}]`; | ||
| } | ||
| } | ||
| this.notSelectors.forEach((notSelector) => (res += `:not(${notSelector})`)); | ||
| return res; | ||
| } | ||
| } | ||
| /** | ||
| * Reads a list of CssSelectors and allows to calculate which ones | ||
| * are contained in a given CssSelector. | ||
| */ | ||
| export class SelectorMatcher { | ||
| constructor() { | ||
| this._elementMap = new Map(); | ||
| this._elementPartialMap = new Map(); | ||
| this._classMap = new Map(); | ||
| this._classPartialMap = new Map(); | ||
| this._attrValueMap = new Map(); | ||
| this._attrValuePartialMap = new Map(); | ||
| this._listContexts = []; | ||
| } | ||
| static createNotMatcher(notSelectors) { | ||
| const notMatcher = new SelectorMatcher(); | ||
| notMatcher.addSelectables(notSelectors, null); | ||
| return notMatcher; | ||
| } | ||
| addSelectables(cssSelectors, callbackCtxt) { | ||
| let listContext = null; | ||
| if (cssSelectors.length > 1) { | ||
| listContext = new SelectorListContext(cssSelectors); | ||
| this._listContexts.push(listContext); | ||
| } | ||
| for (let i = 0; i < cssSelectors.length; i++) { | ||
| this._addSelectable(cssSelectors[i], callbackCtxt, listContext); | ||
| } | ||
| } | ||
| /** | ||
| * Add an object that can be found later on by calling `match`. | ||
| * @param cssSelector A css selector | ||
| * @param callbackCtxt An opaque object that will be given to the callback of the `match` function | ||
| */ | ||
| _addSelectable(cssSelector, callbackCtxt, listContext) { | ||
| let matcher = this; | ||
| const element = cssSelector.element; | ||
| const classNames = cssSelector.classNames; | ||
| const attrs = cssSelector.attrs; | ||
| const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext); | ||
| if (element) { | ||
| const isTerminal = attrs.length === 0 && classNames.length === 0; | ||
| if (isTerminal) { | ||
| this._addTerminal(matcher._elementMap, element, selectable); | ||
| } | ||
| else { | ||
| matcher = this._addPartial(matcher._elementPartialMap, element); | ||
| } | ||
| } | ||
| if (classNames) { | ||
| for (let i = 0; i < classNames.length; i++) { | ||
| const isTerminal = attrs.length === 0 && i === classNames.length - 1; | ||
| const className = classNames[i]; | ||
| if (isTerminal) { | ||
| this._addTerminal(matcher._classMap, className, selectable); | ||
| } | ||
| else { | ||
| matcher = this._addPartial(matcher._classPartialMap, className); | ||
| } | ||
| } | ||
| } | ||
| if (attrs) { | ||
| for (let i = 0; i < attrs.length; i += 2) { | ||
| const isTerminal = i === attrs.length - 2; | ||
| const name = attrs[i]; | ||
| const value = attrs[i + 1]; | ||
| if (isTerminal) { | ||
| const terminalMap = matcher._attrValueMap; | ||
| let terminalValuesMap = terminalMap.get(name); | ||
| if (!terminalValuesMap) { | ||
| terminalValuesMap = new Map(); | ||
| terminalMap.set(name, terminalValuesMap); | ||
| } | ||
| this._addTerminal(terminalValuesMap, value, selectable); | ||
| } | ||
| else { | ||
| const partialMap = matcher._attrValuePartialMap; | ||
| let partialValuesMap = partialMap.get(name); | ||
| if (!partialValuesMap) { | ||
| partialValuesMap = new Map(); | ||
| partialMap.set(name, partialValuesMap); | ||
| } | ||
| matcher = this._addPartial(partialValuesMap, value); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| _addTerminal(map, name, selectable) { | ||
| let terminalList = map.get(name); | ||
| if (!terminalList) { | ||
| terminalList = []; | ||
| map.set(name, terminalList); | ||
| } | ||
| terminalList.push(selectable); | ||
| } | ||
| _addPartial(map, name) { | ||
| let matcher = map.get(name); | ||
| if (!matcher) { | ||
| matcher = new SelectorMatcher(); | ||
| map.set(name, matcher); | ||
| } | ||
| return matcher; | ||
| } | ||
| /** | ||
| * Find the objects that have been added via `addSelectable` | ||
| * whose css selector is contained in the given css selector. | ||
| * @param cssSelector A css selector | ||
| * @param matchedCallback This callback will be called with the object handed into `addSelectable` | ||
| * @return boolean true if a match was found | ||
| */ | ||
| match(cssSelector, matchedCallback) { | ||
| let result = false; | ||
| const element = cssSelector.element; | ||
| const classNames = cssSelector.classNames; | ||
| const attrs = cssSelector.attrs; | ||
| for (let i = 0; i < this._listContexts.length; i++) { | ||
| this._listContexts[i].alreadyMatched = false; | ||
| } | ||
| result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result; | ||
| result = | ||
| this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result; | ||
| if (classNames) { | ||
| for (let i = 0; i < classNames.length; i++) { | ||
| const className = classNames[i]; | ||
| result = | ||
| this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result; | ||
| result = | ||
| this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || | ||
| result; | ||
| } | ||
| } | ||
| if (attrs) { | ||
| for (let i = 0; i < attrs.length; i += 2) { | ||
| const name = attrs[i]; | ||
| const value = attrs[i + 1]; | ||
| const terminalValuesMap = this._attrValueMap.get(name); | ||
| if (value) { | ||
| result = | ||
| this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result; | ||
| } | ||
| result = | ||
| this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result; | ||
| const partialValuesMap = this._attrValuePartialMap.get(name); | ||
| if (value) { | ||
| result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result; | ||
| } | ||
| result = | ||
| this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| /** @internal */ | ||
| _matchTerminal(map, name, cssSelector, matchedCallback) { | ||
| if (!map || typeof name !== 'string') { | ||
| return false; | ||
| } | ||
| let selectables = map.get(name) || []; | ||
| const starSelectables = map.get('*'); | ||
| if (starSelectables) { | ||
| selectables = selectables.concat(starSelectables); | ||
| } | ||
| if (selectables.length === 0) { | ||
| return false; | ||
| } | ||
| let selectable; | ||
| let result = false; | ||
| for (let i = 0; i < selectables.length; i++) { | ||
| selectable = selectables[i]; | ||
| result = selectable.finalize(cssSelector, matchedCallback) || result; | ||
| } | ||
| return result; | ||
| } | ||
| /** @internal */ | ||
| _matchPartial(map, name, cssSelector, matchedCallback) { | ||
| if (!map || typeof name !== 'string') { | ||
| return false; | ||
| } | ||
| const nestedSelector = map.get(name); | ||
| if (!nestedSelector) { | ||
| return false; | ||
| } | ||
| // TODO(perf): get rid of recursion and measure again | ||
| // TODO(perf): don't pass the whole selector into the recursion, | ||
| // but only the not processed parts | ||
| return nestedSelector.match(cssSelector, matchedCallback); | ||
| } | ||
| } | ||
| export class SelectorListContext { | ||
| constructor(selectors) { | ||
| this.selectors = selectors; | ||
| this.alreadyMatched = false; | ||
| } | ||
| } | ||
| // Store context to pass back selector and context when a selector is matched | ||
| export class SelectorContext { | ||
| constructor(selector, cbContext, listContext) { | ||
| this.selector = selector; | ||
| this.cbContext = cbContext; | ||
| this.listContext = listContext; | ||
| this.notSelectors = selector.notSelectors; | ||
| } | ||
| finalize(cssSelector, callback) { | ||
| let result = true; | ||
| if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) { | ||
| const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors); | ||
| result = !notMatcher.match(cssSelector, null); | ||
| } | ||
| if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) { | ||
| if (this.listContext) { | ||
| this.listContext.alreadyMatched = true; | ||
| } | ||
| callback(this.selector, this.cbContext); | ||
| } | ||
| return result; | ||
| } | ||
| } | ||
| export class SelectorlessMatcher { | ||
| constructor(registry) { | ||
| this.registry = registry; | ||
| } | ||
| match(name) { | ||
| return this.registry.has(name) ? this.registry.get(name) : []; | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { ParseSourceSpan } from '../parse_util'; | ||
| /** | ||
| * Describes the text contents of a placeholder as it appears in an ICU expression, including its | ||
| * source span information. | ||
| */ | ||
| export interface MessagePlaceholder { | ||
| /** The text contents of the placeholder */ | ||
| text: string; | ||
| /** The source span of the placeholder */ | ||
| sourceSpan: ParseSourceSpan; | ||
| } | ||
| export declare class Message { | ||
| nodes: Node[]; | ||
| placeholders: { | ||
| [phName: string]: MessagePlaceholder; | ||
| }; | ||
| placeholderToMessage: { | ||
| [phName: string]: Message; | ||
| }; | ||
| meaning: string; | ||
| description: string; | ||
| customId: string; | ||
| sources: MessageSpan[]; | ||
| id: string; | ||
| /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ | ||
| legacyIds: string[]; | ||
| messageString: string; | ||
| /** | ||
| * @param nodes message AST | ||
| * @param placeholders maps placeholder names to static content and their source spans | ||
| * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) | ||
| * @param meaning | ||
| * @param description | ||
| * @param customId | ||
| */ | ||
| constructor(nodes: Node[], placeholders: { | ||
| [phName: string]: MessagePlaceholder; | ||
| }, placeholderToMessage: { | ||
| [phName: string]: Message; | ||
| }, meaning: string, description: string, customId: string); | ||
| } | ||
| export interface MessageSpan { | ||
| filePath: string; | ||
| startLine: number; | ||
| startCol: number; | ||
| endLine: number; | ||
| endCol: number; | ||
| } | ||
| export interface Node { | ||
| sourceSpan: ParseSourceSpan; | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class Text implements Node { | ||
| value: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class Container implements Node { | ||
| children: Node[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(children: Node[], sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class Icu implements Node { | ||
| expression: string; | ||
| type: string; | ||
| cases: { | ||
| [k: string]: Node; | ||
| }; | ||
| sourceSpan: ParseSourceSpan; | ||
| expressionPlaceholder?: string; | ||
| constructor(expression: string, type: string, cases: { | ||
| [k: string]: Node; | ||
| }, sourceSpan: ParseSourceSpan, expressionPlaceholder?: string); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class TagPlaceholder implements Node { | ||
| tag: string; | ||
| attrs: { | ||
| [k: string]: string; | ||
| }; | ||
| startName: string; | ||
| closeName: string; | ||
| children: Node[]; | ||
| isVoid: boolean; | ||
| sourceSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan | null; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(tag: string, attrs: { | ||
| [k: string]: string; | ||
| }, startName: string, closeName: string, children: Node[], isVoid: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan | null, endSourceSpan: ParseSourceSpan | null); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class Placeholder implements Node { | ||
| value: string; | ||
| name: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string, name: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class IcuPlaceholder implements Node { | ||
| value: Icu; | ||
| name: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| /** Used to capture a message computed from a previous processing pass (see `setI18nRefs()`). */ | ||
| previousMessage?: Message; | ||
| constructor(value: Icu, name: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| export declare class BlockPlaceholder implements Node { | ||
| name: string; | ||
| parameters: string[]; | ||
| startName: string; | ||
| closeName: string; | ||
| children: Node[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan | null; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, parameters: string[], startName: string, closeName: string, children: Node[], sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan | null, endSourceSpan: ParseSourceSpan | null); | ||
| visit(visitor: Visitor, context?: any): any; | ||
| } | ||
| /** | ||
| * Each HTML node that is affect by an i18n tag will also have an `i18n` property that is of type | ||
| * `I18nMeta`. | ||
| * This information is either a `Message`, which indicates it is the root of an i18n message, or a | ||
| * `Node`, which indicates is it part of a containing `Message`. | ||
| */ | ||
| export type I18nMeta = Message | Node; | ||
| export interface Visitor { | ||
| visitText(text: Text, context?: any): any; | ||
| visitContainer(container: Container, context?: any): any; | ||
| visitIcu(icu: Icu, context?: any): any; | ||
| visitTagPlaceholder(ph: TagPlaceholder, context?: any): any; | ||
| visitPlaceholder(ph: Placeholder, context?: any): any; | ||
| visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): any; | ||
| visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): any; | ||
| } | ||
| export declare class CloneVisitor implements Visitor { | ||
| visitText(text: Text, context?: any): Text; | ||
| visitContainer(container: Container, context?: any): Container; | ||
| visitIcu(icu: Icu, context?: any): Icu; | ||
| visitTagPlaceholder(ph: TagPlaceholder, context?: any): TagPlaceholder; | ||
| visitPlaceholder(ph: Placeholder, context?: any): Placeholder; | ||
| visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): IcuPlaceholder; | ||
| visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): BlockPlaceholder; | ||
| } | ||
| export declare class RecurseVisitor implements Visitor { | ||
| visitText(text: Text, context?: any): any; | ||
| visitContainer(container: Container, context?: any): any; | ||
| visitIcu(icu: Icu, context?: any): any; | ||
| visitTagPlaceholder(ph: TagPlaceholder, context?: any): any; | ||
| visitPlaceholder(ph: Placeholder, context?: any): any; | ||
| visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): any; | ||
| visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): any; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export class Message { | ||
| /** | ||
| * @param nodes message AST | ||
| * @param placeholders maps placeholder names to static content and their source spans | ||
| * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages) | ||
| * @param meaning | ||
| * @param description | ||
| * @param customId | ||
| */ | ||
| constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) { | ||
| this.nodes = nodes; | ||
| this.placeholders = placeholders; | ||
| this.placeholderToMessage = placeholderToMessage; | ||
| this.meaning = meaning; | ||
| this.description = description; | ||
| this.customId = customId; | ||
| /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */ | ||
| this.legacyIds = []; | ||
| this.id = this.customId; | ||
| this.messageString = serializeMessage(this.nodes); | ||
| if (nodes.length) { | ||
| this.sources = [ | ||
| { | ||
| filePath: nodes[0].sourceSpan.start.file.url, | ||
| startLine: nodes[0].sourceSpan.start.line + 1, | ||
| startCol: nodes[0].sourceSpan.start.col + 1, | ||
| endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1, | ||
| endCol: nodes[0].sourceSpan.start.col + 1, | ||
| }, | ||
| ]; | ||
| } | ||
| else { | ||
| this.sources = []; | ||
| } | ||
| } | ||
| } | ||
| export class Text { | ||
| constructor(value, sourceSpan) { | ||
| this.value = value; | ||
| this.sourceSpan = sourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitText(this, context); | ||
| } | ||
| } | ||
| // TODO(vicb): do we really need this node (vs an array) ? | ||
| export class Container { | ||
| constructor(children, sourceSpan) { | ||
| this.children = children; | ||
| this.sourceSpan = sourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitContainer(this, context); | ||
| } | ||
| } | ||
| export class Icu { | ||
| constructor(expression, type, cases, sourceSpan, expressionPlaceholder) { | ||
| this.expression = expression; | ||
| this.type = type; | ||
| this.cases = cases; | ||
| this.sourceSpan = sourceSpan; | ||
| this.expressionPlaceholder = expressionPlaceholder; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitIcu(this, context); | ||
| } | ||
| } | ||
| export class TagPlaceholder { | ||
| constructor(tag, attrs, startName, closeName, children, isVoid, | ||
| // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan) | ||
| sourceSpan, startSourceSpan, endSourceSpan) { | ||
| this.tag = tag; | ||
| this.attrs = attrs; | ||
| this.startName = startName; | ||
| this.closeName = closeName; | ||
| this.children = children; | ||
| this.isVoid = isVoid; | ||
| this.sourceSpan = sourceSpan; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitTagPlaceholder(this, context); | ||
| } | ||
| } | ||
| export class Placeholder { | ||
| constructor(value, name, sourceSpan) { | ||
| this.value = value; | ||
| this.name = name; | ||
| this.sourceSpan = sourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitPlaceholder(this, context); | ||
| } | ||
| } | ||
| export class IcuPlaceholder { | ||
| constructor(value, name, sourceSpan) { | ||
| this.value = value; | ||
| this.name = name; | ||
| this.sourceSpan = sourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitIcuPlaceholder(this, context); | ||
| } | ||
| } | ||
| export class BlockPlaceholder { | ||
| constructor(name, parameters, startName, closeName, children, sourceSpan, startSourceSpan, endSourceSpan) { | ||
| this.name = name; | ||
| this.parameters = parameters; | ||
| this.startName = startName; | ||
| this.closeName = closeName; | ||
| this.children = children; | ||
| this.sourceSpan = sourceSpan; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitBlockPlaceholder(this, context); | ||
| } | ||
| } | ||
| // Clone the AST | ||
| export class CloneVisitor { | ||
| visitText(text, context) { | ||
| return new Text(text.value, text.sourceSpan); | ||
| } | ||
| visitContainer(container, context) { | ||
| const children = container.children.map((n) => n.visit(this, context)); | ||
| return new Container(children, container.sourceSpan); | ||
| } | ||
| visitIcu(icu, context) { | ||
| const cases = {}; | ||
| Object.keys(icu.cases).forEach((key) => (cases[key] = icu.cases[key].visit(this, context))); | ||
| const msg = new Icu(icu.expression, icu.type, cases, icu.sourceSpan, icu.expressionPlaceholder); | ||
| return msg; | ||
| } | ||
| visitTagPlaceholder(ph, context) { | ||
| const children = ph.children.map((n) => n.visit(this, context)); | ||
| return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan); | ||
| } | ||
| visitPlaceholder(ph, context) { | ||
| return new Placeholder(ph.value, ph.name, ph.sourceSpan); | ||
| } | ||
| visitIcuPlaceholder(ph, context) { | ||
| return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan); | ||
| } | ||
| visitBlockPlaceholder(ph, context) { | ||
| const children = ph.children.map((n) => n.visit(this, context)); | ||
| return new BlockPlaceholder(ph.name, ph.parameters, ph.startName, ph.closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan); | ||
| } | ||
| } | ||
| // Visit all the nodes recursively | ||
| export class RecurseVisitor { | ||
| visitText(text, context) { } | ||
| visitContainer(container, context) { | ||
| container.children.forEach((child) => child.visit(this)); | ||
| } | ||
| visitIcu(icu, context) { | ||
| Object.keys(icu.cases).forEach((k) => { | ||
| icu.cases[k].visit(this); | ||
| }); | ||
| } | ||
| visitTagPlaceholder(ph, context) { | ||
| ph.children.forEach((child) => child.visit(this)); | ||
| } | ||
| visitPlaceholder(ph, context) { } | ||
| visitIcuPlaceholder(ph, context) { } | ||
| visitBlockPlaceholder(ph, context) { | ||
| ph.children.forEach((child) => child.visit(this)); | ||
| } | ||
| } | ||
| /** | ||
| * Serialize the message to the Localize backtick string format that would appear in compiled code. | ||
| */ | ||
| function serializeMessage(messageNodes) { | ||
| const visitor = new LocalizeMessageStringVisitor(); | ||
| const str = messageNodes.map((n) => n.visit(visitor)).join(''); | ||
| return str; | ||
| } | ||
| class LocalizeMessageStringVisitor { | ||
| visitText(text) { | ||
| return text.value; | ||
| } | ||
| visitContainer(container) { | ||
| return container.children.map((child) => child.visit(this)).join(''); | ||
| } | ||
| visitIcu(icu) { | ||
| const strCases = Object.keys(icu.cases).map((k) => `${k} {${icu.cases[k].visit(this)}}`); | ||
| return `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`; | ||
| } | ||
| visitTagPlaceholder(ph) { | ||
| const children = ph.children.map((child) => child.visit(this)).join(''); | ||
| return `{$${ph.startName}}${children}{$${ph.closeName}}`; | ||
| } | ||
| visitPlaceholder(ph) { | ||
| return `{$${ph.name}}`; | ||
| } | ||
| visitIcuPlaceholder(ph) { | ||
| return `{$${ph.name}}`; | ||
| } | ||
| visitBlockPlaceholder(ph) { | ||
| const children = ph.children.map((child) => child.visit(this)).join(''); | ||
| return `{$${ph.startName}}${children}{$${ph.closeName}}`; | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { I18nMeta } from '../i18n/i18n_ast'; | ||
| import { ParseSourceSpan } from '../parse_util'; | ||
| import { InterpolatedAttributeToken, InterpolatedTextToken } from './tokens'; | ||
| interface BaseNode { | ||
| sourceSpan: ParseSourceSpan; | ||
| visit(visitor: Visitor, context: any): any; | ||
| } | ||
| export type Node = Attribute | CDATA | Comment | DocType | Element | Expansion | ExpansionCase | Text | Block | BlockParameter | LetDeclaration | Component | Directive; | ||
| export declare abstract class NodeWithI18n implements BaseNode { | ||
| sourceSpan: ParseSourceSpan; | ||
| i18n?: I18nMeta; | ||
| constructor(sourceSpan: ParseSourceSpan, i18n?: I18nMeta); | ||
| abstract visit(visitor: Visitor, context: any): any; | ||
| } | ||
| export declare class Text extends NodeWithI18n { | ||
| value: string; | ||
| tokens: InterpolatedTextToken[]; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan, tokens: InterpolatedTextToken[], i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "text"; | ||
| } | ||
| export declare class CDATA extends NodeWithI18n { | ||
| value: string; | ||
| tokens: InterpolatedTextToken[]; | ||
| constructor(value: string, sourceSpan: ParseSourceSpan, tokens: InterpolatedTextToken[], i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "cdata"; | ||
| } | ||
| export declare class Expansion extends NodeWithI18n { | ||
| switchValue: string; | ||
| type: string; | ||
| cases: ExpansionCase[]; | ||
| switchValueSourceSpan: ParseSourceSpan; | ||
| constructor(switchValue: string, type: string, cases: ExpansionCase[], sourceSpan: ParseSourceSpan, switchValueSourceSpan: ParseSourceSpan, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| } | ||
| export declare class ExpansionCase implements BaseNode { | ||
| value: string; | ||
| expression: Node[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| valueSourceSpan: ParseSourceSpan; | ||
| expSourceSpan: ParseSourceSpan; | ||
| constructor(value: string, expression: Node[], sourceSpan: ParseSourceSpan, valueSourceSpan: ParseSourceSpan, expSourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "expansionCase"; | ||
| } | ||
| export declare class Attribute extends NodeWithI18n { | ||
| name: string; | ||
| value: string; | ||
| readonly keySpan: ParseSourceSpan | undefined; | ||
| valueSpan: ParseSourceSpan | undefined; | ||
| valueTokens: InterpolatedAttributeToken[] | undefined; | ||
| constructor(name: string, value: string, sourceSpan: ParseSourceSpan, keySpan: ParseSourceSpan | undefined, valueSpan: ParseSourceSpan | undefined, valueTokens: InterpolatedAttributeToken[] | undefined, i18n: I18nMeta | undefined); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "attribute"; | ||
| get nameSpan(): ParseSourceSpan; | ||
| } | ||
| export declare class Element extends NodeWithI18n { | ||
| name: string; | ||
| attrs: Attribute[]; | ||
| readonly directives: Directive[]; | ||
| children: Node[]; | ||
| readonly isSelfClosing: boolean; | ||
| startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| nameSpan: ParseSourceSpan | null; | ||
| readonly isVoid: boolean; | ||
| constructor(name: string, attrs: Attribute[], directives: Directive[], children: Node[], isSelfClosing: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan: ParseSourceSpan | null, nameSpan: ParseSourceSpan | null, isVoid: boolean, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "element"; | ||
| } | ||
| export declare class Comment implements BaseNode { | ||
| value: string | null; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string | null, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "comment"; | ||
| } | ||
| export declare class DocType implements BaseNode { | ||
| value: string | null; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(value: string | null, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "docType"; | ||
| } | ||
| export declare class Block extends NodeWithI18n { | ||
| name: string; | ||
| parameters: BlockParameter[]; | ||
| children: Node[]; | ||
| nameSpan: ParseSourceSpan; | ||
| startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, parameters: BlockParameter[], children: Node[], sourceSpan: ParseSourceSpan, nameSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "block"; | ||
| } | ||
| export declare class Component extends NodeWithI18n { | ||
| readonly componentName: string; | ||
| readonly tagName: string | null; | ||
| readonly fullName: string; | ||
| attrs: Attribute[]; | ||
| readonly directives: Directive[]; | ||
| readonly children: Node[]; | ||
| readonly isSelfClosing: boolean; | ||
| readonly startSourceSpan: ParseSourceSpan; | ||
| endSourceSpan: ParseSourceSpan | null; | ||
| constructor(componentName: string, tagName: string | null, fullName: string, attrs: Attribute[], directives: Directive[], children: Node[], isSelfClosing: boolean, sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null, i18n?: I18nMeta); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "component"; | ||
| } | ||
| export declare class Directive implements BaseNode { | ||
| readonly name: string; | ||
| readonly attrs: Attribute[]; | ||
| readonly sourceSpan: ParseSourceSpan; | ||
| readonly startSourceSpan: ParseSourceSpan; | ||
| readonly endSourceSpan: ParseSourceSpan | null; | ||
| constructor(name: string, attrs: Attribute[], sourceSpan: ParseSourceSpan, startSourceSpan: ParseSourceSpan, endSourceSpan?: ParseSourceSpan | null); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "directive"; | ||
| } | ||
| export declare class BlockParameter implements BaseNode { | ||
| expression: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| constructor(expression: string, sourceSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "blockParameter"; | ||
| readonly startSourceSpan: null; | ||
| readonly endSourceSpan: null; | ||
| } | ||
| export declare class LetDeclaration implements BaseNode { | ||
| name: string; | ||
| value: string; | ||
| sourceSpan: ParseSourceSpan; | ||
| readonly nameSpan: ParseSourceSpan; | ||
| valueSpan: ParseSourceSpan; | ||
| constructor(name: string, value: string, sourceSpan: ParseSourceSpan, nameSpan: ParseSourceSpan, valueSpan: ParseSourceSpan); | ||
| visit(visitor: Visitor, context: any): any; | ||
| readonly type = "letDeclaration"; | ||
| readonly startSourceSpan: null; | ||
| readonly endSourceSpan: null; | ||
| } | ||
| export interface Visitor { | ||
| visit?(node: Node, context: any): any; | ||
| visitElement(element: Element, context: any): any; | ||
| visitAttribute(attribute: Attribute, context: any): any; | ||
| visitText(text: Text, context: any): any; | ||
| visitCdata(text: CDATA, context: any): any; | ||
| visitComment(comment: Comment, context: any): any; | ||
| visitDocType(docType: DocType, context: any): any; | ||
| visitExpansion(expansion: Expansion, context: any): any; | ||
| visitExpansionCase(expansionCase: ExpansionCase, context: any): any; | ||
| visitBlock(block: Block, context: any): any; | ||
| visitBlockParameter(parameter: BlockParameter, context: any): any; | ||
| visitLetDeclaration(decl: LetDeclaration, context: any): any; | ||
| visitComponent(component: Component, context: any): any; | ||
| visitDirective(directive: Directive, context: any): any; | ||
| } | ||
| export declare function visitAll(visitor: Visitor, nodes: Node[], context?: any): any[]; | ||
| export declare class RecursiveVisitor implements Visitor { | ||
| constructor(); | ||
| visitElement(ast: Element, context: any): any; | ||
| visitAttribute(ast: Attribute, context: any): any; | ||
| visitText(ast: Text, context: any): any; | ||
| visitCdata(ast: CDATA, context: any): any; | ||
| visitComment(ast: Comment, context: any): any; | ||
| visitDocType(ast: DocType, context: any): any; | ||
| visitExpansion(ast: Expansion, context: any): any; | ||
| visitExpansionCase(ast: ExpansionCase, context: any): any; | ||
| visitBlock(block: Block, context: any): any; | ||
| visitBlockParameter(ast: BlockParameter, context: any): any; | ||
| visitLetDeclaration(decl: LetDeclaration, context: any): void; | ||
| visitComponent(component: Component, context: any): void; | ||
| visitDirective(directive: Directive, context: any): void; | ||
| private visitChildren; | ||
| } | ||
| export {}; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export class NodeWithI18n { | ||
| constructor(sourceSpan, i18n) { | ||
| this.sourceSpan = sourceSpan; | ||
| this.i18n = i18n; | ||
| } | ||
| } | ||
| export class Text extends NodeWithI18n { | ||
| constructor(value, sourceSpan, tokens, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.value = value; | ||
| this.tokens = tokens; | ||
| this.type = 'text'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitText(this, context); | ||
| } | ||
| } | ||
| export class CDATA extends NodeWithI18n { | ||
| constructor(value, sourceSpan, tokens, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.value = value; | ||
| this.tokens = tokens; | ||
| this.type = 'cdata'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitCdata(this, context); | ||
| } | ||
| } | ||
| export class Expansion extends NodeWithI18n { | ||
| constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.switchValue = switchValue; | ||
| this.type = type; | ||
| this.cases = cases; | ||
| this.switchValueSourceSpan = switchValueSourceSpan; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitExpansion(this, context); | ||
| } | ||
| } | ||
| export class ExpansionCase { | ||
| constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) { | ||
| this.value = value; | ||
| this.expression = expression; | ||
| this.sourceSpan = sourceSpan; | ||
| this.valueSourceSpan = valueSourceSpan; | ||
| this.expSourceSpan = expSourceSpan; | ||
| this.type = 'expansionCase'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitExpansionCase(this, context); | ||
| } | ||
| } | ||
| export class Attribute extends NodeWithI18n { | ||
| constructor(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.name = name; | ||
| this.value = value; | ||
| this.keySpan = keySpan; | ||
| this.valueSpan = valueSpan; | ||
| this.valueTokens = valueTokens; | ||
| this.type = 'attribute'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitAttribute(this, context); | ||
| } | ||
| // angular-html-parser: backwards compatibility for Prettier | ||
| get nameSpan() { | ||
| return this.keySpan; | ||
| } | ||
| } | ||
| export class Element extends NodeWithI18n { | ||
| constructor(name, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, nameSpan = null, isVoid, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.name = name; | ||
| this.attrs = attrs; | ||
| this.directives = directives; | ||
| this.children = children; | ||
| this.isSelfClosing = isSelfClosing; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| this.nameSpan = nameSpan; | ||
| this.isVoid = isVoid; | ||
| this.type = 'element'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitElement(this, context); | ||
| } | ||
| } | ||
| export class Comment { | ||
| constructor(value, sourceSpan) { | ||
| this.value = value; | ||
| this.sourceSpan = sourceSpan; | ||
| this.type = 'comment'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitComment(this, context); | ||
| } | ||
| } | ||
| export class DocType { | ||
| constructor(value, sourceSpan) { | ||
| this.value = value; | ||
| this.sourceSpan = sourceSpan; | ||
| this.type = 'docType'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitDocType(this, context); | ||
| } | ||
| } | ||
| export class Block extends NodeWithI18n { | ||
| constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.name = name; | ||
| this.parameters = parameters; | ||
| this.children = children; | ||
| this.nameSpan = nameSpan; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| this.type = 'block'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitBlock(this, context); | ||
| } | ||
| } | ||
| export class Component extends NodeWithI18n { | ||
| constructor(componentName, tagName, fullName, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) { | ||
| super(sourceSpan, i18n); | ||
| this.componentName = componentName; | ||
| this.tagName = tagName; | ||
| this.fullName = fullName; | ||
| this.attrs = attrs; | ||
| this.directives = directives; | ||
| this.children = children; | ||
| this.isSelfClosing = isSelfClosing; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| this.type = 'component'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitComponent(this, context); | ||
| } | ||
| } | ||
| export class Directive { | ||
| constructor(name, attrs, sourceSpan, startSourceSpan, endSourceSpan = null) { | ||
| this.name = name; | ||
| this.attrs = attrs; | ||
| this.sourceSpan = sourceSpan; | ||
| this.startSourceSpan = startSourceSpan; | ||
| this.endSourceSpan = endSourceSpan; | ||
| this.type = 'directive'; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitDirective(this, context); | ||
| } | ||
| } | ||
| export class BlockParameter { | ||
| constructor(expression, sourceSpan) { | ||
| this.expression = expression; | ||
| this.sourceSpan = sourceSpan; | ||
| this.type = 'blockParameter'; | ||
| this.startSourceSpan = null; | ||
| this.endSourceSpan = null; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitBlockParameter(this, context); | ||
| } | ||
| } | ||
| export class LetDeclaration { | ||
| constructor(name, value, sourceSpan, nameSpan, valueSpan) { | ||
| this.name = name; | ||
| this.value = value; | ||
| this.sourceSpan = sourceSpan; | ||
| this.nameSpan = nameSpan; | ||
| this.valueSpan = valueSpan; | ||
| this.type = 'letDeclaration'; | ||
| this.startSourceSpan = null; | ||
| this.endSourceSpan = null; | ||
| } | ||
| visit(visitor, context) { | ||
| return visitor.visitLetDeclaration(this, context); | ||
| } | ||
| } | ||
| export function visitAll(visitor, nodes, context = null) { | ||
| const result = []; | ||
| const visit = visitor.visit | ||
| ? (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) | ||
| : (ast) => ast.visit(visitor, context); | ||
| nodes.forEach((ast) => { | ||
| const astResult = visit(ast); | ||
| if (astResult) { | ||
| result.push(astResult); | ||
| } | ||
| }); | ||
| return result; | ||
| } | ||
| export class RecursiveVisitor { | ||
| constructor() { } | ||
| visitElement(ast, context) { | ||
| this.visitChildren(context, (visit) => { | ||
| visit(ast.attrs); | ||
| visit(ast.directives); | ||
| visit(ast.children); | ||
| }); | ||
| } | ||
| visitAttribute(ast, context) { } | ||
| visitText(ast, context) { } | ||
| visitCdata(ast, context) { } | ||
| visitComment(ast, context) { } | ||
| visitDocType(ast, context) { } | ||
| visitExpansion(ast, context) { | ||
| return this.visitChildren(context, (visit) => { | ||
| visit(ast.cases); | ||
| }); | ||
| } | ||
| visitExpansionCase(ast, context) { } | ||
| visitBlock(block, context) { | ||
| this.visitChildren(context, (visit) => { | ||
| visit(block.parameters); | ||
| visit(block.children); | ||
| }); | ||
| } | ||
| visitBlockParameter(ast, context) { } | ||
| visitLetDeclaration(decl, context) { } | ||
| visitComponent(component, context) { | ||
| this.visitChildren(context, (visit) => { | ||
| visit(component.attrs); | ||
| visit(component.children); | ||
| }); | ||
| } | ||
| visitDirective(directive, context) { | ||
| this.visitChildren(context, (visit) => { | ||
| visit(directive.attrs); | ||
| }); | ||
| } | ||
| visitChildren(context, cb) { | ||
| let results = []; | ||
| let t = this; | ||
| function visit(children) { | ||
| if (children) | ||
| results.push(visitAll(t, children, context)); | ||
| } | ||
| cb(visit); | ||
| return Array.prototype.concat.apply([], results); | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare class InterpolationConfig { | ||
| start: string; | ||
| end: string; | ||
| static fromArray(markers: [string, string] | null): InterpolationConfig; | ||
| constructor(start: string, end: string); | ||
| } | ||
| export declare const DEFAULT_INTERPOLATION_CONFIG: InterpolationConfig; | ||
| export declare const DEFAULT_CONTAINER_BLOCKS: Set<string>; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { assertInterpolationSymbols } from "../assertions.js"; | ||
| export class InterpolationConfig { | ||
| static fromArray(markers) { | ||
| if (!markers) { | ||
| return DEFAULT_INTERPOLATION_CONFIG; | ||
| } | ||
| assertInterpolationSymbols('interpolation', markers); | ||
| return new InterpolationConfig(markers[0], markers[1]); | ||
| } | ||
| constructor(start, end) { | ||
| this.start = start; | ||
| this.end = end; | ||
| } | ||
| } | ||
| export const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}'); | ||
| export const DEFAULT_CONTAINER_BLOCKS = new Set(['switch']); |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare const NAMED_ENTITIES: Record<string, string>; | ||
| export declare const NGSP_UNICODE = "\uE500"; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| // Mapping between all HTML entity names and their unicode representation. | ||
| // Generated from https://html.spec.whatwg.org/multipage/entities.json by stripping | ||
| // the `&` and `;` from the keys and removing the duplicates. | ||
| // see https://www.w3.org/TR/html51/syntax.html#named-character-references | ||
| export const NAMED_ENTITIES = { | ||
| 'AElig': '\u00C6', | ||
| 'AMP': '\u0026', | ||
| 'amp': '\u0026', | ||
| 'Aacute': '\u00C1', | ||
| 'Abreve': '\u0102', | ||
| 'Acirc': '\u00C2', | ||
| 'Acy': '\u0410', | ||
| 'Afr': '\uD835\uDD04', | ||
| 'Agrave': '\u00C0', | ||
| 'Alpha': '\u0391', | ||
| 'Amacr': '\u0100', | ||
| 'And': '\u2A53', | ||
| 'Aogon': '\u0104', | ||
| 'Aopf': '\uD835\uDD38', | ||
| 'ApplyFunction': '\u2061', | ||
| 'af': '\u2061', | ||
| 'Aring': '\u00C5', | ||
| 'angst': '\u00C5', | ||
| 'Ascr': '\uD835\uDC9C', | ||
| 'Assign': '\u2254', | ||
| 'colone': '\u2254', | ||
| 'coloneq': '\u2254', | ||
| 'Atilde': '\u00C3', | ||
| 'Auml': '\u00C4', | ||
| 'Backslash': '\u2216', | ||
| 'setminus': '\u2216', | ||
| 'setmn': '\u2216', | ||
| 'smallsetminus': '\u2216', | ||
| 'ssetmn': '\u2216', | ||
| 'Barv': '\u2AE7', | ||
| 'Barwed': '\u2306', | ||
| 'doublebarwedge': '\u2306', | ||
| 'Bcy': '\u0411', | ||
| 'Because': '\u2235', | ||
| 'becaus': '\u2235', | ||
| 'because': '\u2235', | ||
| 'Bernoullis': '\u212C', | ||
| 'Bscr': '\u212C', | ||
| 'bernou': '\u212C', | ||
| 'Beta': '\u0392', | ||
| 'Bfr': '\uD835\uDD05', | ||
| 'Bopf': '\uD835\uDD39', | ||
| 'Breve': '\u02D8', | ||
| 'breve': '\u02D8', | ||
| 'Bumpeq': '\u224E', | ||
| 'HumpDownHump': '\u224E', | ||
| 'bump': '\u224E', | ||
| 'CHcy': '\u0427', | ||
| 'COPY': '\u00A9', | ||
| 'copy': '\u00A9', | ||
| 'Cacute': '\u0106', | ||
| 'Cap': '\u22D2', | ||
| 'CapitalDifferentialD': '\u2145', | ||
| 'DD': '\u2145', | ||
| 'Cayleys': '\u212D', | ||
| 'Cfr': '\u212D', | ||
| 'Ccaron': '\u010C', | ||
| 'Ccedil': '\u00C7', | ||
| 'Ccirc': '\u0108', | ||
| 'Cconint': '\u2230', | ||
| 'Cdot': '\u010A', | ||
| 'Cedilla': '\u00B8', | ||
| 'cedil': '\u00B8', | ||
| 'CenterDot': '\u00B7', | ||
| 'centerdot': '\u00B7', | ||
| 'middot': '\u00B7', | ||
| 'Chi': '\u03A7', | ||
| 'CircleDot': '\u2299', | ||
| 'odot': '\u2299', | ||
| 'CircleMinus': '\u2296', | ||
| 'ominus': '\u2296', | ||
| 'CirclePlus': '\u2295', | ||
| 'oplus': '\u2295', | ||
| 'CircleTimes': '\u2297', | ||
| 'otimes': '\u2297', | ||
| 'ClockwiseContourIntegral': '\u2232', | ||
| 'cwconint': '\u2232', | ||
| 'CloseCurlyDoubleQuote': '\u201D', | ||
| 'rdquo': '\u201D', | ||
| 'rdquor': '\u201D', | ||
| 'CloseCurlyQuote': '\u2019', | ||
| 'rsquo': '\u2019', | ||
| 'rsquor': '\u2019', | ||
| 'Colon': '\u2237', | ||
| 'Proportion': '\u2237', | ||
| 'Colone': '\u2A74', | ||
| 'Congruent': '\u2261', | ||
| 'equiv': '\u2261', | ||
| 'Conint': '\u222F', | ||
| 'DoubleContourIntegral': '\u222F', | ||
| 'ContourIntegral': '\u222E', | ||
| 'conint': '\u222E', | ||
| 'oint': '\u222E', | ||
| 'Copf': '\u2102', | ||
| 'complexes': '\u2102', | ||
| 'Coproduct': '\u2210', | ||
| 'coprod': '\u2210', | ||
| 'CounterClockwiseContourIntegral': '\u2233', | ||
| 'awconint': '\u2233', | ||
| 'Cross': '\u2A2F', | ||
| 'Cscr': '\uD835\uDC9E', | ||
| 'Cup': '\u22D3', | ||
| 'CupCap': '\u224D', | ||
| 'asympeq': '\u224D', | ||
| 'DDotrahd': '\u2911', | ||
| 'DJcy': '\u0402', | ||
| 'DScy': '\u0405', | ||
| 'DZcy': '\u040F', | ||
| 'Dagger': '\u2021', | ||
| 'ddagger': '\u2021', | ||
| 'Darr': '\u21A1', | ||
| 'Dashv': '\u2AE4', | ||
| 'DoubleLeftTee': '\u2AE4', | ||
| 'Dcaron': '\u010E', | ||
| 'Dcy': '\u0414', | ||
| 'Del': '\u2207', | ||
| 'nabla': '\u2207', | ||
| 'Delta': '\u0394', | ||
| 'Dfr': '\uD835\uDD07', | ||
| 'DiacriticalAcute': '\u00B4', | ||
| 'acute': '\u00B4', | ||
| 'DiacriticalDot': '\u02D9', | ||
| 'dot': '\u02D9', | ||
| 'DiacriticalDoubleAcute': '\u02DD', | ||
| 'dblac': '\u02DD', | ||
| 'DiacriticalGrave': '\u0060', | ||
| 'grave': '\u0060', | ||
| 'DiacriticalTilde': '\u02DC', | ||
| 'tilde': '\u02DC', | ||
| 'Diamond': '\u22C4', | ||
| 'diam': '\u22C4', | ||
| 'diamond': '\u22C4', | ||
| 'DifferentialD': '\u2146', | ||
| 'dd': '\u2146', | ||
| 'Dopf': '\uD835\uDD3B', | ||
| 'Dot': '\u00A8', | ||
| 'DoubleDot': '\u00A8', | ||
| 'die': '\u00A8', | ||
| 'uml': '\u00A8', | ||
| 'DotDot': '\u20DC', | ||
| 'DotEqual': '\u2250', | ||
| 'doteq': '\u2250', | ||
| 'esdot': '\u2250', | ||
| 'DoubleDownArrow': '\u21D3', | ||
| 'Downarrow': '\u21D3', | ||
| 'dArr': '\u21D3', | ||
| 'DoubleLeftArrow': '\u21D0', | ||
| 'Leftarrow': '\u21D0', | ||
| 'lArr': '\u21D0', | ||
| 'DoubleLeftRightArrow': '\u21D4', | ||
| 'Leftrightarrow': '\u21D4', | ||
| 'hArr': '\u21D4', | ||
| 'iff': '\u21D4', | ||
| 'DoubleLongLeftArrow': '\u27F8', | ||
| 'Longleftarrow': '\u27F8', | ||
| 'xlArr': '\u27F8', | ||
| 'DoubleLongLeftRightArrow': '\u27FA', | ||
| 'Longleftrightarrow': '\u27FA', | ||
| 'xhArr': '\u27FA', | ||
| 'DoubleLongRightArrow': '\u27F9', | ||
| 'Longrightarrow': '\u27F9', | ||
| 'xrArr': '\u27F9', | ||
| 'DoubleRightArrow': '\u21D2', | ||
| 'Implies': '\u21D2', | ||
| 'Rightarrow': '\u21D2', | ||
| 'rArr': '\u21D2', | ||
| 'DoubleRightTee': '\u22A8', | ||
| 'vDash': '\u22A8', | ||
| 'DoubleUpArrow': '\u21D1', | ||
| 'Uparrow': '\u21D1', | ||
| 'uArr': '\u21D1', | ||
| 'DoubleUpDownArrow': '\u21D5', | ||
| 'Updownarrow': '\u21D5', | ||
| 'vArr': '\u21D5', | ||
| 'DoubleVerticalBar': '\u2225', | ||
| 'par': '\u2225', | ||
| 'parallel': '\u2225', | ||
| 'shortparallel': '\u2225', | ||
| 'spar': '\u2225', | ||
| 'DownArrow': '\u2193', | ||
| 'ShortDownArrow': '\u2193', | ||
| 'darr': '\u2193', | ||
| 'downarrow': '\u2193', | ||
| 'DownArrowBar': '\u2913', | ||
| 'DownArrowUpArrow': '\u21F5', | ||
| 'duarr': '\u21F5', | ||
| 'DownBreve': '\u0311', | ||
| 'DownLeftRightVector': '\u2950', | ||
| 'DownLeftTeeVector': '\u295E', | ||
| 'DownLeftVector': '\u21BD', | ||
| 'leftharpoondown': '\u21BD', | ||
| 'lhard': '\u21BD', | ||
| 'DownLeftVectorBar': '\u2956', | ||
| 'DownRightTeeVector': '\u295F', | ||
| 'DownRightVector': '\u21C1', | ||
| 'rhard': '\u21C1', | ||
| 'rightharpoondown': '\u21C1', | ||
| 'DownRightVectorBar': '\u2957', | ||
| 'DownTee': '\u22A4', | ||
| 'top': '\u22A4', | ||
| 'DownTeeArrow': '\u21A7', | ||
| 'mapstodown': '\u21A7', | ||
| 'Dscr': '\uD835\uDC9F', | ||
| 'Dstrok': '\u0110', | ||
| 'ENG': '\u014A', | ||
| 'ETH': '\u00D0', | ||
| 'Eacute': '\u00C9', | ||
| 'Ecaron': '\u011A', | ||
| 'Ecirc': '\u00CA', | ||
| 'Ecy': '\u042D', | ||
| 'Edot': '\u0116', | ||
| 'Efr': '\uD835\uDD08', | ||
| 'Egrave': '\u00C8', | ||
| 'Element': '\u2208', | ||
| 'in': '\u2208', | ||
| 'isin': '\u2208', | ||
| 'isinv': '\u2208', | ||
| 'Emacr': '\u0112', | ||
| 'EmptySmallSquare': '\u25FB', | ||
| 'EmptyVerySmallSquare': '\u25AB', | ||
| 'Eogon': '\u0118', | ||
| 'Eopf': '\uD835\uDD3C', | ||
| 'Epsilon': '\u0395', | ||
| 'Equal': '\u2A75', | ||
| 'EqualTilde': '\u2242', | ||
| 'eqsim': '\u2242', | ||
| 'esim': '\u2242', | ||
| 'Equilibrium': '\u21CC', | ||
| 'rightleftharpoons': '\u21CC', | ||
| 'rlhar': '\u21CC', | ||
| 'Escr': '\u2130', | ||
| 'expectation': '\u2130', | ||
| 'Esim': '\u2A73', | ||
| 'Eta': '\u0397', | ||
| 'Euml': '\u00CB', | ||
| 'Exists': '\u2203', | ||
| 'exist': '\u2203', | ||
| 'ExponentialE': '\u2147', | ||
| 'ee': '\u2147', | ||
| 'exponentiale': '\u2147', | ||
| 'Fcy': '\u0424', | ||
| 'Ffr': '\uD835\uDD09', | ||
| 'FilledSmallSquare': '\u25FC', | ||
| 'FilledVerySmallSquare': '\u25AA', | ||
| 'blacksquare': '\u25AA', | ||
| 'squarf': '\u25AA', | ||
| 'squf': '\u25AA', | ||
| 'Fopf': '\uD835\uDD3D', | ||
| 'ForAll': '\u2200', | ||
| 'forall': '\u2200', | ||
| 'Fouriertrf': '\u2131', | ||
| 'Fscr': '\u2131', | ||
| 'GJcy': '\u0403', | ||
| 'GT': '\u003E', | ||
| 'gt': '\u003E', | ||
| 'Gamma': '\u0393', | ||
| 'Gammad': '\u03DC', | ||
| 'Gbreve': '\u011E', | ||
| 'Gcedil': '\u0122', | ||
| 'Gcirc': '\u011C', | ||
| 'Gcy': '\u0413', | ||
| 'Gdot': '\u0120', | ||
| 'Gfr': '\uD835\uDD0A', | ||
| 'Gg': '\u22D9', | ||
| 'ggg': '\u22D9', | ||
| 'Gopf': '\uD835\uDD3E', | ||
| 'GreaterEqual': '\u2265', | ||
| 'ge': '\u2265', | ||
| 'geq': '\u2265', | ||
| 'GreaterEqualLess': '\u22DB', | ||
| 'gel': '\u22DB', | ||
| 'gtreqless': '\u22DB', | ||
| 'GreaterFullEqual': '\u2267', | ||
| 'gE': '\u2267', | ||
| 'geqq': '\u2267', | ||
| 'GreaterGreater': '\u2AA2', | ||
| 'GreaterLess': '\u2277', | ||
| 'gl': '\u2277', | ||
| 'gtrless': '\u2277', | ||
| 'GreaterSlantEqual': '\u2A7E', | ||
| 'geqslant': '\u2A7E', | ||
| 'ges': '\u2A7E', | ||
| 'GreaterTilde': '\u2273', | ||
| 'gsim': '\u2273', | ||
| 'gtrsim': '\u2273', | ||
| 'Gscr': '\uD835\uDCA2', | ||
| 'Gt': '\u226B', | ||
| 'NestedGreaterGreater': '\u226B', | ||
| 'gg': '\u226B', | ||
| 'HARDcy': '\u042A', | ||
| 'Hacek': '\u02C7', | ||
| 'caron': '\u02C7', | ||
| 'Hat': '\u005E', | ||
| 'Hcirc': '\u0124', | ||
| 'Hfr': '\u210C', | ||
| 'Poincareplane': '\u210C', | ||
| 'HilbertSpace': '\u210B', | ||
| 'Hscr': '\u210B', | ||
| 'hamilt': '\u210B', | ||
| 'Hopf': '\u210D', | ||
| 'quaternions': '\u210D', | ||
| 'HorizontalLine': '\u2500', | ||
| 'boxh': '\u2500', | ||
| 'Hstrok': '\u0126', | ||
| 'HumpEqual': '\u224F', | ||
| 'bumpe': '\u224F', | ||
| 'bumpeq': '\u224F', | ||
| 'IEcy': '\u0415', | ||
| 'IJlig': '\u0132', | ||
| 'IOcy': '\u0401', | ||
| 'Iacute': '\u00CD', | ||
| 'Icirc': '\u00CE', | ||
| 'Icy': '\u0418', | ||
| 'Idot': '\u0130', | ||
| 'Ifr': '\u2111', | ||
| 'Im': '\u2111', | ||
| 'image': '\u2111', | ||
| 'imagpart': '\u2111', | ||
| 'Igrave': '\u00CC', | ||
| 'Imacr': '\u012A', | ||
| 'ImaginaryI': '\u2148', | ||
| 'ii': '\u2148', | ||
| 'Int': '\u222C', | ||
| 'Integral': '\u222B', | ||
| 'int': '\u222B', | ||
| 'Intersection': '\u22C2', | ||
| 'bigcap': '\u22C2', | ||
| 'xcap': '\u22C2', | ||
| 'InvisibleComma': '\u2063', | ||
| 'ic': '\u2063', | ||
| 'InvisibleTimes': '\u2062', | ||
| 'it': '\u2062', | ||
| 'Iogon': '\u012E', | ||
| 'Iopf': '\uD835\uDD40', | ||
| 'Iota': '\u0399', | ||
| 'Iscr': '\u2110', | ||
| 'imagline': '\u2110', | ||
| 'Itilde': '\u0128', | ||
| 'Iukcy': '\u0406', | ||
| 'Iuml': '\u00CF', | ||
| 'Jcirc': '\u0134', | ||
| 'Jcy': '\u0419', | ||
| 'Jfr': '\uD835\uDD0D', | ||
| 'Jopf': '\uD835\uDD41', | ||
| 'Jscr': '\uD835\uDCA5', | ||
| 'Jsercy': '\u0408', | ||
| 'Jukcy': '\u0404', | ||
| 'KHcy': '\u0425', | ||
| 'KJcy': '\u040C', | ||
| 'Kappa': '\u039A', | ||
| 'Kcedil': '\u0136', | ||
| 'Kcy': '\u041A', | ||
| 'Kfr': '\uD835\uDD0E', | ||
| 'Kopf': '\uD835\uDD42', | ||
| 'Kscr': '\uD835\uDCA6', | ||
| 'LJcy': '\u0409', | ||
| 'LT': '\u003C', | ||
| 'lt': '\u003C', | ||
| 'Lacute': '\u0139', | ||
| 'Lambda': '\u039B', | ||
| 'Lang': '\u27EA', | ||
| 'Laplacetrf': '\u2112', | ||
| 'Lscr': '\u2112', | ||
| 'lagran': '\u2112', | ||
| 'Larr': '\u219E', | ||
| 'twoheadleftarrow': '\u219E', | ||
| 'Lcaron': '\u013D', | ||
| 'Lcedil': '\u013B', | ||
| 'Lcy': '\u041B', | ||
| 'LeftAngleBracket': '\u27E8', | ||
| 'lang': '\u27E8', | ||
| 'langle': '\u27E8', | ||
| 'LeftArrow': '\u2190', | ||
| 'ShortLeftArrow': '\u2190', | ||
| 'larr': '\u2190', | ||
| 'leftarrow': '\u2190', | ||
| 'slarr': '\u2190', | ||
| 'LeftArrowBar': '\u21E4', | ||
| 'larrb': '\u21E4', | ||
| 'LeftArrowRightArrow': '\u21C6', | ||
| 'leftrightarrows': '\u21C6', | ||
| 'lrarr': '\u21C6', | ||
| 'LeftCeiling': '\u2308', | ||
| 'lceil': '\u2308', | ||
| 'LeftDoubleBracket': '\u27E6', | ||
| 'lobrk': '\u27E6', | ||
| 'LeftDownTeeVector': '\u2961', | ||
| 'LeftDownVector': '\u21C3', | ||
| 'dharl': '\u21C3', | ||
| 'downharpoonleft': '\u21C3', | ||
| 'LeftDownVectorBar': '\u2959', | ||
| 'LeftFloor': '\u230A', | ||
| 'lfloor': '\u230A', | ||
| 'LeftRightArrow': '\u2194', | ||
| 'harr': '\u2194', | ||
| 'leftrightarrow': '\u2194', | ||
| 'LeftRightVector': '\u294E', | ||
| 'LeftTee': '\u22A3', | ||
| 'dashv': '\u22A3', | ||
| 'LeftTeeArrow': '\u21A4', | ||
| 'mapstoleft': '\u21A4', | ||
| 'LeftTeeVector': '\u295A', | ||
| 'LeftTriangle': '\u22B2', | ||
| 'vartriangleleft': '\u22B2', | ||
| 'vltri': '\u22B2', | ||
| 'LeftTriangleBar': '\u29CF', | ||
| 'LeftTriangleEqual': '\u22B4', | ||
| 'ltrie': '\u22B4', | ||
| 'trianglelefteq': '\u22B4', | ||
| 'LeftUpDownVector': '\u2951', | ||
| 'LeftUpTeeVector': '\u2960', | ||
| 'LeftUpVector': '\u21BF', | ||
| 'uharl': '\u21BF', | ||
| 'upharpoonleft': '\u21BF', | ||
| 'LeftUpVectorBar': '\u2958', | ||
| 'LeftVector': '\u21BC', | ||
| 'leftharpoonup': '\u21BC', | ||
| 'lharu': '\u21BC', | ||
| 'LeftVectorBar': '\u2952', | ||
| 'LessEqualGreater': '\u22DA', | ||
| 'leg': '\u22DA', | ||
| 'lesseqgtr': '\u22DA', | ||
| 'LessFullEqual': '\u2266', | ||
| 'lE': '\u2266', | ||
| 'leqq': '\u2266', | ||
| 'LessGreater': '\u2276', | ||
| 'lessgtr': '\u2276', | ||
| 'lg': '\u2276', | ||
| 'LessLess': '\u2AA1', | ||
| 'LessSlantEqual': '\u2A7D', | ||
| 'leqslant': '\u2A7D', | ||
| 'les': '\u2A7D', | ||
| 'LessTilde': '\u2272', | ||
| 'lesssim': '\u2272', | ||
| 'lsim': '\u2272', | ||
| 'Lfr': '\uD835\uDD0F', | ||
| 'Ll': '\u22D8', | ||
| 'Lleftarrow': '\u21DA', | ||
| 'lAarr': '\u21DA', | ||
| 'Lmidot': '\u013F', | ||
| 'LongLeftArrow': '\u27F5', | ||
| 'longleftarrow': '\u27F5', | ||
| 'xlarr': '\u27F5', | ||
| 'LongLeftRightArrow': '\u27F7', | ||
| 'longleftrightarrow': '\u27F7', | ||
| 'xharr': '\u27F7', | ||
| 'LongRightArrow': '\u27F6', | ||
| 'longrightarrow': '\u27F6', | ||
| 'xrarr': '\u27F6', | ||
| 'Lopf': '\uD835\uDD43', | ||
| 'LowerLeftArrow': '\u2199', | ||
| 'swarr': '\u2199', | ||
| 'swarrow': '\u2199', | ||
| 'LowerRightArrow': '\u2198', | ||
| 'searr': '\u2198', | ||
| 'searrow': '\u2198', | ||
| 'Lsh': '\u21B0', | ||
| 'lsh': '\u21B0', | ||
| 'Lstrok': '\u0141', | ||
| 'Lt': '\u226A', | ||
| 'NestedLessLess': '\u226A', | ||
| 'll': '\u226A', | ||
| 'Map': '\u2905', | ||
| 'Mcy': '\u041C', | ||
| 'MediumSpace': '\u205F', | ||
| 'Mellintrf': '\u2133', | ||
| 'Mscr': '\u2133', | ||
| 'phmmat': '\u2133', | ||
| 'Mfr': '\uD835\uDD10', | ||
| 'MinusPlus': '\u2213', | ||
| 'mnplus': '\u2213', | ||
| 'mp': '\u2213', | ||
| 'Mopf': '\uD835\uDD44', | ||
| 'Mu': '\u039C', | ||
| 'NJcy': '\u040A', | ||
| 'Nacute': '\u0143', | ||
| 'Ncaron': '\u0147', | ||
| 'Ncedil': '\u0145', | ||
| 'Ncy': '\u041D', | ||
| 'NegativeMediumSpace': '\u200B', | ||
| 'NegativeThickSpace': '\u200B', | ||
| 'NegativeThinSpace': '\u200B', | ||
| 'NegativeVeryThinSpace': '\u200B', | ||
| 'ZeroWidthSpace': '\u200B', | ||
| 'NewLine': '\u000A', | ||
| 'Nfr': '\uD835\uDD11', | ||
| 'NoBreak': '\u2060', | ||
| 'NonBreakingSpace': '\u00A0', | ||
| 'nbsp': '\u00A0', | ||
| 'Nopf': '\u2115', | ||
| 'naturals': '\u2115', | ||
| 'Not': '\u2AEC', | ||
| 'NotCongruent': '\u2262', | ||
| 'nequiv': '\u2262', | ||
| 'NotCupCap': '\u226D', | ||
| 'NotDoubleVerticalBar': '\u2226', | ||
| 'npar': '\u2226', | ||
| 'nparallel': '\u2226', | ||
| 'nshortparallel': '\u2226', | ||
| 'nspar': '\u2226', | ||
| 'NotElement': '\u2209', | ||
| 'notin': '\u2209', | ||
| 'notinva': '\u2209', | ||
| 'NotEqual': '\u2260', | ||
| 'ne': '\u2260', | ||
| 'NotEqualTilde': '\u2242\u0338', | ||
| 'nesim': '\u2242\u0338', | ||
| 'NotExists': '\u2204', | ||
| 'nexist': '\u2204', | ||
| 'nexists': '\u2204', | ||
| 'NotGreater': '\u226F', | ||
| 'ngt': '\u226F', | ||
| 'ngtr': '\u226F', | ||
| 'NotGreaterEqual': '\u2271', | ||
| 'nge': '\u2271', | ||
| 'ngeq': '\u2271', | ||
| 'NotGreaterFullEqual': '\u2267\u0338', | ||
| 'ngE': '\u2267\u0338', | ||
| 'ngeqq': '\u2267\u0338', | ||
| 'NotGreaterGreater': '\u226B\u0338', | ||
| 'nGtv': '\u226B\u0338', | ||
| 'NotGreaterLess': '\u2279', | ||
| 'ntgl': '\u2279', | ||
| 'NotGreaterSlantEqual': '\u2A7E\u0338', | ||
| 'ngeqslant': '\u2A7E\u0338', | ||
| 'nges': '\u2A7E\u0338', | ||
| 'NotGreaterTilde': '\u2275', | ||
| 'ngsim': '\u2275', | ||
| 'NotHumpDownHump': '\u224E\u0338', | ||
| 'nbump': '\u224E\u0338', | ||
| 'NotHumpEqual': '\u224F\u0338', | ||
| 'nbumpe': '\u224F\u0338', | ||
| 'NotLeftTriangle': '\u22EA', | ||
| 'nltri': '\u22EA', | ||
| 'ntriangleleft': '\u22EA', | ||
| 'NotLeftTriangleBar': '\u29CF\u0338', | ||
| 'NotLeftTriangleEqual': '\u22EC', | ||
| 'nltrie': '\u22EC', | ||
| 'ntrianglelefteq': '\u22EC', | ||
| 'NotLess': '\u226E', | ||
| 'nless': '\u226E', | ||
| 'nlt': '\u226E', | ||
| 'NotLessEqual': '\u2270', | ||
| 'nle': '\u2270', | ||
| 'nleq': '\u2270', | ||
| 'NotLessGreater': '\u2278', | ||
| 'ntlg': '\u2278', | ||
| 'NotLessLess': '\u226A\u0338', | ||
| 'nLtv': '\u226A\u0338', | ||
| 'NotLessSlantEqual': '\u2A7D\u0338', | ||
| 'nleqslant': '\u2A7D\u0338', | ||
| 'nles': '\u2A7D\u0338', | ||
| 'NotLessTilde': '\u2274', | ||
| 'nlsim': '\u2274', | ||
| 'NotNestedGreaterGreater': '\u2AA2\u0338', | ||
| 'NotNestedLessLess': '\u2AA1\u0338', | ||
| 'NotPrecedes': '\u2280', | ||
| 'npr': '\u2280', | ||
| 'nprec': '\u2280', | ||
| 'NotPrecedesEqual': '\u2AAF\u0338', | ||
| 'npre': '\u2AAF\u0338', | ||
| 'npreceq': '\u2AAF\u0338', | ||
| 'NotPrecedesSlantEqual': '\u22E0', | ||
| 'nprcue': '\u22E0', | ||
| 'NotReverseElement': '\u220C', | ||
| 'notni': '\u220C', | ||
| 'notniva': '\u220C', | ||
| 'NotRightTriangle': '\u22EB', | ||
| 'nrtri': '\u22EB', | ||
| 'ntriangleright': '\u22EB', | ||
| 'NotRightTriangleBar': '\u29D0\u0338', | ||
| 'NotRightTriangleEqual': '\u22ED', | ||
| 'nrtrie': '\u22ED', | ||
| 'ntrianglerighteq': '\u22ED', | ||
| 'NotSquareSubset': '\u228F\u0338', | ||
| 'NotSquareSubsetEqual': '\u22E2', | ||
| 'nsqsube': '\u22E2', | ||
| 'NotSquareSuperset': '\u2290\u0338', | ||
| 'NotSquareSupersetEqual': '\u22E3', | ||
| 'nsqsupe': '\u22E3', | ||
| 'NotSubset': '\u2282\u20D2', | ||
| 'nsubset': '\u2282\u20D2', | ||
| 'vnsub': '\u2282\u20D2', | ||
| 'NotSubsetEqual': '\u2288', | ||
| 'nsube': '\u2288', | ||
| 'nsubseteq': '\u2288', | ||
| 'NotSucceeds': '\u2281', | ||
| 'nsc': '\u2281', | ||
| 'nsucc': '\u2281', | ||
| 'NotSucceedsEqual': '\u2AB0\u0338', | ||
| 'nsce': '\u2AB0\u0338', | ||
| 'nsucceq': '\u2AB0\u0338', | ||
| 'NotSucceedsSlantEqual': '\u22E1', | ||
| 'nsccue': '\u22E1', | ||
| 'NotSucceedsTilde': '\u227F\u0338', | ||
| 'NotSuperset': '\u2283\u20D2', | ||
| 'nsupset': '\u2283\u20D2', | ||
| 'vnsup': '\u2283\u20D2', | ||
| 'NotSupersetEqual': '\u2289', | ||
| 'nsupe': '\u2289', | ||
| 'nsupseteq': '\u2289', | ||
| 'NotTilde': '\u2241', | ||
| 'nsim': '\u2241', | ||
| 'NotTildeEqual': '\u2244', | ||
| 'nsime': '\u2244', | ||
| 'nsimeq': '\u2244', | ||
| 'NotTildeFullEqual': '\u2247', | ||
| 'ncong': '\u2247', | ||
| 'NotTildeTilde': '\u2249', | ||
| 'nap': '\u2249', | ||
| 'napprox': '\u2249', | ||
| 'NotVerticalBar': '\u2224', | ||
| 'nmid': '\u2224', | ||
| 'nshortmid': '\u2224', | ||
| 'nsmid': '\u2224', | ||
| 'Nscr': '\uD835\uDCA9', | ||
| 'Ntilde': '\u00D1', | ||
| 'Nu': '\u039D', | ||
| 'OElig': '\u0152', | ||
| 'Oacute': '\u00D3', | ||
| 'Ocirc': '\u00D4', | ||
| 'Ocy': '\u041E', | ||
| 'Odblac': '\u0150', | ||
| 'Ofr': '\uD835\uDD12', | ||
| 'Ograve': '\u00D2', | ||
| 'Omacr': '\u014C', | ||
| 'Omega': '\u03A9', | ||
| 'ohm': '\u03A9', | ||
| 'Omicron': '\u039F', | ||
| 'Oopf': '\uD835\uDD46', | ||
| 'OpenCurlyDoubleQuote': '\u201C', | ||
| 'ldquo': '\u201C', | ||
| 'OpenCurlyQuote': '\u2018', | ||
| 'lsquo': '\u2018', | ||
| 'Or': '\u2A54', | ||
| 'Oscr': '\uD835\uDCAA', | ||
| 'Oslash': '\u00D8', | ||
| 'Otilde': '\u00D5', | ||
| 'Otimes': '\u2A37', | ||
| 'Ouml': '\u00D6', | ||
| 'OverBar': '\u203E', | ||
| 'oline': '\u203E', | ||
| 'OverBrace': '\u23DE', | ||
| 'OverBracket': '\u23B4', | ||
| 'tbrk': '\u23B4', | ||
| 'OverParenthesis': '\u23DC', | ||
| 'PartialD': '\u2202', | ||
| 'part': '\u2202', | ||
| 'Pcy': '\u041F', | ||
| 'Pfr': '\uD835\uDD13', | ||
| 'Phi': '\u03A6', | ||
| 'Pi': '\u03A0', | ||
| 'PlusMinus': '\u00B1', | ||
| 'plusmn': '\u00B1', | ||
| 'pm': '\u00B1', | ||
| 'Popf': '\u2119', | ||
| 'primes': '\u2119', | ||
| 'Pr': '\u2ABB', | ||
| 'Precedes': '\u227A', | ||
| 'pr': '\u227A', | ||
| 'prec': '\u227A', | ||
| 'PrecedesEqual': '\u2AAF', | ||
| 'pre': '\u2AAF', | ||
| 'preceq': '\u2AAF', | ||
| 'PrecedesSlantEqual': '\u227C', | ||
| 'prcue': '\u227C', | ||
| 'preccurlyeq': '\u227C', | ||
| 'PrecedesTilde': '\u227E', | ||
| 'precsim': '\u227E', | ||
| 'prsim': '\u227E', | ||
| 'Prime': '\u2033', | ||
| 'Product': '\u220F', | ||
| 'prod': '\u220F', | ||
| 'Proportional': '\u221D', | ||
| 'prop': '\u221D', | ||
| 'propto': '\u221D', | ||
| 'varpropto': '\u221D', | ||
| 'vprop': '\u221D', | ||
| 'Pscr': '\uD835\uDCAB', | ||
| 'Psi': '\u03A8', | ||
| 'QUOT': '\u0022', | ||
| 'quot': '\u0022', | ||
| 'Qfr': '\uD835\uDD14', | ||
| 'Qopf': '\u211A', | ||
| 'rationals': '\u211A', | ||
| 'Qscr': '\uD835\uDCAC', | ||
| 'RBarr': '\u2910', | ||
| 'drbkarow': '\u2910', | ||
| 'REG': '\u00AE', | ||
| 'circledR': '\u00AE', | ||
| 'reg': '\u00AE', | ||
| 'Racute': '\u0154', | ||
| 'Rang': '\u27EB', | ||
| 'Rarr': '\u21A0', | ||
| 'twoheadrightarrow': '\u21A0', | ||
| 'Rarrtl': '\u2916', | ||
| 'Rcaron': '\u0158', | ||
| 'Rcedil': '\u0156', | ||
| 'Rcy': '\u0420', | ||
| 'Re': '\u211C', | ||
| 'Rfr': '\u211C', | ||
| 'real': '\u211C', | ||
| 'realpart': '\u211C', | ||
| 'ReverseElement': '\u220B', | ||
| 'SuchThat': '\u220B', | ||
| 'ni': '\u220B', | ||
| 'niv': '\u220B', | ||
| 'ReverseEquilibrium': '\u21CB', | ||
| 'leftrightharpoons': '\u21CB', | ||
| 'lrhar': '\u21CB', | ||
| 'ReverseUpEquilibrium': '\u296F', | ||
| 'duhar': '\u296F', | ||
| 'Rho': '\u03A1', | ||
| 'RightAngleBracket': '\u27E9', | ||
| 'rang': '\u27E9', | ||
| 'rangle': '\u27E9', | ||
| 'RightArrow': '\u2192', | ||
| 'ShortRightArrow': '\u2192', | ||
| 'rarr': '\u2192', | ||
| 'rightarrow': '\u2192', | ||
| 'srarr': '\u2192', | ||
| 'RightArrowBar': '\u21E5', | ||
| 'rarrb': '\u21E5', | ||
| 'RightArrowLeftArrow': '\u21C4', | ||
| 'rightleftarrows': '\u21C4', | ||
| 'rlarr': '\u21C4', | ||
| 'RightCeiling': '\u2309', | ||
| 'rceil': '\u2309', | ||
| 'RightDoubleBracket': '\u27E7', | ||
| 'robrk': '\u27E7', | ||
| 'RightDownTeeVector': '\u295D', | ||
| 'RightDownVector': '\u21C2', | ||
| 'dharr': '\u21C2', | ||
| 'downharpoonright': '\u21C2', | ||
| 'RightDownVectorBar': '\u2955', | ||
| 'RightFloor': '\u230B', | ||
| 'rfloor': '\u230B', | ||
| 'RightTee': '\u22A2', | ||
| 'vdash': '\u22A2', | ||
| 'RightTeeArrow': '\u21A6', | ||
| 'map': '\u21A6', | ||
| 'mapsto': '\u21A6', | ||
| 'RightTeeVector': '\u295B', | ||
| 'RightTriangle': '\u22B3', | ||
| 'vartriangleright': '\u22B3', | ||
| 'vrtri': '\u22B3', | ||
| 'RightTriangleBar': '\u29D0', | ||
| 'RightTriangleEqual': '\u22B5', | ||
| 'rtrie': '\u22B5', | ||
| 'trianglerighteq': '\u22B5', | ||
| 'RightUpDownVector': '\u294F', | ||
| 'RightUpTeeVector': '\u295C', | ||
| 'RightUpVector': '\u21BE', | ||
| 'uharr': '\u21BE', | ||
| 'upharpoonright': '\u21BE', | ||
| 'RightUpVectorBar': '\u2954', | ||
| 'RightVector': '\u21C0', | ||
| 'rharu': '\u21C0', | ||
| 'rightharpoonup': '\u21C0', | ||
| 'RightVectorBar': '\u2953', | ||
| 'Ropf': '\u211D', | ||
| 'reals': '\u211D', | ||
| 'RoundImplies': '\u2970', | ||
| 'Rrightarrow': '\u21DB', | ||
| 'rAarr': '\u21DB', | ||
| 'Rscr': '\u211B', | ||
| 'realine': '\u211B', | ||
| 'Rsh': '\u21B1', | ||
| 'rsh': '\u21B1', | ||
| 'RuleDelayed': '\u29F4', | ||
| 'SHCHcy': '\u0429', | ||
| 'SHcy': '\u0428', | ||
| 'SOFTcy': '\u042C', | ||
| 'Sacute': '\u015A', | ||
| 'Sc': '\u2ABC', | ||
| 'Scaron': '\u0160', | ||
| 'Scedil': '\u015E', | ||
| 'Scirc': '\u015C', | ||
| 'Scy': '\u0421', | ||
| 'Sfr': '\uD835\uDD16', | ||
| 'ShortUpArrow': '\u2191', | ||
| 'UpArrow': '\u2191', | ||
| 'uarr': '\u2191', | ||
| 'uparrow': '\u2191', | ||
| 'Sigma': '\u03A3', | ||
| 'SmallCircle': '\u2218', | ||
| 'compfn': '\u2218', | ||
| 'Sopf': '\uD835\uDD4A', | ||
| 'Sqrt': '\u221A', | ||
| 'radic': '\u221A', | ||
| 'Square': '\u25A1', | ||
| 'squ': '\u25A1', | ||
| 'square': '\u25A1', | ||
| 'SquareIntersection': '\u2293', | ||
| 'sqcap': '\u2293', | ||
| 'SquareSubset': '\u228F', | ||
| 'sqsub': '\u228F', | ||
| 'sqsubset': '\u228F', | ||
| 'SquareSubsetEqual': '\u2291', | ||
| 'sqsube': '\u2291', | ||
| 'sqsubseteq': '\u2291', | ||
| 'SquareSuperset': '\u2290', | ||
| 'sqsup': '\u2290', | ||
| 'sqsupset': '\u2290', | ||
| 'SquareSupersetEqual': '\u2292', | ||
| 'sqsupe': '\u2292', | ||
| 'sqsupseteq': '\u2292', | ||
| 'SquareUnion': '\u2294', | ||
| 'sqcup': '\u2294', | ||
| 'Sscr': '\uD835\uDCAE', | ||
| 'Star': '\u22C6', | ||
| 'sstarf': '\u22C6', | ||
| 'Sub': '\u22D0', | ||
| 'Subset': '\u22D0', | ||
| 'SubsetEqual': '\u2286', | ||
| 'sube': '\u2286', | ||
| 'subseteq': '\u2286', | ||
| 'Succeeds': '\u227B', | ||
| 'sc': '\u227B', | ||
| 'succ': '\u227B', | ||
| 'SucceedsEqual': '\u2AB0', | ||
| 'sce': '\u2AB0', | ||
| 'succeq': '\u2AB0', | ||
| 'SucceedsSlantEqual': '\u227D', | ||
| 'sccue': '\u227D', | ||
| 'succcurlyeq': '\u227D', | ||
| 'SucceedsTilde': '\u227F', | ||
| 'scsim': '\u227F', | ||
| 'succsim': '\u227F', | ||
| 'Sum': '\u2211', | ||
| 'sum': '\u2211', | ||
| 'Sup': '\u22D1', | ||
| 'Supset': '\u22D1', | ||
| 'Superset': '\u2283', | ||
| 'sup': '\u2283', | ||
| 'supset': '\u2283', | ||
| 'SupersetEqual': '\u2287', | ||
| 'supe': '\u2287', | ||
| 'supseteq': '\u2287', | ||
| 'THORN': '\u00DE', | ||
| 'TRADE': '\u2122', | ||
| 'trade': '\u2122', | ||
| 'TSHcy': '\u040B', | ||
| 'TScy': '\u0426', | ||
| 'Tab': '\u0009', | ||
| 'Tau': '\u03A4', | ||
| 'Tcaron': '\u0164', | ||
| 'Tcedil': '\u0162', | ||
| 'Tcy': '\u0422', | ||
| 'Tfr': '\uD835\uDD17', | ||
| 'Therefore': '\u2234', | ||
| 'there4': '\u2234', | ||
| 'therefore': '\u2234', | ||
| 'Theta': '\u0398', | ||
| 'ThickSpace': '\u205F\u200A', | ||
| 'ThinSpace': '\u2009', | ||
| 'thinsp': '\u2009', | ||
| 'Tilde': '\u223C', | ||
| 'sim': '\u223C', | ||
| 'thicksim': '\u223C', | ||
| 'thksim': '\u223C', | ||
| 'TildeEqual': '\u2243', | ||
| 'sime': '\u2243', | ||
| 'simeq': '\u2243', | ||
| 'TildeFullEqual': '\u2245', | ||
| 'cong': '\u2245', | ||
| 'TildeTilde': '\u2248', | ||
| 'ap': '\u2248', | ||
| 'approx': '\u2248', | ||
| 'asymp': '\u2248', | ||
| 'thickapprox': '\u2248', | ||
| 'thkap': '\u2248', | ||
| 'Topf': '\uD835\uDD4B', | ||
| 'TripleDot': '\u20DB', | ||
| 'tdot': '\u20DB', | ||
| 'Tscr': '\uD835\uDCAF', | ||
| 'Tstrok': '\u0166', | ||
| 'Uacute': '\u00DA', | ||
| 'Uarr': '\u219F', | ||
| 'Uarrocir': '\u2949', | ||
| 'Ubrcy': '\u040E', | ||
| 'Ubreve': '\u016C', | ||
| 'Ucirc': '\u00DB', | ||
| 'Ucy': '\u0423', | ||
| 'Udblac': '\u0170', | ||
| 'Ufr': '\uD835\uDD18', | ||
| 'Ugrave': '\u00D9', | ||
| 'Umacr': '\u016A', | ||
| 'UnderBar': '\u005F', | ||
| 'lowbar': '\u005F', | ||
| 'UnderBrace': '\u23DF', | ||
| 'UnderBracket': '\u23B5', | ||
| 'bbrk': '\u23B5', | ||
| 'UnderParenthesis': '\u23DD', | ||
| 'Union': '\u22C3', | ||
| 'bigcup': '\u22C3', | ||
| 'xcup': '\u22C3', | ||
| 'UnionPlus': '\u228E', | ||
| 'uplus': '\u228E', | ||
| 'Uogon': '\u0172', | ||
| 'Uopf': '\uD835\uDD4C', | ||
| 'UpArrowBar': '\u2912', | ||
| 'UpArrowDownArrow': '\u21C5', | ||
| 'udarr': '\u21C5', | ||
| 'UpDownArrow': '\u2195', | ||
| 'updownarrow': '\u2195', | ||
| 'varr': '\u2195', | ||
| 'UpEquilibrium': '\u296E', | ||
| 'udhar': '\u296E', | ||
| 'UpTee': '\u22A5', | ||
| 'bot': '\u22A5', | ||
| 'bottom': '\u22A5', | ||
| 'perp': '\u22A5', | ||
| 'UpTeeArrow': '\u21A5', | ||
| 'mapstoup': '\u21A5', | ||
| 'UpperLeftArrow': '\u2196', | ||
| 'nwarr': '\u2196', | ||
| 'nwarrow': '\u2196', | ||
| 'UpperRightArrow': '\u2197', | ||
| 'nearr': '\u2197', | ||
| 'nearrow': '\u2197', | ||
| 'Upsi': '\u03D2', | ||
| 'upsih': '\u03D2', | ||
| 'Upsilon': '\u03A5', | ||
| 'Uring': '\u016E', | ||
| 'Uscr': '\uD835\uDCB0', | ||
| 'Utilde': '\u0168', | ||
| 'Uuml': '\u00DC', | ||
| 'VDash': '\u22AB', | ||
| 'Vbar': '\u2AEB', | ||
| 'Vcy': '\u0412', | ||
| 'Vdash': '\u22A9', | ||
| 'Vdashl': '\u2AE6', | ||
| 'Vee': '\u22C1', | ||
| 'bigvee': '\u22C1', | ||
| 'xvee': '\u22C1', | ||
| 'Verbar': '\u2016', | ||
| 'Vert': '\u2016', | ||
| 'VerticalBar': '\u2223', | ||
| 'mid': '\u2223', | ||
| 'shortmid': '\u2223', | ||
| 'smid': '\u2223', | ||
| 'VerticalLine': '\u007C', | ||
| 'verbar': '\u007C', | ||
| 'vert': '\u007C', | ||
| 'VerticalSeparator': '\u2758', | ||
| 'VerticalTilde': '\u2240', | ||
| 'wr': '\u2240', | ||
| 'wreath': '\u2240', | ||
| 'VeryThinSpace': '\u200A', | ||
| 'hairsp': '\u200A', | ||
| 'Vfr': '\uD835\uDD19', | ||
| 'Vopf': '\uD835\uDD4D', | ||
| 'Vscr': '\uD835\uDCB1', | ||
| 'Vvdash': '\u22AA', | ||
| 'Wcirc': '\u0174', | ||
| 'Wedge': '\u22C0', | ||
| 'bigwedge': '\u22C0', | ||
| 'xwedge': '\u22C0', | ||
| 'Wfr': '\uD835\uDD1A', | ||
| 'Wopf': '\uD835\uDD4E', | ||
| 'Wscr': '\uD835\uDCB2', | ||
| 'Xfr': '\uD835\uDD1B', | ||
| 'Xi': '\u039E', | ||
| 'Xopf': '\uD835\uDD4F', | ||
| 'Xscr': '\uD835\uDCB3', | ||
| 'YAcy': '\u042F', | ||
| 'YIcy': '\u0407', | ||
| 'YUcy': '\u042E', | ||
| 'Yacute': '\u00DD', | ||
| 'Ycirc': '\u0176', | ||
| 'Ycy': '\u042B', | ||
| 'Yfr': '\uD835\uDD1C', | ||
| 'Yopf': '\uD835\uDD50', | ||
| 'Yscr': '\uD835\uDCB4', | ||
| 'Yuml': '\u0178', | ||
| 'ZHcy': '\u0416', | ||
| 'Zacute': '\u0179', | ||
| 'Zcaron': '\u017D', | ||
| 'Zcy': '\u0417', | ||
| 'Zdot': '\u017B', | ||
| 'Zeta': '\u0396', | ||
| 'Zfr': '\u2128', | ||
| 'zeetrf': '\u2128', | ||
| 'Zopf': '\u2124', | ||
| 'integers': '\u2124', | ||
| 'Zscr': '\uD835\uDCB5', | ||
| 'aacute': '\u00E1', | ||
| 'abreve': '\u0103', | ||
| 'ac': '\u223E', | ||
| 'mstpos': '\u223E', | ||
| 'acE': '\u223E\u0333', | ||
| 'acd': '\u223F', | ||
| 'acirc': '\u00E2', | ||
| 'acy': '\u0430', | ||
| 'aelig': '\u00E6', | ||
| 'afr': '\uD835\uDD1E', | ||
| 'agrave': '\u00E0', | ||
| 'alefsym': '\u2135', | ||
| 'aleph': '\u2135', | ||
| 'alpha': '\u03B1', | ||
| 'amacr': '\u0101', | ||
| 'amalg': '\u2A3F', | ||
| 'and': '\u2227', | ||
| 'wedge': '\u2227', | ||
| 'andand': '\u2A55', | ||
| 'andd': '\u2A5C', | ||
| 'andslope': '\u2A58', | ||
| 'andv': '\u2A5A', | ||
| 'ang': '\u2220', | ||
| 'angle': '\u2220', | ||
| 'ange': '\u29A4', | ||
| 'angmsd': '\u2221', | ||
| 'measuredangle': '\u2221', | ||
| 'angmsdaa': '\u29A8', | ||
| 'angmsdab': '\u29A9', | ||
| 'angmsdac': '\u29AA', | ||
| 'angmsdad': '\u29AB', | ||
| 'angmsdae': '\u29AC', | ||
| 'angmsdaf': '\u29AD', | ||
| 'angmsdag': '\u29AE', | ||
| 'angmsdah': '\u29AF', | ||
| 'angrt': '\u221F', | ||
| 'angrtvb': '\u22BE', | ||
| 'angrtvbd': '\u299D', | ||
| 'angsph': '\u2222', | ||
| 'angzarr': '\u237C', | ||
| 'aogon': '\u0105', | ||
| 'aopf': '\uD835\uDD52', | ||
| 'apE': '\u2A70', | ||
| 'apacir': '\u2A6F', | ||
| 'ape': '\u224A', | ||
| 'approxeq': '\u224A', | ||
| 'apid': '\u224B', | ||
| 'apos': '\u0027', | ||
| 'aring': '\u00E5', | ||
| 'ascr': '\uD835\uDCB6', | ||
| 'ast': '\u002A', | ||
| 'midast': '\u002A', | ||
| 'atilde': '\u00E3', | ||
| 'auml': '\u00E4', | ||
| 'awint': '\u2A11', | ||
| 'bNot': '\u2AED', | ||
| 'backcong': '\u224C', | ||
| 'bcong': '\u224C', | ||
| 'backepsilon': '\u03F6', | ||
| 'bepsi': '\u03F6', | ||
| 'backprime': '\u2035', | ||
| 'bprime': '\u2035', | ||
| 'backsim': '\u223D', | ||
| 'bsim': '\u223D', | ||
| 'backsimeq': '\u22CD', | ||
| 'bsime': '\u22CD', | ||
| 'barvee': '\u22BD', | ||
| 'barwed': '\u2305', | ||
| 'barwedge': '\u2305', | ||
| 'bbrktbrk': '\u23B6', | ||
| 'bcy': '\u0431', | ||
| 'bdquo': '\u201E', | ||
| 'ldquor': '\u201E', | ||
| 'bemptyv': '\u29B0', | ||
| 'beta': '\u03B2', | ||
| 'beth': '\u2136', | ||
| 'between': '\u226C', | ||
| 'twixt': '\u226C', | ||
| 'bfr': '\uD835\uDD1F', | ||
| 'bigcirc': '\u25EF', | ||
| 'xcirc': '\u25EF', | ||
| 'bigodot': '\u2A00', | ||
| 'xodot': '\u2A00', | ||
| 'bigoplus': '\u2A01', | ||
| 'xoplus': '\u2A01', | ||
| 'bigotimes': '\u2A02', | ||
| 'xotime': '\u2A02', | ||
| 'bigsqcup': '\u2A06', | ||
| 'xsqcup': '\u2A06', | ||
| 'bigstar': '\u2605', | ||
| 'starf': '\u2605', | ||
| 'bigtriangledown': '\u25BD', | ||
| 'xdtri': '\u25BD', | ||
| 'bigtriangleup': '\u25B3', | ||
| 'xutri': '\u25B3', | ||
| 'biguplus': '\u2A04', | ||
| 'xuplus': '\u2A04', | ||
| 'bkarow': '\u290D', | ||
| 'rbarr': '\u290D', | ||
| 'blacklozenge': '\u29EB', | ||
| 'lozf': '\u29EB', | ||
| 'blacktriangle': '\u25B4', | ||
| 'utrif': '\u25B4', | ||
| 'blacktriangledown': '\u25BE', | ||
| 'dtrif': '\u25BE', | ||
| 'blacktriangleleft': '\u25C2', | ||
| 'ltrif': '\u25C2', | ||
| 'blacktriangleright': '\u25B8', | ||
| 'rtrif': '\u25B8', | ||
| 'blank': '\u2423', | ||
| 'blk12': '\u2592', | ||
| 'blk14': '\u2591', | ||
| 'blk34': '\u2593', | ||
| 'block': '\u2588', | ||
| 'bne': '\u003D\u20E5', | ||
| 'bnequiv': '\u2261\u20E5', | ||
| 'bnot': '\u2310', | ||
| 'bopf': '\uD835\uDD53', | ||
| 'bowtie': '\u22C8', | ||
| 'boxDL': '\u2557', | ||
| 'boxDR': '\u2554', | ||
| 'boxDl': '\u2556', | ||
| 'boxDr': '\u2553', | ||
| 'boxH': '\u2550', | ||
| 'boxHD': '\u2566', | ||
| 'boxHU': '\u2569', | ||
| 'boxHd': '\u2564', | ||
| 'boxHu': '\u2567', | ||
| 'boxUL': '\u255D', | ||
| 'boxUR': '\u255A', | ||
| 'boxUl': '\u255C', | ||
| 'boxUr': '\u2559', | ||
| 'boxV': '\u2551', | ||
| 'boxVH': '\u256C', | ||
| 'boxVL': '\u2563', | ||
| 'boxVR': '\u2560', | ||
| 'boxVh': '\u256B', | ||
| 'boxVl': '\u2562', | ||
| 'boxVr': '\u255F', | ||
| 'boxbox': '\u29C9', | ||
| 'boxdL': '\u2555', | ||
| 'boxdR': '\u2552', | ||
| 'boxdl': '\u2510', | ||
| 'boxdr': '\u250C', | ||
| 'boxhD': '\u2565', | ||
| 'boxhU': '\u2568', | ||
| 'boxhd': '\u252C', | ||
| 'boxhu': '\u2534', | ||
| 'boxminus': '\u229F', | ||
| 'minusb': '\u229F', | ||
| 'boxplus': '\u229E', | ||
| 'plusb': '\u229E', | ||
| 'boxtimes': '\u22A0', | ||
| 'timesb': '\u22A0', | ||
| 'boxuL': '\u255B', | ||
| 'boxuR': '\u2558', | ||
| 'boxul': '\u2518', | ||
| 'boxur': '\u2514', | ||
| 'boxv': '\u2502', | ||
| 'boxvH': '\u256A', | ||
| 'boxvL': '\u2561', | ||
| 'boxvR': '\u255E', | ||
| 'boxvh': '\u253C', | ||
| 'boxvl': '\u2524', | ||
| 'boxvr': '\u251C', | ||
| 'brvbar': '\u00A6', | ||
| 'bscr': '\uD835\uDCB7', | ||
| 'bsemi': '\u204F', | ||
| 'bsol': '\u005C', | ||
| 'bsolb': '\u29C5', | ||
| 'bsolhsub': '\u27C8', | ||
| 'bull': '\u2022', | ||
| 'bullet': '\u2022', | ||
| 'bumpE': '\u2AAE', | ||
| 'cacute': '\u0107', | ||
| 'cap': '\u2229', | ||
| 'capand': '\u2A44', | ||
| 'capbrcup': '\u2A49', | ||
| 'capcap': '\u2A4B', | ||
| 'capcup': '\u2A47', | ||
| 'capdot': '\u2A40', | ||
| 'caps': '\u2229\uFE00', | ||
| 'caret': '\u2041', | ||
| 'ccaps': '\u2A4D', | ||
| 'ccaron': '\u010D', | ||
| 'ccedil': '\u00E7', | ||
| 'ccirc': '\u0109', | ||
| 'ccups': '\u2A4C', | ||
| 'ccupssm': '\u2A50', | ||
| 'cdot': '\u010B', | ||
| 'cemptyv': '\u29B2', | ||
| 'cent': '\u00A2', | ||
| 'cfr': '\uD835\uDD20', | ||
| 'chcy': '\u0447', | ||
| 'check': '\u2713', | ||
| 'checkmark': '\u2713', | ||
| 'chi': '\u03C7', | ||
| 'cir': '\u25CB', | ||
| 'cirE': '\u29C3', | ||
| 'circ': '\u02C6', | ||
| 'circeq': '\u2257', | ||
| 'cire': '\u2257', | ||
| 'circlearrowleft': '\u21BA', | ||
| 'olarr': '\u21BA', | ||
| 'circlearrowright': '\u21BB', | ||
| 'orarr': '\u21BB', | ||
| 'circledS': '\u24C8', | ||
| 'oS': '\u24C8', | ||
| 'circledast': '\u229B', | ||
| 'oast': '\u229B', | ||
| 'circledcirc': '\u229A', | ||
| 'ocir': '\u229A', | ||
| 'circleddash': '\u229D', | ||
| 'odash': '\u229D', | ||
| 'cirfnint': '\u2A10', | ||
| 'cirmid': '\u2AEF', | ||
| 'cirscir': '\u29C2', | ||
| 'clubs': '\u2663', | ||
| 'clubsuit': '\u2663', | ||
| 'colon': '\u003A', | ||
| 'comma': '\u002C', | ||
| 'commat': '\u0040', | ||
| 'comp': '\u2201', | ||
| 'complement': '\u2201', | ||
| 'congdot': '\u2A6D', | ||
| 'copf': '\uD835\uDD54', | ||
| 'copysr': '\u2117', | ||
| 'crarr': '\u21B5', | ||
| 'cross': '\u2717', | ||
| 'cscr': '\uD835\uDCB8', | ||
| 'csub': '\u2ACF', | ||
| 'csube': '\u2AD1', | ||
| 'csup': '\u2AD0', | ||
| 'csupe': '\u2AD2', | ||
| 'ctdot': '\u22EF', | ||
| 'cudarrl': '\u2938', | ||
| 'cudarrr': '\u2935', | ||
| 'cuepr': '\u22DE', | ||
| 'curlyeqprec': '\u22DE', | ||
| 'cuesc': '\u22DF', | ||
| 'curlyeqsucc': '\u22DF', | ||
| 'cularr': '\u21B6', | ||
| 'curvearrowleft': '\u21B6', | ||
| 'cularrp': '\u293D', | ||
| 'cup': '\u222A', | ||
| 'cupbrcap': '\u2A48', | ||
| 'cupcap': '\u2A46', | ||
| 'cupcup': '\u2A4A', | ||
| 'cupdot': '\u228D', | ||
| 'cupor': '\u2A45', | ||
| 'cups': '\u222A\uFE00', | ||
| 'curarr': '\u21B7', | ||
| 'curvearrowright': '\u21B7', | ||
| 'curarrm': '\u293C', | ||
| 'curlyvee': '\u22CE', | ||
| 'cuvee': '\u22CE', | ||
| 'curlywedge': '\u22CF', | ||
| 'cuwed': '\u22CF', | ||
| 'curren': '\u00A4', | ||
| 'cwint': '\u2231', | ||
| 'cylcty': '\u232D', | ||
| 'dHar': '\u2965', | ||
| 'dagger': '\u2020', | ||
| 'daleth': '\u2138', | ||
| 'dash': '\u2010', | ||
| 'hyphen': '\u2010', | ||
| 'dbkarow': '\u290F', | ||
| 'rBarr': '\u290F', | ||
| 'dcaron': '\u010F', | ||
| 'dcy': '\u0434', | ||
| 'ddarr': '\u21CA', | ||
| 'downdownarrows': '\u21CA', | ||
| 'ddotseq': '\u2A77', | ||
| 'eDDot': '\u2A77', | ||
| 'deg': '\u00B0', | ||
| 'delta': '\u03B4', | ||
| 'demptyv': '\u29B1', | ||
| 'dfisht': '\u297F', | ||
| 'dfr': '\uD835\uDD21', | ||
| 'diamondsuit': '\u2666', | ||
| 'diams': '\u2666', | ||
| 'digamma': '\u03DD', | ||
| 'gammad': '\u03DD', | ||
| 'disin': '\u22F2', | ||
| 'div': '\u00F7', | ||
| 'divide': '\u00F7', | ||
| 'divideontimes': '\u22C7', | ||
| 'divonx': '\u22C7', | ||
| 'djcy': '\u0452', | ||
| 'dlcorn': '\u231E', | ||
| 'llcorner': '\u231E', | ||
| 'dlcrop': '\u230D', | ||
| 'dollar': '\u0024', | ||
| 'dopf': '\uD835\uDD55', | ||
| 'doteqdot': '\u2251', | ||
| 'eDot': '\u2251', | ||
| 'dotminus': '\u2238', | ||
| 'minusd': '\u2238', | ||
| 'dotplus': '\u2214', | ||
| 'plusdo': '\u2214', | ||
| 'dotsquare': '\u22A1', | ||
| 'sdotb': '\u22A1', | ||
| 'drcorn': '\u231F', | ||
| 'lrcorner': '\u231F', | ||
| 'drcrop': '\u230C', | ||
| 'dscr': '\uD835\uDCB9', | ||
| 'dscy': '\u0455', | ||
| 'dsol': '\u29F6', | ||
| 'dstrok': '\u0111', | ||
| 'dtdot': '\u22F1', | ||
| 'dtri': '\u25BF', | ||
| 'triangledown': '\u25BF', | ||
| 'dwangle': '\u29A6', | ||
| 'dzcy': '\u045F', | ||
| 'dzigrarr': '\u27FF', | ||
| 'eacute': '\u00E9', | ||
| 'easter': '\u2A6E', | ||
| 'ecaron': '\u011B', | ||
| 'ecir': '\u2256', | ||
| 'eqcirc': '\u2256', | ||
| 'ecirc': '\u00EA', | ||
| 'ecolon': '\u2255', | ||
| 'eqcolon': '\u2255', | ||
| 'ecy': '\u044D', | ||
| 'edot': '\u0117', | ||
| 'efDot': '\u2252', | ||
| 'fallingdotseq': '\u2252', | ||
| 'efr': '\uD835\uDD22', | ||
| 'eg': '\u2A9A', | ||
| 'egrave': '\u00E8', | ||
| 'egs': '\u2A96', | ||
| 'eqslantgtr': '\u2A96', | ||
| 'egsdot': '\u2A98', | ||
| 'el': '\u2A99', | ||
| 'elinters': '\u23E7', | ||
| 'ell': '\u2113', | ||
| 'els': '\u2A95', | ||
| 'eqslantless': '\u2A95', | ||
| 'elsdot': '\u2A97', | ||
| 'emacr': '\u0113', | ||
| 'empty': '\u2205', | ||
| 'emptyset': '\u2205', | ||
| 'emptyv': '\u2205', | ||
| 'varnothing': '\u2205', | ||
| 'emsp13': '\u2004', | ||
| 'emsp14': '\u2005', | ||
| 'emsp': '\u2003', | ||
| 'eng': '\u014B', | ||
| 'ensp': '\u2002', | ||
| 'eogon': '\u0119', | ||
| 'eopf': '\uD835\uDD56', | ||
| 'epar': '\u22D5', | ||
| 'eparsl': '\u29E3', | ||
| 'eplus': '\u2A71', | ||
| 'epsi': '\u03B5', | ||
| 'epsilon': '\u03B5', | ||
| 'epsiv': '\u03F5', | ||
| 'straightepsilon': '\u03F5', | ||
| 'varepsilon': '\u03F5', | ||
| 'equals': '\u003D', | ||
| 'equest': '\u225F', | ||
| 'questeq': '\u225F', | ||
| 'equivDD': '\u2A78', | ||
| 'eqvparsl': '\u29E5', | ||
| 'erDot': '\u2253', | ||
| 'risingdotseq': '\u2253', | ||
| 'erarr': '\u2971', | ||
| 'escr': '\u212F', | ||
| 'eta': '\u03B7', | ||
| 'eth': '\u00F0', | ||
| 'euml': '\u00EB', | ||
| 'euro': '\u20AC', | ||
| 'excl': '\u0021', | ||
| 'fcy': '\u0444', | ||
| 'female': '\u2640', | ||
| 'ffilig': '\uFB03', | ||
| 'fflig': '\uFB00', | ||
| 'ffllig': '\uFB04', | ||
| 'ffr': '\uD835\uDD23', | ||
| 'filig': '\uFB01', | ||
| 'fjlig': '\u0066\u006A', | ||
| 'flat': '\u266D', | ||
| 'fllig': '\uFB02', | ||
| 'fltns': '\u25B1', | ||
| 'fnof': '\u0192', | ||
| 'fopf': '\uD835\uDD57', | ||
| 'fork': '\u22D4', | ||
| 'pitchfork': '\u22D4', | ||
| 'forkv': '\u2AD9', | ||
| 'fpartint': '\u2A0D', | ||
| 'frac12': '\u00BD', | ||
| 'half': '\u00BD', | ||
| 'frac13': '\u2153', | ||
| 'frac14': '\u00BC', | ||
| 'frac15': '\u2155', | ||
| 'frac16': '\u2159', | ||
| 'frac18': '\u215B', | ||
| 'frac23': '\u2154', | ||
| 'frac25': '\u2156', | ||
| 'frac34': '\u00BE', | ||
| 'frac35': '\u2157', | ||
| 'frac38': '\u215C', | ||
| 'frac45': '\u2158', | ||
| 'frac56': '\u215A', | ||
| 'frac58': '\u215D', | ||
| 'frac78': '\u215E', | ||
| 'frasl': '\u2044', | ||
| 'frown': '\u2322', | ||
| 'sfrown': '\u2322', | ||
| 'fscr': '\uD835\uDCBB', | ||
| 'gEl': '\u2A8C', | ||
| 'gtreqqless': '\u2A8C', | ||
| 'gacute': '\u01F5', | ||
| 'gamma': '\u03B3', | ||
| 'gap': '\u2A86', | ||
| 'gtrapprox': '\u2A86', | ||
| 'gbreve': '\u011F', | ||
| 'gcirc': '\u011D', | ||
| 'gcy': '\u0433', | ||
| 'gdot': '\u0121', | ||
| 'gescc': '\u2AA9', | ||
| 'gesdot': '\u2A80', | ||
| 'gesdoto': '\u2A82', | ||
| 'gesdotol': '\u2A84', | ||
| 'gesl': '\u22DB\uFE00', | ||
| 'gesles': '\u2A94', | ||
| 'gfr': '\uD835\uDD24', | ||
| 'gimel': '\u2137', | ||
| 'gjcy': '\u0453', | ||
| 'glE': '\u2A92', | ||
| 'gla': '\u2AA5', | ||
| 'glj': '\u2AA4', | ||
| 'gnE': '\u2269', | ||
| 'gneqq': '\u2269', | ||
| 'gnap': '\u2A8A', | ||
| 'gnapprox': '\u2A8A', | ||
| 'gne': '\u2A88', | ||
| 'gneq': '\u2A88', | ||
| 'gnsim': '\u22E7', | ||
| 'gopf': '\uD835\uDD58', | ||
| 'gscr': '\u210A', | ||
| 'gsime': '\u2A8E', | ||
| 'gsiml': '\u2A90', | ||
| 'gtcc': '\u2AA7', | ||
| 'gtcir': '\u2A7A', | ||
| 'gtdot': '\u22D7', | ||
| 'gtrdot': '\u22D7', | ||
| 'gtlPar': '\u2995', | ||
| 'gtquest': '\u2A7C', | ||
| 'gtrarr': '\u2978', | ||
| 'gvertneqq': '\u2269\uFE00', | ||
| 'gvnE': '\u2269\uFE00', | ||
| 'hardcy': '\u044A', | ||
| 'harrcir': '\u2948', | ||
| 'harrw': '\u21AD', | ||
| 'leftrightsquigarrow': '\u21AD', | ||
| 'hbar': '\u210F', | ||
| 'hslash': '\u210F', | ||
| 'planck': '\u210F', | ||
| 'plankv': '\u210F', | ||
| 'hcirc': '\u0125', | ||
| 'hearts': '\u2665', | ||
| 'heartsuit': '\u2665', | ||
| 'hellip': '\u2026', | ||
| 'mldr': '\u2026', | ||
| 'hercon': '\u22B9', | ||
| 'hfr': '\uD835\uDD25', | ||
| 'hksearow': '\u2925', | ||
| 'searhk': '\u2925', | ||
| 'hkswarow': '\u2926', | ||
| 'swarhk': '\u2926', | ||
| 'hoarr': '\u21FF', | ||
| 'homtht': '\u223B', | ||
| 'hookleftarrow': '\u21A9', | ||
| 'larrhk': '\u21A9', | ||
| 'hookrightarrow': '\u21AA', | ||
| 'rarrhk': '\u21AA', | ||
| 'hopf': '\uD835\uDD59', | ||
| 'horbar': '\u2015', | ||
| 'hscr': '\uD835\uDCBD', | ||
| 'hstrok': '\u0127', | ||
| 'hybull': '\u2043', | ||
| 'iacute': '\u00ED', | ||
| 'icirc': '\u00EE', | ||
| 'icy': '\u0438', | ||
| 'iecy': '\u0435', | ||
| 'iexcl': '\u00A1', | ||
| 'ifr': '\uD835\uDD26', | ||
| 'igrave': '\u00EC', | ||
| 'iiiint': '\u2A0C', | ||
| 'qint': '\u2A0C', | ||
| 'iiint': '\u222D', | ||
| 'tint': '\u222D', | ||
| 'iinfin': '\u29DC', | ||
| 'iiota': '\u2129', | ||
| 'ijlig': '\u0133', | ||
| 'imacr': '\u012B', | ||
| 'imath': '\u0131', | ||
| 'inodot': '\u0131', | ||
| 'imof': '\u22B7', | ||
| 'imped': '\u01B5', | ||
| 'incare': '\u2105', | ||
| 'infin': '\u221E', | ||
| 'infintie': '\u29DD', | ||
| 'intcal': '\u22BA', | ||
| 'intercal': '\u22BA', | ||
| 'intlarhk': '\u2A17', | ||
| 'intprod': '\u2A3C', | ||
| 'iprod': '\u2A3C', | ||
| 'iocy': '\u0451', | ||
| 'iogon': '\u012F', | ||
| 'iopf': '\uD835\uDD5A', | ||
| 'iota': '\u03B9', | ||
| 'iquest': '\u00BF', | ||
| 'iscr': '\uD835\uDCBE', | ||
| 'isinE': '\u22F9', | ||
| 'isindot': '\u22F5', | ||
| 'isins': '\u22F4', | ||
| 'isinsv': '\u22F3', | ||
| 'itilde': '\u0129', | ||
| 'iukcy': '\u0456', | ||
| 'iuml': '\u00EF', | ||
| 'jcirc': '\u0135', | ||
| 'jcy': '\u0439', | ||
| 'jfr': '\uD835\uDD27', | ||
| 'jmath': '\u0237', | ||
| 'jopf': '\uD835\uDD5B', | ||
| 'jscr': '\uD835\uDCBF', | ||
| 'jsercy': '\u0458', | ||
| 'jukcy': '\u0454', | ||
| 'kappa': '\u03BA', | ||
| 'kappav': '\u03F0', | ||
| 'varkappa': '\u03F0', | ||
| 'kcedil': '\u0137', | ||
| 'kcy': '\u043A', | ||
| 'kfr': '\uD835\uDD28', | ||
| 'kgreen': '\u0138', | ||
| 'khcy': '\u0445', | ||
| 'kjcy': '\u045C', | ||
| 'kopf': '\uD835\uDD5C', | ||
| 'kscr': '\uD835\uDCC0', | ||
| 'lAtail': '\u291B', | ||
| 'lBarr': '\u290E', | ||
| 'lEg': '\u2A8B', | ||
| 'lesseqqgtr': '\u2A8B', | ||
| 'lHar': '\u2962', | ||
| 'lacute': '\u013A', | ||
| 'laemptyv': '\u29B4', | ||
| 'lambda': '\u03BB', | ||
| 'langd': '\u2991', | ||
| 'lap': '\u2A85', | ||
| 'lessapprox': '\u2A85', | ||
| 'laquo': '\u00AB', | ||
| 'larrbfs': '\u291F', | ||
| 'larrfs': '\u291D', | ||
| 'larrlp': '\u21AB', | ||
| 'looparrowleft': '\u21AB', | ||
| 'larrpl': '\u2939', | ||
| 'larrsim': '\u2973', | ||
| 'larrtl': '\u21A2', | ||
| 'leftarrowtail': '\u21A2', | ||
| 'lat': '\u2AAB', | ||
| 'latail': '\u2919', | ||
| 'late': '\u2AAD', | ||
| 'lates': '\u2AAD\uFE00', | ||
| 'lbarr': '\u290C', | ||
| 'lbbrk': '\u2772', | ||
| 'lbrace': '\u007B', | ||
| 'lcub': '\u007B', | ||
| 'lbrack': '\u005B', | ||
| 'lsqb': '\u005B', | ||
| 'lbrke': '\u298B', | ||
| 'lbrksld': '\u298F', | ||
| 'lbrkslu': '\u298D', | ||
| 'lcaron': '\u013E', | ||
| 'lcedil': '\u013C', | ||
| 'lcy': '\u043B', | ||
| 'ldca': '\u2936', | ||
| 'ldrdhar': '\u2967', | ||
| 'ldrushar': '\u294B', | ||
| 'ldsh': '\u21B2', | ||
| 'le': '\u2264', | ||
| 'leq': '\u2264', | ||
| 'leftleftarrows': '\u21C7', | ||
| 'llarr': '\u21C7', | ||
| 'leftthreetimes': '\u22CB', | ||
| 'lthree': '\u22CB', | ||
| 'lescc': '\u2AA8', | ||
| 'lesdot': '\u2A7F', | ||
| 'lesdoto': '\u2A81', | ||
| 'lesdotor': '\u2A83', | ||
| 'lesg': '\u22DA\uFE00', | ||
| 'lesges': '\u2A93', | ||
| 'lessdot': '\u22D6', | ||
| 'ltdot': '\u22D6', | ||
| 'lfisht': '\u297C', | ||
| 'lfr': '\uD835\uDD29', | ||
| 'lgE': '\u2A91', | ||
| 'lharul': '\u296A', | ||
| 'lhblk': '\u2584', | ||
| 'ljcy': '\u0459', | ||
| 'llhard': '\u296B', | ||
| 'lltri': '\u25FA', | ||
| 'lmidot': '\u0140', | ||
| 'lmoust': '\u23B0', | ||
| 'lmoustache': '\u23B0', | ||
| 'lnE': '\u2268', | ||
| 'lneqq': '\u2268', | ||
| 'lnap': '\u2A89', | ||
| 'lnapprox': '\u2A89', | ||
| 'lne': '\u2A87', | ||
| 'lneq': '\u2A87', | ||
| 'lnsim': '\u22E6', | ||
| 'loang': '\u27EC', | ||
| 'loarr': '\u21FD', | ||
| 'longmapsto': '\u27FC', | ||
| 'xmap': '\u27FC', | ||
| 'looparrowright': '\u21AC', | ||
| 'rarrlp': '\u21AC', | ||
| 'lopar': '\u2985', | ||
| 'lopf': '\uD835\uDD5D', | ||
| 'loplus': '\u2A2D', | ||
| 'lotimes': '\u2A34', | ||
| 'lowast': '\u2217', | ||
| 'loz': '\u25CA', | ||
| 'lozenge': '\u25CA', | ||
| 'lpar': '\u0028', | ||
| 'lparlt': '\u2993', | ||
| 'lrhard': '\u296D', | ||
| 'lrm': '\u200E', | ||
| 'lrtri': '\u22BF', | ||
| 'lsaquo': '\u2039', | ||
| 'lscr': '\uD835\uDCC1', | ||
| 'lsime': '\u2A8D', | ||
| 'lsimg': '\u2A8F', | ||
| 'lsquor': '\u201A', | ||
| 'sbquo': '\u201A', | ||
| 'lstrok': '\u0142', | ||
| 'ltcc': '\u2AA6', | ||
| 'ltcir': '\u2A79', | ||
| 'ltimes': '\u22C9', | ||
| 'ltlarr': '\u2976', | ||
| 'ltquest': '\u2A7B', | ||
| 'ltrPar': '\u2996', | ||
| 'ltri': '\u25C3', | ||
| 'triangleleft': '\u25C3', | ||
| 'lurdshar': '\u294A', | ||
| 'luruhar': '\u2966', | ||
| 'lvertneqq': '\u2268\uFE00', | ||
| 'lvnE': '\u2268\uFE00', | ||
| 'mDDot': '\u223A', | ||
| 'macr': '\u00AF', | ||
| 'strns': '\u00AF', | ||
| 'male': '\u2642', | ||
| 'malt': '\u2720', | ||
| 'maltese': '\u2720', | ||
| 'marker': '\u25AE', | ||
| 'mcomma': '\u2A29', | ||
| 'mcy': '\u043C', | ||
| 'mdash': '\u2014', | ||
| 'mfr': '\uD835\uDD2A', | ||
| 'mho': '\u2127', | ||
| 'micro': '\u00B5', | ||
| 'midcir': '\u2AF0', | ||
| 'minus': '\u2212', | ||
| 'minusdu': '\u2A2A', | ||
| 'mlcp': '\u2ADB', | ||
| 'models': '\u22A7', | ||
| 'mopf': '\uD835\uDD5E', | ||
| 'mscr': '\uD835\uDCC2', | ||
| 'mu': '\u03BC', | ||
| 'multimap': '\u22B8', | ||
| 'mumap': '\u22B8', | ||
| 'nGg': '\u22D9\u0338', | ||
| 'nGt': '\u226B\u20D2', | ||
| 'nLeftarrow': '\u21CD', | ||
| 'nlArr': '\u21CD', | ||
| 'nLeftrightarrow': '\u21CE', | ||
| 'nhArr': '\u21CE', | ||
| 'nLl': '\u22D8\u0338', | ||
| 'nLt': '\u226A\u20D2', | ||
| 'nRightarrow': '\u21CF', | ||
| 'nrArr': '\u21CF', | ||
| 'nVDash': '\u22AF', | ||
| 'nVdash': '\u22AE', | ||
| 'nacute': '\u0144', | ||
| 'nang': '\u2220\u20D2', | ||
| 'napE': '\u2A70\u0338', | ||
| 'napid': '\u224B\u0338', | ||
| 'napos': '\u0149', | ||
| 'natur': '\u266E', | ||
| 'natural': '\u266E', | ||
| 'ncap': '\u2A43', | ||
| 'ncaron': '\u0148', | ||
| 'ncedil': '\u0146', | ||
| 'ncongdot': '\u2A6D\u0338', | ||
| 'ncup': '\u2A42', | ||
| 'ncy': '\u043D', | ||
| 'ndash': '\u2013', | ||
| 'neArr': '\u21D7', | ||
| 'nearhk': '\u2924', | ||
| 'nedot': '\u2250\u0338', | ||
| 'nesear': '\u2928', | ||
| 'toea': '\u2928', | ||
| 'nfr': '\uD835\uDD2B', | ||
| 'nharr': '\u21AE', | ||
| 'nleftrightarrow': '\u21AE', | ||
| 'nhpar': '\u2AF2', | ||
| 'nis': '\u22FC', | ||
| 'nisd': '\u22FA', | ||
| 'njcy': '\u045A', | ||
| 'nlE': '\u2266\u0338', | ||
| 'nleqq': '\u2266\u0338', | ||
| 'nlarr': '\u219A', | ||
| 'nleftarrow': '\u219A', | ||
| 'nldr': '\u2025', | ||
| 'nopf': '\uD835\uDD5F', | ||
| 'not': '\u00AC', | ||
| 'notinE': '\u22F9\u0338', | ||
| 'notindot': '\u22F5\u0338', | ||
| 'notinvb': '\u22F7', | ||
| 'notinvc': '\u22F6', | ||
| 'notnivb': '\u22FE', | ||
| 'notnivc': '\u22FD', | ||
| 'nparsl': '\u2AFD\u20E5', | ||
| 'npart': '\u2202\u0338', | ||
| 'npolint': '\u2A14', | ||
| 'nrarr': '\u219B', | ||
| 'nrightarrow': '\u219B', | ||
| 'nrarrc': '\u2933\u0338', | ||
| 'nrarrw': '\u219D\u0338', | ||
| 'nscr': '\uD835\uDCC3', | ||
| 'nsub': '\u2284', | ||
| 'nsubE': '\u2AC5\u0338', | ||
| 'nsubseteqq': '\u2AC5\u0338', | ||
| 'nsup': '\u2285', | ||
| 'nsupE': '\u2AC6\u0338', | ||
| 'nsupseteqq': '\u2AC6\u0338', | ||
| 'ntilde': '\u00F1', | ||
| 'nu': '\u03BD', | ||
| 'num': '\u0023', | ||
| 'numero': '\u2116', | ||
| 'numsp': '\u2007', | ||
| 'nvDash': '\u22AD', | ||
| 'nvHarr': '\u2904', | ||
| 'nvap': '\u224D\u20D2', | ||
| 'nvdash': '\u22AC', | ||
| 'nvge': '\u2265\u20D2', | ||
| 'nvgt': '\u003E\u20D2', | ||
| 'nvinfin': '\u29DE', | ||
| 'nvlArr': '\u2902', | ||
| 'nvle': '\u2264\u20D2', | ||
| 'nvlt': '\u003C\u20D2', | ||
| 'nvltrie': '\u22B4\u20D2', | ||
| 'nvrArr': '\u2903', | ||
| 'nvrtrie': '\u22B5\u20D2', | ||
| 'nvsim': '\u223C\u20D2', | ||
| 'nwArr': '\u21D6', | ||
| 'nwarhk': '\u2923', | ||
| 'nwnear': '\u2927', | ||
| 'oacute': '\u00F3', | ||
| 'ocirc': '\u00F4', | ||
| 'ocy': '\u043E', | ||
| 'odblac': '\u0151', | ||
| 'odiv': '\u2A38', | ||
| 'odsold': '\u29BC', | ||
| 'oelig': '\u0153', | ||
| 'ofcir': '\u29BF', | ||
| 'ofr': '\uD835\uDD2C', | ||
| 'ogon': '\u02DB', | ||
| 'ograve': '\u00F2', | ||
| 'ogt': '\u29C1', | ||
| 'ohbar': '\u29B5', | ||
| 'olcir': '\u29BE', | ||
| 'olcross': '\u29BB', | ||
| 'olt': '\u29C0', | ||
| 'omacr': '\u014D', | ||
| 'omega': '\u03C9', | ||
| 'omicron': '\u03BF', | ||
| 'omid': '\u29B6', | ||
| 'oopf': '\uD835\uDD60', | ||
| 'opar': '\u29B7', | ||
| 'operp': '\u29B9', | ||
| 'or': '\u2228', | ||
| 'vee': '\u2228', | ||
| 'ord': '\u2A5D', | ||
| 'order': '\u2134', | ||
| 'orderof': '\u2134', | ||
| 'oscr': '\u2134', | ||
| 'ordf': '\u00AA', | ||
| 'ordm': '\u00BA', | ||
| 'origof': '\u22B6', | ||
| 'oror': '\u2A56', | ||
| 'orslope': '\u2A57', | ||
| 'orv': '\u2A5B', | ||
| 'oslash': '\u00F8', | ||
| 'osol': '\u2298', | ||
| 'otilde': '\u00F5', | ||
| 'otimesas': '\u2A36', | ||
| 'ouml': '\u00F6', | ||
| 'ovbar': '\u233D', | ||
| 'para': '\u00B6', | ||
| 'parsim': '\u2AF3', | ||
| 'parsl': '\u2AFD', | ||
| 'pcy': '\u043F', | ||
| 'percnt': '\u0025', | ||
| 'period': '\u002E', | ||
| 'permil': '\u2030', | ||
| 'pertenk': '\u2031', | ||
| 'pfr': '\uD835\uDD2D', | ||
| 'phi': '\u03C6', | ||
| 'phiv': '\u03D5', | ||
| 'straightphi': '\u03D5', | ||
| 'varphi': '\u03D5', | ||
| 'phone': '\u260E', | ||
| 'pi': '\u03C0', | ||
| 'piv': '\u03D6', | ||
| 'varpi': '\u03D6', | ||
| 'planckh': '\u210E', | ||
| 'plus': '\u002B', | ||
| 'plusacir': '\u2A23', | ||
| 'pluscir': '\u2A22', | ||
| 'plusdu': '\u2A25', | ||
| 'pluse': '\u2A72', | ||
| 'plussim': '\u2A26', | ||
| 'plustwo': '\u2A27', | ||
| 'pointint': '\u2A15', | ||
| 'popf': '\uD835\uDD61', | ||
| 'pound': '\u00A3', | ||
| 'prE': '\u2AB3', | ||
| 'prap': '\u2AB7', | ||
| 'precapprox': '\u2AB7', | ||
| 'precnapprox': '\u2AB9', | ||
| 'prnap': '\u2AB9', | ||
| 'precneqq': '\u2AB5', | ||
| 'prnE': '\u2AB5', | ||
| 'precnsim': '\u22E8', | ||
| 'prnsim': '\u22E8', | ||
| 'prime': '\u2032', | ||
| 'profalar': '\u232E', | ||
| 'profline': '\u2312', | ||
| 'profsurf': '\u2313', | ||
| 'prurel': '\u22B0', | ||
| 'pscr': '\uD835\uDCC5', | ||
| 'psi': '\u03C8', | ||
| 'puncsp': '\u2008', | ||
| 'qfr': '\uD835\uDD2E', | ||
| 'qopf': '\uD835\uDD62', | ||
| 'qprime': '\u2057', | ||
| 'qscr': '\uD835\uDCC6', | ||
| 'quatint': '\u2A16', | ||
| 'quest': '\u003F', | ||
| 'rAtail': '\u291C', | ||
| 'rHar': '\u2964', | ||
| 'race': '\u223D\u0331', | ||
| 'racute': '\u0155', | ||
| 'raemptyv': '\u29B3', | ||
| 'rangd': '\u2992', | ||
| 'range': '\u29A5', | ||
| 'raquo': '\u00BB', | ||
| 'rarrap': '\u2975', | ||
| 'rarrbfs': '\u2920', | ||
| 'rarrc': '\u2933', | ||
| 'rarrfs': '\u291E', | ||
| 'rarrpl': '\u2945', | ||
| 'rarrsim': '\u2974', | ||
| 'rarrtl': '\u21A3', | ||
| 'rightarrowtail': '\u21A3', | ||
| 'rarrw': '\u219D', | ||
| 'rightsquigarrow': '\u219D', | ||
| 'ratail': '\u291A', | ||
| 'ratio': '\u2236', | ||
| 'rbbrk': '\u2773', | ||
| 'rbrace': '\u007D', | ||
| 'rcub': '\u007D', | ||
| 'rbrack': '\u005D', | ||
| 'rsqb': '\u005D', | ||
| 'rbrke': '\u298C', | ||
| 'rbrksld': '\u298E', | ||
| 'rbrkslu': '\u2990', | ||
| 'rcaron': '\u0159', | ||
| 'rcedil': '\u0157', | ||
| 'rcy': '\u0440', | ||
| 'rdca': '\u2937', | ||
| 'rdldhar': '\u2969', | ||
| 'rdsh': '\u21B3', | ||
| 'rect': '\u25AD', | ||
| 'rfisht': '\u297D', | ||
| 'rfr': '\uD835\uDD2F', | ||
| 'rharul': '\u296C', | ||
| 'rho': '\u03C1', | ||
| 'rhov': '\u03F1', | ||
| 'varrho': '\u03F1', | ||
| 'rightrightarrows': '\u21C9', | ||
| 'rrarr': '\u21C9', | ||
| 'rightthreetimes': '\u22CC', | ||
| 'rthree': '\u22CC', | ||
| 'ring': '\u02DA', | ||
| 'rlm': '\u200F', | ||
| 'rmoust': '\u23B1', | ||
| 'rmoustache': '\u23B1', | ||
| 'rnmid': '\u2AEE', | ||
| 'roang': '\u27ED', | ||
| 'roarr': '\u21FE', | ||
| 'ropar': '\u2986', | ||
| 'ropf': '\uD835\uDD63', | ||
| 'roplus': '\u2A2E', | ||
| 'rotimes': '\u2A35', | ||
| 'rpar': '\u0029', | ||
| 'rpargt': '\u2994', | ||
| 'rppolint': '\u2A12', | ||
| 'rsaquo': '\u203A', | ||
| 'rscr': '\uD835\uDCC7', | ||
| 'rtimes': '\u22CA', | ||
| 'rtri': '\u25B9', | ||
| 'triangleright': '\u25B9', | ||
| 'rtriltri': '\u29CE', | ||
| 'ruluhar': '\u2968', | ||
| 'rx': '\u211E', | ||
| 'sacute': '\u015B', | ||
| 'scE': '\u2AB4', | ||
| 'scap': '\u2AB8', | ||
| 'succapprox': '\u2AB8', | ||
| 'scaron': '\u0161', | ||
| 'scedil': '\u015F', | ||
| 'scirc': '\u015D', | ||
| 'scnE': '\u2AB6', | ||
| 'succneqq': '\u2AB6', | ||
| 'scnap': '\u2ABA', | ||
| 'succnapprox': '\u2ABA', | ||
| 'scnsim': '\u22E9', | ||
| 'succnsim': '\u22E9', | ||
| 'scpolint': '\u2A13', | ||
| 'scy': '\u0441', | ||
| 'sdot': '\u22C5', | ||
| 'sdote': '\u2A66', | ||
| 'seArr': '\u21D8', | ||
| 'sect': '\u00A7', | ||
| 'semi': '\u003B', | ||
| 'seswar': '\u2929', | ||
| 'tosa': '\u2929', | ||
| 'sext': '\u2736', | ||
| 'sfr': '\uD835\uDD30', | ||
| 'sharp': '\u266F', | ||
| 'shchcy': '\u0449', | ||
| 'shcy': '\u0448', | ||
| 'shy': '\u00AD', | ||
| 'sigma': '\u03C3', | ||
| 'sigmaf': '\u03C2', | ||
| 'sigmav': '\u03C2', | ||
| 'varsigma': '\u03C2', | ||
| 'simdot': '\u2A6A', | ||
| 'simg': '\u2A9E', | ||
| 'simgE': '\u2AA0', | ||
| 'siml': '\u2A9D', | ||
| 'simlE': '\u2A9F', | ||
| 'simne': '\u2246', | ||
| 'simplus': '\u2A24', | ||
| 'simrarr': '\u2972', | ||
| 'smashp': '\u2A33', | ||
| 'smeparsl': '\u29E4', | ||
| 'smile': '\u2323', | ||
| 'ssmile': '\u2323', | ||
| 'smt': '\u2AAA', | ||
| 'smte': '\u2AAC', | ||
| 'smtes': '\u2AAC\uFE00', | ||
| 'softcy': '\u044C', | ||
| 'sol': '\u002F', | ||
| 'solb': '\u29C4', | ||
| 'solbar': '\u233F', | ||
| 'sopf': '\uD835\uDD64', | ||
| 'spades': '\u2660', | ||
| 'spadesuit': '\u2660', | ||
| 'sqcaps': '\u2293\uFE00', | ||
| 'sqcups': '\u2294\uFE00', | ||
| 'sscr': '\uD835\uDCC8', | ||
| 'star': '\u2606', | ||
| 'sub': '\u2282', | ||
| 'subset': '\u2282', | ||
| 'subE': '\u2AC5', | ||
| 'subseteqq': '\u2AC5', | ||
| 'subdot': '\u2ABD', | ||
| 'subedot': '\u2AC3', | ||
| 'submult': '\u2AC1', | ||
| 'subnE': '\u2ACB', | ||
| 'subsetneqq': '\u2ACB', | ||
| 'subne': '\u228A', | ||
| 'subsetneq': '\u228A', | ||
| 'subplus': '\u2ABF', | ||
| 'subrarr': '\u2979', | ||
| 'subsim': '\u2AC7', | ||
| 'subsub': '\u2AD5', | ||
| 'subsup': '\u2AD3', | ||
| 'sung': '\u266A', | ||
| 'sup1': '\u00B9', | ||
| 'sup2': '\u00B2', | ||
| 'sup3': '\u00B3', | ||
| 'supE': '\u2AC6', | ||
| 'supseteqq': '\u2AC6', | ||
| 'supdot': '\u2ABE', | ||
| 'supdsub': '\u2AD8', | ||
| 'supedot': '\u2AC4', | ||
| 'suphsol': '\u27C9', | ||
| 'suphsub': '\u2AD7', | ||
| 'suplarr': '\u297B', | ||
| 'supmult': '\u2AC2', | ||
| 'supnE': '\u2ACC', | ||
| 'supsetneqq': '\u2ACC', | ||
| 'supne': '\u228B', | ||
| 'supsetneq': '\u228B', | ||
| 'supplus': '\u2AC0', | ||
| 'supsim': '\u2AC8', | ||
| 'supsub': '\u2AD4', | ||
| 'supsup': '\u2AD6', | ||
| 'swArr': '\u21D9', | ||
| 'swnwar': '\u292A', | ||
| 'szlig': '\u00DF', | ||
| 'target': '\u2316', | ||
| 'tau': '\u03C4', | ||
| 'tcaron': '\u0165', | ||
| 'tcedil': '\u0163', | ||
| 'tcy': '\u0442', | ||
| 'telrec': '\u2315', | ||
| 'tfr': '\uD835\uDD31', | ||
| 'theta': '\u03B8', | ||
| 'thetasym': '\u03D1', | ||
| 'thetav': '\u03D1', | ||
| 'vartheta': '\u03D1', | ||
| 'thorn': '\u00FE', | ||
| 'times': '\u00D7', | ||
| 'timesbar': '\u2A31', | ||
| 'timesd': '\u2A30', | ||
| 'topbot': '\u2336', | ||
| 'topcir': '\u2AF1', | ||
| 'topf': '\uD835\uDD65', | ||
| 'topfork': '\u2ADA', | ||
| 'tprime': '\u2034', | ||
| 'triangle': '\u25B5', | ||
| 'utri': '\u25B5', | ||
| 'triangleq': '\u225C', | ||
| 'trie': '\u225C', | ||
| 'tridot': '\u25EC', | ||
| 'triminus': '\u2A3A', | ||
| 'triplus': '\u2A39', | ||
| 'trisb': '\u29CD', | ||
| 'tritime': '\u2A3B', | ||
| 'trpezium': '\u23E2', | ||
| 'tscr': '\uD835\uDCC9', | ||
| 'tscy': '\u0446', | ||
| 'tshcy': '\u045B', | ||
| 'tstrok': '\u0167', | ||
| 'uHar': '\u2963', | ||
| 'uacute': '\u00FA', | ||
| 'ubrcy': '\u045E', | ||
| 'ubreve': '\u016D', | ||
| 'ucirc': '\u00FB', | ||
| 'ucy': '\u0443', | ||
| 'udblac': '\u0171', | ||
| 'ufisht': '\u297E', | ||
| 'ufr': '\uD835\uDD32', | ||
| 'ugrave': '\u00F9', | ||
| 'uhblk': '\u2580', | ||
| 'ulcorn': '\u231C', | ||
| 'ulcorner': '\u231C', | ||
| 'ulcrop': '\u230F', | ||
| 'ultri': '\u25F8', | ||
| 'umacr': '\u016B', | ||
| 'uogon': '\u0173', | ||
| 'uopf': '\uD835\uDD66', | ||
| 'upsi': '\u03C5', | ||
| 'upsilon': '\u03C5', | ||
| 'upuparrows': '\u21C8', | ||
| 'uuarr': '\u21C8', | ||
| 'urcorn': '\u231D', | ||
| 'urcorner': '\u231D', | ||
| 'urcrop': '\u230E', | ||
| 'uring': '\u016F', | ||
| 'urtri': '\u25F9', | ||
| 'uscr': '\uD835\uDCCA', | ||
| 'utdot': '\u22F0', | ||
| 'utilde': '\u0169', | ||
| 'uuml': '\u00FC', | ||
| 'uwangle': '\u29A7', | ||
| 'vBar': '\u2AE8', | ||
| 'vBarv': '\u2AE9', | ||
| 'vangrt': '\u299C', | ||
| 'varsubsetneq': '\u228A\uFE00', | ||
| 'vsubne': '\u228A\uFE00', | ||
| 'varsubsetneqq': '\u2ACB\uFE00', | ||
| 'vsubnE': '\u2ACB\uFE00', | ||
| 'varsupsetneq': '\u228B\uFE00', | ||
| 'vsupne': '\u228B\uFE00', | ||
| 'varsupsetneqq': '\u2ACC\uFE00', | ||
| 'vsupnE': '\u2ACC\uFE00', | ||
| 'vcy': '\u0432', | ||
| 'veebar': '\u22BB', | ||
| 'veeeq': '\u225A', | ||
| 'vellip': '\u22EE', | ||
| 'vfr': '\uD835\uDD33', | ||
| 'vopf': '\uD835\uDD67', | ||
| 'vscr': '\uD835\uDCCB', | ||
| 'vzigzag': '\u299A', | ||
| 'wcirc': '\u0175', | ||
| 'wedbar': '\u2A5F', | ||
| 'wedgeq': '\u2259', | ||
| 'weierp': '\u2118', | ||
| 'wp': '\u2118', | ||
| 'wfr': '\uD835\uDD34', | ||
| 'wopf': '\uD835\uDD68', | ||
| 'wscr': '\uD835\uDCCC', | ||
| 'xfr': '\uD835\uDD35', | ||
| 'xi': '\u03BE', | ||
| 'xnis': '\u22FB', | ||
| 'xopf': '\uD835\uDD69', | ||
| 'xscr': '\uD835\uDCCD', | ||
| 'yacute': '\u00FD', | ||
| 'yacy': '\u044F', | ||
| 'ycirc': '\u0177', | ||
| 'ycy': '\u044B', | ||
| 'yen': '\u00A5', | ||
| 'yfr': '\uD835\uDD36', | ||
| 'yicy': '\u0457', | ||
| 'yopf': '\uD835\uDD6A', | ||
| 'yscr': '\uD835\uDCCE', | ||
| 'yucy': '\u044E', | ||
| 'yuml': '\u00FF', | ||
| 'zacute': '\u017A', | ||
| 'zcaron': '\u017E', | ||
| 'zcy': '\u0437', | ||
| 'zdot': '\u017C', | ||
| 'zeta': '\u03B6', | ||
| 'zfr': '\uD835\uDD37', | ||
| 'zhcy': '\u0436', | ||
| 'zigrarr': '\u21DD', | ||
| 'zopf': '\uD835\uDD6B', | ||
| 'zscr': '\uD835\uDCCF', | ||
| 'zwj': '\u200D', | ||
| 'zwnj': '\u200C', | ||
| }; | ||
| // The &ngsp; pseudo-entity is denoting a space. | ||
| // 0xE500 is a PUA (Private Use Areas) unicode character | ||
| // This is inspired by the Angular Dart implementation. | ||
| export const NGSP_UNICODE = '\uE500'; | ||
| NAMED_ENTITIES['ngsp'] = NGSP_UNICODE; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { TokenizeOptions } from './lexer'; | ||
| import { Parser, ParseTreeResult } from './parser'; | ||
| import { TagContentType } from './tags'; | ||
| export declare class HtmlParser extends Parser { | ||
| constructor(); | ||
| parse(source: string, url: string, options?: TokenizeOptions, isTagNameCaseSensitive?: boolean, getTagContentType?: (tagName: string, prefix: string, hasParent: boolean, attrs: Array<{ | ||
| prefix: string; | ||
| name: string; | ||
| value?: string; | ||
| }>) => void | TagContentType): ParseTreeResult; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { getHtmlTagDefinition } from "./html_tags.js"; | ||
| import { Parser } from "./parser.js"; | ||
| export class HtmlParser extends Parser { | ||
| constructor() { | ||
| super(getHtmlTagDefinition); | ||
| } | ||
| // angular-html-parser: More options | ||
| parse(source, url, options, isTagNameCaseSensitive = false, getTagContentType) { | ||
| return super.parse(source, url, options, isTagNameCaseSensitive, getTagContentType); | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { TagContentType, TagDefinition } from './tags'; | ||
| export declare class HtmlTagDefinition implements TagDefinition { | ||
| private closedByChildren; | ||
| private contentType; | ||
| closedByParent: boolean; | ||
| implicitNamespacePrefix: string | null; | ||
| isVoid: boolean; | ||
| ignoreFirstLf: boolean; | ||
| canSelfClose: boolean; | ||
| preventNamespaceInheritance: boolean; | ||
| constructor({ closedByChildren, implicitNamespacePrefix, contentType, closedByParent, isVoid, ignoreFirstLf, preventNamespaceInheritance, canSelfClose, }?: { | ||
| closedByChildren?: string[]; | ||
| closedByParent?: boolean; | ||
| implicitNamespacePrefix?: string; | ||
| contentType?: TagContentType | { | ||
| default: TagContentType; | ||
| [namespace: string]: TagContentType; | ||
| }; | ||
| isVoid?: boolean; | ||
| ignoreFirstLf?: boolean; | ||
| preventNamespaceInheritance?: boolean; | ||
| canSelfClose?: boolean; | ||
| }); | ||
| isClosedByChild(name: string): boolean; | ||
| getContentType(prefix?: string): TagContentType; | ||
| } | ||
| export declare function getHtmlTagDefinition(tagName: string): HtmlTagDefinition; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { DomElementSchemaRegistry } from "../schema/dom_element_schema_registry.js"; | ||
| import { getNsPrefix, TagContentType } from "./tags.js"; | ||
| export class HtmlTagDefinition { | ||
| constructor({ closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false, ignoreFirstLf = false, preventNamespaceInheritance = false, canSelfClose = false, } = {}) { | ||
| this.closedByChildren = {}; | ||
| this.closedByParent = false; | ||
| if (closedByChildren && closedByChildren.length > 0) { | ||
| closedByChildren.forEach((tagName) => (this.closedByChildren[tagName] = true)); | ||
| } | ||
| this.isVoid = isVoid; | ||
| this.closedByParent = closedByParent || isVoid; | ||
| this.implicitNamespacePrefix = implicitNamespacePrefix || null; | ||
| this.contentType = contentType; | ||
| this.ignoreFirstLf = ignoreFirstLf; | ||
| this.preventNamespaceInheritance = preventNamespaceInheritance; | ||
| this.canSelfClose = canSelfClose ?? isVoid; | ||
| } | ||
| isClosedByChild(name) { | ||
| return this.isVoid || name.toLowerCase() in this.closedByChildren; | ||
| } | ||
| getContentType(prefix) { | ||
| if (typeof this.contentType === 'object') { | ||
| const overrideType = prefix === undefined ? undefined : this.contentType[prefix]; | ||
| return overrideType ?? this.contentType.default; | ||
| } | ||
| return this.contentType; | ||
| } | ||
| } | ||
| let DEFAULT_TAG_DEFINITION; | ||
| // see https://www.w3.org/TR/html51/syntax.html#optional-tags | ||
| // This implementation does not fully conform to the HTML5 spec. | ||
| let TAG_DEFINITIONS; | ||
| export function getHtmlTagDefinition(tagName) { | ||
| if (!TAG_DEFINITIONS) { | ||
| DEFAULT_TAG_DEFINITION = new HtmlTagDefinition({ canSelfClose: true }); | ||
| TAG_DEFINITIONS = Object.assign(Object.create(null), { | ||
| 'base': new HtmlTagDefinition({ isVoid: true }), | ||
| 'meta': new HtmlTagDefinition({ isVoid: true }), | ||
| 'area': new HtmlTagDefinition({ isVoid: true }), | ||
| 'embed': new HtmlTagDefinition({ isVoid: true }), | ||
| 'link': new HtmlTagDefinition({ isVoid: true }), | ||
| 'img': new HtmlTagDefinition({ isVoid: true }), | ||
| 'input': new HtmlTagDefinition({ isVoid: true }), | ||
| 'param': new HtmlTagDefinition({ isVoid: true }), | ||
| 'hr': new HtmlTagDefinition({ isVoid: true }), | ||
| 'br': new HtmlTagDefinition({ isVoid: true }), | ||
| 'source': new HtmlTagDefinition({ isVoid: true }), | ||
| 'track': new HtmlTagDefinition({ isVoid: true }), | ||
| 'wbr': new HtmlTagDefinition({ isVoid: true }), | ||
| 'p': new HtmlTagDefinition({ | ||
| closedByChildren: [ | ||
| 'address', | ||
| 'article', | ||
| 'aside', | ||
| 'blockquote', | ||
| 'div', | ||
| 'dl', | ||
| 'fieldset', | ||
| 'footer', | ||
| 'form', | ||
| 'h1', | ||
| 'h2', | ||
| 'h3', | ||
| 'h4', | ||
| 'h5', | ||
| 'h6', | ||
| 'header', | ||
| 'hgroup', | ||
| 'hr', | ||
| 'main', | ||
| 'nav', | ||
| 'ol', | ||
| 'p', | ||
| 'pre', | ||
| 'section', | ||
| 'table', | ||
| 'ul', | ||
| ], | ||
| closedByParent: true, | ||
| }), | ||
| 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }), | ||
| 'tbody': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'], closedByParent: true }), | ||
| 'tfoot': new HtmlTagDefinition({ closedByChildren: ['tbody'], closedByParent: true }), | ||
| 'tr': new HtmlTagDefinition({ closedByChildren: ['tr'], closedByParent: true }), | ||
| 'td': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }), | ||
| 'th': new HtmlTagDefinition({ closedByChildren: ['td', 'th'], closedByParent: true }), | ||
| 'col': new HtmlTagDefinition({ isVoid: true }), | ||
| 'svg': new HtmlTagDefinition({ implicitNamespacePrefix: 'svg' }), | ||
| 'foreignObject': new HtmlTagDefinition({ | ||
| // Usually the implicit namespace here would be redundant since it will be inherited from | ||
| // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser | ||
| // works is that the parent node of an end tag is its own start tag which means that | ||
| // the `preventNamespaceInheritance` on `foreignObject` would have it default to the | ||
| // implicit namespace which is `html`, unless specified otherwise. | ||
| implicitNamespacePrefix: 'svg', | ||
| // We want to prevent children of foreignObject from inheriting its namespace, because | ||
| // the point of the element is to allow nodes from other namespaces to be inserted. | ||
| preventNamespaceInheritance: true, | ||
| }), | ||
| 'math': new HtmlTagDefinition({ implicitNamespacePrefix: 'math' }), | ||
| 'li': new HtmlTagDefinition({ closedByChildren: ['li'], closedByParent: true }), | ||
| 'dt': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'] }), | ||
| 'dd': new HtmlTagDefinition({ closedByChildren: ['dt', 'dd'], closedByParent: true }), | ||
| 'rb': new HtmlTagDefinition({ | ||
| closedByChildren: ['rb', 'rt', 'rtc', 'rp'], | ||
| closedByParent: true, | ||
| }), | ||
| 'rt': new HtmlTagDefinition({ | ||
| closedByChildren: ['rb', 'rt', 'rtc', 'rp'], | ||
| closedByParent: true, | ||
| }), | ||
| 'rtc': new HtmlTagDefinition({ closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true }), | ||
| 'rp': new HtmlTagDefinition({ | ||
| closedByChildren: ['rb', 'rt', 'rtc', 'rp'], | ||
| closedByParent: true, | ||
| }), | ||
| 'optgroup': new HtmlTagDefinition({ closedByChildren: ['optgroup'], closedByParent: true }), | ||
| 'option': new HtmlTagDefinition({ | ||
| closedByChildren: ['option', 'optgroup'], | ||
| closedByParent: true, | ||
| }), | ||
| 'pre': new HtmlTagDefinition({ ignoreFirstLf: true }), | ||
| 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }), | ||
| 'style': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }), | ||
| 'script': new HtmlTagDefinition({ contentType: TagContentType.RAW_TEXT }), | ||
| 'title': new HtmlTagDefinition({ | ||
| // The browser supports two separate `title` tags which have to use | ||
| // a different content type: `HTMLTitleElement` and `SVGTitleElement` | ||
| contentType: { | ||
| default: TagContentType.ESCAPABLE_RAW_TEXT, | ||
| svg: TagContentType.PARSABLE_DATA, | ||
| }, | ||
| }), | ||
| 'textarea': new HtmlTagDefinition({ | ||
| contentType: TagContentType.ESCAPABLE_RAW_TEXT, | ||
| ignoreFirstLf: true, | ||
| }), | ||
| }); | ||
| new DomElementSchemaRegistry().allKnownElementNames().forEach((knownTagName) => { | ||
| if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) { | ||
| TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({ canSelfClose: false }); | ||
| } | ||
| }); | ||
| } | ||
| // We have to make both a case-sensitive and a case-insensitive lookup, because | ||
| // HTML tag names are case insensitive, whereas some SVG tags are case sensitive. | ||
| // angular-html-parser: modification | ||
| return (TAG_DEFINITIONS[tagName] ?? DEFAULT_TAG_DEFINITION); | ||
| // return ( | ||
| // TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ?? DEFAULT_TAG_DEFINITION | ||
| // ); | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { ParseError, ParseSourceSpan } from '../parse_util'; | ||
| import { InterpolationConfig } from './defaults'; | ||
| import { TagContentType } from './tags'; | ||
| import { Token } from './tokens'; | ||
| export declare class TokenizeResult { | ||
| tokens: Token[]; | ||
| errors: ParseError[]; | ||
| nonNormalizedIcuExpressions: Token[]; | ||
| constructor(tokens: Token[], errors: ParseError[], nonNormalizedIcuExpressions: Token[]); | ||
| } | ||
| export interface LexerRange { | ||
| startPos: number; | ||
| startLine: number; | ||
| startCol: number; | ||
| endPos: number; | ||
| } | ||
| /** | ||
| * Options that modify how the text is tokenized. | ||
| */ | ||
| export interface TokenizeOptions { | ||
| /** Whether to tokenize ICU messages (considered as text nodes when false). */ | ||
| tokenizeExpansionForms?: boolean; | ||
| /** How to tokenize interpolation markers. */ | ||
| interpolationConfig?: InterpolationConfig; | ||
| /** | ||
| * The start and end point of the text to parse within the `source` string. | ||
| * The entire `source` string is parsed if this is not provided. | ||
| * */ | ||
| range?: LexerRange; | ||
| /** | ||
| * If this text is stored in a JavaScript string, then we have to deal with escape sequences. | ||
| * | ||
| * **Example 1:** | ||
| * | ||
| * ``` | ||
| * "abc\"def\nghi" | ||
| * ``` | ||
| * | ||
| * - The `\"` must be converted to `"`. | ||
| * - The `\n` must be converted to a new line character in a token, | ||
| * but it should not increment the current line for source mapping. | ||
| * | ||
| * **Example 2:** | ||
| * | ||
| * ``` | ||
| * "abc\ | ||
| * def" | ||
| * ``` | ||
| * | ||
| * The line continuation (`\` followed by a newline) should be removed from a token | ||
| * but the new line should increment the current line for source mapping. | ||
| */ | ||
| escapedString?: boolean; | ||
| /** | ||
| * If this text is stored in an external template (e.g. via `templateUrl`) then we need to decide | ||
| * whether or not to normalize the line-endings (from `\r\n` to `\n`) when processing ICU | ||
| * expressions. | ||
| * | ||
| * If `true` then we will normalize ICU expression line endings. | ||
| * The default is `false`, but this will be switched in a future major release. | ||
| */ | ||
| i18nNormalizeLineEndingsInICUs?: boolean; | ||
| /** | ||
| * An array of characters that should be considered as leading trivia. | ||
| * Leading trivia are characters that are not important to the developer, and so should not be | ||
| * included in source-map segments. A common example is whitespace. | ||
| */ | ||
| leadingTriviaChars?: string[]; | ||
| /** | ||
| * If true, do not convert CRLF to LF. | ||
| */ | ||
| preserveLineEndings?: boolean; | ||
| /** | ||
| * Whether to tokenize @ block syntax. Otherwise considered text, | ||
| * or ICU tokens if `tokenizeExpansionForms` is enabled. | ||
| */ | ||
| tokenizeBlocks?: boolean; | ||
| /** | ||
| * Whether to tokenize the `@let` syntax. Otherwise will be considered either | ||
| * text or an incomplete block, depending on whether `tokenizeBlocks` is enabled. | ||
| */ | ||
| tokenizeLet?: boolean; | ||
| /** Whether the selectorless syntax is enabled. */ | ||
| selectorlessEnabled?: boolean; | ||
| canSelfClose?: boolean; | ||
| allowHtmComponentClosingTags?: boolean; | ||
| } | ||
| export declare function tokenize(source: string, url: string, getTagContentType: (tagName: string, prefix: string, hasParent: boolean, attrs: Array<{ | ||
| prefix: string; | ||
| name: string; | ||
| value?: string; | ||
| }>) => TagContentType, options?: TokenizeOptions): TokenizeResult; | ||
| /** | ||
| * The _Tokenizer uses objects of this type to move through the input text, | ||
| * extracting "parsed characters". These could be more than one actual character | ||
| * if the text contains escape sequences. | ||
| */ | ||
| interface CharacterCursor { | ||
| /** Initialize the cursor. */ | ||
| init(): void; | ||
| /** The parsed character at the current cursor position. */ | ||
| peek(): number; | ||
| /** Advance the cursor by one parsed character. */ | ||
| advance(): void; | ||
| /** Get a span from the marked start point to the current point. */ | ||
| getSpan(start?: this, leadingTriviaCodePoints?: number[]): ParseSourceSpan; | ||
| /** Get the parsed characters from the marked start point to the current point. */ | ||
| getChars(start: this): string; | ||
| /** The number of characters left before the end of the cursor. */ | ||
| charsLeft(): number; | ||
| /** The number of characters between `this` cursor and `other` cursor. */ | ||
| diff(other: this): number; | ||
| /** Make a copy of this cursor */ | ||
| clone(): CharacterCursor; | ||
| } | ||
| export declare class CursorError extends Error { | ||
| msg: string; | ||
| cursor: CharacterCursor; | ||
| constructor(msg: string, cursor: CharacterCursor); | ||
| } | ||
| export {}; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import * as chars from "../chars.js"; | ||
| import { ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan } from "../parse_util.js"; | ||
| import { DEFAULT_INTERPOLATION_CONFIG } from "./defaults.js"; | ||
| import { NAMED_ENTITIES } from "./entities.js"; | ||
| import { mergeNsAndName, TagContentType } from "./tags.js"; | ||
| export class TokenizeResult { | ||
| constructor(tokens, errors, nonNormalizedIcuExpressions) { | ||
| this.tokens = tokens; | ||
| this.errors = errors; | ||
| this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions; | ||
| } | ||
| } | ||
| export function tokenize(source, url, getTagContentType, options = {}) { | ||
| const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagContentType, options); | ||
| tokenizer.tokenize(); | ||
| return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions); | ||
| } | ||
| const _CR_OR_CRLF_REGEXP = /\r\n?/g; | ||
| function _unexpectedCharacterErrorMsg(charCode) { | ||
| const char = charCode === chars.$EOF ? 'EOF' : String.fromCharCode(charCode); | ||
| return `Unexpected character "${char}"`; | ||
| } | ||
| function _unknownEntityErrorMsg(entitySrc) { | ||
| return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or "&#x<hex>;" syntax`; | ||
| } | ||
| function _unparsableEntityErrorMsg(type, entityStr) { | ||
| return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`; | ||
| } | ||
| var CharacterReferenceType; | ||
| (function (CharacterReferenceType) { | ||
| CharacterReferenceType["HEX"] = "hexadecimal"; | ||
| CharacterReferenceType["DEC"] = "decimal"; | ||
| })(CharacterReferenceType || (CharacterReferenceType = {})); | ||
| const SUPPORTED_BLOCKS = [ | ||
| '@if', | ||
| '@else', // Covers `@else if` as well | ||
| '@for', | ||
| '@switch', | ||
| '@case', | ||
| '@default', | ||
| '@empty', | ||
| '@defer', | ||
| '@placeholder', | ||
| '@loading', | ||
| '@error', | ||
| ]; | ||
| // See https://www.w3.org/TR/html51/syntax.html#writing-html-documents | ||
| class _Tokenizer { | ||
| /** | ||
| * @param _file The html source file being tokenized. | ||
| * @param _getTagContentType A function that will retrieve a tag content type for a given tag | ||
| * name. | ||
| * @param options Configuration of the tokenization. | ||
| */ | ||
| constructor(_file, _getTagContentType, options) { | ||
| this._getTagContentType = _getTagContentType; | ||
| this._currentTokenStart = null; | ||
| this._currentTokenType = null; | ||
| this._expansionCaseStack = []; | ||
| this._openDirectiveCount = 0; | ||
| this._inInterpolation = false; | ||
| this._fullNameStack = []; | ||
| this.tokens = []; | ||
| this.errors = []; | ||
| this.nonNormalizedIcuExpressions = []; | ||
| this._tokenizeIcu = options.tokenizeExpansionForms || false; | ||
| this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG; | ||
| this._leadingTriviaCodePoints = | ||
| options.leadingTriviaChars && options.leadingTriviaChars.map((c) => c.codePointAt(0) || 0); | ||
| this._canSelfClose = options.canSelfClose || false; | ||
| this._allowHtmComponentClosingTags = options.allowHtmComponentClosingTags || false; | ||
| const range = options.range || { | ||
| endPos: _file.content.length, | ||
| startPos: 0, | ||
| startLine: 0, | ||
| startCol: 0, | ||
| }; | ||
| this._cursor = options.escapedString | ||
| ? new EscapedCharacterCursor(_file, range) | ||
| : new PlainCharacterCursor(_file, range); | ||
| this._preserveLineEndings = options.preserveLineEndings || false; | ||
| this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false; | ||
| this._tokenizeBlocks = options.tokenizeBlocks ?? true; | ||
| this._tokenizeLet = options.tokenizeLet ?? true; | ||
| this._selectorlessEnabled = options.selectorlessEnabled ?? false; | ||
| try { | ||
| this._cursor.init(); | ||
| } | ||
| catch (e) { | ||
| this.handleError(e); | ||
| } | ||
| } | ||
| _processCarriageReturns(content) { | ||
| if (this._preserveLineEndings) { | ||
| return content; | ||
| } | ||
| // https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream | ||
| // In order to keep the original position in the source, we can not | ||
| // pre-process it. | ||
| // Instead CRs are processed right before instantiating the tokens. | ||
| return content.replace(_CR_OR_CRLF_REGEXP, '\n'); | ||
| } | ||
| tokenize() { | ||
| while (this._cursor.peek() !== chars.$EOF) { | ||
| const start = this._cursor.clone(); | ||
| try { | ||
| if (this._attemptCharCode(chars.$LT)) { | ||
| if (this._attemptCharCode(chars.$BANG)) { | ||
| if (this._attemptStr('[CDATA[')) { | ||
| this._consumeCdata(start); | ||
| } | ||
| else if (this._attemptStr('--')) { | ||
| this._consumeComment(start); | ||
| } | ||
| else if (this._attemptStrCaseInsensitive('doctype')) { | ||
| this._consumeDocType(start); | ||
| } | ||
| else { | ||
| this._consumeBogusComment(start); | ||
| } | ||
| } | ||
| else if (this._attemptCharCode(chars.$SLASH)) { | ||
| this._consumeTagClose(start); | ||
| } | ||
| else { | ||
| const savedPos = this._cursor.clone(); | ||
| if (this._attemptCharCode(chars.$QUESTION)) { | ||
| this._cursor = savedPos; | ||
| this._consumeBogusComment(start); | ||
| } | ||
| else { | ||
| this._consumeTagOpen(start); | ||
| } | ||
| } | ||
| } | ||
| else if (this._tokenizeLet && | ||
| // Use `peek` instead of `attempCharCode` since we | ||
| // don't want to advance in case it's not `@let`. | ||
| this._cursor.peek() === chars.$AT && | ||
| !this._inInterpolation && | ||
| this._isLetStart()) { | ||
| this._consumeLetDeclaration(start); | ||
| } | ||
| else if (this._tokenizeBlocks && this._isBlockStart()) { | ||
| this._consumeBlockStart(start); | ||
| } | ||
| else if (this._tokenizeBlocks && | ||
| !this._inInterpolation && | ||
| !this._isInExpansionCase() && | ||
| !this._isInExpansionForm() && | ||
| this._attemptCharCode(chars.$RBRACE)) { | ||
| this._consumeBlockEnd(start); | ||
| } | ||
| else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) { | ||
| // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while | ||
| // the premature end of an interpolation is given by the start of a new HTML element. | ||
| this._consumeWithInterpolation(5 /* TokenType.TEXT */, 8 /* TokenType.INTERPOLATION */, () => this._isTextEnd(), () => this._isTagStart()); | ||
| } | ||
| } | ||
| catch (e) { | ||
| this.handleError(e); | ||
| } | ||
| } | ||
| this._beginToken(42 /* TokenType.EOF */); | ||
| this._endToken([]); | ||
| } | ||
| _getBlockName() { | ||
| // This allows us to capture up something like `@else if`, but not `@ if`. | ||
| let spacesInNameAllowed = false; | ||
| const nameCursor = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn((code) => { | ||
| if (chars.isWhitespace(code)) { | ||
| return !spacesInNameAllowed; | ||
| } | ||
| if (isBlockNameChar(code)) { | ||
| spacesInNameAllowed = true; | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| return this._cursor.getChars(nameCursor).trim(); | ||
| } | ||
| _consumeBlockStart(start) { | ||
| this._requireCharCode(chars.$AT); | ||
| this._beginToken(25 /* TokenType.BLOCK_OPEN_START */, start); | ||
| const startToken = this._endToken([this._getBlockName()]); | ||
| if (this._cursor.peek() === chars.$LPAREN) { | ||
| // Advance past the opening paren. | ||
| this._cursor.advance(); | ||
| // Capture the parameters. | ||
| this._consumeBlockParameters(); | ||
| // Allow spaces before the closing paren. | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| if (this._attemptCharCode(chars.$RPAREN)) { | ||
| // Allow spaces after the paren. | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| else { | ||
| startToken.type = 29 /* TokenType.INCOMPLETE_BLOCK_OPEN */; | ||
| return; | ||
| } | ||
| } | ||
| if (this._attemptCharCode(chars.$LBRACE)) { | ||
| this._beginToken(26 /* TokenType.BLOCK_OPEN_END */); | ||
| this._endToken([]); | ||
| } | ||
| else { | ||
| startToken.type = 29 /* TokenType.INCOMPLETE_BLOCK_OPEN */; | ||
| } | ||
| } | ||
| _consumeBlockEnd(start) { | ||
| this._beginToken(27 /* TokenType.BLOCK_CLOSE */, start); | ||
| this._endToken([]); | ||
| } | ||
| _consumeBlockParameters() { | ||
| // Trim the whitespace until the first parameter. | ||
| this._attemptCharCodeUntilFn(isBlockParameterChar); | ||
| while (this._cursor.peek() !== chars.$RPAREN && this._cursor.peek() !== chars.$EOF) { | ||
| this._beginToken(28 /* TokenType.BLOCK_PARAMETER */); | ||
| const start = this._cursor.clone(); | ||
| let inQuote = null; | ||
| let openParens = 0; | ||
| // Consume the parameter until the next semicolon or brace. | ||
| // Note that we skip over semicolons/braces inside of strings. | ||
| while ((this._cursor.peek() !== chars.$SEMICOLON && this._cursor.peek() !== chars.$EOF) || | ||
| inQuote !== null) { | ||
| const char = this._cursor.peek(); | ||
| // Skip to the next character if it was escaped. | ||
| if (char === chars.$BACKSLASH) { | ||
| this._cursor.advance(); | ||
| } | ||
| else if (char === inQuote) { | ||
| inQuote = null; | ||
| } | ||
| else if (inQuote === null && chars.isQuote(char)) { | ||
| inQuote = char; | ||
| } | ||
| else if (char === chars.$LPAREN && inQuote === null) { | ||
| openParens++; | ||
| } | ||
| else if (char === chars.$RPAREN && inQuote === null) { | ||
| if (openParens === 0) { | ||
| break; | ||
| } | ||
| else if (openParens > 0) { | ||
| openParens--; | ||
| } | ||
| } | ||
| this._cursor.advance(); | ||
| } | ||
| this._endToken([this._cursor.getChars(start)]); | ||
| // Skip to the next parameter. | ||
| this._attemptCharCodeUntilFn(isBlockParameterChar); | ||
| } | ||
| } | ||
| _consumeLetDeclaration(start) { | ||
| this._requireStr('@let'); | ||
| this._beginToken(30 /* TokenType.LET_START */, start); | ||
| // Require at least one white space after the `@let`. | ||
| if (chars.isWhitespace(this._cursor.peek())) { | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| else { | ||
| const token = this._endToken([this._cursor.getChars(start)]); | ||
| token.type = 33 /* TokenType.INCOMPLETE_LET */; | ||
| return; | ||
| } | ||
| const startToken = this._endToken([this._getLetDeclarationName()]); | ||
| // Skip over white space before the equals character. | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| // Expect an equals sign. | ||
| if (!this._attemptCharCode(chars.$EQ)) { | ||
| startToken.type = 33 /* TokenType.INCOMPLETE_LET */; | ||
| return; | ||
| } | ||
| // Skip spaces after the equals. | ||
| this._attemptCharCodeUntilFn((code) => isNotWhitespace(code) && !chars.isNewLine(code)); | ||
| this._consumeLetDeclarationValue(); | ||
| // Terminate the `@let` with a semicolon. | ||
| const endChar = this._cursor.peek(); | ||
| if (endChar === chars.$SEMICOLON) { | ||
| this._beginToken(32 /* TokenType.LET_END */); | ||
| this._endToken([]); | ||
| this._cursor.advance(); | ||
| } | ||
| else { | ||
| startToken.type = 33 /* TokenType.INCOMPLETE_LET */; | ||
| startToken.sourceSpan = this._cursor.getSpan(start); | ||
| } | ||
| } | ||
| _getLetDeclarationName() { | ||
| const nameCursor = this._cursor.clone(); | ||
| let allowDigit = false; | ||
| this._attemptCharCodeUntilFn((code) => { | ||
| if (chars.isAsciiLetter(code) || | ||
| code === chars.$$ || | ||
| code === chars.$_ || | ||
| // `@let` names can't start with a digit, but digits are valid anywhere else in the name. | ||
| (allowDigit && chars.isDigit(code))) { | ||
| allowDigit = true; | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| return this._cursor.getChars(nameCursor).trim(); | ||
| } | ||
| _consumeLetDeclarationValue() { | ||
| const start = this._cursor.clone(); | ||
| this._beginToken(31 /* TokenType.LET_VALUE */, start); | ||
| while (this._cursor.peek() !== chars.$EOF) { | ||
| const char = this._cursor.peek(); | ||
| // `@let` declarations terminate with a semicolon. | ||
| if (char === chars.$SEMICOLON) { | ||
| break; | ||
| } | ||
| // If we hit a quote, skip over its content since we don't care what's inside. | ||
| if (chars.isQuote(char)) { | ||
| this._cursor.advance(); | ||
| this._attemptCharCodeUntilFn((inner) => { | ||
| if (inner === chars.$BACKSLASH) { | ||
| this._cursor.advance(); | ||
| return false; | ||
| } | ||
| return inner === char; | ||
| }); | ||
| } | ||
| this._cursor.advance(); | ||
| } | ||
| this._endToken([this._cursor.getChars(start)]); | ||
| } | ||
| /** | ||
| * @returns whether an ICU token has been created | ||
| * @internal | ||
| */ | ||
| _tokenizeExpansionForm() { | ||
| if (this.isExpansionFormStart()) { | ||
| this._consumeExpansionFormStart(); | ||
| return true; | ||
| } | ||
| if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) { | ||
| this._consumeExpansionCaseStart(); | ||
| return true; | ||
| } | ||
| if (this._cursor.peek() === chars.$RBRACE) { | ||
| if (this._isInExpansionCase()) { | ||
| this._consumeExpansionCaseEnd(); | ||
| return true; | ||
| } | ||
| if (this._isInExpansionForm()) { | ||
| this._consumeExpansionFormEnd(); | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| _beginToken(type, start = this._cursor.clone()) { | ||
| this._currentTokenStart = start; | ||
| this._currentTokenType = type; | ||
| } | ||
| _endToken(parts, end) { | ||
| if (this._currentTokenStart === null) { | ||
| throw new ParseError(this._cursor.getSpan(end), 'Programming error - attempted to end a token when there was no start to the token'); | ||
| } | ||
| if (this._currentTokenType === null) { | ||
| throw new ParseError(this._cursor.getSpan(this._currentTokenStart), 'Programming error - attempted to end a token which has no token type'); | ||
| } | ||
| const token = { | ||
| type: this._currentTokenType, | ||
| parts, | ||
| sourceSpan: (end ?? this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints), | ||
| }; | ||
| this.tokens.push(token); | ||
| this._currentTokenStart = null; | ||
| this._currentTokenType = null; | ||
| return token; | ||
| } | ||
| _createError(msg, span) { | ||
| if (this._isInExpansionForm()) { | ||
| msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`; | ||
| } | ||
| const error = new ParseError(span, msg); | ||
| this._currentTokenStart = null; | ||
| this._currentTokenType = null; | ||
| return error; | ||
| } | ||
| handleError(e) { | ||
| if (e instanceof CursorError) { | ||
| e = this._createError(e.msg, this._cursor.getSpan(e.cursor)); | ||
| } | ||
| if (e instanceof ParseError) { | ||
| this.errors.push(e); | ||
| } | ||
| else { | ||
| throw e; | ||
| } | ||
| } | ||
| _attemptCharCode(charCode) { | ||
| if (this._cursor.peek() === charCode) { | ||
| this._cursor.advance(); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| _attemptCharCodeCaseInsensitive(charCode) { | ||
| if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) { | ||
| this._cursor.advance(); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| _requireCharCode(charCode) { | ||
| const location = this._cursor.clone(); | ||
| if (!this._attemptCharCode(charCode)) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location)); | ||
| } | ||
| } | ||
| _attemptStr(chars) { | ||
| const len = chars.length; | ||
| if (this._cursor.charsLeft() < len) { | ||
| return false; | ||
| } | ||
| const initialPosition = this._cursor.clone(); | ||
| for (let i = 0; i < len; i++) { | ||
| if (!this._attemptCharCode(chars.charCodeAt(i))) { | ||
| // If attempting to parse the string fails, we want to reset the parser | ||
| // to where it was before the attempt | ||
| this._cursor = initialPosition; | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| _attemptStrCaseInsensitive(chars) { | ||
| for (let i = 0; i < chars.length; i++) { | ||
| if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| _requireStr(chars) { | ||
| const location = this._cursor.clone(); | ||
| if (!this._attemptStr(chars)) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location)); | ||
| } | ||
| } | ||
| _requireStrCaseInsensitive(chars) { | ||
| const location = this._cursor.clone(); | ||
| if (!this._attemptStrCaseInsensitive(chars)) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location)); | ||
| } | ||
| } | ||
| _attemptCharCodeUntilFn(predicate) { | ||
| while (!predicate(this._cursor.peek())) { | ||
| this._cursor.advance(); | ||
| } | ||
| } | ||
| _requireCharCodeUntilFn(predicate, len) { | ||
| const start = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn(predicate); | ||
| if (this._cursor.diff(start) < len) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start)); | ||
| } | ||
| } | ||
| _attemptUntilChar(char) { | ||
| while (this._cursor.peek() !== char) { | ||
| this._cursor.advance(); | ||
| } | ||
| } | ||
| _readChar() { | ||
| // Don't rely upon reading directly from `_input` as the actual char value | ||
| // may have been generated from an escape sequence. | ||
| const char = String.fromCodePoint(this._cursor.peek()); | ||
| this._cursor.advance(); | ||
| return char; | ||
| } | ||
| _peekStr(chars) { | ||
| const len = chars.length; | ||
| if (this._cursor.charsLeft() < len) { | ||
| return false; | ||
| } | ||
| const cursor = this._cursor.clone(); | ||
| for (let i = 0; i < len; i++) { | ||
| if (cursor.peek() !== chars.charCodeAt(i)) { | ||
| return false; | ||
| } | ||
| cursor.advance(); | ||
| } | ||
| return true; | ||
| } | ||
| _isBlockStart() { | ||
| return (this._cursor.peek() === chars.$AT && | ||
| SUPPORTED_BLOCKS.some((blockName) => this._peekStr(blockName))); | ||
| } | ||
| _isLetStart() { | ||
| return this._cursor.peek() === chars.$AT && this._peekStr('@let'); | ||
| } | ||
| _consumeEntity(textTokenType) { | ||
| this._beginToken(9 /* TokenType.ENCODED_ENTITY */); | ||
| const start = this._cursor.clone(); | ||
| this._cursor.advance(); | ||
| if (this._attemptCharCode(chars.$HASH)) { | ||
| const isHex = this._attemptCharCode(chars.$x) || this._attemptCharCode(chars.$X); | ||
| const codeStart = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn(isDigitEntityEnd); | ||
| if (this._cursor.peek() != chars.$SEMICOLON) { | ||
| // Advance cursor to include the peeked character in the string provided to the error | ||
| // message. | ||
| this._cursor.advance(); | ||
| const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC; | ||
| throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan()); | ||
| } | ||
| const strNum = this._cursor.getChars(codeStart); | ||
| this._cursor.advance(); | ||
| try { | ||
| const charCode = parseInt(strNum, isHex ? 16 : 10); | ||
| this._endToken([String.fromCharCode(charCode), this._cursor.getChars(start)]); | ||
| } | ||
| catch { | ||
| throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan()); | ||
| } | ||
| } | ||
| else { | ||
| const nameStart = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn(isNamedEntityEnd); | ||
| if (this._cursor.peek() != chars.$SEMICOLON) { | ||
| // No semicolon was found so abort the encoded entity token that was in progress, and treat | ||
| // this as a text token | ||
| this._beginToken(textTokenType, start); | ||
| this._cursor = nameStart; | ||
| this._endToken(['&']); | ||
| } | ||
| else { | ||
| const name = this._cursor.getChars(nameStart); | ||
| this._cursor.advance(); | ||
| const char = NAMED_ENTITIES.hasOwnProperty(name) && NAMED_ENTITIES[name]; | ||
| if (!char) { | ||
| throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start)); | ||
| } | ||
| this._endToken([char, `&${name};`]); | ||
| } | ||
| } | ||
| } | ||
| _consumeRawText(consumeEntities, endMarkerPredicate) { | ||
| this._beginToken(consumeEntities ? 6 /* TokenType.ESCAPABLE_RAW_TEXT */ : 7 /* TokenType.RAW_TEXT */); | ||
| const parts = []; | ||
| while (true) { | ||
| const tagCloseStart = this._cursor.clone(); | ||
| const foundEndMarker = endMarkerPredicate(); | ||
| this._cursor = tagCloseStart; | ||
| if (foundEndMarker) { | ||
| break; | ||
| } | ||
| if (consumeEntities && this._cursor.peek() === chars.$AMPERSAND) { | ||
| this._endToken([this._processCarriageReturns(parts.join(''))]); | ||
| parts.length = 0; | ||
| this._consumeEntity(6 /* TokenType.ESCAPABLE_RAW_TEXT */); | ||
| this._beginToken(6 /* TokenType.ESCAPABLE_RAW_TEXT */); | ||
| } | ||
| else { | ||
| parts.push(this._readChar()); | ||
| } | ||
| } | ||
| this._endToken([this._processCarriageReturns(parts.join(''))]); | ||
| } | ||
| _consumeComment(start) { | ||
| this._beginToken(10 /* TokenType.COMMENT_START */, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._attemptStr('-->')); | ||
| this._beginToken(11 /* TokenType.COMMENT_END */); | ||
| this._requireStr('-->'); | ||
| this._endToken([]); | ||
| } | ||
| // https://www.w3.org/TR/html5/syntax.html#bogus-comment-state | ||
| _consumeBogusComment(start) { | ||
| this._beginToken(10 /* TokenType.COMMENT_START */, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._cursor.peek() === chars.$GT); | ||
| this._beginToken(11 /* TokenType.COMMENT_END */); | ||
| this._cursor.advance(); | ||
| this._endToken([]); | ||
| } | ||
| _consumeCdata(start) { | ||
| this._beginToken(12 /* TokenType.CDATA_START */, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._attemptStr(']]>')); | ||
| this._beginToken(13 /* TokenType.CDATA_END */); | ||
| this._requireStr(']]>'); | ||
| this._endToken([]); | ||
| } | ||
| _consumeDocType(start) { | ||
| this._beginToken(18 /* TokenType.DOC_TYPE_START */, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._cursor.peek() === chars.$GT); | ||
| this._beginToken(19 /* TokenType.DOC_TYPE_END */); | ||
| this._cursor.advance(); | ||
| this._endToken([]); | ||
| } | ||
| _consumePrefixAndName(endPredicate) { | ||
| const nameOrPrefixStart = this._cursor.clone(); | ||
| let prefix = ''; | ||
| while (this._cursor.peek() !== chars.$COLON && !isPrefixEnd(this._cursor.peek())) { | ||
| this._cursor.advance(); | ||
| } | ||
| let nameStart; | ||
| if (this._cursor.peek() === chars.$COLON) { | ||
| prefix = this._cursor.getChars(nameOrPrefixStart); | ||
| this._cursor.advance(); | ||
| nameStart = this._cursor.clone(); | ||
| } | ||
| else { | ||
| nameStart = nameOrPrefixStart; | ||
| } | ||
| this._requireCharCodeUntilFn(endPredicate, prefix === '' ? 0 : 1); | ||
| const name = this._cursor.getChars(nameStart); | ||
| return [prefix, name]; | ||
| } | ||
| _consumeTagOpen(start) { | ||
| let tagName; | ||
| let prefix; | ||
| let closingTagName; | ||
| let openToken; | ||
| const attrs = []; | ||
| try { | ||
| if (this._selectorlessEnabled && isSelectorlessNameStart(this._cursor.peek())) { | ||
| openToken = this._consumeComponentOpenStart(start); | ||
| [closingTagName, prefix, tagName] = openToken.parts; | ||
| if (prefix) { | ||
| closingTagName += `:${prefix}`; | ||
| } | ||
| if (tagName) { | ||
| closingTagName += `:${tagName}`; | ||
| } | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| else { | ||
| if (!chars.isAsciiLetter(this._cursor.peek())) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start)); | ||
| } | ||
| openToken = this._consumeTagOpenStart(start); | ||
| prefix = openToken.parts[0]; | ||
| tagName = closingTagName = openToken.parts[1]; | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| while (!isAttributeTerminator(this._cursor.peek())) { | ||
| if (this._selectorlessEnabled && this._cursor.peek() === chars.$AT) { | ||
| const start = this._cursor.clone(); | ||
| const nameStart = start.clone(); | ||
| nameStart.advance(); | ||
| if (isSelectorlessNameStart(nameStart.peek())) { | ||
| this._consumeDirective(start, nameStart); | ||
| } | ||
| } | ||
| else { | ||
| const attr = this._consumeAttribute(); | ||
| attrs.push(attr); | ||
| } | ||
| } | ||
| if (openToken.type === 34 /* TokenType.COMPONENT_OPEN_START */) { | ||
| this._consumeComponentOpenEnd(); | ||
| } | ||
| else { | ||
| this._consumeTagOpenEnd(); | ||
| } | ||
| } | ||
| catch (e) { | ||
| if (e instanceof ParseError) { | ||
| if (openToken) { | ||
| // We errored before we could close the opening tag, so it is incomplete. | ||
| openToken.type = | ||
| openToken.type === 34 /* TokenType.COMPONENT_OPEN_START */ | ||
| ? 38 /* TokenType.INCOMPLETE_COMPONENT_OPEN */ | ||
| : 4 /* TokenType.INCOMPLETE_TAG_OPEN */; | ||
| } | ||
| else { | ||
| // When the start tag is invalid, assume we want a "<" as text. | ||
| // Back to back text tokens are merged at the end. | ||
| this._beginToken(5 /* TokenType.TEXT */, start); | ||
| this._endToken(['<']); | ||
| } | ||
| return; | ||
| } | ||
| throw e; | ||
| } | ||
| if (this._canSelfClose && | ||
| this.tokens[this.tokens.length - 1].type === 2 /* TokenType.TAG_OPEN_END_VOID */) { | ||
| return; | ||
| } | ||
| const contentTokenType = this._getTagContentType(tagName, prefix, this._fullNameStack.length > 0, attrs); | ||
| this._handleFullNameStackForTagOpen(prefix, tagName); | ||
| if (contentTokenType === TagContentType.RAW_TEXT) { | ||
| this._consumeRawTextWithTagClose(prefix, openToken, closingTagName, false); | ||
| } | ||
| else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) { | ||
| this._consumeRawTextWithTagClose(prefix, openToken, closingTagName, true); | ||
| } | ||
| } | ||
| _consumeRawTextWithTagClose(prefix, openToken, tagName, consumeEntities) { | ||
| this._consumeRawText(consumeEntities, () => { | ||
| if (!this._attemptCharCode(chars.$LT)) | ||
| return false; | ||
| if (!this._attemptCharCode(chars.$SLASH)) | ||
| return false; | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| if (!this._attemptStrCaseInsensitive(prefix && openToken.type !== 34 /* TokenType.COMPONENT_OPEN_START */ ? | ||
| `${prefix}:${tagName}` | ||
| : tagName)) | ||
| return false; | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| return this._attemptCharCode(chars.$GT); | ||
| }); | ||
| this._beginToken(openToken.type === 34 /* TokenType.COMPONENT_OPEN_START */ | ||
| ? 37 /* TokenType.COMPONENT_CLOSE */ | ||
| : 3 /* TokenType.TAG_CLOSE */); | ||
| this._requireCharCodeUntilFn((code) => code === chars.$GT, 3); | ||
| this._cursor.advance(); // Consume the `>` | ||
| this._endToken(openToken.parts); | ||
| this._handleFullNameStackForTagClose(prefix, tagName); | ||
| } | ||
| _consumeTagOpenStart(start) { | ||
| this._beginToken(0 /* TokenType.TAG_OPEN_START */, start); | ||
| const parts = this._consumePrefixAndName(isNameEnd); | ||
| return this._endToken(parts); | ||
| } | ||
| _consumeComponentOpenStart(start) { | ||
| this._beginToken(34 /* TokenType.COMPONENT_OPEN_START */, start); | ||
| const parts = this._consumeComponentName(); | ||
| return this._endToken(parts); | ||
| } | ||
| _consumeComponentName() { | ||
| const nameStart = this._cursor.clone(); | ||
| while (isSelectorlessNameChar(this._cursor.peek())) { | ||
| this._cursor.advance(); | ||
| } | ||
| const name = this._cursor.getChars(nameStart); | ||
| let prefix = ''; | ||
| let tagName = ''; | ||
| if (this._cursor.peek() === chars.$COLON) { | ||
| this._cursor.advance(); | ||
| [prefix, tagName] = this._consumePrefixAndName(isNameEnd); | ||
| } | ||
| return [name, prefix, tagName]; | ||
| } | ||
| _consumeAttribute() { | ||
| const [prefix, name] = this._consumeAttributeName(); | ||
| let value; | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| if (this._attemptCharCode(chars.$EQ)) { | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| value = this._consumeAttributeValue(); | ||
| } | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| return { prefix, name, value }; | ||
| } | ||
| _consumeAttributeName() { | ||
| const attrNameStart = this._cursor.peek(); | ||
| if (attrNameStart === chars.$SQ || attrNameStart === chars.$DQ) { | ||
| throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan()); | ||
| } | ||
| this._beginToken(14 /* TokenType.ATTR_NAME */); | ||
| let nameEndPredicate; | ||
| if (this._openDirectiveCount > 0) { | ||
| // If we're parsing attributes inside of directive syntax, we have to terminate the name | ||
| // on the first non-matching closing paren. For example, if we have `@Dir(someAttr)`, | ||
| // `@Dir` and `(` will have already been captured as `DIRECTIVE_NAME` and `DIRECTIVE_OPEN` | ||
| // respectively, but the `)` will get captured as a part of the name for `someAttr` | ||
| // because normally that would be an event binding. | ||
| let openParens = 0; | ||
| nameEndPredicate = (code) => { | ||
| if (this._openDirectiveCount > 0) { | ||
| if (code === chars.$LPAREN) { | ||
| openParens++; | ||
| } | ||
| else if (code === chars.$RPAREN) { | ||
| if (openParens === 0) { | ||
| return true; | ||
| } | ||
| openParens--; | ||
| } | ||
| } | ||
| return isNameEnd(code); | ||
| }; | ||
| } | ||
| else if (attrNameStart === chars.$LBRACKET) { | ||
| let openBrackets = 0; | ||
| // Be more permissive for which characters are allowed inside square-bracketed attributes, | ||
| // because they usually end up being bound as attribute values. Some third-party packages | ||
| // like Tailwind take advantage of this. | ||
| nameEndPredicate = (code) => { | ||
| if (code === chars.$LBRACKET) { | ||
| openBrackets++; | ||
| } | ||
| else if (code === chars.$RBRACKET) { | ||
| openBrackets--; | ||
| } | ||
| // Only check for name-ending characters if the brackets are balanced or mismatched. | ||
| // Also interrupt the matching on new lines. | ||
| return openBrackets <= 0 ? isNameEnd(code) : chars.isNewLine(code); | ||
| }; | ||
| } | ||
| else { | ||
| nameEndPredicate = isNameEnd; | ||
| } | ||
| const prefixAndName = this._consumePrefixAndName(nameEndPredicate); | ||
| this._endToken(prefixAndName); | ||
| return prefixAndName; | ||
| } | ||
| _consumeAttributeValue() { | ||
| let value; | ||
| if (this._cursor.peek() === chars.$SQ || this._cursor.peek() === chars.$DQ) { | ||
| const quoteChar = this._cursor.peek(); | ||
| this._consumeQuote(quoteChar); | ||
| // In an attribute then end of the attribute value and the premature end to an interpolation | ||
| // are both triggered by the `quoteChar`. | ||
| const endPredicate = () => this._cursor.peek() === quoteChar; | ||
| value = this._consumeWithInterpolation(16 /* TokenType.ATTR_VALUE_TEXT */, 17 /* TokenType.ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate); | ||
| this._consumeQuote(quoteChar); | ||
| } | ||
| else { | ||
| const endPredicate = () => isNameEnd(this._cursor.peek()); | ||
| value = this._consumeWithInterpolation(16 /* TokenType.ATTR_VALUE_TEXT */, 17 /* TokenType.ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate); | ||
| } | ||
| return value; | ||
| } | ||
| _consumeQuote(quoteChar) { | ||
| this._beginToken(15 /* TokenType.ATTR_QUOTE */); | ||
| this._requireCharCode(quoteChar); | ||
| this._endToken([String.fromCodePoint(quoteChar)]); | ||
| } | ||
| _consumeTagOpenEnd() { | ||
| const tokenType = this._attemptCharCode(chars.$SLASH) | ||
| ? 2 /* TokenType.TAG_OPEN_END_VOID */ | ||
| : 1 /* TokenType.TAG_OPEN_END */; | ||
| this._beginToken(tokenType); | ||
| this._requireCharCode(chars.$GT); | ||
| this._endToken([]); | ||
| } | ||
| _consumeComponentOpenEnd() { | ||
| const tokenType = this._attemptCharCode(chars.$SLASH) | ||
| ? 36 /* TokenType.COMPONENT_OPEN_END_VOID */ | ||
| : 35 /* TokenType.COMPONENT_OPEN_END */; | ||
| this._beginToken(tokenType); | ||
| this._requireCharCode(chars.$GT); | ||
| this._endToken([]); | ||
| } | ||
| _consumeTagClose(start) { | ||
| if (this._selectorlessEnabled) { | ||
| const clone = start.clone(); | ||
| while (clone.peek() !== chars.$GT && !isSelectorlessNameStart(clone.peek())) { | ||
| clone.advance(); | ||
| } | ||
| if (isSelectorlessNameStart(clone.peek())) { | ||
| this._beginToken(37 /* TokenType.COMPONENT_CLOSE */, start); | ||
| const parts = this._consumeComponentName(); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._requireCharCode(chars.$GT); | ||
| this._endToken(parts); | ||
| return; | ||
| } | ||
| } | ||
| this._beginToken(3 /* TokenType.TAG_CLOSE */, start); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| // https://github.com/developit/htm | ||
| if (this._allowHtmComponentClosingTags && this._attemptCharCode(chars.$SLASH)) { | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._requireCharCode(chars.$GT); | ||
| this._endToken([]); | ||
| } | ||
| else { | ||
| const [prefix, name] = this._consumePrefixAndName(isNameEnd); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._requireCharCode(chars.$GT); | ||
| this._endToken([prefix, name]); | ||
| this._handleFullNameStackForTagClose(prefix, name); | ||
| } | ||
| } | ||
| _consumeExpansionFormStart() { | ||
| this._beginToken(20 /* TokenType.EXPANSION_FORM_START */); | ||
| this._requireCharCode(chars.$LBRACE); | ||
| this._endToken([]); | ||
| this._expansionCaseStack.push(20 /* TokenType.EXPANSION_FORM_START */); | ||
| this._beginToken(7 /* TokenType.RAW_TEXT */); | ||
| const condition = this._readUntil(chars.$COMMA); | ||
| const normalizedCondition = this._processCarriageReturns(condition); | ||
| if (this._i18nNormalizeLineEndingsInICUs) { | ||
| // We explicitly want to normalize line endings for this text. | ||
| this._endToken([normalizedCondition]); | ||
| } | ||
| else { | ||
| // We are not normalizing line endings. | ||
| const conditionToken = this._endToken([condition]); | ||
| if (normalizedCondition !== condition) { | ||
| this.nonNormalizedIcuExpressions.push(conditionToken); | ||
| } | ||
| } | ||
| this._requireCharCode(chars.$COMMA); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._beginToken(7 /* TokenType.RAW_TEXT */); | ||
| const type = this._readUntil(chars.$COMMA); | ||
| this._endToken([type]); | ||
| this._requireCharCode(chars.$COMMA); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| _consumeExpansionCaseStart() { | ||
| this._beginToken(21 /* TokenType.EXPANSION_CASE_VALUE */); | ||
| const value = this._readUntil(chars.$LBRACE).trim(); | ||
| this._endToken([value]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._beginToken(22 /* TokenType.EXPANSION_CASE_EXP_START */); | ||
| this._requireCharCode(chars.$LBRACE); | ||
| this._endToken([]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._expansionCaseStack.push(22 /* TokenType.EXPANSION_CASE_EXP_START */); | ||
| } | ||
| _consumeExpansionCaseEnd() { | ||
| this._beginToken(23 /* TokenType.EXPANSION_CASE_EXP_END */); | ||
| this._requireCharCode(chars.$RBRACE); | ||
| this._endToken([]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._expansionCaseStack.pop(); | ||
| } | ||
| _consumeExpansionFormEnd() { | ||
| this._beginToken(24 /* TokenType.EXPANSION_FORM_END */); | ||
| this._requireCharCode(chars.$RBRACE); | ||
| this._endToken([]); | ||
| this._expansionCaseStack.pop(); | ||
| } | ||
| /** | ||
| * Consume a string that may contain interpolation expressions. | ||
| * | ||
| * The first token consumed will be of `tokenType` and then there will be alternating | ||
| * `interpolationTokenType` and `tokenType` tokens until the `endPredicate()` returns true. | ||
| * | ||
| * If an interpolation token ends prematurely it will have no end marker in its `parts` array. | ||
| * | ||
| * @param textTokenType the kind of tokens to interleave around interpolation tokens. | ||
| * @param interpolationTokenType the kind of tokens that contain interpolation. | ||
| * @param endPredicate a function that should return true when we should stop consuming. | ||
| * @param endInterpolation a function that should return true if there is a premature end to an | ||
| * interpolation expression - i.e. before we get to the normal interpolation closing marker. | ||
| */ | ||
| _consumeWithInterpolation(textTokenType, interpolationTokenType, endPredicate, endInterpolation) { | ||
| this._beginToken(textTokenType); | ||
| const parts = []; | ||
| while (!endPredicate()) { | ||
| const current = this._cursor.clone(); | ||
| if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) { | ||
| this._endToken([this._processCarriageReturns(parts.join(''))], current); | ||
| parts.length = 0; | ||
| this._consumeInterpolation(interpolationTokenType, current, endInterpolation); | ||
| this._beginToken(textTokenType); | ||
| } | ||
| else if (this._cursor.peek() === chars.$AMPERSAND) { | ||
| this._endToken([this._processCarriageReturns(parts.join(''))]); | ||
| parts.length = 0; | ||
| this._consumeEntity(textTokenType); | ||
| this._beginToken(textTokenType); | ||
| } | ||
| else { | ||
| parts.push(this._readChar()); | ||
| } | ||
| } | ||
| // It is possible that an interpolation was started but not ended inside this text token. | ||
| // Make sure that we reset the state of the lexer correctly. | ||
| this._inInterpolation = false; | ||
| const value = this._processCarriageReturns(parts.join('')); | ||
| this._endToken([value]); | ||
| return value; | ||
| } | ||
| /** | ||
| * Consume a block of text that has been interpreted as an Angular interpolation. | ||
| * | ||
| * @param interpolationTokenType the type of the interpolation token to generate. | ||
| * @param interpolationStart a cursor that points to the start of this interpolation. | ||
| * @param prematureEndPredicate a function that should return true if the next characters indicate | ||
| * an end to the interpolation before its normal closing marker. | ||
| */ | ||
| _consumeInterpolation(interpolationTokenType, interpolationStart, prematureEndPredicate) { | ||
| const parts = []; | ||
| this._beginToken(interpolationTokenType, interpolationStart); | ||
| parts.push(this._interpolationConfig.start); | ||
| // Find the end of the interpolation, ignoring content inside quotes. | ||
| const expressionStart = this._cursor.clone(); | ||
| let inQuote = null; | ||
| let inComment = false; | ||
| while (this._cursor.peek() !== chars.$EOF && | ||
| (prematureEndPredicate === null || !prematureEndPredicate())) { | ||
| const current = this._cursor.clone(); | ||
| if (this._isTagStart()) { | ||
| // We are starting what looks like an HTML element in the middle of this interpolation. | ||
| // Reset the cursor to before the `<` character and end the interpolation token. | ||
| // (This is actually wrong but here for backward compatibility). | ||
| this._cursor = current; | ||
| parts.push(this._getProcessedChars(expressionStart, current)); | ||
| this._endToken(parts); | ||
| return; | ||
| } | ||
| if (inQuote === null) { | ||
| if (this._attemptStr(this._interpolationConfig.end)) { | ||
| // We are not in a string, and we hit the end interpolation marker | ||
| parts.push(this._getProcessedChars(expressionStart, current)); | ||
| parts.push(this._interpolationConfig.end); | ||
| this._endToken(parts); | ||
| return; | ||
| } | ||
| else if (this._attemptStr('//')) { | ||
| // Once we are in a comment we ignore any quotes | ||
| inComment = true; | ||
| } | ||
| } | ||
| const char = this._cursor.peek(); | ||
| this._cursor.advance(); | ||
| if (char === chars.$BACKSLASH) { | ||
| // Skip the next character because it was escaped. | ||
| this._cursor.advance(); | ||
| } | ||
| else if (char === inQuote) { | ||
| // Exiting the current quoted string | ||
| inQuote = null; | ||
| } | ||
| else if (!inComment && inQuote === null && chars.isQuote(char)) { | ||
| // Entering a new quoted string | ||
| inQuote = char; | ||
| } | ||
| } | ||
| // We hit EOF without finding a closing interpolation marker | ||
| parts.push(this._getProcessedChars(expressionStart, this._cursor)); | ||
| this._endToken(parts); | ||
| } | ||
| _consumeDirective(start, nameStart) { | ||
| this._requireCharCode(chars.$AT); | ||
| // Skip over the @ since it's not part of the name. | ||
| this._cursor.advance(); | ||
| // Capture the rest of the name. | ||
| while (isSelectorlessNameChar(this._cursor.peek())) { | ||
| this._cursor.advance(); | ||
| } | ||
| // Capture the opening token. | ||
| this._beginToken(39 /* TokenType.DIRECTIVE_NAME */, start); | ||
| const name = this._cursor.getChars(nameStart); | ||
| this._endToken([name]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| // Optionally there might be attributes bound to the specific directive. | ||
| // Stop parsing if there's no opening character for them. | ||
| if (this._cursor.peek() !== chars.$LPAREN) { | ||
| return; | ||
| } | ||
| this._openDirectiveCount++; | ||
| this._beginToken(40 /* TokenType.DIRECTIVE_OPEN */); | ||
| this._cursor.advance(); | ||
| this._endToken([]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| // Capture all the attributes until we hit a closing paren. | ||
| while (!isAttributeTerminator(this._cursor.peek()) && this._cursor.peek() !== chars.$RPAREN) { | ||
| this._consumeAttribute(); | ||
| } | ||
| // Trim any trailing whitespace. | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._openDirectiveCount--; | ||
| if (this._cursor.peek() !== chars.$RPAREN) { | ||
| // Stop parsing, instead of throwing, if we've hit the end of the tag. | ||
| // This can be handled better later when turning the tokens into AST. | ||
| if (this._cursor.peek() === chars.$GT || this._cursor.peek() === chars.$SLASH) { | ||
| return; | ||
| } | ||
| throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start)); | ||
| } | ||
| // Capture the closing token. | ||
| this._beginToken(41 /* TokenType.DIRECTIVE_CLOSE */); | ||
| this._cursor.advance(); | ||
| this._endToken([]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| _getProcessedChars(start, end) { | ||
| return this._processCarriageReturns(end.getChars(start)); | ||
| } | ||
| _isTextEnd() { | ||
| if (this._isTagStart() || this._cursor.peek() === chars.$EOF) { | ||
| return true; | ||
| } | ||
| if (this._tokenizeIcu && !this._inInterpolation) { | ||
| if (this.isExpansionFormStart()) { | ||
| // start of an expansion form | ||
| return true; | ||
| } | ||
| if (this._cursor.peek() === chars.$RBRACE && this._isInExpansionCase()) { | ||
| // end of and expansion case | ||
| return true; | ||
| } | ||
| } | ||
| if (this._tokenizeBlocks && | ||
| !this._inInterpolation && | ||
| !this._isInExpansion() && | ||
| (this._isBlockStart() || this._isLetStart() || this._cursor.peek() === chars.$RBRACE)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Returns true if the current cursor is pointing to the start of a tag | ||
| * (opening/closing/comments/cdata/etc). | ||
| */ | ||
| _isTagStart() { | ||
| if (this._cursor.peek() === chars.$LT) { | ||
| // We assume that `<` followed by whitespace is not the start of an HTML element. | ||
| const tmp = this._cursor.clone(); | ||
| tmp.advance(); | ||
| // If the next character is alphabetic, ! nor / then it is a tag start | ||
| const code = tmp.peek(); | ||
| if ((chars.$a <= code && code <= chars.$z) || | ||
| (chars.$A <= code && code <= chars.$Z) || | ||
| code === chars.$SLASH || | ||
| code === chars.$BANG) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| _readUntil(char) { | ||
| const start = this._cursor.clone(); | ||
| this._attemptUntilChar(char); | ||
| return this._cursor.getChars(start); | ||
| } | ||
| _isInExpansion() { | ||
| return this._isInExpansionCase() || this._isInExpansionForm(); | ||
| } | ||
| _isInExpansionCase() { | ||
| return (this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === | ||
| 22) /* TokenType.EXPANSION_CASE_EXP_START */; | ||
| } | ||
| _isInExpansionForm() { | ||
| return (this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === | ||
| 20) /* TokenType.EXPANSION_FORM_START */; | ||
| } | ||
| isExpansionFormStart() { | ||
| if (this._cursor.peek() !== chars.$LBRACE) { | ||
| return false; | ||
| } | ||
| if (this._interpolationConfig) { | ||
| const start = this._cursor.clone(); | ||
| const isInterpolation = this._attemptStr(this._interpolationConfig.start); | ||
| this._cursor = start; | ||
| return !isInterpolation; | ||
| } | ||
| return true; | ||
| } | ||
| _handleFullNameStackForTagOpen(prefix, tagName) { | ||
| const fullName = mergeNsAndName(prefix, tagName); | ||
| if (this._fullNameStack.length === 0 || | ||
| this._fullNameStack[this._fullNameStack.length - 1] === fullName) { | ||
| this._fullNameStack.push(fullName); | ||
| } | ||
| } | ||
| _handleFullNameStackForTagClose(prefix, tagName) { | ||
| const fullName = mergeNsAndName(prefix, tagName); | ||
| if (this._fullNameStack.length !== 0 && | ||
| this._fullNameStack[this._fullNameStack.length - 1] === fullName) { | ||
| this._fullNameStack.pop(); | ||
| } | ||
| } | ||
| } | ||
| function isNotWhitespace(code) { | ||
| return !chars.isWhitespace(code) || code === chars.$EOF; | ||
| } | ||
| function isNameEnd(code) { | ||
| return (chars.isWhitespace(code) || | ||
| code === chars.$GT || | ||
| code === chars.$LT || | ||
| code === chars.$SLASH || | ||
| code === chars.$SQ || | ||
| code === chars.$DQ || | ||
| code === chars.$EQ || | ||
| code === chars.$EOF); | ||
| } | ||
| function isPrefixEnd(code) { | ||
| return ((code < chars.$a || chars.$z < code) && | ||
| (code < chars.$A || chars.$Z < code) && | ||
| (code < chars.$0 || code > chars.$9)); | ||
| } | ||
| function isDigitEntityEnd(code) { | ||
| return code === chars.$SEMICOLON || code === chars.$EOF || !chars.isAsciiHexDigit(code); | ||
| } | ||
| function isNamedEntityEnd(code) { | ||
| return code === chars.$SEMICOLON || code === chars.$EOF || !chars.isAsciiLetter(code); | ||
| } | ||
| function isExpansionCaseStart(peek) { | ||
| return peek !== chars.$RBRACE; | ||
| } | ||
| function compareCharCodeCaseInsensitive(code1, code2) { | ||
| return toUpperCaseCharCode(code1) === toUpperCaseCharCode(code2); | ||
| } | ||
| function toUpperCaseCharCode(code) { | ||
| return code >= chars.$a && code <= chars.$z ? code - chars.$a + chars.$A : code; | ||
| } | ||
| function isBlockNameChar(code) { | ||
| return chars.isAsciiLetter(code) || chars.isDigit(code) || code === chars.$_; | ||
| } | ||
| function isBlockParameterChar(code) { | ||
| return code !== chars.$SEMICOLON && isNotWhitespace(code); | ||
| } | ||
| function isSelectorlessNameStart(code) { | ||
| return code === chars.$_ || (code >= chars.$A && code <= chars.$Z); | ||
| } | ||
| function isSelectorlessNameChar(code) { | ||
| return chars.isAsciiLetter(code) || chars.isDigit(code) || code === chars.$_; | ||
| } | ||
| function isAttributeTerminator(code) { | ||
| return code === chars.$SLASH || code === chars.$GT || code === chars.$LT || code === chars.$EOF; | ||
| } | ||
| function mergeTextTokens(srcTokens) { | ||
| const dstTokens = []; | ||
| let lastDstToken = undefined; | ||
| for (let i = 0; i < srcTokens.length; i++) { | ||
| const token = srcTokens[i]; | ||
| if (((lastDstToken && lastDstToken.type === 5 /* TokenType.TEXT */ && token.type === 5) /* TokenType.TEXT */) || | ||
| ((lastDstToken && | ||
| lastDstToken.type === 16 /* TokenType.ATTR_VALUE_TEXT */ && token.type === 16) /* TokenType.ATTR_VALUE_TEXT */)) { | ||
| lastDstToken.parts[0] += token.parts[0]; | ||
| lastDstToken.sourceSpan.end = token.sourceSpan.end; | ||
| } | ||
| else { | ||
| lastDstToken = token; | ||
| dstTokens.push(lastDstToken); | ||
| } | ||
| } | ||
| return dstTokens; | ||
| } | ||
| class PlainCharacterCursor { | ||
| constructor(fileOrCursor, range) { | ||
| if (fileOrCursor instanceof PlainCharacterCursor) { | ||
| this.file = fileOrCursor.file; | ||
| this.input = fileOrCursor.input; | ||
| this.end = fileOrCursor.end; | ||
| const state = fileOrCursor.state; | ||
| // Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty. | ||
| // In ES5 bundles the object spread operator is translated into the `__assign` helper, which | ||
| // is not optimized by VMs as efficiently as a raw object literal. Since this constructor is | ||
| // called in tight loops, this difference matters. | ||
| this.state = { | ||
| peek: state.peek, | ||
| offset: state.offset, | ||
| line: state.line, | ||
| column: state.column, | ||
| }; | ||
| } | ||
| else { | ||
| if (!range) { | ||
| throw new Error('Programming error: the range argument must be provided with a file argument.'); | ||
| } | ||
| this.file = fileOrCursor; | ||
| this.input = fileOrCursor.content; | ||
| this.end = range.endPos; | ||
| this.state = { | ||
| peek: -1, | ||
| offset: range.startPos, | ||
| line: range.startLine, | ||
| column: range.startCol, | ||
| }; | ||
| } | ||
| } | ||
| clone() { | ||
| return new PlainCharacterCursor(this); | ||
| } | ||
| peek() { | ||
| return this.state.peek; | ||
| } | ||
| charsLeft() { | ||
| return this.end - this.state.offset; | ||
| } | ||
| diff(other) { | ||
| return this.state.offset - other.state.offset; | ||
| } | ||
| advance() { | ||
| this.advanceState(this.state); | ||
| } | ||
| init() { | ||
| this.updatePeek(this.state); | ||
| } | ||
| getSpan(start, leadingTriviaCodePoints) { | ||
| start = start || this; | ||
| let fullStart = start; | ||
| if (leadingTriviaCodePoints) { | ||
| while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) { | ||
| if (fullStart === start) { | ||
| start = start.clone(); | ||
| } | ||
| start.advance(); | ||
| } | ||
| } | ||
| const startLocation = this.locationFromCursor(start); | ||
| const endLocation = this.locationFromCursor(this); | ||
| const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation; | ||
| return new ParseSourceSpan(startLocation, endLocation, fullStartLocation); | ||
| } | ||
| getChars(start) { | ||
| return this.input.substring(start.state.offset, this.state.offset); | ||
| } | ||
| charAt(pos) { | ||
| return this.input.charCodeAt(pos); | ||
| } | ||
| advanceState(state) { | ||
| if (state.offset >= this.end) { | ||
| this.state = state; | ||
| throw new CursorError('Unexpected character "EOF"', this); | ||
| } | ||
| const currentChar = this.charAt(state.offset); | ||
| if (currentChar === chars.$LF) { | ||
| state.line++; | ||
| state.column = 0; | ||
| } | ||
| else if (!chars.isNewLine(currentChar)) { | ||
| state.column++; | ||
| } | ||
| state.offset++; | ||
| this.updatePeek(state); | ||
| } | ||
| updatePeek(state) { | ||
| state.peek = state.offset >= this.end ? chars.$EOF : this.charAt(state.offset); | ||
| } | ||
| locationFromCursor(cursor) { | ||
| return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column); | ||
| } | ||
| } | ||
| class EscapedCharacterCursor extends PlainCharacterCursor { | ||
| constructor(fileOrCursor, range) { | ||
| if (fileOrCursor instanceof EscapedCharacterCursor) { | ||
| super(fileOrCursor); | ||
| this.internalState = { ...fileOrCursor.internalState }; | ||
| } | ||
| else { | ||
| super(fileOrCursor, range); | ||
| this.internalState = this.state; | ||
| } | ||
| } | ||
| advance() { | ||
| this.state = this.internalState; | ||
| super.advance(); | ||
| this.processEscapeSequence(); | ||
| } | ||
| init() { | ||
| super.init(); | ||
| this.processEscapeSequence(); | ||
| } | ||
| clone() { | ||
| return new EscapedCharacterCursor(this); | ||
| } | ||
| getChars(start) { | ||
| const cursor = start.clone(); | ||
| let chars = ''; | ||
| while (cursor.internalState.offset < this.internalState.offset) { | ||
| chars += String.fromCodePoint(cursor.peek()); | ||
| cursor.advance(); | ||
| } | ||
| return chars; | ||
| } | ||
| /** | ||
| * Process the escape sequence that starts at the current position in the text. | ||
| * | ||
| * This method is called to ensure that `peek` has the unescaped value of escape sequences. | ||
| */ | ||
| processEscapeSequence() { | ||
| const peek = () => this.internalState.peek; | ||
| if (peek() === chars.$BACKSLASH) { | ||
| // We have hit an escape sequence so we need the internal state to become independent | ||
| // of the external state. | ||
| this.internalState = { ...this.state }; | ||
| // Move past the backslash | ||
| this.advanceState(this.internalState); | ||
| // First check for standard control char sequences | ||
| if (peek() === chars.$n) { | ||
| this.state.peek = chars.$LF; | ||
| } | ||
| else if (peek() === chars.$r) { | ||
| this.state.peek = chars.$CR; | ||
| } | ||
| else if (peek() === chars.$v) { | ||
| this.state.peek = chars.$VTAB; | ||
| } | ||
| else if (peek() === chars.$t) { | ||
| this.state.peek = chars.$TAB; | ||
| } | ||
| else if (peek() === chars.$b) { | ||
| this.state.peek = chars.$BSPACE; | ||
| } | ||
| else if (peek() === chars.$f) { | ||
| this.state.peek = chars.$FF; | ||
| } | ||
| // Now consider more complex sequences | ||
| else if (peek() === chars.$u) { | ||
| // Unicode code-point sequence | ||
| this.advanceState(this.internalState); // advance past the `u` char | ||
| if (peek() === chars.$LBRACE) { | ||
| // Variable length Unicode, e.g. `\x{123}` | ||
| this.advanceState(this.internalState); // advance past the `{` char | ||
| // Advance past the variable number of hex digits until we hit a `}` char | ||
| const digitStart = this.clone(); | ||
| let length = 0; | ||
| while (peek() !== chars.$RBRACE) { | ||
| this.advanceState(this.internalState); | ||
| length++; | ||
| } | ||
| this.state.peek = this.decodeHexDigits(digitStart, length); | ||
| } | ||
| else { | ||
| // Fixed length Unicode, e.g. `\u1234` | ||
| const digitStart = this.clone(); | ||
| this.advanceState(this.internalState); | ||
| this.advanceState(this.internalState); | ||
| this.advanceState(this.internalState); | ||
| this.state.peek = this.decodeHexDigits(digitStart, 4); | ||
| } | ||
| } | ||
| else if (peek() === chars.$x) { | ||
| // Hex char code, e.g. `\x2F` | ||
| this.advanceState(this.internalState); // advance past the `x` char | ||
| const digitStart = this.clone(); | ||
| this.advanceState(this.internalState); | ||
| this.state.peek = this.decodeHexDigits(digitStart, 2); | ||
| } | ||
| else if (chars.isOctalDigit(peek())) { | ||
| // Octal char code, e.g. `\012`, | ||
| let octal = ''; | ||
| let length = 0; | ||
| let previous = this.clone(); | ||
| while (chars.isOctalDigit(peek()) && length < 3) { | ||
| previous = this.clone(); | ||
| octal += String.fromCodePoint(peek()); | ||
| this.advanceState(this.internalState); | ||
| length++; | ||
| } | ||
| this.state.peek = parseInt(octal, 8); | ||
| // Backup one char | ||
| this.internalState = previous.internalState; | ||
| } | ||
| else if (chars.isNewLine(this.internalState.peek)) { | ||
| // Line continuation `\` followed by a new line | ||
| this.advanceState(this.internalState); // advance over the newline | ||
| this.state = this.internalState; | ||
| } | ||
| else { | ||
| // If none of the `if` blocks were executed then we just have an escaped normal character. | ||
| // In that case we just, effectively, skip the backslash from the character. | ||
| this.state.peek = this.internalState.peek; | ||
| } | ||
| } | ||
| } | ||
| decodeHexDigits(start, length) { | ||
| const hex = this.input.slice(start.internalState.offset, start.internalState.offset + length); | ||
| const charCode = parseInt(hex, 16); | ||
| if (!isNaN(charCode)) { | ||
| return charCode; | ||
| } | ||
| else { | ||
| start.state = start.internalState; | ||
| throw new CursorError('Invalid hexadecimal escape sequence', start); | ||
| } | ||
| } | ||
| } | ||
| export class CursorError extends Error { | ||
| constructor(msg, cursor) { | ||
| super(msg); | ||
| this.msg = msg; | ||
| this.cursor = cursor; | ||
| // Extending `Error` does not always work when code is transpiled. See: | ||
| // https://stackoverflow.com/questions/41102060/typescript-extending-error-class | ||
| Object.setPrototypeOf(this, new.target.prototype); | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { ParseError, ParseSourceSpan } from '../parse_util'; | ||
| import * as html from './ast'; | ||
| import { TokenizeOptions } from './lexer'; | ||
| import { TagContentType, TagDefinition } from './tags'; | ||
| export declare class TreeError extends ParseError { | ||
| elementName: string | null; | ||
| static create(elementName: string | null, span: ParseSourceSpan, msg: string): TreeError; | ||
| constructor(elementName: string | null, span: ParseSourceSpan, msg: string); | ||
| } | ||
| export declare class ParseTreeResult { | ||
| rootNodes: html.Node[]; | ||
| errors: ParseError[]; | ||
| constructor(rootNodes: html.Node[], errors: ParseError[]); | ||
| } | ||
| export declare class Parser { | ||
| getTagDefinition: (tagName: string) => TagDefinition; | ||
| constructor(getTagDefinition: (tagName: string) => TagDefinition); | ||
| parse(source: string, url: string, options?: TokenizeOptions, isTagNameCaseSensitive?: boolean, getTagContentType?: (tagName: string, prefix: string, hasParent: boolean, attrs: Array<{ | ||
| prefix: string; | ||
| name: string; | ||
| value?: string; | ||
| }>) => void | TagContentType): ParseTreeResult; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { ParseError, ParseSourceSpan } from "../parse_util.js"; | ||
| import * as html from "./ast.js"; | ||
| import { NAMED_ENTITIES } from "./entities.js"; | ||
| import { tokenize } from "./lexer.js"; | ||
| import { getNsPrefix, mergeNsAndName, splitNsName } from "./tags.js"; | ||
| export class TreeError extends ParseError { | ||
| static create(elementName, span, msg) { | ||
| return new TreeError(elementName, span, msg); | ||
| } | ||
| constructor(elementName, span, msg) { | ||
| super(span, msg); | ||
| this.elementName = elementName; | ||
| } | ||
| } | ||
| export class ParseTreeResult { | ||
| constructor(rootNodes, errors) { | ||
| this.rootNodes = rootNodes; | ||
| this.errors = errors; | ||
| } | ||
| } | ||
| export class Parser { | ||
| constructor(getTagDefinition) { | ||
| this.getTagDefinition = getTagDefinition; | ||
| } | ||
| parse(source, url, options, isTagNameCaseSensitive = false, getTagContentType) { | ||
| const lowercasify = (fn) => (x, ...args) => fn(x.toLowerCase(), ...args); | ||
| const getTagDefinition = isTagNameCaseSensitive ? this.getTagDefinition : lowercasify(this.getTagDefinition); | ||
| const getDefaultTagContentType = (tagName) => getTagDefinition(tagName).getContentType(); | ||
| const getTagContentTypeWithProcessedTagName = isTagNameCaseSensitive ? getTagContentType : lowercasify(getTagContentType); | ||
| const _getTagContentType = getTagContentType ? | ||
| (tagName, prefix, hasParent, attrs) => { | ||
| const contentType = getTagContentTypeWithProcessedTagName(tagName, prefix, hasParent, attrs); | ||
| return contentType !== undefined ? contentType : getDefaultTagContentType(tagName); | ||
| } : | ||
| getDefaultTagContentType; | ||
| const tokenizeResult = tokenize(source, url, _getTagContentType, options); | ||
| const canSelfClose = (options && options.canSelfClose) || false; | ||
| const allowHtmComponentClosingTags = (options && options.allowHtmComponentClosingTags) || false; | ||
| const parser = new _TreeBuilder(tokenizeResult.tokens, getTagDefinition, canSelfClose, allowHtmComponentClosingTags, isTagNameCaseSensitive); | ||
| parser.build(); | ||
| return new ParseTreeResult(parser.rootNodes, [...tokenizeResult.errors, ...parser.errors]); | ||
| } | ||
| } | ||
| class _TreeBuilder { | ||
| constructor(tokens, tagDefinitionResolver, canSelfClose, allowHtmComponentClosingTags, isTagNameCaseSensitive) { | ||
| this.tokens = tokens; | ||
| this.tagDefinitionResolver = tagDefinitionResolver; | ||
| this.canSelfClose = canSelfClose; | ||
| this.allowHtmComponentClosingTags = allowHtmComponentClosingTags; | ||
| this.isTagNameCaseSensitive = isTagNameCaseSensitive; | ||
| this._index = -1; | ||
| this._containerStack = []; | ||
| this.rootNodes = []; | ||
| this.errors = []; | ||
| this._advance(); | ||
| } | ||
| build() { | ||
| while (this._peek.type !== 42 /* TokenType.EOF */) { | ||
| if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ || | ||
| this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) { | ||
| this._consumeElementStartTag(this._advance()); | ||
| } | ||
| else if (this._peek.type === 3 /* TokenType.TAG_CLOSE */) { | ||
| this._closeVoidElement(); | ||
| this._consumeElementEndTag(this._advance()); | ||
| } | ||
| else if (this._peek.type === 12 /* TokenType.CDATA_START */) { | ||
| this._closeVoidElement(); | ||
| this._consumeCdata(this._advance()); | ||
| } | ||
| else if (this._peek.type === 10 /* TokenType.COMMENT_START */) { | ||
| this._closeVoidElement(); | ||
| this._consumeComment(this._advance()); | ||
| } | ||
| else if (this._peek.type === 5 /* TokenType.TEXT */ || | ||
| this._peek.type === 7 /* TokenType.RAW_TEXT */ || | ||
| this._peek.type === 6 /* TokenType.ESCAPABLE_RAW_TEXT */) { | ||
| this._closeVoidElement(); | ||
| this._consumeText(this._advance()); | ||
| } | ||
| else if (this._peek.type === 20 /* TokenType.EXPANSION_FORM_START */) { | ||
| this._consumeExpansion(this._advance()); | ||
| } | ||
| else if (this._peek.type === 25 /* TokenType.BLOCK_OPEN_START */) { | ||
| this._closeVoidElement(); | ||
| this._consumeBlockOpen(this._advance()); | ||
| } | ||
| else if (this._peek.type === 27 /* TokenType.BLOCK_CLOSE */) { | ||
| this._closeVoidElement(); | ||
| this._consumeBlockClose(this._advance()); | ||
| } | ||
| else if (this._peek.type === 29 /* TokenType.INCOMPLETE_BLOCK_OPEN */) { | ||
| this._closeVoidElement(); | ||
| this._consumeIncompleteBlock(this._advance()); | ||
| } | ||
| else if (this._peek.type === 30 /* TokenType.LET_START */) { | ||
| this._closeVoidElement(); | ||
| this._consumeLet(this._advance()); | ||
| } | ||
| else if (this._peek.type === 18 /* TokenType.DOC_TYPE_START */) { | ||
| this._consumeDocType(this._advance()); | ||
| } | ||
| else if (this._peek.type === 33 /* TokenType.INCOMPLETE_LET */) { | ||
| this._closeVoidElement(); | ||
| this._consumeIncompleteLet(this._advance()); | ||
| } | ||
| else if (this._peek.type === 34 /* TokenType.COMPONENT_OPEN_START */ || | ||
| this._peek.type === 38 /* TokenType.INCOMPLETE_COMPONENT_OPEN */) { | ||
| this._consumeComponentStartTag(this._advance()); | ||
| } | ||
| else if (this._peek.type === 37 /* TokenType.COMPONENT_CLOSE */) { | ||
| this._consumeComponentEndTag(this._advance()); | ||
| } | ||
| else { | ||
| // Skip all other tokens... | ||
| this._advance(); | ||
| } | ||
| } | ||
| for (const leftoverContainer of this._containerStack) { | ||
| // Unlike HTML elements, blocks aren't closed implicitly by the end of the file. | ||
| if (leftoverContainer instanceof html.Block) { | ||
| this.errors.push(TreeError.create(leftoverContainer.name, leftoverContainer.sourceSpan, `Unclosed block "${leftoverContainer.name}"`)); | ||
| } | ||
| } | ||
| } | ||
| _advance() { | ||
| const prev = this._peek; | ||
| if (this._index < this.tokens.length - 1) { | ||
| // Note: there is always an EOF token at the end | ||
| this._index++; | ||
| } | ||
| this._peek = this.tokens[this._index]; | ||
| return prev; | ||
| } | ||
| _advanceIf(type) { | ||
| if (this._peek.type === type) { | ||
| return this._advance(); | ||
| } | ||
| return null; | ||
| } | ||
| _consumeCdata(startToken) { | ||
| const text = this._advance(); | ||
| const value = this._getText(text); | ||
| const endToken = this._advanceIf(13 /* TokenType.CDATA_END */); | ||
| this._addToParent(new html.CDATA(value, new ParseSourceSpan(startToken.sourceSpan.start, (endToken || text).sourceSpan.end), [text])); | ||
| } | ||
| _consumeComment(token) { | ||
| const text = this._advanceIf(7 /* TokenType.RAW_TEXT */); | ||
| const endToken = this._advanceIf(11 /* TokenType.COMMENT_END */); | ||
| const value = text != null ? text.parts[0].trim() : null; | ||
| const sourceSpan = endToken == null | ||
| ? token.sourceSpan | ||
| : new ParseSourceSpan(token.sourceSpan.start, endToken.sourceSpan.end, token.sourceSpan.fullStart); | ||
| this._addToParent(new html.Comment(value, sourceSpan)); | ||
| } | ||
| _consumeDocType(startToken) { | ||
| const text = this._advanceIf(7 /* TokenType.RAW_TEXT */); | ||
| const endToken = this._advanceIf(19 /* TokenType.DOC_TYPE_END */); | ||
| const value = text != null ? text.parts[0].trim() : null; | ||
| const sourceSpan = new ParseSourceSpan(startToken.sourceSpan.start, (endToken || text || startToken).sourceSpan.end); | ||
| this._addToParent(new html.DocType(value, sourceSpan)); | ||
| } | ||
| _consumeExpansion(token) { | ||
| const switchValue = this._advance(); | ||
| const type = this._advance(); | ||
| const cases = []; | ||
| // read = | ||
| while (this._peek.type === 21 /* TokenType.EXPANSION_CASE_VALUE */) { | ||
| const expCase = this._parseExpansionCase(); | ||
| if (!expCase) | ||
| return; // error | ||
| cases.push(expCase); | ||
| } | ||
| // read the final } | ||
| if (this._peek.type !== 24 /* TokenType.EXPANSION_FORM_END */) { | ||
| this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
| return; | ||
| } | ||
| const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart); | ||
| this._addToParent(new html.Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan)); | ||
| this._advance(); | ||
| } | ||
| _parseExpansionCase() { | ||
| const value = this._advance(); | ||
| // read { | ||
| if (this._peek.type !== 22 /* TokenType.EXPANSION_CASE_EXP_START */) { | ||
| this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`)); | ||
| return null; | ||
| } | ||
| // read until } | ||
| const start = this._advance(); | ||
| const exp = this._collectExpansionExpTokens(start); | ||
| if (!exp) | ||
| return null; | ||
| const end = this._advance(); | ||
| exp.push({ type: 42 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan }); | ||
| // parse everything in between { and } | ||
| const expansionCaseParser = new _TreeBuilder(exp, this.tagDefinitionResolver, this.canSelfClose, this.allowHtmComponentClosingTags, this.isTagNameCaseSensitive); | ||
| expansionCaseParser.build(); | ||
| if (expansionCaseParser.errors.length > 0) { | ||
| this.errors = this.errors.concat(expansionCaseParser.errors); | ||
| return null; | ||
| } | ||
| const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart); | ||
| const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart); | ||
| return new html.ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan); | ||
| } | ||
| _collectExpansionExpTokens(start) { | ||
| const exp = []; | ||
| const expansionFormStack = [22 /* TokenType.EXPANSION_CASE_EXP_START */]; | ||
| while (true) { | ||
| if (this._peek.type === 20 /* TokenType.EXPANSION_FORM_START */ || | ||
| this._peek.type === 22 /* TokenType.EXPANSION_CASE_EXP_START */) { | ||
| expansionFormStack.push(this._peek.type); | ||
| } | ||
| if (this._peek.type === 23 /* TokenType.EXPANSION_CASE_EXP_END */) { | ||
| if (lastOnStack(expansionFormStack, 22 /* TokenType.EXPANSION_CASE_EXP_START */)) { | ||
| expansionFormStack.pop(); | ||
| if (expansionFormStack.length === 0) | ||
| return exp; | ||
| } | ||
| else { | ||
| this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
| return null; | ||
| } | ||
| } | ||
| if (this._peek.type === 24 /* TokenType.EXPANSION_FORM_END */) { | ||
| if (lastOnStack(expansionFormStack, 20 /* TokenType.EXPANSION_FORM_START */)) { | ||
| expansionFormStack.pop(); | ||
| } | ||
| else { | ||
| this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
| return null; | ||
| } | ||
| } | ||
| if (this._peek.type === 42 /* TokenType.EOF */) { | ||
| this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
| return null; | ||
| } | ||
| exp.push(this._advance()); | ||
| } | ||
| } | ||
| _getText(token) { | ||
| let text = token.parts[0]; | ||
| if (text.length > 0 && text[0] == '\n') { | ||
| const parent = this._getClosestElementLikeParent(); | ||
| if (parent != null && parent.children.length == 0 && | ||
| this._getTagDefinition(parent)?.ignoreFirstLf) { | ||
| text = text.substring(1); | ||
| } | ||
| } | ||
| return text; | ||
| } | ||
| _consumeText(token) { | ||
| const tokens = [token]; | ||
| const startSpan = token.sourceSpan; | ||
| let text = token.parts[0]; | ||
| if (text.length > 0 && text[0] === '\n') { | ||
| const parent = this._getContainer(); | ||
| if (parent != null && | ||
| parent.children.length === 0 && | ||
| this._getTagDefinition(parent)?.ignoreFirstLf) { | ||
| text = text.substring(1); | ||
| tokens[0] = { type: token.type, sourceSpan: token.sourceSpan, parts: [text] }; | ||
| } | ||
| } | ||
| while (this._peek.type === 8 /* TokenType.INTERPOLATION */ || | ||
| this._peek.type === 5 /* TokenType.TEXT */ || | ||
| this._peek.type === 9 /* TokenType.ENCODED_ENTITY */) { | ||
| token = this._advance(); | ||
| tokens.push(token); | ||
| if (token.type === 8 /* TokenType.INTERPOLATION */) { | ||
| // For backward compatibility we decode HTML entities that appear in interpolation | ||
| // expressions. This is arguably a bug, but it could be a considerable breaking change to | ||
| // fix it. It should be addressed in a larger project to refactor the entire parser/lexer | ||
| // chain after View Engine has been removed. | ||
| text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity); | ||
| } | ||
| else if (token.type === 9 /* TokenType.ENCODED_ENTITY */) { | ||
| text += token.parts[0]; | ||
| } | ||
| else { | ||
| text += token.parts.join(''); | ||
| } | ||
| } | ||
| if (text.length > 0) { | ||
| const endSpan = token.sourceSpan; | ||
| this._addToParent(new html.Text(text, new ParseSourceSpan(startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens)); | ||
| } | ||
| } | ||
| _closeVoidElement() { | ||
| const el = this._getContainer(); | ||
| if (el !== null && this._getTagDefinition(el)?.isVoid) { | ||
| this._containerStack.pop(); | ||
| } | ||
| } | ||
| _consumeElementStartTag(startTagToken) { | ||
| const attrs = []; | ||
| const directives = []; | ||
| this._consumeAttributesAndDirectives(attrs, directives); | ||
| const fullName = this._getElementFullName(startTagToken, this._getClosestElementLikeParent()); | ||
| const tagDef = this._getTagDefinition(fullName); | ||
| let selfClosing = false; | ||
| // Note: There could have been a tokenizer error | ||
| // so that we don't get a token for the end tag... | ||
| if (this._peek.type === 2 /* TokenType.TAG_OPEN_END_VOID */) { | ||
| this._advance(); | ||
| selfClosing = true; | ||
| const tagDef = this._getTagDefinition(fullName); | ||
| if (!(this.canSelfClose || tagDef?.canSelfClose || getNsPrefix(fullName) !== null || tagDef?.isVoid)) { | ||
| this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void, custom and foreign elements can be self closed "${startTagToken.parts[1]}"`)); | ||
| } | ||
| } | ||
| else if (this._peek.type === 1 /* TokenType.TAG_OPEN_END */) { | ||
| this._advance(); | ||
| selfClosing = false; | ||
| } | ||
| const end = this._peek.sourceSpan.fullStart; | ||
| const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart); | ||
| // Create a separate `startSpan` because `span` will be modified when there is an `end` span. | ||
| const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart); | ||
| const nameSpan = new ParseSourceSpan(startTagToken.sourceSpan.start.moveBy(1), startTagToken.sourceSpan.end); | ||
| const el = new html.Element(fullName, attrs, directives, [], selfClosing, span, startSpan, undefined, nameSpan, tagDef?.isVoid ?? false); | ||
| const parent = this._getContainer(); | ||
| const isClosedByChild = parent !== null && !!this._getTagDefinition(parent)?.isClosedByChild(el.name); | ||
| this._pushContainer(el, isClosedByChild); | ||
| if (selfClosing) { | ||
| // Elements that are self-closed have their `endSourceSpan` set to the full span, as the | ||
| // element start tag also represents the end tag. | ||
| this._popContainer(fullName, html.Element, span); | ||
| } | ||
| else if (startTagToken.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) { | ||
| // We already know the opening tag is not complete, so it is unlikely it has a corresponding | ||
| // close tag. Let's optimistically parse it as a full element and emit an error. | ||
| this._popContainer(fullName, html.Element, null); | ||
| this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`)); | ||
| } | ||
| } | ||
| _consumeComponentStartTag(startToken) { | ||
| const componentName = startToken.parts[0]; | ||
| const attrs = []; | ||
| const directives = []; | ||
| this._consumeAttributesAndDirectives(attrs, directives); | ||
| const closestElement = this._getClosestElementLikeParent(); | ||
| const tagName = this._getComponentTagName(startToken, closestElement); | ||
| const fullName = this._getComponentFullName(startToken, closestElement); | ||
| const selfClosing = this._peek.type === 36 /* TokenType.COMPONENT_OPEN_END_VOID */; | ||
| this._advance(); | ||
| const end = this._peek.sourceSpan.fullStart; | ||
| const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart); | ||
| const startSpan = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart); | ||
| const node = new html.Component(componentName, tagName, fullName, attrs, directives, [], selfClosing, span, startSpan, undefined); | ||
| const parent = this._getContainer(); | ||
| const isClosedByChild = parent !== null && | ||
| node.tagName !== null && | ||
| !!this._getTagDefinition(parent)?.isClosedByChild(node.tagName); | ||
| this._pushContainer(node, isClosedByChild); | ||
| if (selfClosing) { | ||
| this._popContainer(fullName, html.Component, span); | ||
| } | ||
| else if (startToken.type === 38 /* TokenType.INCOMPLETE_COMPONENT_OPEN */) { | ||
| this._popContainer(fullName, html.Component, null); | ||
| this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`)); | ||
| } | ||
| } | ||
| _consumeAttributesAndDirectives(attributesResult, directivesResult) { | ||
| while (this._peek.type === 14 /* TokenType.ATTR_NAME */ || | ||
| this._peek.type === 39 /* TokenType.DIRECTIVE_NAME */) { | ||
| if (this._peek.type === 39 /* TokenType.DIRECTIVE_NAME */) { | ||
| directivesResult.push(this._consumeDirective(this._peek)); | ||
| } | ||
| else { | ||
| attributesResult.push(this._consumeAttr(this._advance())); | ||
| } | ||
| } | ||
| } | ||
| _consumeComponentEndTag(endToken) { | ||
| const fullName = this._getComponentFullName(endToken, this._getClosestElementLikeParent()); | ||
| if (!this._popContainer(fullName, html.Component, endToken.sourceSpan)) { | ||
| const container = this._containerStack[this._containerStack.length - 1]; | ||
| let suffix; | ||
| if (container instanceof html.Component && container.componentName === endToken.parts[0]) { | ||
| suffix = `, did you mean "${container.fullName}"?`; | ||
| } | ||
| else { | ||
| suffix = '. It may happen when the tag has already been closed by another tag.'; | ||
| } | ||
| const errMsg = `Unexpected closing tag "${fullName}"${suffix}`; | ||
| this.errors.push(TreeError.create(fullName, endToken.sourceSpan, errMsg)); | ||
| } | ||
| } | ||
| _getTagDefinition(nodeOrName) { | ||
| if (typeof nodeOrName === 'string') { | ||
| return this.tagDefinitionResolver(nodeOrName); | ||
| } | ||
| else if (nodeOrName instanceof html.Element) { | ||
| return this.tagDefinitionResolver(nodeOrName.name); | ||
| } | ||
| else if (nodeOrName instanceof html.Component && nodeOrName.tagName !== null) { | ||
| return this.tagDefinitionResolver(nodeOrName.tagName); | ||
| } | ||
| else { | ||
| return null; | ||
| } | ||
| } | ||
| _pushContainer(node, isClosedByChild) { | ||
| if (isClosedByChild) { | ||
| this._containerStack.pop(); | ||
| } | ||
| this._addToParent(node); | ||
| this._containerStack.push(node); | ||
| } | ||
| _consumeElementEndTag(endTagToken) { | ||
| // @ts-expect-error -- in angular-html-parser endTagToken.parts.length can be 0 (HTM component end-tags) | ||
| const fullName = this.allowHtmComponentClosingTags && endTagToken.parts.length === 0 ? | ||
| null : | ||
| this._getElementFullName(endTagToken, this._getClosestElementLikeParent()); | ||
| ; | ||
| if (fullName && this._getTagDefinition(fullName)?.isVoid) { | ||
| this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`)); | ||
| } | ||
| else if (!this._popContainer(fullName, html.Element, endTagToken.sourceSpan)) { | ||
| const errMsg = `Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`; | ||
| this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg)); | ||
| } | ||
| } | ||
| /** | ||
| * Closes the nearest element with the tag name `fullName` in the parse tree. | ||
| * `endSourceSpan` is the span of the closing tag, or null if the element does | ||
| * not have a closing tag (for example, this happens when an incomplete | ||
| * opening tag is recovered). | ||
| */ | ||
| _popContainer(expectedName, expectedType, endSourceSpan) { | ||
| let unexpectedCloseTagDetected = false; | ||
| for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) { | ||
| const node = this._containerStack[stackIndex]; | ||
| const nodeName = node instanceof html.Component ? node.fullName : node.name; | ||
| if ( | ||
| /* isForeignElement */ getNsPrefix(nodeName) ? | ||
| nodeName === expectedName : | ||
| (nodeName === expectedName || expectedName === null) && node instanceof expectedType) { | ||
| // Record the parse span with the element that is being closed. Any elements that are | ||
| // removed from the element stack at this point are closed implicitly, so they won't get | ||
| // an end source span (as there is no explicit closing element). | ||
| node.endSourceSpan = endSourceSpan; | ||
| node.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : node.sourceSpan.end; | ||
| this._containerStack.splice(stackIndex, this._containerStack.length - stackIndex); | ||
| return !unexpectedCloseTagDetected; | ||
| } | ||
| // Blocks and most elements are not self closing. | ||
| if (node instanceof html.Block || !this._getTagDefinition(node)?.closedByParent) { | ||
| // Note that we encountered an unexpected close tag but continue processing the element | ||
| // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this | ||
| // end tag in the stack. | ||
| unexpectedCloseTagDetected = true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| _consumeAttr(attrName) { | ||
| const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]); | ||
| let attrEnd = attrName.sourceSpan.end; | ||
| let startQuoteToken; | ||
| // Consume any quote | ||
| if (this._peek.type === 15 /* TokenType.ATTR_QUOTE */) { | ||
| startQuoteToken = this._advance(); | ||
| } | ||
| // Consume the attribute value | ||
| let value = ''; | ||
| const valueTokens = []; | ||
| let valueStartSpan = undefined; | ||
| let valueEnd = undefined; | ||
| // NOTE: We need to use a new variable `nextTokenType` here to hide the actual type of | ||
| // `_peek.type` from TS. Otherwise TS will narrow the type of `_peek.type` preventing it from | ||
| // being able to consider `ATTR_VALUE_INTERPOLATION` as an option. This is because TS is not | ||
| // able to see that `_advance()` will actually mutate `_peek`. | ||
| const nextTokenType = this._peek.type; | ||
| if (nextTokenType === 16 /* TokenType.ATTR_VALUE_TEXT */) { | ||
| valueStartSpan = this._peek.sourceSpan; | ||
| valueEnd = this._peek.sourceSpan.end; | ||
| while (this._peek.type === 16 /* TokenType.ATTR_VALUE_TEXT */ || | ||
| this._peek.type === 17 /* TokenType.ATTR_VALUE_INTERPOLATION */ || | ||
| this._peek.type === 9 /* TokenType.ENCODED_ENTITY */) { | ||
| const valueToken = this._advance(); | ||
| valueTokens.push(valueToken); | ||
| if (valueToken.type === 17 /* TokenType.ATTR_VALUE_INTERPOLATION */) { | ||
| // For backward compatibility we decode HTML entities that appear in interpolation | ||
| // expressions. This is arguably a bug, but it could be a considerable breaking change to | ||
| // fix it. It should be addressed in a larger project to refactor the entire parser/lexer | ||
| // chain after View Engine has been removed. | ||
| value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity); | ||
| } | ||
| else if (valueToken.type === 9 /* TokenType.ENCODED_ENTITY */) { | ||
| value += valueToken.parts[0]; | ||
| } | ||
| else { | ||
| value += valueToken.parts.join(''); | ||
| } | ||
| valueEnd = attrEnd = valueToken.sourceSpan.end; | ||
| } | ||
| } | ||
| // Consume any quote | ||
| if (this._peek.type === 15 /* TokenType.ATTR_QUOTE */) { | ||
| const quoteToken = this._advance(); | ||
| valueEnd = attrEnd = quoteToken.sourceSpan.end; | ||
| } | ||
| const valueSpan = valueStartSpan && | ||
| valueEnd && | ||
| new ParseSourceSpan(startQuoteToken?.sourceSpan.start ?? valueStartSpan.start, valueEnd, startQuoteToken?.sourceSpan.fullStart ?? valueStartSpan.fullStart); | ||
| return new html.Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined); | ||
| } | ||
| _consumeDirective(nameToken) { | ||
| const attributes = []; | ||
| let startSourceSpanEnd = nameToken.sourceSpan.end; | ||
| let endSourceSpan = null; | ||
| this._advance(); | ||
| if (this._peek.type === 40 /* TokenType.DIRECTIVE_OPEN */) { | ||
| // Capture the opening token in the start span. | ||
| startSourceSpanEnd = this._peek.sourceSpan.end; | ||
| this._advance(); | ||
| // Cast here is necessary, because TS doesn't know that `_advance` changed `_peek`. | ||
| while (this._peek.type === 14 /* TokenType.ATTR_NAME */) { | ||
| attributes.push(this._consumeAttr(this._advance())); | ||
| } | ||
| if (this._peek.type === 41 /* TokenType.DIRECTIVE_CLOSE */) { | ||
| endSourceSpan = this._peek.sourceSpan; | ||
| this._advance(); | ||
| } | ||
| else { | ||
| this.errors.push(TreeError.create(null, nameToken.sourceSpan, 'Unterminated directive definition')); | ||
| } | ||
| } | ||
| const startSourceSpan = new ParseSourceSpan(nameToken.sourceSpan.start, startSourceSpanEnd, nameToken.sourceSpan.fullStart); | ||
| const sourceSpan = new ParseSourceSpan(startSourceSpan.start, endSourceSpan === null ? nameToken.sourceSpan.end : endSourceSpan.end, startSourceSpan.fullStart); | ||
| return new html.Directive(nameToken.parts[0], attributes, sourceSpan, startSourceSpan, endSourceSpan); | ||
| } | ||
| _consumeBlockOpen(token) { | ||
| const parameters = []; | ||
| while (this._peek.type === 28 /* TokenType.BLOCK_PARAMETER */) { | ||
| const paramToken = this._advance(); | ||
| parameters.push(new html.BlockParameter(paramToken.parts[0], paramToken.sourceSpan)); | ||
| } | ||
| if (this._peek.type === 26 /* TokenType.BLOCK_OPEN_END */) { | ||
| this._advance(); | ||
| } | ||
| const end = this._peek.sourceSpan.fullStart; | ||
| const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
| // Create a separate `startSpan` because `span` will be modified when there is an `end` span. | ||
| const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
| const block = new html.Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan); | ||
| this._pushContainer(block, false); | ||
| } | ||
| _consumeBlockClose(token) { | ||
| if (!this._popContainer(null, html.Block, token.sourceSpan)) { | ||
| this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` + | ||
| `If you meant to write the } character, you should use the "}" ` + | ||
| `HTML entity instead.`)); | ||
| } | ||
| } | ||
| _consumeIncompleteBlock(token) { | ||
| const parameters = []; | ||
| while (this._peek.type === 28 /* TokenType.BLOCK_PARAMETER */) { | ||
| const paramToken = this._advance(); | ||
| parameters.push(new html.BlockParameter(paramToken.parts[0], paramToken.sourceSpan)); | ||
| } | ||
| const end = this._peek.sourceSpan.fullStart; | ||
| const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
| // Create a separate `startSpan` because `span` will be modified when there is an `end` span. | ||
| const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
| const block = new html.Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan); | ||
| this._pushContainer(block, false); | ||
| // Incomplete blocks don't have children so we close them immediately and report an error. | ||
| this._popContainer(null, html.Block, null); | ||
| this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` + | ||
| `you should use the "@" HTML entity instead.`)); | ||
| } | ||
| _consumeLet(startToken) { | ||
| const name = startToken.parts[0]; | ||
| let valueToken; | ||
| let endToken; | ||
| if (this._peek.type !== 31 /* TokenType.LET_VALUE */) { | ||
| this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Invalid @let declaration "${name}". Declaration must have a value.`)); | ||
| return; | ||
| } | ||
| else { | ||
| valueToken = this._advance(); | ||
| } | ||
| // Type cast is necessary here since TS narrowed the type of `peek` above. | ||
| if (this._peek.type !== 32 /* TokenType.LET_END */) { | ||
| this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Unterminated @let declaration "${name}". Declaration must be terminated with a semicolon.`)); | ||
| return; | ||
| } | ||
| else { | ||
| endToken = this._advance(); | ||
| } | ||
| const end = endToken.sourceSpan.fullStart; | ||
| const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart); | ||
| // The start token usually captures the `@let`. Construct a name span by | ||
| // offsetting the start by the length of any text before the name. | ||
| const startOffset = startToken.sourceSpan.toString().lastIndexOf(name); | ||
| const nameStart = startToken.sourceSpan.start.moveBy(startOffset); | ||
| const nameSpan = new ParseSourceSpan(nameStart, startToken.sourceSpan.end); | ||
| const node = new html.LetDeclaration(name, valueToken.parts[0], span, nameSpan, valueToken.sourceSpan); | ||
| this._addToParent(node); | ||
| } | ||
| _consumeIncompleteLet(token) { | ||
| // Incomplete `@let` declaration may end up with an empty name. | ||
| const name = token.parts[0] ?? ''; | ||
| const nameString = name ? ` "${name}"` : ''; | ||
| // If there's at least a name, we can salvage an AST node that can be used for completions. | ||
| if (name.length > 0) { | ||
| const startOffset = token.sourceSpan.toString().lastIndexOf(name); | ||
| const nameStart = token.sourceSpan.start.moveBy(startOffset); | ||
| const nameSpan = new ParseSourceSpan(nameStart, token.sourceSpan.end); | ||
| const valueSpan = new ParseSourceSpan(token.sourceSpan.start, token.sourceSpan.start.moveBy(0)); | ||
| const node = new html.LetDeclaration(name, '', token.sourceSpan, nameSpan, valueSpan); | ||
| this._addToParent(node); | ||
| } | ||
| this.errors.push(TreeError.create(token.parts[0], token.sourceSpan, `Incomplete @let declaration${nameString}. ` + | ||
| `@let declarations must be written as \`@let <name> = <value>;\``)); | ||
| } | ||
| _getContainer() { | ||
| return this._containerStack.length > 0 | ||
| ? this._containerStack[this._containerStack.length - 1] | ||
| : null; | ||
| } | ||
| _getClosestElementLikeParent() { | ||
| for (let i = this._containerStack.length - 1; i > -1; i--) { | ||
| const current = this._containerStack[i]; | ||
| if (current instanceof html.Element || current instanceof html.Component) { | ||
| return current; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| _addToParent(node) { | ||
| const parent = this._getContainer(); | ||
| if (parent === null) { | ||
| this.rootNodes.push(node); | ||
| } | ||
| else { | ||
| parent.children.push(node); | ||
| } | ||
| } | ||
| _getElementFullName(token, parent) { | ||
| const prefix = this._getPrefix(token, parent); | ||
| return mergeNsAndName(prefix, token.parts[1]); | ||
| } | ||
| _getComponentFullName(token, parent) { | ||
| const componentName = token.parts[0]; | ||
| const tagName = this._getComponentTagName(token, parent); | ||
| if (tagName === null) { | ||
| return componentName; | ||
| } | ||
| return tagName.startsWith(':') ? componentName + tagName : `${componentName}:${tagName}`; | ||
| } | ||
| _getComponentTagName(token, parent) { | ||
| const prefix = this._getPrefix(token, parent); | ||
| const tagName = token.parts[2]; | ||
| if (!prefix && !tagName) { | ||
| return null; | ||
| } | ||
| else if (!prefix && tagName) { | ||
| return tagName; | ||
| } | ||
| else { | ||
| // TODO(crisbeto): re-evaluate this fallback. Maybe base it off the class name? | ||
| return mergeNsAndName(prefix, tagName || 'ng-component'); | ||
| } | ||
| } | ||
| _getPrefix(token, parent) { | ||
| let prefix; | ||
| let tagName; | ||
| if (token.type === 34 /* TokenType.COMPONENT_OPEN_START */ || | ||
| token.type === 38 /* TokenType.INCOMPLETE_COMPONENT_OPEN */ || | ||
| token.type === 37 /* TokenType.COMPONENT_CLOSE */) { | ||
| prefix = token.parts[1]; | ||
| tagName = token.parts[2]; | ||
| } | ||
| else { | ||
| prefix = token.parts[0]; | ||
| tagName = token.parts[1]; | ||
| } | ||
| prefix = prefix || this._getTagDefinition(tagName)?.implicitNamespacePrefix || ''; | ||
| if (!prefix && parent) { | ||
| const parentName = parent instanceof html.Element ? parent.name : parent.tagName; | ||
| if (parentName !== null) { | ||
| const parentTagName = splitNsName(parentName)[1]; | ||
| const parentTagDefinition = this._getTagDefinition(parentTagName); | ||
| if (parentTagDefinition !== null && !parentTagDefinition.preventNamespaceInheritance) { | ||
| prefix = getNsPrefix(parentName); | ||
| } | ||
| } | ||
| } | ||
| return prefix; | ||
| } | ||
| } | ||
| function lastOnStack(stack, element) { | ||
| return stack.length > 0 && stack[stack.length - 1] === element; | ||
| } | ||
| /** | ||
| * Decode the `entity` string, which we believe is the contents of an HTML entity. | ||
| * | ||
| * If the string is not actually a valid/known entity then just return the original `match` string. | ||
| */ | ||
| function decodeEntity(match, entity) { | ||
| if (NAMED_ENTITIES[entity] !== undefined) { | ||
| return NAMED_ENTITIES[entity] || match; | ||
| } | ||
| if (/^#x[a-f0-9]+$/i.test(entity)) { | ||
| return String.fromCodePoint(parseInt(entity.slice(2), 16)); | ||
| } | ||
| if (/^#\d+$/.test(entity)) { | ||
| return String.fromCodePoint(parseInt(entity.slice(1), 10)); | ||
| } | ||
| return match; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare enum TagContentType { | ||
| RAW_TEXT = 0, | ||
| ESCAPABLE_RAW_TEXT = 1, | ||
| PARSABLE_DATA = 2 | ||
| } | ||
| export interface TagDefinition { | ||
| closedByParent: boolean; | ||
| implicitNamespacePrefix: string | null; | ||
| isVoid: boolean; | ||
| ignoreFirstLf: boolean; | ||
| canSelfClose: boolean; | ||
| preventNamespaceInheritance: boolean; | ||
| isClosedByChild(name: string): boolean; | ||
| getContentType(prefix?: string): TagContentType; | ||
| } | ||
| export declare function splitNsName(elementName: string, fatal?: boolean): [string | null, string]; | ||
| export declare function isNgContainer(tagName: string): boolean; | ||
| export declare function isNgContent(tagName: string): boolean; | ||
| export declare function isNgTemplate(tagName: string): boolean; | ||
| export declare function getNsPrefix(fullName: string): string; | ||
| export declare function getNsPrefix(fullName: null): null; | ||
| export declare function mergeNsAndName(prefix: string, localName: string): string; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export var TagContentType; | ||
| (function (TagContentType) { | ||
| TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT"; | ||
| TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT"; | ||
| TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA"; | ||
| })(TagContentType || (TagContentType = {})); | ||
| export function splitNsName(elementName, fatal = true) { | ||
| if (elementName[0] != ':') { | ||
| return [null, elementName]; | ||
| } | ||
| const colonIndex = elementName.indexOf(':', 1); | ||
| if (colonIndex === -1) { | ||
| if (fatal) { | ||
| throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`); | ||
| } | ||
| else { | ||
| return [null, elementName]; | ||
| } | ||
| } | ||
| return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)]; | ||
| } | ||
| // `<ng-container>` tags work the same regardless the namespace | ||
| export function isNgContainer(tagName) { | ||
| return splitNsName(tagName)[1] === 'ng-container'; | ||
| } | ||
| // `<ng-content>` tags work the same regardless the namespace | ||
| export function isNgContent(tagName) { | ||
| return splitNsName(tagName)[1] === 'ng-content'; | ||
| } | ||
| // `<ng-template>` tags work the same regardless the namespace | ||
| export function isNgTemplate(tagName) { | ||
| return splitNsName(tagName)[1] === 'ng-template'; | ||
| } | ||
| export function getNsPrefix(fullName) { | ||
| return fullName === null ? null : splitNsName(fullName)[0]; | ||
| } | ||
| export function mergeNsAndName(prefix, localName) { | ||
| return prefix ? `:${prefix}:${localName}` : localName; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { ParseSourceSpan } from '../parse_util'; | ||
| export declare const enum TokenType { | ||
| TAG_OPEN_START = 0, | ||
| TAG_OPEN_END = 1, | ||
| TAG_OPEN_END_VOID = 2, | ||
| TAG_CLOSE = 3, | ||
| INCOMPLETE_TAG_OPEN = 4, | ||
| TEXT = 5, | ||
| ESCAPABLE_RAW_TEXT = 6, | ||
| RAW_TEXT = 7, | ||
| INTERPOLATION = 8, | ||
| ENCODED_ENTITY = 9, | ||
| COMMENT_START = 10, | ||
| COMMENT_END = 11, | ||
| CDATA_START = 12, | ||
| CDATA_END = 13, | ||
| ATTR_NAME = 14, | ||
| ATTR_QUOTE = 15, | ||
| ATTR_VALUE_TEXT = 16, | ||
| ATTR_VALUE_INTERPOLATION = 17, | ||
| DOC_TYPE_START = 18, | ||
| DOC_TYPE_END = 19, | ||
| EXPANSION_FORM_START = 20, | ||
| EXPANSION_CASE_VALUE = 21, | ||
| EXPANSION_CASE_EXP_START = 22, | ||
| EXPANSION_CASE_EXP_END = 23, | ||
| EXPANSION_FORM_END = 24, | ||
| BLOCK_OPEN_START = 25, | ||
| BLOCK_OPEN_END = 26, | ||
| BLOCK_CLOSE = 27, | ||
| BLOCK_PARAMETER = 28, | ||
| INCOMPLETE_BLOCK_OPEN = 29, | ||
| LET_START = 30, | ||
| LET_VALUE = 31, | ||
| LET_END = 32, | ||
| INCOMPLETE_LET = 33, | ||
| COMPONENT_OPEN_START = 34, | ||
| COMPONENT_OPEN_END = 35, | ||
| COMPONENT_OPEN_END_VOID = 36, | ||
| COMPONENT_CLOSE = 37, | ||
| INCOMPLETE_COMPONENT_OPEN = 38, | ||
| DIRECTIVE_NAME = 39, | ||
| DIRECTIVE_OPEN = 40, | ||
| DIRECTIVE_CLOSE = 41, | ||
| EOF = 42 | ||
| } | ||
| export type Token = TagOpenStartToken | TagOpenEndToken | TagOpenEndVoidToken | TagCloseToken | IncompleteTagOpenToken | TextToken | InterpolationToken | EncodedEntityToken | CommentStartToken | CommentEndToken | CdataStartToken | CdataEndToken | AttributeNameToken | AttributeQuoteToken | AttributeValueTextToken | AttributeValueInterpolationToken | DocTypeStartToken | ExpansionFormStartToken | ExpansionCaseValueToken | ExpansionCaseExpressionStartToken | ExpansionCaseExpressionEndToken | ExpansionFormEndToken | EndOfFileToken | BlockParameterToken | BlockOpenStartToken | BlockOpenEndToken | BlockCloseToken | IncompleteBlockOpenToken | LetStartToken | LetValueToken | LetEndToken | IncompleteLetToken | ComponentOpenStartToken | ComponentOpenEndToken | ComponentOpenEndVoidToken | ComponentCloseToken | IncompleteComponentOpenToken | DirectiveNameToken | DirectiveOpenToken | DirectiveCloseToken; | ||
| export type InterpolatedTextToken = TextToken | InterpolationToken | EncodedEntityToken; | ||
| export type InterpolatedAttributeToken = AttributeValueTextToken | AttributeValueInterpolationToken | EncodedEntityToken; | ||
| export interface TokenBase { | ||
| type: TokenType; | ||
| parts: string[]; | ||
| sourceSpan: ParseSourceSpan; | ||
| } | ||
| export interface TagOpenStartToken extends TokenBase { | ||
| type: TokenType.TAG_OPEN_START; | ||
| parts: [prefix: string, name: string]; | ||
| } | ||
| export interface TagOpenEndToken extends TokenBase { | ||
| type: TokenType.TAG_OPEN_END; | ||
| parts: []; | ||
| } | ||
| export interface TagOpenEndVoidToken extends TokenBase { | ||
| type: TokenType.TAG_OPEN_END_VOID; | ||
| parts: []; | ||
| } | ||
| export interface TagCloseToken extends TokenBase { | ||
| type: TokenType.TAG_CLOSE; | ||
| parts: [prefix: string, name: string]; | ||
| } | ||
| export interface IncompleteTagOpenToken extends TokenBase { | ||
| type: TokenType.INCOMPLETE_TAG_OPEN; | ||
| parts: [prefix: string, name: string]; | ||
| } | ||
| export interface TextToken extends TokenBase { | ||
| type: TokenType.TEXT | TokenType.ESCAPABLE_RAW_TEXT | TokenType.RAW_TEXT; | ||
| parts: [text: string]; | ||
| } | ||
| export interface InterpolationToken extends TokenBase { | ||
| type: TokenType.INTERPOLATION; | ||
| parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
| } | ||
| export interface EncodedEntityToken extends TokenBase { | ||
| type: TokenType.ENCODED_ENTITY; | ||
| parts: [decoded: string, encoded: string]; | ||
| } | ||
| export interface CommentStartToken extends TokenBase { | ||
| type: TokenType.COMMENT_START; | ||
| parts: []; | ||
| } | ||
| export interface CommentEndToken extends TokenBase { | ||
| type: TokenType.COMMENT_END; | ||
| parts: []; | ||
| } | ||
| export interface CdataStartToken extends TokenBase { | ||
| type: TokenType.CDATA_START; | ||
| parts: []; | ||
| } | ||
| export interface CdataEndToken extends TokenBase { | ||
| type: TokenType.CDATA_END; | ||
| parts: []; | ||
| } | ||
| export interface AttributeNameToken extends TokenBase { | ||
| type: TokenType.ATTR_NAME; | ||
| parts: [prefix: string, name: string]; | ||
| } | ||
| export interface AttributeQuoteToken extends TokenBase { | ||
| type: TokenType.ATTR_QUOTE; | ||
| parts: [quote: "'" | '"']; | ||
| } | ||
| export interface AttributeValueTextToken extends TokenBase { | ||
| type: TokenType.ATTR_VALUE_TEXT; | ||
| parts: [value: string]; | ||
| } | ||
| export interface AttributeValueInterpolationToken extends TokenBase { | ||
| type: TokenType.ATTR_VALUE_INTERPOLATION; | ||
| parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
| } | ||
| export interface DocTypeStartToken extends TokenBase { | ||
| type: TokenType.DOC_TYPE_START; | ||
| parts: []; | ||
| } | ||
| export interface DocTypeEndToken extends TokenBase { | ||
| type: TokenType.DOC_TYPE_END; | ||
| parts: []; | ||
| } | ||
| export interface ExpansionFormStartToken extends TokenBase { | ||
| type: TokenType.EXPANSION_FORM_START; | ||
| parts: []; | ||
| } | ||
| export interface ExpansionCaseValueToken extends TokenBase { | ||
| type: TokenType.EXPANSION_CASE_VALUE; | ||
| parts: [value: string]; | ||
| } | ||
| export interface ExpansionCaseExpressionStartToken extends TokenBase { | ||
| type: TokenType.EXPANSION_CASE_EXP_START; | ||
| parts: []; | ||
| } | ||
| export interface ExpansionCaseExpressionEndToken extends TokenBase { | ||
| type: TokenType.EXPANSION_CASE_EXP_END; | ||
| parts: []; | ||
| } | ||
| export interface ExpansionFormEndToken extends TokenBase { | ||
| type: TokenType.EXPANSION_FORM_END; | ||
| parts: []; | ||
| } | ||
| export interface EndOfFileToken extends TokenBase { | ||
| type: TokenType.EOF; | ||
| parts: []; | ||
| } | ||
| export interface BlockParameterToken extends TokenBase { | ||
| type: TokenType.BLOCK_PARAMETER; | ||
| parts: [expression: string]; | ||
| } | ||
| export interface BlockOpenStartToken extends TokenBase { | ||
| type: TokenType.BLOCK_OPEN_START; | ||
| parts: [name: string]; | ||
| } | ||
| export interface BlockOpenEndToken extends TokenBase { | ||
| type: TokenType.BLOCK_OPEN_END; | ||
| parts: []; | ||
| } | ||
| export interface BlockCloseToken extends TokenBase { | ||
| type: TokenType.BLOCK_CLOSE; | ||
| parts: []; | ||
| } | ||
| export interface IncompleteBlockOpenToken extends TokenBase { | ||
| type: TokenType.INCOMPLETE_BLOCK_OPEN; | ||
| parts: [name: string]; | ||
| } | ||
| export interface LetStartToken extends TokenBase { | ||
| type: TokenType.LET_START; | ||
| parts: [name: string]; | ||
| } | ||
| export interface LetValueToken extends TokenBase { | ||
| type: TokenType.LET_VALUE; | ||
| parts: [value: string]; | ||
| } | ||
| export interface LetEndToken extends TokenBase { | ||
| type: TokenType.LET_END; | ||
| parts: []; | ||
| } | ||
| export interface IncompleteLetToken extends TokenBase { | ||
| type: TokenType.INCOMPLETE_LET; | ||
| parts: [name: string]; | ||
| } | ||
| export interface ComponentOpenStartToken extends TokenBase { | ||
| type: TokenType.COMPONENT_OPEN_START; | ||
| parts: [componentName: string, prefix: string, tagName: string]; | ||
| } | ||
| export interface ComponentOpenEndToken extends TokenBase { | ||
| type: TokenType.COMPONENT_OPEN_END; | ||
| parts: []; | ||
| } | ||
| export interface ComponentOpenEndVoidToken extends TokenBase { | ||
| type: TokenType.COMPONENT_OPEN_END_VOID; | ||
| parts: []; | ||
| } | ||
| export interface ComponentCloseToken extends TokenBase { | ||
| type: TokenType.COMPONENT_CLOSE; | ||
| parts: [componentName: string, prefix: string, tagName: string]; | ||
| } | ||
| export interface IncompleteComponentOpenToken extends TokenBase { | ||
| type: TokenType.INCOMPLETE_COMPONENT_OPEN; | ||
| parts: [componentName: string, prefix: string, tagName: string]; | ||
| } | ||
| export interface DirectiveNameToken extends TokenBase { | ||
| type: TokenType.DIRECTIVE_NAME; | ||
| parts: [name: string]; | ||
| } | ||
| export interface DirectiveOpenToken extends TokenBase { | ||
| type: TokenType.DIRECTIVE_OPEN; | ||
| parts: []; | ||
| } | ||
| export interface DirectiveCloseToken extends TokenBase { | ||
| type: TokenType.DIRECTIVE_CLOSE; | ||
| parts: []; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export {}; |
| export declare class ParseLocation { | ||
| file: ParseSourceFile; | ||
| offset: number; | ||
| line: number; | ||
| col: number; | ||
| constructor(file: ParseSourceFile, offset: number, line: number, col: number); | ||
| toString(): string; | ||
| moveBy(delta: number): ParseLocation; | ||
| getContext(maxChars: number, maxLines: number): { | ||
| before: string; | ||
| after: string; | ||
| } | null; | ||
| } | ||
| export declare class ParseSourceFile { | ||
| content: string; | ||
| url: string; | ||
| constructor(content: string, url: string); | ||
| } | ||
| export declare class ParseSourceSpan { | ||
| start: ParseLocation; | ||
| end: ParseLocation; | ||
| fullStart: ParseLocation; | ||
| details: string | null; | ||
| /** | ||
| * Create an object that holds information about spans of tokens/nodes captured during | ||
| * lexing/parsing of text. | ||
| * | ||
| * @param start | ||
| * The location of the start of the span (having skipped leading trivia). | ||
| * Skipping leading trivia makes source-spans more "user friendly", since things like HTML | ||
| * elements will appear to begin at the start of the opening tag, rather than at the start of any | ||
| * leading trivia, which could include newlines. | ||
| * | ||
| * @param end | ||
| * The location of the end of the span. | ||
| * | ||
| * @param fullStart | ||
| * The start of the token without skipping the leading trivia. | ||
| * This is used by tooling that splits tokens further, such as extracting Angular interpolations | ||
| * from text tokens. Such tooling creates new source-spans relative to the original token's | ||
| * source-span. If leading trivia characters have been skipped then the new source-spans may be | ||
| * incorrectly offset. | ||
| * | ||
| * @param details | ||
| * Additional information (such as identifier names) that should be associated with the span. | ||
| */ | ||
| constructor(start: ParseLocation, end: ParseLocation, fullStart?: ParseLocation, details?: string | null); | ||
| toString(): string; | ||
| } | ||
| export declare enum ParseErrorLevel { | ||
| WARNING = 0, | ||
| ERROR = 1 | ||
| } | ||
| export declare class ParseError extends Error { | ||
| /** Location of the error. */ | ||
| readonly span: ParseSourceSpan; | ||
| /** Error message. */ | ||
| readonly msg: string; | ||
| /** Severity level of the error. */ | ||
| readonly level: ParseErrorLevel; | ||
| /** | ||
| * Error that caused the error to be surfaced. For example, an error in a sub-expression that | ||
| * couldn't be parsed. Not guaranteed to be defined, but can be used to provide more context. | ||
| */ | ||
| readonly relatedError?: unknown; | ||
| constructor( | ||
| /** Location of the error. */ | ||
| span: ParseSourceSpan, | ||
| /** Error message. */ | ||
| msg: string, | ||
| /** Severity level of the error. */ | ||
| level?: ParseErrorLevel, | ||
| /** | ||
| * Error that caused the error to be surfaced. For example, an error in a sub-expression that | ||
| * couldn't be parsed. Not guaranteed to be defined, but can be used to provide more context. | ||
| */ | ||
| relatedError?: unknown); | ||
| contextualMessage(): string; | ||
| toString(): string; | ||
| } | ||
| /** | ||
| * Generates Source Span object for a given R3 Type for JIT mode. | ||
| * | ||
| * @param kind Component or Directive. | ||
| * @param typeName name of the Component or Directive. | ||
| * @param sourceUrl reference to Component or Directive source. | ||
| * @returns instance of ParseSourceSpan that represent a given Component or Directive. | ||
| */ | ||
| export declare function r3JitTypeSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan; | ||
| export declare function identifierName(compileIdentifier: CompileIdentifierMetadata | null | undefined): string | null; | ||
| export interface CompileIdentifierMetadata { | ||
| reference: any; | ||
| } | ||
| export declare function sanitizeIdentifier(name: string): string; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import * as chars from "./chars.js"; | ||
| import { stringify } from "./util.js"; | ||
| export class ParseLocation { | ||
| constructor(file, offset, line, col) { | ||
| this.file = file; | ||
| this.offset = offset; | ||
| this.line = line; | ||
| this.col = col; | ||
| } | ||
| toString() { | ||
| return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url; | ||
| } | ||
| moveBy(delta) { | ||
| const source = this.file.content; | ||
| const len = source.length; | ||
| let offset = this.offset; | ||
| let line = this.line; | ||
| let col = this.col; | ||
| while (offset > 0 && delta < 0) { | ||
| offset--; | ||
| delta++; | ||
| const ch = source.charCodeAt(offset); | ||
| if (ch == chars.$LF) { | ||
| line--; | ||
| const priorLine = source | ||
| .substring(0, offset - 1) | ||
| .lastIndexOf(String.fromCharCode(chars.$LF)); | ||
| col = priorLine > 0 ? offset - priorLine : offset; | ||
| } | ||
| else { | ||
| col--; | ||
| } | ||
| } | ||
| while (offset < len && delta > 0) { | ||
| const ch = source.charCodeAt(offset); | ||
| offset++; | ||
| delta--; | ||
| if (ch == chars.$LF) { | ||
| line++; | ||
| col = 0; | ||
| } | ||
| else { | ||
| col++; | ||
| } | ||
| } | ||
| return new ParseLocation(this.file, offset, line, col); | ||
| } | ||
| // Return the source around the location | ||
| // Up to `maxChars` or `maxLines` on each side of the location | ||
| getContext(maxChars, maxLines) { | ||
| const content = this.file.content; | ||
| let startOffset = this.offset; | ||
| if (startOffset != null) { | ||
| if (startOffset > content.length - 1) { | ||
| startOffset = content.length - 1; | ||
| } | ||
| let endOffset = startOffset; | ||
| let ctxChars = 0; | ||
| let ctxLines = 0; | ||
| while (ctxChars < maxChars && startOffset > 0) { | ||
| startOffset--; | ||
| ctxChars++; | ||
| if (content[startOffset] == '\n') { | ||
| if (++ctxLines == maxLines) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| ctxChars = 0; | ||
| ctxLines = 0; | ||
| while (ctxChars < maxChars && endOffset < content.length - 1) { | ||
| endOffset++; | ||
| ctxChars++; | ||
| if (content[endOffset] == '\n') { | ||
| if (++ctxLines == maxLines) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return { | ||
| before: content.substring(startOffset, this.offset), | ||
| after: content.substring(this.offset, endOffset + 1), | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| export class ParseSourceFile { | ||
| constructor(content, url) { | ||
| this.content = content; | ||
| this.url = url; | ||
| } | ||
| } | ||
| export class ParseSourceSpan { | ||
| /** | ||
| * Create an object that holds information about spans of tokens/nodes captured during | ||
| * lexing/parsing of text. | ||
| * | ||
| * @param start | ||
| * The location of the start of the span (having skipped leading trivia). | ||
| * Skipping leading trivia makes source-spans more "user friendly", since things like HTML | ||
| * elements will appear to begin at the start of the opening tag, rather than at the start of any | ||
| * leading trivia, which could include newlines. | ||
| * | ||
| * @param end | ||
| * The location of the end of the span. | ||
| * | ||
| * @param fullStart | ||
| * The start of the token without skipping the leading trivia. | ||
| * This is used by tooling that splits tokens further, such as extracting Angular interpolations | ||
| * from text tokens. Such tooling creates new source-spans relative to the original token's | ||
| * source-span. If leading trivia characters have been skipped then the new source-spans may be | ||
| * incorrectly offset. | ||
| * | ||
| * @param details | ||
| * Additional information (such as identifier names) that should be associated with the span. | ||
| */ | ||
| constructor(start, end, fullStart = start, details = null) { | ||
| this.start = start; | ||
| this.end = end; | ||
| this.fullStart = fullStart; | ||
| this.details = details; | ||
| } | ||
| toString() { | ||
| return this.start.file.content.substring(this.start.offset, this.end.offset); | ||
| } | ||
| } | ||
| export var ParseErrorLevel; | ||
| (function (ParseErrorLevel) { | ||
| ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING"; | ||
| ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR"; | ||
| })(ParseErrorLevel || (ParseErrorLevel = {})); | ||
| export class ParseError extends Error { | ||
| constructor( | ||
| /** Location of the error. */ | ||
| span, | ||
| /** Error message. */ | ||
| msg, | ||
| /** Severity level of the error. */ | ||
| level = ParseErrorLevel.ERROR, | ||
| /** | ||
| * Error that caused the error to be surfaced. For example, an error in a sub-expression that | ||
| * couldn't be parsed. Not guaranteed to be defined, but can be used to provide more context. | ||
| */ | ||
| relatedError) { | ||
| super(msg); | ||
| this.span = span; | ||
| this.msg = msg; | ||
| this.level = level; | ||
| this.relatedError = relatedError; | ||
| // Extending `Error` ends up breaking some internal tests. This appears to be a known issue | ||
| // when extending errors in TS and the workaround is to explicitly set the prototype. | ||
| // https://stackoverflow.com/questions/41102060/typescript-extending-error-class | ||
| Object.setPrototypeOf(this, new.target.prototype); | ||
| } | ||
| contextualMessage() { | ||
| const ctx = this.span.start.getContext(100, 3); | ||
| return ctx | ||
| ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` | ||
| : this.msg; | ||
| } | ||
| toString() { | ||
| const details = this.span.details ? `, ${this.span.details}` : ''; | ||
| return `${this.contextualMessage()}: ${this.span.start}${details}`; | ||
| } | ||
| } | ||
| /** | ||
| * Generates Source Span object for a given R3 Type for JIT mode. | ||
| * | ||
| * @param kind Component or Directive. | ||
| * @param typeName name of the Component or Directive. | ||
| * @param sourceUrl reference to Component or Directive source. | ||
| * @returns instance of ParseSourceSpan that represent a given Component or Directive. | ||
| */ | ||
| export function r3JitTypeSourceSpan(kind, typeName, sourceUrl) { | ||
| const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`; | ||
| const sourceFile = new ParseSourceFile('', sourceFileName); | ||
| return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); | ||
| } | ||
| let _anonymousTypeIndex = 0; | ||
| export function identifierName(compileIdentifier) { | ||
| if (!compileIdentifier || !compileIdentifier.reference) { | ||
| return null; | ||
| } | ||
| const ref = compileIdentifier.reference; | ||
| if (ref['__anonymousType']) { | ||
| return ref['__anonymousType']; | ||
| } | ||
| if (ref['__forward_ref__']) { | ||
| // We do not want to try to stringify a `forwardRef()` function because that would cause the | ||
| // inner function to be evaluated too early, defeating the whole point of the `forwardRef`. | ||
| return '__forward_ref__'; | ||
| } | ||
| let identifier = stringify(ref); | ||
| if (identifier.indexOf('(') >= 0) { | ||
| // case: anonymous functions! | ||
| identifier = `anonymous_${_anonymousTypeIndex++}`; | ||
| ref['__anonymousType'] = identifier; | ||
| } | ||
| else { | ||
| identifier = sanitizeIdentifier(identifier); | ||
| } | ||
| return identifier; | ||
| } | ||
| export function sanitizeIdentifier(name) { | ||
| return name.replace(/\W/g, '_'); | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { SchemaMetadata, SecurityContext } from '../core'; | ||
| import { ElementSchemaRegistry } from './element_schema_registry'; | ||
| export declare class DomElementSchemaRegistry extends ElementSchemaRegistry { | ||
| private _schema; | ||
| private _eventSchema; | ||
| constructor(); | ||
| hasProperty(tagName: string, propName: string, schemaMetas: SchemaMetadata[]): boolean; | ||
| hasElement(tagName: string, schemaMetas: SchemaMetadata[]): boolean; | ||
| /** | ||
| * securityContext returns the security context for the given property on the given DOM tag. | ||
| * | ||
| * Tag and property name are statically known and cannot change at runtime, i.e. it is not | ||
| * possible to bind a value into a changing attribute or tag name. | ||
| * | ||
| * The filtering is based on a list of allowed tags|attributes. All attributes in the schema | ||
| * above are assumed to have the 'NONE' security context, i.e. that they are safe inert | ||
| * string values. Only specific well known attack vectors are assigned their appropriate context. | ||
| */ | ||
| securityContext(tagName: string, propName: string, isAttribute: boolean): SecurityContext; | ||
| getMappedPropName(propName: string): string; | ||
| getDefaultComponentElementName(): string; | ||
| validateProperty(name: string): { | ||
| error: boolean; | ||
| msg?: string; | ||
| }; | ||
| validateAttribute(name: string): { | ||
| error: boolean; | ||
| msg?: string; | ||
| }; | ||
| allKnownElementNames(): string[]; | ||
| allKnownAttributesOfElement(tagName: string): string[]; | ||
| allKnownEventsOfElement(tagName: string): string[]; | ||
| normalizeAnimationStyleProperty(propName: string): string; | ||
| normalizeAnimationStyleValue(camelCaseProp: string, userProvidedProp: string, val: string | number): { | ||
| error: string; | ||
| value: string; | ||
| }; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SecurityContext } from "../core.js"; | ||
| import { isNgContainer, isNgContent } from "../ml_parser/tags.js"; | ||
| import { dashCaseToCamelCase } from "../util.js"; | ||
| import { SECURITY_SCHEMA } from "./dom_security_schema.js"; | ||
| import { ElementSchemaRegistry } from "./element_schema_registry.js"; | ||
| const BOOLEAN = 'boolean'; | ||
| const NUMBER = 'number'; | ||
| const STRING = 'string'; | ||
| const OBJECT = 'object'; | ||
| /** | ||
| * This array represents the DOM schema. It encodes inheritance, properties, and events. | ||
| * | ||
| * ## Overview | ||
| * | ||
| * Each line represents one kind of element. The `element_inheritance` and properties are joined | ||
| * using `element_inheritance|properties` syntax. | ||
| * | ||
| * ## Element Inheritance | ||
| * | ||
| * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`. | ||
| * Here the individual elements are separated by `,` (commas). Every element in the list | ||
| * has identical properties. | ||
| * | ||
| * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is | ||
| * specified then `""` (blank) element is assumed. | ||
| * | ||
| * NOTE: The blank element inherits from root `[Element]` element, the super element of all | ||
| * elements. | ||
| * | ||
| * NOTE an element prefix such as `:svg:` has no special meaning to the schema. | ||
| * | ||
| * ## Properties | ||
| * | ||
| * Each element has a set of properties separated by `,` (commas). Each property can be prefixed | ||
| * by a special character designating its type: | ||
| * | ||
| * - (no prefix): property is a string. | ||
| * - `*`: property represents an event. | ||
| * - `!`: property is a boolean. | ||
| * - `#`: property is a number. | ||
| * - `%`: property is an object. | ||
| * | ||
| * ## Query | ||
| * | ||
| * The class creates an internal squas representation which allows to easily answer the query of | ||
| * if a given property exist on a given element. | ||
| * | ||
| * NOTE: We don't yet support querying for types or events. | ||
| * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder, | ||
| * see dom_element_schema_registry_spec.ts | ||
| */ | ||
| // ================================================================================================= | ||
| // ================================================================================================= | ||
| // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P =========== | ||
| // ================================================================================================= | ||
| // ================================================================================================= | ||
| // | ||
| // DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW! | ||
| // | ||
| // Newly added properties must be security reviewed and assigned an appropriate SecurityContext in | ||
| // dom_security_schema.ts. Reach out to mprobst & rjamet for details. | ||
| // | ||
| // ================================================================================================= | ||
| const SCHEMA = [ | ||
| '[Element]|textContent,%ariaAtomic,%ariaAutoComplete,%ariaBusy,%ariaChecked,%ariaColCount,%ariaColIndex,%ariaColSpan,%ariaCurrent,%ariaDescription,%ariaDisabled,%ariaExpanded,%ariaHasPopup,%ariaHidden,%ariaKeyShortcuts,%ariaLabel,%ariaLevel,%ariaLive,%ariaModal,%ariaMultiLine,%ariaMultiSelectable,%ariaOrientation,%ariaPlaceholder,%ariaPosInSet,%ariaPressed,%ariaReadOnly,%ariaRelevant,%ariaRequired,%ariaRoleDescription,%ariaRowCount,%ariaRowIndex,%ariaRowSpan,%ariaSelected,%ariaSetSize,%ariaSort,%ariaValueMax,%ariaValueMin,%ariaValueNow,%ariaValueText,%classList,className,elementTiming,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*fullscreenchange,*fullscreenerror,*search,*webkitfullscreenchange,*webkitfullscreenerror,outerHTML,%part,#scrollLeft,#scrollTop,slot' + | ||
| /* added manually to avoid breaking changes */ | ||
| ',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored', | ||
| '[HTMLElement]^[Element]|accessKey,autocapitalize,!autofocus,contentEditable,dir,!draggable,enterKeyHint,!hidden,!inert,innerText,inputMode,lang,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate,virtualKeyboardPolicy', | ||
| 'abbr,address,article,aside,b,bdi,bdo,cite,content,code,dd,dfn,dt,em,figcaption,figure,footer,header,hgroup,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,search,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,autocapitalize,!autofocus,contentEditable,dir,!draggable,enterKeyHint,!hidden,innerText,inputMode,lang,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate,virtualKeyboardPolicy', | ||
| 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,!preservesPitch,src,%srcObject,#volume', | ||
| ':svg:^[HTMLElement]|!autofocus,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,%style,#tabIndex', | ||
| ':svg:graphics^:svg:|', | ||
| ':svg:animation^:svg:|*begin,*end,*repeat', | ||
| ':svg:geometry^:svg:|', | ||
| ':svg:componentTransferFunction^:svg:|', | ||
| ':svg:gradient^:svg:|', | ||
| ':svg:textContent^:svg:graphics|', | ||
| ':svg:textPositioning^:svg:textContent|', | ||
| 'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,%relList,rev,search,shape,target,text,type,username', | ||
| 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,%relList,search,shape,target,username', | ||
| 'audio^media|', | ||
| 'br^[HTMLElement]|clear', | ||
| 'base^[HTMLElement]|href,target', | ||
| 'body^[HTMLElement]|aLink,background,bgColor,link,*afterprint,*beforeprint,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*messageerror,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink', | ||
| 'button^[HTMLElement]|!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value', | ||
| 'canvas^[HTMLElement]|#height,#width', | ||
| 'content^[HTMLElement]|select', | ||
| 'dl^[HTMLElement]|!compact', | ||
| 'data^[HTMLElement]|value', | ||
| 'datalist^[HTMLElement]|', | ||
| 'details^[HTMLElement]|!open', | ||
| 'dialog^[HTMLElement]|!open,returnValue', | ||
| 'dir^[HTMLElement]|!compact', | ||
| 'div^[HTMLElement]|align', | ||
| 'embed^[HTMLElement]|align,height,name,src,type,width', | ||
| 'fieldset^[HTMLElement]|!disabled,name', | ||
| 'font^[HTMLElement]|color,face,size', | ||
| 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target', | ||
| 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src', | ||
| 'frameset^[HTMLElement]|cols,*afterprint,*beforeprint,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*messageerror,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows', | ||
| 'hr^[HTMLElement]|align,color,!noShade,size,width', | ||
| 'head^[HTMLElement]|', | ||
| 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align', | ||
| 'html^[HTMLElement]|version', | ||
| 'iframe^[HTMLElement]|align,allow,!allowFullscreen,!allowPaymentRequest,csp,frameBorder,height,loading,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width', | ||
| 'img^[HTMLElement]|align,alt,border,%crossOrigin,decoding,#height,#hspace,!isMap,loading,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width', | ||
| 'input^[HTMLElement]|accept,align,alt,autocomplete,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width', | ||
| 'li^[HTMLElement]|type,#value', | ||
| 'label^[HTMLElement]|htmlFor', | ||
| 'legend^[HTMLElement]|align', | ||
| 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,imageSizes,imageSrcset,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type', | ||
| 'map^[HTMLElement]|name', | ||
| 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width', | ||
| 'menu^[HTMLElement]|!compact', | ||
| 'meta^[HTMLElement]|content,httpEquiv,media,name,scheme', | ||
| 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value', | ||
| 'ins,del^[HTMLElement]|cite,dateTime', | ||
| 'ol^[HTMLElement]|!compact,!reversed,#start,type', | ||
| 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width', | ||
| 'optgroup^[HTMLElement]|!disabled,label', | ||
| 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value', | ||
| 'output^[HTMLElement]|defaultValue,%htmlFor,name,value', | ||
| 'p^[HTMLElement]|align', | ||
| 'param^[HTMLElement]|name,type,value,valueType', | ||
| 'picture^[HTMLElement]|', | ||
| 'pre^[HTMLElement]|#width', | ||
| 'progress^[HTMLElement]|#max,#value', | ||
| 'q,blockquote,cite^[HTMLElement]|', | ||
| 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,!noModule,%referrerPolicy,src,text,type', | ||
| 'select^[HTMLElement]|autocomplete,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value', | ||
| 'selectedcontent^[HTMLElement]|', | ||
| 'slot^[HTMLElement]|name', | ||
| 'source^[HTMLElement]|#height,media,sizes,src,srcset,type,#width', | ||
| 'span^[HTMLElement]|', | ||
| 'style^[HTMLElement]|!disabled,media,type', | ||
| 'search^[HTMLELement]|', | ||
| 'caption^[HTMLElement]|align', | ||
| 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width', | ||
| 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width', | ||
| 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width', | ||
| 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign', | ||
| 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign', | ||
| 'template^[HTMLElement]|', | ||
| 'textarea^[HTMLElement]|autocomplete,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap', | ||
| 'time^[HTMLElement]|dateTime', | ||
| 'title^[HTMLElement]|text', | ||
| 'track^[HTMLElement]|!default,kind,label,src,srclang', | ||
| 'ul^[HTMLElement]|!compact,type', | ||
| 'unknown^[HTMLElement]|', | ||
| 'video^media|!disablePictureInPicture,#height,*enterpictureinpicture,*leavepictureinpicture,!playsInline,poster,#width', | ||
| ':svg:a^:svg:graphics|', | ||
| ':svg:animate^:svg:animation|', | ||
| ':svg:animateMotion^:svg:animation|', | ||
| ':svg:animateTransform^:svg:animation|', | ||
| ':svg:circle^:svg:geometry|', | ||
| ':svg:clipPath^:svg:graphics|', | ||
| ':svg:defs^:svg:graphics|', | ||
| ':svg:desc^:svg:|', | ||
| ':svg:discard^:svg:|', | ||
| ':svg:ellipse^:svg:geometry|', | ||
| ':svg:feBlend^:svg:|', | ||
| ':svg:feColorMatrix^:svg:|', | ||
| ':svg:feComponentTransfer^:svg:|', | ||
| ':svg:feComposite^:svg:|', | ||
| ':svg:feConvolveMatrix^:svg:|', | ||
| ':svg:feDiffuseLighting^:svg:|', | ||
| ':svg:feDisplacementMap^:svg:|', | ||
| ':svg:feDistantLight^:svg:|', | ||
| ':svg:feDropShadow^:svg:|', | ||
| ':svg:feFlood^:svg:|', | ||
| ':svg:feFuncA^:svg:componentTransferFunction|', | ||
| ':svg:feFuncB^:svg:componentTransferFunction|', | ||
| ':svg:feFuncG^:svg:componentTransferFunction|', | ||
| ':svg:feFuncR^:svg:componentTransferFunction|', | ||
| ':svg:feGaussianBlur^:svg:|', | ||
| ':svg:feImage^:svg:|', | ||
| ':svg:feMerge^:svg:|', | ||
| ':svg:feMergeNode^:svg:|', | ||
| ':svg:feMorphology^:svg:|', | ||
| ':svg:feOffset^:svg:|', | ||
| ':svg:fePointLight^:svg:|', | ||
| ':svg:feSpecularLighting^:svg:|', | ||
| ':svg:feSpotLight^:svg:|', | ||
| ':svg:feTile^:svg:|', | ||
| ':svg:feTurbulence^:svg:|', | ||
| ':svg:filter^:svg:|', | ||
| ':svg:foreignObject^:svg:graphics|', | ||
| ':svg:g^:svg:graphics|', | ||
| ':svg:image^:svg:graphics|decoding', | ||
| ':svg:line^:svg:geometry|', | ||
| ':svg:linearGradient^:svg:gradient|', | ||
| ':svg:mpath^:svg:|', | ||
| ':svg:marker^:svg:|', | ||
| ':svg:mask^:svg:|', | ||
| ':svg:metadata^:svg:|', | ||
| ':svg:path^:svg:geometry|', | ||
| ':svg:pattern^:svg:|', | ||
| ':svg:polygon^:svg:geometry|', | ||
| ':svg:polyline^:svg:geometry|', | ||
| ':svg:radialGradient^:svg:gradient|', | ||
| ':svg:rect^:svg:geometry|', | ||
| ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan', | ||
| ':svg:script^:svg:|type', | ||
| ':svg:set^:svg:animation|', | ||
| ':svg:stop^:svg:|', | ||
| ':svg:style^:svg:|!disabled,media,title,type', | ||
| ':svg:switch^:svg:graphics|', | ||
| ':svg:symbol^:svg:|', | ||
| ':svg:tspan^:svg:textPositioning|', | ||
| ':svg:text^:svg:textPositioning|', | ||
| ':svg:textPath^:svg:textContent|', | ||
| ':svg:title^:svg:|', | ||
| ':svg:use^:svg:graphics|', | ||
| ':svg:view^:svg:|#zoomAndPan', | ||
| 'data^[HTMLElement]|value', | ||
| 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name', | ||
| 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default', | ||
| 'summary^[HTMLElement]|', | ||
| 'time^[HTMLElement]|dateTime', | ||
| ':svg:cursor^:svg:|', | ||
| ':math:^[HTMLElement]|!autofocus,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforeinput,*beforematch,*beforetoggle,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contentvisibilityautostatechange,*contextlost,*contextmenu,*contextrestored,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*scrollend,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,%style,#tabIndex', | ||
| ':math:math^:math:|', | ||
| ':math:maction^:math:|', | ||
| ':math:menclose^:math:|', | ||
| ':math:merror^:math:|', | ||
| ':math:mfenced^:math:|', | ||
| ':math:mfrac^:math:|', | ||
| ':math:mi^:math:|', | ||
| ':math:mmultiscripts^:math:|', | ||
| ':math:mn^:math:|', | ||
| ':math:mo^:math:|', | ||
| ':math:mover^:math:|', | ||
| ':math:mpadded^:math:|', | ||
| ':math:mphantom^:math:|', | ||
| ':math:mroot^:math:|', | ||
| ':math:mrow^:math:|', | ||
| ':math:ms^:math:|', | ||
| ':math:mspace^:math:|', | ||
| ':math:msqrt^:math:|', | ||
| ':math:mstyle^:math:|', | ||
| ':math:msub^:math:|', | ||
| ':math:msubsup^:math:|', | ||
| ':math:msup^:math:|', | ||
| ':math:mtable^:math:|', | ||
| ':math:mtd^:math:|', | ||
| ':math:mtext^:math:|', | ||
| ':math:mtr^:math:|', | ||
| ':math:munder^:math:|', | ||
| ':math:munderover^:math:|', | ||
| ':math:semantics^:math:|', | ||
| ]; | ||
| const _ATTR_TO_PROP = new Map(Object.entries({ | ||
| 'class': 'className', | ||
| 'for': 'htmlFor', | ||
| 'formaction': 'formAction', | ||
| 'innerHtml': 'innerHTML', | ||
| 'readonly': 'readOnly', | ||
| 'tabindex': 'tabIndex', | ||
| // https://www.w3.org/TR/wai-aria-1.2/#accessibilityroleandproperties-correspondence | ||
| 'aria-atomic': 'ariaAtomic', | ||
| 'aria-autocomplete': 'ariaAutoComplete', | ||
| 'aria-busy': 'ariaBusy', | ||
| 'aria-checked': 'ariaChecked', | ||
| 'aria-colcount': 'ariaColCount', | ||
| 'aria-colindex': 'ariaColIndex', | ||
| 'aria-colspan': 'ariaColSpan', | ||
| 'aria-current': 'ariaCurrent', | ||
| 'aria-disabled': 'ariaDisabled', | ||
| 'aria-expanded': 'ariaExpanded', | ||
| 'aria-haspopup': 'ariaHasPopup', | ||
| 'aria-hidden': 'ariaHidden', | ||
| 'aria-invalid': 'ariaInvalid', | ||
| 'aria-keyshortcuts': 'ariaKeyShortcuts', | ||
| 'aria-label': 'ariaLabel', | ||
| 'aria-level': 'ariaLevel', | ||
| 'aria-live': 'ariaLive', | ||
| 'aria-modal': 'ariaModal', | ||
| 'aria-multiline': 'ariaMultiLine', | ||
| 'aria-multiselectable': 'ariaMultiSelectable', | ||
| 'aria-orientation': 'ariaOrientation', | ||
| 'aria-placeholder': 'ariaPlaceholder', | ||
| 'aria-posinset': 'ariaPosInSet', | ||
| 'aria-pressed': 'ariaPressed', | ||
| 'aria-readonly': 'ariaReadOnly', | ||
| 'aria-required': 'ariaRequired', | ||
| 'aria-roledescription': 'ariaRoleDescription', | ||
| 'aria-rowcount': 'ariaRowCount', | ||
| 'aria-rowindex': 'ariaRowIndex', | ||
| 'aria-rowspan': 'ariaRowSpan', | ||
| 'aria-selected': 'ariaSelected', | ||
| 'aria-setsize': 'ariaSetSize', | ||
| 'aria-sort': 'ariaSort', | ||
| 'aria-valuemax': 'ariaValueMax', | ||
| 'aria-valuemin': 'ariaValueMin', | ||
| 'aria-valuenow': 'ariaValueNow', | ||
| 'aria-valuetext': 'ariaValueText', | ||
| })); | ||
| // Invert _ATTR_TO_PROP. | ||
| const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => { | ||
| inverted.set(propertyName, attributeName); | ||
| return inverted; | ||
| }, new Map()); | ||
| export class DomElementSchemaRegistry extends ElementSchemaRegistry { | ||
| constructor() { | ||
| super(); | ||
| this._schema = new Map(); | ||
| // We don't allow binding to events for security reasons. Allowing event bindings would almost | ||
| // certainly introduce bad XSS vulnerabilities. Instead, we store events in a separate schema. | ||
| this._eventSchema = new Map(); | ||
| SCHEMA.forEach((encodedType) => { | ||
| const type = new Map(); | ||
| const events = new Set(); | ||
| const [strType, strProperties] = encodedType.split('|'); | ||
| const properties = strProperties.split(','); | ||
| const [typeNames, superName] = strType.split('^'); | ||
| typeNames.split(',').forEach((tag) => { | ||
| this._schema.set(tag.toLowerCase(), type); | ||
| this._eventSchema.set(tag.toLowerCase(), events); | ||
| }); | ||
| const superType = superName && this._schema.get(superName.toLowerCase()); | ||
| if (superType) { | ||
| for (const [prop, value] of superType) { | ||
| type.set(prop, value); | ||
| } | ||
| for (const superEvent of this._eventSchema.get(superName.toLowerCase())) { | ||
| events.add(superEvent); | ||
| } | ||
| } | ||
| properties.forEach((property) => { | ||
| if (property.length > 0) { | ||
| switch (property[0]) { | ||
| case '*': | ||
| events.add(property.substring(1)); | ||
| break; | ||
| case '!': | ||
| type.set(property.substring(1), BOOLEAN); | ||
| break; | ||
| case '#': | ||
| type.set(property.substring(1), NUMBER); | ||
| break; | ||
| case '%': | ||
| type.set(property.substring(1), OBJECT); | ||
| break; | ||
| default: | ||
| type.set(property, STRING); | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
| hasProperty(tagName, propName, schemaMetas) { | ||
| if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) { | ||
| return true; | ||
| } | ||
| if (tagName.indexOf('-') > -1) { | ||
| if (isNgContainer(tagName) || isNgContent(tagName)) { | ||
| return false; | ||
| } | ||
| if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) { | ||
| // Can't tell now as we don't know which properties a custom element will get | ||
| // once it is instantiated | ||
| return true; | ||
| } | ||
| } | ||
| const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown'); | ||
| return elementProperties.has(propName); | ||
| } | ||
| hasElement(tagName, schemaMetas) { | ||
| if (schemaMetas.some((schema) => schema.name === NO_ERRORS_SCHEMA.name)) { | ||
| return true; | ||
| } | ||
| if (tagName.indexOf('-') > -1) { | ||
| if (isNgContainer(tagName) || isNgContent(tagName)) { | ||
| return true; | ||
| } | ||
| if (schemaMetas.some((schema) => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) { | ||
| // Allow any custom elements | ||
| return true; | ||
| } | ||
| } | ||
| return this._schema.has(tagName.toLowerCase()); | ||
| } | ||
| /** | ||
| * securityContext returns the security context for the given property on the given DOM tag. | ||
| * | ||
| * Tag and property name are statically known and cannot change at runtime, i.e. it is not | ||
| * possible to bind a value into a changing attribute or tag name. | ||
| * | ||
| * The filtering is based on a list of allowed tags|attributes. All attributes in the schema | ||
| * above are assumed to have the 'NONE' security context, i.e. that they are safe inert | ||
| * string values. Only specific well known attack vectors are assigned their appropriate context. | ||
| */ | ||
| securityContext(tagName, propName, isAttribute) { | ||
| if (isAttribute) { | ||
| // NB: For security purposes, use the mapped property name, not the attribute name. | ||
| propName = this.getMappedPropName(propName); | ||
| } | ||
| // Make sure comparisons are case insensitive, so that case differences between attribute and | ||
| // property names do not have a security impact. | ||
| tagName = tagName.toLowerCase(); | ||
| propName = propName.toLowerCase(); | ||
| let ctx = SECURITY_SCHEMA()[tagName + '|' + propName]; | ||
| if (ctx) { | ||
| return ctx; | ||
| } | ||
| ctx = SECURITY_SCHEMA()['*|' + propName]; | ||
| return ctx ? ctx : SecurityContext.NONE; | ||
| } | ||
| getMappedPropName(propName) { | ||
| return _ATTR_TO_PROP.get(propName) ?? propName; | ||
| } | ||
| getDefaultComponentElementName() { | ||
| return 'ng-component'; | ||
| } | ||
| validateProperty(name) { | ||
| if (name.toLowerCase().startsWith('on')) { | ||
| const msg = `Binding to event property '${name}' is disallowed for security reasons, ` + | ||
| `please use (${name.slice(2)})=...` + | ||
| `\nIf '${name}' is a directive input, make sure the directive is imported by the` + | ||
| ` current module.`; | ||
| return { error: true, msg: msg }; | ||
| } | ||
| else { | ||
| return { error: false }; | ||
| } | ||
| } | ||
| validateAttribute(name) { | ||
| if (name.toLowerCase().startsWith('on')) { | ||
| const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` + | ||
| `please use (${name.slice(2)})=...`; | ||
| return { error: true, msg: msg }; | ||
| } | ||
| else { | ||
| return { error: false }; | ||
| } | ||
| } | ||
| allKnownElementNames() { | ||
| return Array.from(this._schema.keys()); | ||
| } | ||
| allKnownAttributesOfElement(tagName) { | ||
| const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown'); | ||
| // Convert properties to attributes. | ||
| return Array.from(elementProperties.keys()).map((prop) => _PROP_TO_ATTR.get(prop) ?? prop); | ||
| } | ||
| allKnownEventsOfElement(tagName) { | ||
| return Array.from(this._eventSchema.get(tagName.toLowerCase()) ?? []); | ||
| } | ||
| normalizeAnimationStyleProperty(propName) { | ||
| return dashCaseToCamelCase(propName); | ||
| } | ||
| normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) { | ||
| let unit = ''; | ||
| const strVal = val.toString().trim(); | ||
| let errorMsg = null; | ||
| if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') { | ||
| if (typeof val === 'number') { | ||
| unit = 'px'; | ||
| } | ||
| else { | ||
| const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/); | ||
| if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) { | ||
| errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`; | ||
| } | ||
| } | ||
| } | ||
| return { error: errorMsg, value: strVal + unit }; | ||
| } | ||
| } | ||
| function _isPixelDimensionStyle(prop) { | ||
| switch (prop) { | ||
| case 'width': | ||
| case 'height': | ||
| case 'minWidth': | ||
| case 'minHeight': | ||
| case 'maxWidth': | ||
| case 'maxHeight': | ||
| case 'left': | ||
| case 'top': | ||
| case 'bottom': | ||
| case 'right': | ||
| case 'fontSize': | ||
| case 'outlineWidth': | ||
| case 'outlineOffset': | ||
| case 'paddingTop': | ||
| case 'paddingLeft': | ||
| case 'paddingBottom': | ||
| case 'paddingRight': | ||
| case 'marginTop': | ||
| case 'marginLeft': | ||
| case 'marginBottom': | ||
| case 'marginRight': | ||
| case 'borderRadius': | ||
| case 'borderWidth': | ||
| case 'borderTopWidth': | ||
| case 'borderLeftWidth': | ||
| case 'borderRightWidth': | ||
| case 'borderBottomWidth': | ||
| case 'textIndent': | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { SecurityContext } from '../core'; | ||
| export declare function SECURITY_SCHEMA(): { | ||
| [k: string]: SecurityContext; | ||
| }; | ||
| /** | ||
| * The set of security-sensitive attributes of an `<iframe>` that *must* be | ||
| * applied as a static attribute only. This ensures that all security-sensitive | ||
| * attributes are taken into account while creating an instance of an `<iframe>` | ||
| * at runtime. | ||
| * | ||
| * Note: avoid using this set directly, use the `isIframeSecuritySensitiveAttr` function | ||
| * in the code instead. | ||
| */ | ||
| export declare const IFRAME_SECURITY_SENSITIVE_ATTRS: Set<string>; | ||
| /** | ||
| * Checks whether a given attribute name might represent a security-sensitive | ||
| * attribute of an <iframe>. | ||
| */ | ||
| export declare function isIframeSecuritySensitiveAttr(attrName: string): boolean; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { SecurityContext } from "../core.js"; | ||
| // ================================================================================================= | ||
| // ================================================================================================= | ||
| // =========== S T O P - S T O P - S T O P - S T O P - S T O P - S T O P =========== | ||
| // ================================================================================================= | ||
| // ================================================================================================= | ||
| // | ||
| // DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW! | ||
| // Reach out to mprobst for details. | ||
| // | ||
| // ================================================================================================= | ||
| /** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */ | ||
| let _SECURITY_SCHEMA; | ||
| export function SECURITY_SCHEMA() { | ||
| if (!_SECURITY_SCHEMA) { | ||
| _SECURITY_SCHEMA = {}; | ||
| // Case is insignificant below, all element and attribute names are lower-cased for lookup. | ||
| registerContext(SecurityContext.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']); | ||
| registerContext(SecurityContext.STYLE, ['*|style']); | ||
| // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them. | ||
| registerContext(SecurityContext.URL, [ | ||
| '*|formAction', | ||
| 'area|href', | ||
| 'area|ping', | ||
| 'audio|src', | ||
| 'a|href', | ||
| 'a|ping', | ||
| 'blockquote|cite', | ||
| 'body|background', | ||
| 'del|cite', | ||
| 'form|action', | ||
| 'img|src', | ||
| 'input|src', | ||
| 'ins|cite', | ||
| 'q|cite', | ||
| 'source|src', | ||
| 'track|src', | ||
| 'video|poster', | ||
| 'video|src', | ||
| ]); | ||
| registerContext(SecurityContext.RESOURCE_URL, [ | ||
| 'applet|code', | ||
| 'applet|codebase', | ||
| 'base|href', | ||
| 'embed|src', | ||
| 'frame|src', | ||
| 'head|profile', | ||
| 'html|manifest', | ||
| 'iframe|src', | ||
| 'link|href', | ||
| 'media|src', | ||
| 'object|codebase', | ||
| 'object|data', | ||
| 'script|src', | ||
| ]); | ||
| } | ||
| return _SECURITY_SCHEMA; | ||
| } | ||
| function registerContext(ctx, specs) { | ||
| for (const spec of specs) | ||
| _SECURITY_SCHEMA[spec.toLowerCase()] = ctx; | ||
| } | ||
| /** | ||
| * The set of security-sensitive attributes of an `<iframe>` that *must* be | ||
| * applied as a static attribute only. This ensures that all security-sensitive | ||
| * attributes are taken into account while creating an instance of an `<iframe>` | ||
| * at runtime. | ||
| * | ||
| * Note: avoid using this set directly, use the `isIframeSecuritySensitiveAttr` function | ||
| * in the code instead. | ||
| */ | ||
| export const IFRAME_SECURITY_SENSITIVE_ATTRS = new Set([ | ||
| 'sandbox', | ||
| 'allow', | ||
| 'allowfullscreen', | ||
| 'referrerpolicy', | ||
| 'csp', | ||
| 'fetchpriority', | ||
| ]); | ||
| /** | ||
| * Checks whether a given attribute name might represent a security-sensitive | ||
| * attribute of an <iframe>. | ||
| */ | ||
| export function isIframeSecuritySensitiveAttr(attrName) { | ||
| // The `setAttribute` DOM API is case-insensitive, so we lowercase the value | ||
| // before checking it against a known security-sensitive attributes. | ||
| return IFRAME_SECURITY_SENSITIVE_ATTRS.has(attrName.toLowerCase()); | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| import { SchemaMetadata, SecurityContext } from '../core'; | ||
| export declare abstract class ElementSchemaRegistry { | ||
| abstract hasProperty(tagName: string, propName: string, schemaMetas: SchemaMetadata[]): boolean; | ||
| abstract hasElement(tagName: string, schemaMetas: SchemaMetadata[]): boolean; | ||
| abstract securityContext(elementName: string, propName: string, isAttribute: boolean): SecurityContext; | ||
| abstract allKnownElementNames(): string[]; | ||
| abstract getMappedPropName(propName: string): string; | ||
| abstract getDefaultComponentElementName(): string; | ||
| abstract validateProperty(name: string): { | ||
| error: boolean; | ||
| msg?: string; | ||
| }; | ||
| abstract validateAttribute(name: string): { | ||
| error: boolean; | ||
| msg?: string; | ||
| }; | ||
| abstract normalizeAnimationStyleProperty(propName: string): string; | ||
| abstract normalizeAnimationStyleValue(camelCaseProp: string, userProvidedProp: string, val: string | number): { | ||
| error: string; | ||
| value: string; | ||
| }; | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export class ElementSchemaRegistry { | ||
| } |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| export declare function dashCaseToCamelCase(input: string): string; | ||
| export declare function splitAtColon(input: string, defaultValues: (string | null)[]): (string | null)[]; | ||
| export declare function splitAtPeriod(input: string, defaultValues: (string | null)[]): (string | null)[]; | ||
| export declare function noUndefined<T>(val: T | undefined): T; | ||
| export declare function error(msg: string): never; | ||
| export declare function escapeRegExp(s: string): string; | ||
| export type Byte = number; | ||
| export declare function utf8Encode(str: string): Byte[]; | ||
| export declare function stringify(token: any): string; | ||
| export declare class Version { | ||
| full: string; | ||
| readonly major: string; | ||
| readonly minor: string; | ||
| readonly patch: string; | ||
| constructor(full: string); | ||
| } | ||
| export interface Console { | ||
| log(message: string): void; | ||
| warn(message: string): void; | ||
| } | ||
| declare const _global: { | ||
| [name: string]: any; | ||
| }; | ||
| export { _global as global }; | ||
| export declare function getJitStandaloneDefaultForVersion(version: string): boolean; |
| /** | ||
| * @license | ||
| * Copyright Google LLC All Rights Reserved. | ||
| * | ||
| * Use of this source code is governed by an MIT-style license that can be | ||
| * found in the LICENSE file at https://angular.dev/license | ||
| */ | ||
| const DASH_CASE_REGEXP = /-+([a-z0-9])/g; | ||
| export function dashCaseToCamelCase(input) { | ||
| return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase()); | ||
| } | ||
| export function splitAtColon(input, defaultValues) { | ||
| return _splitAt(input, ':', defaultValues); | ||
| } | ||
| export function splitAtPeriod(input, defaultValues) { | ||
| return _splitAt(input, '.', defaultValues); | ||
| } | ||
| function _splitAt(input, character, defaultValues) { | ||
| const characterIndex = input.indexOf(character); | ||
| if (characterIndex == -1) | ||
| return defaultValues; | ||
| return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()]; | ||
| } | ||
| export function noUndefined(val) { | ||
| return val === undefined ? null : val; | ||
| } | ||
| export function error(msg) { | ||
| throw new Error(`Internal Error: ${msg}`); | ||
| } | ||
| // Escape characters that have a special meaning in Regular Expressions | ||
| export function escapeRegExp(s) { | ||
| return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); | ||
| } | ||
| export function utf8Encode(str) { | ||
| let encoded = []; | ||
| for (let index = 0; index < str.length; index++) { | ||
| let codePoint = str.charCodeAt(index); | ||
| // decode surrogate | ||
| // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae | ||
| if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > index + 1) { | ||
| const low = str.charCodeAt(index + 1); | ||
| if (low >= 0xdc00 && low <= 0xdfff) { | ||
| index++; | ||
| codePoint = ((codePoint - 0xd800) << 10) + low - 0xdc00 + 0x10000; | ||
| } | ||
| } | ||
| if (codePoint <= 0x7f) { | ||
| encoded.push(codePoint); | ||
| } | ||
| else if (codePoint <= 0x7ff) { | ||
| encoded.push(((codePoint >> 6) & 0x1f) | 0xc0, (codePoint & 0x3f) | 0x80); | ||
| } | ||
| else if (codePoint <= 0xffff) { | ||
| encoded.push((codePoint >> 12) | 0xe0, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80); | ||
| } | ||
| else if (codePoint <= 0x1fffff) { | ||
| encoded.push(((codePoint >> 18) & 0x07) | 0xf0, ((codePoint >> 12) & 0x3f) | 0x80, ((codePoint >> 6) & 0x3f) | 0x80, (codePoint & 0x3f) | 0x80); | ||
| } | ||
| } | ||
| return encoded; | ||
| } | ||
| export function stringify(token) { | ||
| if (typeof token === 'string') { | ||
| return token; | ||
| } | ||
| if (Array.isArray(token)) { | ||
| return `[${token.map(stringify).join(', ')}]`; | ||
| } | ||
| if (token == null) { | ||
| return '' + token; | ||
| } | ||
| const name = token.overriddenName || token.name; | ||
| if (name) { | ||
| return `${name}`; | ||
| } | ||
| if (!token.toString) { | ||
| return 'object'; | ||
| } | ||
| // WARNING: do not try to `JSON.stringify(token)` here | ||
| // see https://github.com/angular/angular/issues/23440 | ||
| const result = token.toString(); | ||
| if (result == null) { | ||
| return '' + result; | ||
| } | ||
| const newLineIndex = result.indexOf('\n'); | ||
| return newLineIndex >= 0 ? result.slice(0, newLineIndex) : result; | ||
| } | ||
| export class Version { | ||
| constructor(full) { | ||
| this.full = full; | ||
| const splits = full.split('.'); | ||
| this.major = splits[0]; | ||
| this.minor = splits[1]; | ||
| this.patch = splits.slice(2).join('.'); | ||
| } | ||
| } | ||
| const _global = globalThis; | ||
| export { _global as global }; | ||
| const V1_TO_18 = /^([1-9]|1[0-8])\./; | ||
| export function getJitStandaloneDefaultForVersion(version) { | ||
| if (version.startsWith('0.')) { | ||
| // 0.0.0 is always "latest", default is true. | ||
| return true; | ||
| } | ||
| if (V1_TO_18.test(version)) { | ||
| // Angular v2 - v18 default is false. | ||
| return false; | ||
| } | ||
| // All other Angular versions (v19+) default to true. | ||
| return true; | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
8
-33.33%184589
-42.02%6
-86.36%5607
-31.71%1
Infinity%