angular-html-parser
Advanced tools
Comparing version 5.2.0 to 6.0.0
@@ -0,0 +0,0 @@ import { TagContentType } from '../../compiler/src/ml_parser/tags.js'; |
@@ -0,0 +0,0 @@ import { HtmlParser } from "../../compiler/src/ml_parser/html_parser.js"; |
@@ -0,0 +0,0 @@ /** |
@@ -9,2 +9,3 @@ /** | ||
const UNUSABLE_INTERPOLATION_REGEXPS = [ | ||
/@/, | ||
/^\s*$/, | ||
@@ -24,3 +25,3 @@ /[<>]/, | ||
// Check for unusable interpolation symbols | ||
UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => { | ||
UNUSABLE_INTERPOLATION_REGEXPS.forEach((regexp) => { | ||
if (regexp.test(start) || regexp.test(end)) { | ||
@@ -27,0 +28,0 @@ throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`); |
@@ -0,0 +0,0 @@ /** |
@@ -70,3 +70,3 @@ /** | ||
export function isWhitespace(code) { | ||
return (code >= $TAB && code <= $SPACE) || (code == $NBSP); | ||
return (code >= $TAB && code <= $SPACE) || code == $NBSP; | ||
} | ||
@@ -77,6 +77,6 @@ export function isDigit(code) { | ||
export function isAsciiLetter(code) { | ||
return code >= $a && code <= $z || code >= $A && code <= $Z; | ||
return (code >= $a && code <= $z) || (code >= $A && code <= $Z); | ||
} | ||
export function isAsciiHexDigit(code) { | ||
return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code); | ||
return (code >= $a && code <= $f) || (code >= $A && code <= $F) || isDigit(code); | ||
} | ||
@@ -83,0 +83,0 @@ export function isNewLine(code) { |
@@ -22,3 +22,10 @@ /** | ||
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 { | ||
@@ -25,0 +32,0 @@ alias?: string; |
@@ -29,7 +29,14 @@ /** | ||
})(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' | ||
name: 'custom-elements', | ||
}; | ||
export const NO_ERRORS_SCHEMA = { | ||
name: 'no-errors-schema' | ||
name: 'no-errors-schema', | ||
}; | ||
@@ -53,5 +60,5 @@ export const Type = Function; | ||
function parserSelectorToSimpleSelector(selector) { | ||
const classes = selector.classNames && selector.classNames.length ? | ||
[8 /* SelectorFlags.CLASS */, ...selector.classNames] : | ||
[]; | ||
const classes = selector.classNames && selector.classNames.length | ||
? [8 /* SelectorFlags.CLASS */, ...selector.classNames] | ||
: []; | ||
const elementName = selector.element && selector.element !== '*' ? selector.element : ''; | ||
@@ -61,8 +68,11 @@ return [elementName, ...selector.attrs, ...classes]; | ||
function parserSelectorToNegativeSelector(selector) { | ||
const classes = selector.classNames && selector.classNames.length ? | ||
[8 /* SelectorFlags.CLASS */, ...selector.classNames] : | ||
[]; | ||
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 | ||
1 /* SelectorFlags.NOT */ | 4 /* SelectorFlags.ELEMENT */, | ||
selector.element, | ||
...selector.attrs, | ||
...classes, | ||
]; | ||
@@ -74,5 +84,5 @@ } | ||
else { | ||
return selector.classNames && selector.classNames.length ? | ||
[1 /* SelectorFlags.NOT */ | 8 /* SelectorFlags.CLASS */, ...selector.classNames] : | ||
[]; | ||
return selector.classNames && selector.classNames.length | ||
? [1 /* SelectorFlags.NOT */ | 8 /* SelectorFlags.CLASS */, ...selector.classNames] | ||
: []; | ||
} | ||
@@ -82,5 +92,5 @@ } | ||
const positive = parserSelectorToSimpleSelector(selector); | ||
const negative = selector.notSelectors && selector.notSelectors.length ? | ||
selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) : | ||
[]; | ||
const negative = selector.notSelectors && selector.notSelectors.length | ||
? selector.notSelectors.map((notSelector) => parserSelectorToNegativeSelector(notSelector)) | ||
: []; | ||
return positive.concat(...negative); | ||
@@ -87,0 +97,0 @@ } |
@@ -118,2 +118,14 @@ /** | ||
} | ||
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; | ||
} | ||
/** | ||
@@ -133,2 +145,3 @@ * Each HTML node that is affect by an i18n tag will also have an `i18n` property that is of type | ||
visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): any; | ||
visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): any; | ||
} | ||
@@ -142,2 +155,3 @@ export declare class CloneVisitor implements Visitor { | ||
visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): IcuPlaceholder; | ||
visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): BlockPlaceholder; | ||
} | ||
@@ -151,2 +165,3 @@ export declare class RecurseVisitor implements Visitor { | ||
visitIcuPlaceholder(ph: IcuPlaceholder, context?: any): any; | ||
visitBlockPlaceholder(ph: BlockPlaceholder, context?: any): any; | ||
} |
@@ -29,3 +29,4 @@ /** | ||
if (nodes.length) { | ||
this.sources = [{ | ||
this.sources = [ | ||
{ | ||
filePath: nodes[0].sourceSpan.start.file.url, | ||
@@ -35,4 +36,5 @@ startLine: nodes[0].sourceSpan.start.line + 1, | ||
endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1, | ||
endCol: nodes[0].sourceSpan.start.col + 1 | ||
}]; | ||
endCol: nodes[0].sourceSpan.start.col + 1, | ||
}, | ||
]; | ||
} | ||
@@ -113,2 +115,17 @@ else { | ||
} | ||
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 | ||
@@ -120,3 +137,3 @@ export class CloneVisitor { | ||
visitContainer(container, context) { | ||
const children = container.children.map(n => n.visit(this, context)); | ||
const children = container.children.map((n) => n.visit(this, context)); | ||
return new Container(children, container.sourceSpan); | ||
@@ -126,3 +143,3 @@ } | ||
const cases = {}; | ||
Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context)); | ||
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); | ||
@@ -132,3 +149,3 @@ return msg; | ||
visitTagPlaceholder(ph, context) { | ||
const children = ph.children.map(n => n.visit(this, 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); | ||
@@ -142,2 +159,6 @@ } | ||
} | ||
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); | ||
} | ||
} | ||
@@ -148,6 +169,6 @@ // Visit all the nodes recursively | ||
visitContainer(container, context) { | ||
container.children.forEach(child => child.visit(this)); | ||
container.children.forEach((child) => child.visit(this)); | ||
} | ||
visitIcu(icu, context) { | ||
Object.keys(icu.cases).forEach(k => { | ||
Object.keys(icu.cases).forEach((k) => { | ||
icu.cases[k].visit(this); | ||
@@ -157,6 +178,9 @@ }); | ||
visitTagPlaceholder(ph, context) { | ||
ph.children.forEach(child => child.visit(this)); | ||
ph.children.forEach((child) => child.visit(this)); | ||
} | ||
visitPlaceholder(ph, context) { } | ||
visitIcuPlaceholder(ph, context) { } | ||
visitBlockPlaceholder(ph, context) { | ||
ph.children.forEach((child) => child.visit(this)); | ||
} | ||
} | ||
@@ -168,3 +192,3 @@ /** | ||
const visitor = new LocalizeMessageStringVisitor(); | ||
const str = messageNodes.map(n => n.visit(visitor)).join(''); | ||
const str = messageNodes.map((n) => n.visit(visitor)).join(''); | ||
return str; | ||
@@ -177,3 +201,3 @@ } | ||
visitContainer(container) { | ||
return container.children.map(child => child.visit(this)).join(''); | ||
return container.children.map((child) => child.visit(this)).join(''); | ||
} | ||
@@ -185,3 +209,3 @@ visitIcu(icu) { | ||
visitTagPlaceholder(ph) { | ||
const children = ph.children.map(child => child.visit(this)).join(''); | ||
const children = ph.children.map((child) => child.visit(this)).join(''); | ||
return `{$${ph.startName}}${children}{$${ph.closeName}}`; | ||
@@ -195,2 +219,6 @@ } | ||
} | ||
visitBlockPlaceholder(ph) { | ||
const children = ph.children.map((child) => child.visit(this)).join(''); | ||
return `{$${ph.startName}}${children}{$${ph.closeName}}`; | ||
} | ||
} |
@@ -15,3 +15,3 @@ /** | ||
} | ||
export type Node = Attribute | CDATA | Comment | DocType | Element | Text | Block | BlockParameter; | ||
export type Node = Attribute | CDATA | Comment | DocType | Element | Text | Block | BlockParameter | LetDeclaration; | ||
export declare abstract class NodeWithI18n implements BaseNode { | ||
@@ -91,10 +91,10 @@ sourceSpan: ParseSourceSpan; | ||
} | ||
export declare class Block implements BaseNode { | ||
export declare class Block extends NodeWithI18n { | ||
name: string; | ||
parameters: BlockParameter[]; | ||
children: Node[]; | ||
sourceSpan: ParseSourceSpan; | ||
nameSpan: ParseSourceSpan; | ||
startSourceSpan: ParseSourceSpan; | ||
endSourceSpan: ParseSourceSpan | null; | ||
constructor(name: string, parameters: BlockParameter[], children: Node[], sourceSpan: 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; | ||
@@ -112,2 +112,11 @@ readonly type = "block"; | ||
} | ||
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; | ||
} | ||
export interface Visitor { | ||
@@ -125,2 +134,3 @@ visit?(node: Node, context: any): any; | ||
visitBlockParameter(parameter: BlockParameter, context: any): any; | ||
visitLetDeclaration(decl: LetDeclaration, context: any): any; | ||
} | ||
@@ -140,4 +150,5 @@ export declare function visitAll(visitor: Visitor, nodes: Node[], context?: any): any[]; | ||
visitBlockParameter(ast: BlockParameter, context: any): any; | ||
visitLetDeclaration(decl: LetDeclaration, context: any): void; | ||
private visitChildren; | ||
} | ||
export {}; |
@@ -56,3 +56,3 @@ /** | ||
this.expSourceSpan = expSourceSpan; | ||
this.type = "expansionCase"; | ||
this.type = 'expansionCase'; | ||
} | ||
@@ -116,8 +116,9 @@ visit(visitor, context) { | ||
} | ||
export class Block { | ||
constructor(name, parameters, children, sourceSpan, startSourceSpan, endSourceSpan = null) { | ||
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.sourceSpan = sourceSpan; | ||
this.nameSpan = nameSpan; | ||
this.startSourceSpan = startSourceSpan; | ||
@@ -143,8 +144,20 @@ this.endSourceSpan = endSourceSpan; | ||
} | ||
export class LetDeclaration { | ||
constructor(name, value, sourceSpan, nameSpan, valueSpan) { | ||
this.name = name; | ||
this.value = value; | ||
this.sourceSpan = sourceSpan; | ||
this.nameSpan = nameSpan; | ||
this.valueSpan = valueSpan; | ||
} | ||
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 visit = visitor.visit | ||
? (ast) => visitor.visit(ast, context) || ast.visit(visitor, context) | ||
: (ast) => ast.visit(visitor, context); | ||
nodes.forEach((ast) => { | ||
const astResult = visit(ast); | ||
@@ -160,3 +173,3 @@ if (astResult) { | ||
visitElement(ast, context) { | ||
this.visitChildren(context, visit => { | ||
this.visitChildren(context, (visit) => { | ||
visit(ast.attrs); | ||
@@ -172,3 +185,3 @@ visit(ast.children); | ||
visitExpansion(ast, context) { | ||
return this.visitChildren(context, visit => { | ||
return this.visitChildren(context, (visit) => { | ||
visit(ast.cases); | ||
@@ -179,3 +192,3 @@ }); | ||
visitBlock(block, context) { | ||
this.visitChildren(context, visit => { | ||
this.visitChildren(context, (visit) => { | ||
visit(block.parameters); | ||
@@ -186,2 +199,3 @@ visit(block.children); | ||
visitBlockParameter(ast, context) { } | ||
visitLetDeclaration(decl, context) { } | ||
visitChildren(context, cb) { | ||
@@ -188,0 +202,0 @@ let results = []; |
@@ -0,0 +0,0 @@ /** |
@@ -2137,3 +2137,3 @@ /** | ||
'zwj': '\u200D', | ||
'zwnj': '\u200C' | ||
'zwnj': '\u200C', | ||
}; | ||
@@ -2140,0 +2140,0 @@ // The &ngsp; pseudo-entity is denoting a space. |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -15,3 +15,3 @@ /** | ||
if (closedByChildren && closedByChildren.length > 0) { | ||
closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true); | ||
closedByChildren.forEach((tagName) => (this.closedByChildren[tagName] = true)); | ||
} | ||
@@ -60,8 +60,30 @@ this.isVoid = isVoid; | ||
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' | ||
'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 | ||
closedByParent: true, | ||
}), | ||
@@ -91,8 +113,20 @@ 'thead': new HtmlTagDefinition({ closedByChildren: ['tbody', 'tfoot'] }), | ||
'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 }), | ||
'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 }), | ||
'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 }), | ||
'option': new HtmlTagDefinition({ | ||
closedByChildren: ['option', 'optgroup'], | ||
closedByParent: true, | ||
}), | ||
'pre': new HtmlTagDefinition({ ignoreFirstLf: true }), | ||
@@ -105,7 +139,13 @@ 'listing': new HtmlTagDefinition({ ignoreFirstLf: true }), | ||
// a different content type: `HTMLTitleElement` and `SVGTitleElement` | ||
contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA } | ||
contentType: { | ||
default: TagContentType.ESCAPABLE_RAW_TEXT, | ||
svg: TagContentType.PARSABLE_DATA, | ||
}, | ||
}), | ||
'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }), | ||
'textarea': new HtmlTagDefinition({ | ||
contentType: TagContentType.ESCAPABLE_RAW_TEXT, | ||
ignoreFirstLf: true, | ||
}), | ||
}); | ||
new DomElementSchemaRegistry().allKnownElementNames().forEach(knownTagName => { | ||
new DomElementSchemaRegistry().allKnownElementNames().forEach((knownTagName) => { | ||
if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) { | ||
@@ -118,5 +158,5 @@ TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({ canSelfClose: false }); | ||
// HTML tag names are case insensitive, whereas some SVG tags are case sensitive. | ||
return TAG_DEFINITIONS[tagName] ?? // TAG_DEFINITIONS[tagName.toLowerCase()] ?? -- | ||
// angular-html-parser modification | ||
DEFAULT_TAG_DEFINITION; | ||
return (TAG_DEFINITIONS[tagName] ?? | ||
// TAG_DEFINITIONS[tagName.toLowerCase()] ?? -- angular-html-parser modification | ||
DEFAULT_TAG_DEFINITION); | ||
} |
@@ -9,3 +9,3 @@ /** | ||
import { ParseError, ParseSourceSpan } from "../parse_util.js"; | ||
import { InterpolationConfig } from "./interpolation_config.js"; | ||
import { InterpolationConfig } from "./defaults.js"; | ||
import { TagContentType } from "./tags.js"; | ||
@@ -90,2 +90,7 @@ import { Token, TokenType } from "./tokens.js"; | ||
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; | ||
canSelfClose?: boolean; | ||
@@ -92,0 +97,0 @@ allowHtmComponentClosingTags?: boolean; |
@@ -10,4 +10,4 @@ /** | ||
import { ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan } from "../parse_util.js"; | ||
import { DEFAULT_INTERPOLATION_CONFIG } from "./defaults.js"; | ||
import { NAMED_ENTITIES } from "./entities.js"; | ||
import { DEFAULT_INTERPOLATION_CONFIG } from "./interpolation_config.js"; | ||
import { mergeNsAndName, TagContentType } from "./tags.js"; | ||
@@ -74,11 +74,18 @@ export class TokenError extends ParseError { | ||
this._leadingTriviaCodePoints = | ||
options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0); | ||
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); | ||
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; | ||
try { | ||
@@ -134,7 +141,18 @@ this._cursor.init(); | ||
} | ||
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._attemptStr('@let')) { | ||
this._consumeLetDeclaration(start); | ||
} | ||
else if (this._tokenizeBlocks && this._attemptCharCode(chars.$AT)) { | ||
this._consumeBlockStart(start); | ||
} | ||
else if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansionCase() && | ||
!this._isInExpansionForm() && this._attemptCharCode(chars.$RBRACE)) { | ||
else if (this._tokenizeBlocks && | ||
!this._inInterpolation && | ||
!this._isInExpansionCase() && | ||
!this._isInExpansionForm() && | ||
this._attemptCharCode(chars.$RBRACE)) { | ||
this._consumeBlockEnd(start); | ||
@@ -152,3 +170,3 @@ } | ||
} | ||
this._beginToken(30 /* TokenType.EOF */); | ||
this._beginToken(34 /* TokenType.EOF */); | ||
this._endToken([]); | ||
@@ -160,3 +178,3 @@ } | ||
const nameCursor = this._cursor.clone(); | ||
this._attemptCharCodeUntilFn(code => { | ||
this._attemptCharCodeUntilFn((code) => { | ||
if (chars.isWhitespace(code)) { | ||
@@ -245,2 +263,76 @@ return !spacesInNameAllowed; | ||
} | ||
_consumeLetDeclaration(start) { | ||
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)]); | ||
} | ||
/** | ||
@@ -525,4 +617,6 @@ * @returns whether an ICU token has been created | ||
this._attemptCharCodeUntilFn(isNotWhitespace); | ||
while (this._cursor.peek() !== chars.$SLASH && this._cursor.peek() !== chars.$GT && | ||
this._cursor.peek() !== chars.$LT && this._cursor.peek() !== chars.$EOF) { | ||
while (this._cursor.peek() !== chars.$SLASH && | ||
this._cursor.peek() !== chars.$GT && | ||
this._cursor.peek() !== chars.$LT && | ||
this._cursor.peek() !== chars.$EOF) { | ||
const [prefix, name] = this._consumeAttributeName(); | ||
@@ -584,3 +678,3 @@ this._attemptCharCodeUntilFn(isNotWhitespace); | ||
this._beginToken(3 /* TokenType.TAG_CLOSE */); | ||
this._requireCharCodeUntilFn(code => code === chars.$GT, 3); | ||
this._requireCharCodeUntilFn((code) => code === chars.$GT, 3); | ||
this._cursor.advance(); // Consume the `>` | ||
@@ -628,3 +722,5 @@ this._endToken([prefix, tagName]); | ||
_consumeTagOpenEnd() { | ||
const tokenType = this._attemptCharCode(chars.$SLASH) ? 2 /* TokenType.TAG_OPEN_END_VOID */ : 1 /* TokenType.TAG_OPEN_END */; | ||
const tokenType = this._attemptCharCode(chars.$SLASH) | ||
? 2 /* TokenType.TAG_OPEN_END_VOID */ | ||
: 1 /* TokenType.TAG_OPEN_END */; | ||
this._beginToken(tokenType); | ||
@@ -821,4 +917,6 @@ this._requireCharCode(chars.$GT); | ||
} | ||
if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansion() && | ||
(this._isBlockStart() || this._cursor.peek() === chars.$RBRACE)) { | ||
if (this._tokenizeBlocks && | ||
!this._inInterpolation && | ||
!this._isInExpansion() && | ||
(this._isBlockStart() || this._cursor.peek() === chars.$AT || this._cursor.peek() === chars.$RBRACE)) { | ||
return true; | ||
@@ -839,4 +937,6 @@ } | ||
const code = tmp.peek(); | ||
if ((chars.$a <= code && code <= chars.$z) || (chars.$A <= code && code <= chars.$Z) || | ||
code === chars.$SLASH || code === chars.$BANG) { | ||
if ((chars.$a <= code && code <= chars.$z) || | ||
(chars.$A <= code && code <= chars.$Z) || | ||
code === chars.$SLASH || | ||
code === chars.$BANG) { | ||
return true; | ||
@@ -867,10 +967,8 @@ } | ||
_isInExpansionCase() { | ||
return this._expansionCaseStack.length > 0 && | ||
this._expansionCaseStack[this._expansionCaseStack.length - 1] === | ||
22 /* TokenType.EXPANSION_CASE_EXP_START */; | ||
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 */; | ||
return (this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === | ||
20) /* TokenType.EXPANSION_FORM_START */; | ||
} | ||
@@ -908,9 +1006,15 @@ isExpansionFormStart() { | ||
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; | ||
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); | ||
return ((code < chars.$a || chars.$z < code) && | ||
(code < chars.$A || chars.$Z < code) && | ||
(code < chars.$0 || code > chars.$9)); | ||
} | ||
@@ -944,3 +1048,4 @@ function isDigitEntityEnd(code) { | ||
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 && | ||
lastDstToken.type === 16 /* TokenType.ATTR_VALUE_TEXT */ && token.type === 16) /* TokenType.ATTR_VALUE_TEXT */)) { | ||
lastDstToken.parts[0] += token.parts[0]; | ||
@@ -947,0 +1052,0 @@ lastDstToken.sourceSpan.end = token.sourceSpan.end; |
@@ -0,0 +0,0 @@ /** |
@@ -65,3 +65,3 @@ /** | ||
build() { | ||
while (this._peek.type !== 30 /* TokenType.EOF */) { | ||
while (this._peek.type !== 34 /* TokenType.EOF */) { | ||
if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ || | ||
@@ -83,3 +83,4 @@ this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) { | ||
} | ||
else if (this._peek.type === 5 /* TokenType.TEXT */ || this._peek.type === 7 /* TokenType.RAW_TEXT */ || | ||
else if (this._peek.type === 5 /* TokenType.TEXT */ || | ||
this._peek.type === 7 /* TokenType.RAW_TEXT */ || | ||
this._peek.type === 6 /* TokenType.ESCAPABLE_RAW_TEXT */) { | ||
@@ -104,5 +105,13 @@ this._closeVoidElement(); | ||
} | ||
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 { | ||
@@ -141,7 +150,9 @@ // Skip all other tokens... | ||
} | ||
_consumeComment(startToken) { | ||
_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 = new ParseSourceSpan(startToken.sourceSpan.start, (endToken || text || startToken).sourceSpan.end); | ||
const sourceSpan = endToken == null | ||
? token.sourceSpan | ||
: new ParseSourceSpan(token.sourceSpan.start, endToken.sourceSpan.end, token.sourceSpan.fullStart); | ||
this._addToParent(new html.Comment(value, sourceSpan)); | ||
@@ -189,3 +200,3 @@ } | ||
const end = this._advance(); | ||
exp.push({ type: 30 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan }); | ||
exp.push({ type: 34 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan }); | ||
// parse everything in between { and } | ||
@@ -230,3 +241,3 @@ const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition, this.canSelfClose, this.allowHtmComponentClosingTags, this.isTagNameCaseSensitive); | ||
} | ||
if (this._peek.type === 30 /* TokenType.EOF */) { | ||
if (this._peek.type === 34 /* TokenType.EOF */) { | ||
this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
@@ -255,3 +266,4 @@ return null; | ||
const parent = this._getContainer(); | ||
if (parent != null && parent.children.length === 0 && | ||
if (parent != null && | ||
parent.children.length === 0 && | ||
this.getTagDefinition(parent.name).ignoreFirstLf) { | ||
@@ -262,3 +274,4 @@ text = text.substring(1); | ||
} | ||
while (this._peek.type === 8 /* TokenType.INTERPOLATION */ || this._peek.type === 5 /* TokenType.TEXT */ || | ||
while (this._peek.type === 8 /* TokenType.INTERPOLATION */ || | ||
this._peek.type === 5 /* TokenType.TEXT */ || | ||
this._peek.type === 9 /* TokenType.ENCODED_ENTITY */) { | ||
@@ -306,4 +319,3 @@ token = this._advance(); | ||
const tagDef = this.getTagDefinition(fullName); | ||
if (!(this.canSelfClose || tagDef.canSelfClose || getNsPrefix(fullName) !== null || | ||
tagDef.isVoid)) { | ||
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]}"`)); | ||
@@ -380,3 +392,3 @@ } | ||
if (node instanceof html.Block || | ||
node instanceof html.Element && !this.getTagDefinition(node.name).closedByParent) { | ||
(node instanceof html.Element && !this.getTagDefinition(node.name).closedByParent)) { | ||
// Note that we encountered an unexpected close tag but continue processing the element | ||
@@ -437,3 +449,4 @@ // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this | ||
} | ||
const valueSpan = valueStartSpan && valueEnd && | ||
const valueSpan = valueStartSpan && | ||
valueEnd && | ||
new ParseSourceSpan(startQuoteToken?.sourceSpan.start ?? valueStartSpan.start, valueEnd, startQuoteToken?.sourceSpan.fullStart ?? valueStartSpan.fullStart); | ||
@@ -455,3 +468,3 @@ return new html.Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined); | ||
const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
const block = new html.Block(token.parts[0], parameters, [], span, startSpan); | ||
const block = new html.Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan); | ||
this._pushContainer(block, false); | ||
@@ -476,3 +489,3 @@ } | ||
const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
const block = new html.Block(token.parts[0], parameters, [], span, startSpan); | ||
const block = new html.Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan); | ||
this._pushContainer(block, false); | ||
@@ -484,5 +497,51 @@ // Incomplete blocks don't have children so we close them immediately and report an error. | ||
} | ||
_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; | ||
return this._containerStack.length > 0 | ||
? this._containerStack[this._containerStack.length - 1] | ||
: null; | ||
} | ||
@@ -489,0 +548,0 @@ _getClosestParentElement() { |
@@ -23,3 +23,3 @@ /** | ||
} | ||
export declare function splitNsName(elementName: string): [string | null, string]; | ||
export declare function splitNsName(elementName: string, fatal?: boolean): [string | null, string]; | ||
export declare function isNgContainer(tagName: string): boolean; | ||
@@ -26,0 +26,0 @@ export declare function isNgContent(tagName: string): boolean; |
@@ -14,3 +14,3 @@ /** | ||
})(TagContentType || (TagContentType = {})); | ||
export function splitNsName(elementName) { | ||
export function splitNsName(elementName, fatal = true) { | ||
if (elementName[0] != ':') { | ||
@@ -21,3 +21,8 @@ return [null, elementName]; | ||
if (colonIndex === -1) { | ||
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`); | ||
if (fatal) { | ||
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`); | ||
} | ||
else { | ||
return [null, elementName]; | ||
} | ||
} | ||
@@ -24,0 +29,0 @@ return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)]; |
@@ -40,5 +40,9 @@ /** | ||
INCOMPLETE_BLOCK_OPEN = 29, | ||
EOF = 30 | ||
LET_START = 30, | ||
LET_VALUE = 31, | ||
LET_END = 32, | ||
INCOMPLETE_LET = 33, | ||
EOF = 34 | ||
} | ||
export type Token = TagOpenStartToken | TagOpenEndToken | TagOpenEndVoidToken | TagCloseToken | IncompleteTagOpenToken | TextToken | InterpolationToken | EncodedEntityToken | CommentStartToken | CommentEndToken | CdataStartToken | CdataEndToken | AttributeNameToken | AttributeQuoteToken | AttributeValueTextToken | AttributeValueInterpolationToken | DocTypeStartToken | DocTypeEndToken | ExpansionFormStartToken | ExpansionCaseValueToken | ExpansionCaseExpressionStartToken | ExpansionCaseExpressionEndToken | ExpansionFormEndToken | EndOfFileToken | BlockParameterToken | BlockOpenStartToken | BlockOpenEndToken | BlockCloseToken | IncompleteBlockOpenToken; | ||
export type Token = TagOpenStartToken | TagOpenEndToken | TagOpenEndVoidToken | TagCloseToken | IncompleteTagOpenToken | TextToken | InterpolationToken | EncodedEntityToken | CommentStartToken | CommentEndToken | CdataStartToken | CdataEndToken | AttributeNameToken | AttributeQuoteToken | AttributeValueTextToken | AttributeValueInterpolationToken | ExpansionFormStartToken | ExpansionCaseValueToken | ExpansionCaseExpressionStartToken | ExpansionCaseExpressionEndToken | ExpansionFormEndToken | EndOfFileToken | BlockParameterToken | BlockOpenStartToken | BlockOpenEndToken | BlockCloseToken | IncompleteBlockOpenToken | LetStartToken | LetValueToken | LetEndToken | IncompleteLetToken | DocTypeStartToken; | ||
export type InterpolatedTextToken = TextToken | InterpolationToken | EncodedEntityToken; | ||
@@ -77,6 +81,3 @@ export type InterpolatedAttributeToken = AttributeValueTextToken | AttributeValueInterpolationToken | EncodedEntityToken; | ||
type: TokenType.INTERPOLATION; | ||
parts: [startMarker: string, expression: string, endMarker: string] | [ | ||
startMarker: string, | ||
expression: string | ||
]; | ||
parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
} | ||
@@ -109,3 +110,3 @@ export interface EncodedEntityToken extends TokenBase { | ||
type: TokenType.ATTR_QUOTE; | ||
parts: [quote: '\'' | '"']; | ||
parts: [quote: "'" | '"']; | ||
} | ||
@@ -118,6 +119,3 @@ export interface AttributeValueTextToken extends TokenBase { | ||
type: TokenType.ATTR_VALUE_INTERPOLATION; | ||
parts: [startMarker: string, expression: string, endMarker: string] | [ | ||
startMarker: string, | ||
expression: string | ||
]; | ||
parts: [startMarker: string, expression: string, endMarker: string] | [startMarker: string, expression: string]; | ||
} | ||
@@ -176,1 +174,17 @@ export interface DocTypeStartToken extends TokenBase { | ||
} | ||
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]; | ||
} |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ export declare class ParseLocation { |
@@ -32,3 +32,5 @@ /** | ||
line--; | ||
const priorLine = source.substring(0, offset - 1).lastIndexOf(String.fromCharCode(chars.$LF)); | ||
const priorLine = source | ||
.substring(0, offset - 1) | ||
.lastIndexOf(String.fromCharCode(chars.$LF)); | ||
col = priorLine > 0 ? offset - priorLine : offset; | ||
@@ -147,4 +149,5 @@ } | ||
const ctx = this.span.start.getContext(100, 3); | ||
return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` : | ||
this.msg; | ||
return ctx | ||
? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` | ||
: this.msg; | ||
} | ||
@@ -151,0 +154,0 @@ toString() { |
@@ -0,0 +0,0 @@ /** |
@@ -75,3 +75,3 @@ /** | ||
',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored', | ||
'[HTMLElement]^[Element]|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', | ||
'[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,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', | ||
@@ -227,2 +227,32 @@ 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,!preservesPitch,src,%srcObject,#volume', | ||
':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:|', | ||
]; | ||
@@ -248,4 +278,4 @@ const _ATTR_TO_PROP = new Map(Object.entries({ | ||
// certainly introduce bad XSS vulnerabilities. Instead, we store events in a separate schema. | ||
this._eventSchema = new Map; | ||
SCHEMA.forEach(encodedType => { | ||
this._eventSchema = new Map(); | ||
SCHEMA.forEach((encodedType) => { | ||
const type = new Map(); | ||
@@ -256,3 +286,3 @@ const events = new Set(); | ||
const [typeNames, superName] = strType.split('^'); | ||
typeNames.split(',').forEach(tag => { | ||
typeNames.split(',').forEach((tag) => { | ||
this._schema.set(tag.toLowerCase(), type); | ||
@@ -384,3 +414,3 @@ this._eventSchema.set(tag.toLowerCase(), events); | ||
// Convert properties to attributes. | ||
return Array.from(elementProperties.keys()).map(prop => _PROP_TO_ATTR.get(prop) ?? prop); | ||
return Array.from(elementProperties.keys()).map((prop) => _PROP_TO_ATTR.get(prop) ?? prop); | ||
} | ||
@@ -387,0 +417,0 @@ allKnownEventsOfElement(tagName) { |
@@ -0,0 +0,0 @@ /** |
@@ -25,7 +25,3 @@ /** | ||
// Case is insignificant below, all element and attribute names are lower-cased for lookup. | ||
registerContext(SecurityContext.HTML, [ | ||
'iframe|srcdoc', | ||
'*|innerHTML', | ||
'*|outerHTML', | ||
]); | ||
registerContext(SecurityContext.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']); | ||
registerContext(SecurityContext.STYLE, ['*|style']); | ||
@@ -84,3 +80,10 @@ // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them. | ||
*/ | ||
export const IFRAME_SECURITY_SENSITIVE_ATTRS = new Set(['sandbox', 'allow', 'allowfullscreen', 'referrerpolicy', 'csp', 'fetchpriority']); | ||
export const IFRAME_SECURITY_SENSITIVE_ATTRS = new Set([ | ||
'sandbox', | ||
'allow', | ||
'allowfullscreen', | ||
'referrerpolicy', | ||
'csp', | ||
'fetchpriority', | ||
]); | ||
/** | ||
@@ -87,0 +90,0 @@ * Checks whether a given attribute name might represent a security-sensitive |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -12,3 +12,3 @@ /** | ||
// 4: attribute; 5: attribute_string; 6: attribute_value | ||
'(?:\\[([-.\\w*\\\\$]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' + // "[name]", "[name=value]", | ||
'(?:\\[([-.\\w*\\\\$]+)(?:=(["\']?)([^\\]"\']*)\\5)?\\])|' + // "[name]", "[name=value]", | ||
// "[name="value"]", | ||
@@ -45,3 +45,5 @@ // "[name='value']" | ||
const _addResult = (res, cssSel) => { | ||
if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 && | ||
if (cssSel.notSelectors.length > 0 && | ||
!cssSel.element && | ||
cssSel.classNames.length == 0 && | ||
cssSel.attrs.length == 0) { | ||
@@ -57,3 +59,3 @@ cssSel.element = '*'; | ||
_SELECTOR_REGEXP.lastIndex = 0; | ||
while (match = _SELECTOR_REGEXP.exec(selector)) { | ||
while ((match = _SELECTOR_REGEXP.exec(selector))) { | ||
if (match[1 /* SelectorRegexp.NOT */]) { | ||
@@ -144,4 +146,6 @@ if (inNot) { | ||
isElementSelector() { | ||
return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 && | ||
this.notSelectors.length === 0; | ||
return (this.hasElementSelector() && | ||
this.classNames.length == 0 && | ||
this.attrs.length == 0 && | ||
this.notSelectors.length === 0); | ||
} | ||
@@ -162,3 +166,3 @@ hasElementSelector() { | ||
addAttribute(name, value = '') { | ||
this.attrs.push(name, value && value.toLowerCase() || ''); | ||
this.attrs.push(name, (value && value.toLowerCase()) || ''); | ||
} | ||
@@ -171,3 +175,3 @@ addClassName(name) { | ||
if (this.classNames) { | ||
this.classNames.forEach(klass => res += `.${klass}`); | ||
this.classNames.forEach((klass) => (res += `.${klass}`)); | ||
} | ||
@@ -181,3 +185,3 @@ if (this.attrs) { | ||
} | ||
this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`); | ||
this.notSelectors.forEach((notSelector) => (res += `:not(${notSelector})`)); | ||
return res; | ||
@@ -305,4 +309,4 @@ } | ||
result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result; | ||
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || | ||
result; | ||
result = | ||
this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result; | ||
if (classNames) { | ||
@@ -309,0 +313,0 @@ for (let i = 0; i < classNames.length; i++) { |
@@ -0,0 +0,0 @@ /** |
@@ -40,3 +40,3 @@ /** | ||
// see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae | ||
if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > (index + 1)) { | ||
if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > index + 1) { | ||
const low = str.charCodeAt(index + 1); | ||
@@ -52,3 +52,3 @@ if (low >= 0xdc00 && low <= 0xdfff) { | ||
else if (codePoint <= 0x7ff) { | ||
encoded.push(((codePoint >> 6) & 0x1F) | 0xc0, (codePoint & 0x3f) | 0x80); | ||
encoded.push(((codePoint >> 6) & 0x1f) | 0xc0, (codePoint & 0x3f) | 0x80); | ||
} | ||
@@ -55,0 +55,0 @@ else if (codePoint <= 0xffff) { |
{ | ||
"name": "angular-html-parser", | ||
"version": "5.2.0", | ||
"version": "6.0.0", | ||
"description": "A HTML parser extracted from Angular with some modifications", | ||
@@ -5,0 +5,0 @@ "main": "./lib/angular-html-parser/src/index.js", |
@@ -0,0 +0,0 @@ # angular-html-parser |
@@ -0,0 +0,0 @@ This project incorporates third party material from the projects listed below. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
295630
7672
1
5