angular-html-parser
Advanced tools
@@ -49,3 +49,4 @@ import { mergeNsAndName } from "./tags.mjs"; | ||
| "@loading", | ||
| "@error" | ||
| "@error", | ||
| "@content" | ||
| ]; | ||
@@ -63,2 +64,3 @@ const INTERPOLATION = { | ||
| _allowHtmComponentClosingTags; | ||
| _allowInElementComments; | ||
| _currentTokenStart = null; | ||
@@ -90,2 +92,3 @@ _currentTokenType = null; | ||
| this._allowHtmComponentClosingTags = options.allowHtmComponentClosingTags || false; | ||
| this._allowInElementComments = options.allowInElementComments ?? true; | ||
| const range = options.range || { | ||
@@ -137,3 +140,3 @@ endPos: _file.content.length, | ||
| } | ||
| this._beginToken(42); | ||
| this._beginToken(43); | ||
| this._endToken([]); | ||
@@ -156,3 +159,3 @@ } | ||
| this._requireCharCode(64); | ||
| this._beginToken(25, start); | ||
| this._beginToken(26, start); | ||
| const startToken = this._endToken([this._getBlockName()]); | ||
@@ -165,3 +168,3 @@ if (this._cursor.peek() === 40) { | ||
| else { | ||
| startToken.type = 29; | ||
| startToken.type = 30; | ||
| return; | ||
@@ -171,20 +174,20 @@ } | ||
| if (startToken.parts[0] === "default never" && this._attemptCharCode(59)) { | ||
| this._beginToken(26); | ||
| this._endToken([]); | ||
| this._beginToken(27); | ||
| this._endToken([]); | ||
| this._beginToken(28); | ||
| this._endToken([]); | ||
| return; | ||
| } | ||
| if (this._attemptCharCode(123)) { | ||
| this._beginToken(26); | ||
| this._beginToken(27); | ||
| this._endToken([]); | ||
| } else if (this._isBlockStart() && (startToken.parts[0] === "case" || startToken.parts[0] === "default")) { | ||
| this._beginToken(26); | ||
| this._endToken([]); | ||
| this._beginToken(27); | ||
| this._endToken([]); | ||
| } else startToken.type = 29; | ||
| this._beginToken(28); | ||
| this._endToken([]); | ||
| } else startToken.type = 30; | ||
| } | ||
| _consumeBlockEnd(start) { | ||
| this._beginToken(27, start); | ||
| this._beginToken(28, start); | ||
| this._endToken([]); | ||
@@ -195,3 +198,3 @@ } | ||
| while (this._cursor.peek() !== 41 && this._cursor.peek() !== 0) { | ||
| this._beginToken(28); | ||
| this._beginToken(29); | ||
| const start = this._cursor.clone(); | ||
@@ -218,7 +221,7 @@ let inQuote = null; | ||
| this._requireStr("@let"); | ||
| this._beginToken(30, start); | ||
| this._beginToken(31, start); | ||
| if (isWhitespace(this._cursor.peek())) this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| else { | ||
| const token = this._endToken([this._cursor.getChars(start)]); | ||
| token.type = 33; | ||
| token.type = 34; | ||
| return; | ||
@@ -229,3 +232,3 @@ } | ||
| if (!this._attemptCharCode(61)) { | ||
| startToken.type = 33; | ||
| startToken.type = 34; | ||
| return; | ||
@@ -236,7 +239,7 @@ } | ||
| if (this._cursor.peek() === 59) { | ||
| this._beginToken(32); | ||
| this._beginToken(33); | ||
| this._cursor.advance(); | ||
| this._endToken([]); | ||
| } else { | ||
| startToken.type = 33; | ||
| startToken.type = 34; | ||
| startToken.sourceSpan = this._cursor.getSpan(start); | ||
@@ -259,3 +262,3 @@ } | ||
| const start = this._cursor.clone(); | ||
| this._beginToken(31, start); | ||
| this._beginToken(32, start); | ||
| while (this._cursor.peek() !== 0) { | ||
@@ -475,6 +478,6 @@ const char = this._cursor.peek(); | ||
| _consumeCdata(start) { | ||
| this._beginToken(12, start); | ||
| this._beginToken(13, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._attemptStr("]]>")); | ||
| this._beginToken(13); | ||
| this._beginToken(14); | ||
| this._requireStr("]]>"); | ||
@@ -484,6 +487,6 @@ this._endToken([]); | ||
| _consumeDocType(start) { | ||
| this._beginToken(18, start); | ||
| this._beginToken(19, start); | ||
| this._endToken([]); | ||
| this._consumeRawText(false, () => this._cursor.peek() === 62); | ||
| this._beginToken(19); | ||
| this._beginToken(20); | ||
| this._cursor.advance(); | ||
@@ -506,7 +509,13 @@ this._endToken([]); | ||
| } | ||
| _consumeSingleLineComment() { | ||
| _consumeSingleLineComment(start) { | ||
| const contentStart = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn((code) => isNewLine(code) || code === 0); | ||
| const spanEnd = this._cursor.clone(); | ||
| const content = spanEnd.getChars(contentStart); | ||
| this._beginToken(12, start); | ||
| this._endToken([content], spanEnd); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| _consumeMultiLineComment() { | ||
| _consumeMultiLineComment(start) { | ||
| const contentStart = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn((code) => { | ||
@@ -521,3 +530,11 @@ if (code === 0) return true; | ||
| }); | ||
| if (this._attemptStr("*/")) this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| const contentEnd = this._cursor.clone(); | ||
| const content = contentEnd.getChars(contentStart); | ||
| let spanEnd = contentEnd; | ||
| if (this._attemptStr("*/")) { | ||
| spanEnd = this._cursor.clone(); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| } | ||
| this._beginToken(12, start); | ||
| this._endToken([content], spanEnd); | ||
| } | ||
@@ -545,10 +562,13 @@ _consumeTagOpen(start) { | ||
| while (true) { | ||
| if (this._attemptStr("//")) { | ||
| this._consumeSingleLineComment(); | ||
| continue; | ||
| if (this._allowInElementComments) { | ||
| const commentStart = this._cursor.clone(); | ||
| if (this._attemptStr("//")) { | ||
| this._consumeSingleLineComment(commentStart); | ||
| continue; | ||
| } | ||
| if (this._attemptStr("/*")) { | ||
| this._consumeMultiLineComment(commentStart); | ||
| continue; | ||
| } | ||
| } | ||
| if (this._attemptStr("/*")) { | ||
| this._consumeMultiLineComment(); | ||
| continue; | ||
| } | ||
| if (isAttributeTerminator(this._cursor.peek())) break; | ||
@@ -565,7 +585,7 @@ if (this._selectorlessEnabled && this._cursor.peek() === 64) { | ||
| } | ||
| if (openToken.type === 34) this._consumeComponentOpenEnd(); | ||
| if (openToken.type === 35) this._consumeComponentOpenEnd(); | ||
| else this._consumeTagOpenEnd(); | ||
| } catch (e) { | ||
| if (e instanceof ParseError) { | ||
| if (openToken) openToken.type = openToken.type === 34 ? 38 : 4; | ||
| if (openToken) openToken.type = openToken.type === 35 ? 39 : 4; | ||
| else { | ||
@@ -590,7 +610,7 @@ this._beginToken(5, start); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| if (!this._attemptStrCaseInsensitive(prefix && openToken.type !== 34 ? `${prefix}:${tagName}` : tagName)) return false; | ||
| if (!this._attemptStrCaseInsensitive(prefix && openToken.type !== 35 ? `${prefix}:${tagName}` : tagName)) return false; | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| return this._attemptCharCode(62); | ||
| }); | ||
| this._beginToken(openToken.type === 34 ? 37 : 3); | ||
| this._beginToken(openToken.type === 35 ? 38 : 3); | ||
| this._requireCharCodeUntilFn((code) => code === 62, 3); | ||
@@ -607,3 +627,3 @@ this._cursor.advance(); | ||
| _consumeComponentOpenStart(start) { | ||
| this._beginToken(34, start); | ||
| this._beginToken(35, start); | ||
| const parts = this._consumeComponentName(); | ||
@@ -646,3 +666,3 @@ return this._endToken(parts); | ||
| if (attrNameStart === 39 || attrNameStart === 34) throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan()); | ||
| this._beginToken(14); | ||
| this._beginToken(15); | ||
| let nameEndPredicate; | ||
@@ -679,7 +699,7 @@ if (this._openDirectiveCount > 0) { | ||
| const endPredicate = () => this._cursor.peek() === quoteChar; | ||
| value = this._consumeWithInterpolation(16, 17, endPredicate, endPredicate); | ||
| value = this._consumeWithInterpolation(17, 18, endPredicate, endPredicate); | ||
| this._consumeQuote(quoteChar); | ||
| } else { | ||
| const endPredicate = () => isNameEnd(this._cursor.peek()); | ||
| value = this._consumeWithInterpolation(16, 17, endPredicate, endPredicate); | ||
| value = this._consumeWithInterpolation(17, 18, endPredicate, endPredicate); | ||
| } | ||
@@ -689,3 +709,3 @@ return value; | ||
| _consumeQuote(quoteChar) { | ||
| this._beginToken(15); | ||
| this._beginToken(16); | ||
| this._requireCharCode(quoteChar); | ||
@@ -701,3 +721,3 @@ this._endToken([String.fromCodePoint(quoteChar)]); | ||
| _consumeComponentOpenEnd() { | ||
| const tokenType = this._attemptCharCode(47) ? 36 : 35; | ||
| const tokenType = this._attemptCharCode(47) ? 37 : 36; | ||
| this._beginToken(tokenType); | ||
@@ -712,3 +732,3 @@ this._requireCharCode(62); | ||
| if (isSelectorlessNameStart(clone.peek())) { | ||
| this._beginToken(37, start); | ||
| this._beginToken(38, start); | ||
| const parts = this._consumeComponentName(); | ||
@@ -736,6 +756,6 @@ this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| _consumeExpansionFormStart() { | ||
| this._beginToken(20); | ||
| this._beginToken(21); | ||
| this._requireCharCode(123); | ||
| this._endToken([]); | ||
| this._expansionCaseStack.push(20); | ||
| this._expansionCaseStack.push(21); | ||
| this._beginToken(7); | ||
@@ -758,14 +778,14 @@ const condition = this._readUntil(44); | ||
| _consumeExpansionCaseStart() { | ||
| this._beginToken(21); | ||
| this._beginToken(22); | ||
| const value = this._readUntil(123).trim(); | ||
| this._endToken([value]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._beginToken(22); | ||
| this._beginToken(23); | ||
| this._requireCharCode(123); | ||
| this._endToken([]); | ||
| this._attemptCharCodeUntilFn(isNotWhitespace); | ||
| this._expansionCaseStack.push(22); | ||
| this._expansionCaseStack.push(23); | ||
| } | ||
| _consumeExpansionCaseEnd() { | ||
| this._beginToken(23); | ||
| this._beginToken(24); | ||
| this._requireCharCode(125); | ||
@@ -777,3 +797,3 @@ this._endToken([]); | ||
| _consumeExpansionFormEnd() { | ||
| this._beginToken(24); | ||
| this._beginToken(25); | ||
| this._requireCharCode(125); | ||
@@ -863,3 +883,3 @@ this._endToken([]); | ||
| while (isSelectorlessNameChar(this._cursor.peek())) this._cursor.advance(); | ||
| this._beginToken(39, start); | ||
| this._beginToken(40, start); | ||
| const name = this._cursor.getChars(nameStart); | ||
@@ -870,3 +890,3 @@ this._endToken([name]); | ||
| this._openDirectiveCount++; | ||
| this._beginToken(40); | ||
| this._beginToken(41); | ||
| this._cursor.advance(); | ||
@@ -882,3 +902,3 @@ this._endToken([]); | ||
| } | ||
| this._beginToken(41); | ||
| this._beginToken(42); | ||
| this._cursor.advance(); | ||
@@ -922,6 +942,6 @@ this._endToken([]); | ||
| _isInExpansionCase() { | ||
| return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 22; | ||
| return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 23; | ||
| } | ||
| _isInExpansionForm() { | ||
| return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 20; | ||
| return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 21; | ||
| } | ||
@@ -988,3 +1008,3 @@ isExpansionFormStart() { | ||
| const token = srcTokens[i]; | ||
| if (lastDstToken && lastDstToken.type === 5 && token.type === 5 || lastDstToken && lastDstToken.type === 16 && token.type === 16) { | ||
| if (lastDstToken && lastDstToken.type === 5 && token.type === 5 || lastDstToken && lastDstToken.type === 17 && token.type === 17) { | ||
| lastDstToken.parts[0] += token.parts[0]; | ||
@@ -991,0 +1011,0 @@ lastDstToken.sourceSpan.end = token.sourceSpan.end; |
@@ -73,7 +73,7 @@ import { getNsPrefix, mergeNsAndName, splitNsName } from "./tags.mjs"; | ||
| build() { | ||
| while (this._peek.type !== 42) if (this._peek.type === 0 || this._peek.type === 4) this._consumeElementStartTag(this._advance()); | ||
| while (this._peek.type !== 43) if (this._peek.type === 0 || this._peek.type === 4) this._consumeElementStartTag(this._advance()); | ||
| else if (this._peek.type === 3) { | ||
| this._closeVoidElement(); | ||
| this._consumeElementEndTag(this._advance()); | ||
| } else if (this._peek.type === 12) { | ||
| } else if (this._peek.type === 13) { | ||
| this._closeVoidElement(); | ||
@@ -87,21 +87,21 @@ this._consumeCdata(this._advance()); | ||
| this._consumeText(this._advance()); | ||
| } else if (this._peek.type === 20) this._consumeExpansion(this._advance()); | ||
| else if (this._peek.type === 25) { | ||
| } else if (this._peek.type === 21) this._consumeExpansion(this._advance()); | ||
| else if (this._peek.type === 26) { | ||
| this._closeVoidElement(); | ||
| this._consumeBlockOpen(this._advance()); | ||
| } else if (this._peek.type === 27) { | ||
| } else if (this._peek.type === 28) { | ||
| this._closeVoidElement(); | ||
| this._consumeBlockClose(this._advance()); | ||
| } else if (this._peek.type === 29) { | ||
| } else if (this._peek.type === 30) { | ||
| this._closeVoidElement(); | ||
| this._consumeIncompleteBlock(this._advance()); | ||
| } else if (this._peek.type === 30) { | ||
| } else if (this._peek.type === 31) { | ||
| this._closeVoidElement(); | ||
| this._consumeLet(this._advance()); | ||
| } else if (this._peek.type === 18) this._consumeDocType(this._advance()); | ||
| else if (this._peek.type === 33) { | ||
| } else if (this._peek.type === 19) this._consumeDocType(this._advance()); | ||
| else if (this._peek.type === 34) { | ||
| this._closeVoidElement(); | ||
| this._consumeIncompleteLet(this._advance()); | ||
| } else if (this._peek.type === 34 || this._peek.type === 38) this._consumeComponentStartTag(this._advance()); | ||
| else if (this._peek.type === 37) this._consumeComponentEndTag(this._advance()); | ||
| } else if (this._peek.type === 35 || this._peek.type === 39) this._consumeComponentStartTag(this._advance()); | ||
| else if (this._peek.type === 38) this._consumeComponentEndTag(this._advance()); | ||
| else this._advance(); | ||
@@ -123,3 +123,3 @@ for (const leftoverContainer of this._containerStack) if (leftoverContainer instanceof Block) this.errors.push(TreeError.create(leftoverContainer.name, leftoverContainer.sourceSpan, `Unclosed block "${leftoverContainer.name}"`)); | ||
| const value = this._getText(text); | ||
| const endToken = this._advanceIf(13); | ||
| const endToken = this._advanceIf(14); | ||
| this._addToParent(new CDATA(value, new ParseSourceSpan(startToken.sourceSpan.start, (endToken || text).sourceSpan.end), [text])); | ||
@@ -136,3 +136,3 @@ } | ||
| const text = this._advanceIf(7); | ||
| const endToken = this._advanceIf(19); | ||
| const endToken = this._advanceIf(20); | ||
| const value = text != null ? text.parts[0].trim() : null; | ||
@@ -146,3 +146,3 @@ const sourceSpan = new ParseSourceSpan(startToken.sourceSpan.start, (endToken || text || startToken).sourceSpan.end); | ||
| const cases = []; | ||
| while (this._peek.type === 21) { | ||
| while (this._peek.type === 22) { | ||
| const expCase = this._parseExpansionCase(); | ||
@@ -152,3 +152,3 @@ if (!expCase) return; | ||
| } | ||
| if (this._peek.type !== 24) { | ||
| if (this._peek.type !== 25) { | ||
| this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
@@ -163,3 +163,3 @@ return; | ||
| const value = this._advance(); | ||
| if (this._peek.type !== 22) { | ||
| if (this._peek.type !== 23) { | ||
| this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`)); | ||
@@ -173,3 +173,3 @@ return null; | ||
| exp.push({ | ||
| type: 42, | ||
| type: 43, | ||
| parts: [], | ||
@@ -190,6 +190,6 @@ sourceSpan: end.sourceSpan | ||
| const exp = []; | ||
| const expansionFormStack = [22]; | ||
| const expansionFormStack = [23]; | ||
| while (true) { | ||
| if (this._peek.type === 20 || this._peek.type === 22) expansionFormStack.push(this._peek.type); | ||
| if (this._peek.type === 23) if (lastOnStack(expansionFormStack, 22)) { | ||
| if (this._peek.type === 21 || this._peek.type === 23) expansionFormStack.push(this._peek.type); | ||
| if (this._peek.type === 24) if (lastOnStack(expansionFormStack, 23)) { | ||
| expansionFormStack.pop(); | ||
@@ -201,3 +201,3 @@ if (expansionFormStack.length === 0) return exp; | ||
| } | ||
| if (this._peek.type === 24) if (lastOnStack(expansionFormStack, 20)) expansionFormStack.pop(); | ||
| if (this._peek.type === 25) if (lastOnStack(expansionFormStack, 21)) expansionFormStack.pop(); | ||
| else { | ||
@@ -207,3 +207,3 @@ this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
| } | ||
| if (this._peek.type === 42) { | ||
| if (this._peek.type === 43) { | ||
| this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`)); | ||
@@ -297,3 +297,3 @@ return null; | ||
| const fullName = this._getComponentFullName(startToken, closestElement); | ||
| const selfClosing = this._peek.type === 36; | ||
| const selfClosing = this._peek.type === 37; | ||
| this._advance(); | ||
@@ -307,3 +307,3 @@ const end = this._peek.sourceSpan.fullStart; | ||
| if (selfClosing) this._popContainer(fullName, Component, span); | ||
| else if (startToken.type === 38) { | ||
| else if (startToken.type === 39) { | ||
| this._popContainer(fullName, Component, null); | ||
@@ -314,4 +314,8 @@ this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`)); | ||
| _consumeAttributesAndDirectives(attributesResult, directivesResult) { | ||
| while (this._peek.type === 14 || this._peek.type === 39) if (this._peek.type === 39) directivesResult.push(this._consumeDirective(this._peek)); | ||
| else attributesResult.push(this._consumeAttr(this._advance())); | ||
| while (this._peek.type === 15 || this._peek.type === 40 || this._peek.type === 12) if (this._peek.type === 40) directivesResult.push(this._consumeDirective(this._peek)); | ||
| else if (this._peek.type === 15) attributesResult.push(this._consumeAttr(this._advance())); | ||
| else { | ||
| const commentToken = this._advance(); | ||
| this._addToParent(new Comment(commentToken.parts[0], commentToken.sourceSpan)); | ||
| } | ||
| } | ||
@@ -375,3 +379,3 @@ _consumeComponentEndTag(endToken) { | ||
| let startQuoteToken; | ||
| if (this._peek.type === 15) startQuoteToken = this._advance(); | ||
| if (this._peek.type === 16) startQuoteToken = this._advance(); | ||
| let value = ""; | ||
@@ -381,9 +385,9 @@ const valueTokens = []; | ||
| let valueEnd = void 0; | ||
| if (this._peek.type === 16) { | ||
| if (this._peek.type === 17) { | ||
| valueStartSpan = this._peek.sourceSpan; | ||
| valueEnd = this._peek.sourceSpan.end; | ||
| while (this._peek.type === 16 || this._peek.type === 17 || this._peek.type === 9) { | ||
| while (this._peek.type === 17 || this._peek.type === 18 || this._peek.type === 9) { | ||
| const valueToken = this._advance(); | ||
| valueTokens.push(valueToken); | ||
| if (valueToken.type === 17) value += valueToken.parts.join("").replace(/&([^;]+);/g, decodeEntity); | ||
| if (valueToken.type === 18) value += valueToken.parts.join("").replace(/&([^;]+);/g, decodeEntity); | ||
| else if (valueToken.type === 9) value += valueToken.parts[0]; | ||
@@ -394,3 +398,3 @@ else value += valueToken.parts.join(""); | ||
| } | ||
| if (this._peek.type === 15) valueEnd = attrEnd = this._advance().sourceSpan.end; | ||
| if (this._peek.type === 16) valueEnd = attrEnd = this._advance().sourceSpan.end; | ||
| const valueSpan = valueStartSpan && valueEnd && new ParseSourceSpan((startQuoteToken === null || startQuoteToken === void 0 ? void 0 : startQuoteToken.sourceSpan.start) ?? valueStartSpan.start, valueEnd, (startQuoteToken === null || startQuoteToken === void 0 ? void 0 : startQuoteToken.sourceSpan.fullStart) ?? valueStartSpan.fullStart); | ||
@@ -404,7 +408,7 @@ return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : void 0, void 0); | ||
| this._advance(); | ||
| if (this._peek.type === 40) { | ||
| if (this._peek.type === 41) { | ||
| startSourceSpanEnd = this._peek.sourceSpan.end; | ||
| this._advance(); | ||
| while (this._peek.type === 14) attributes.push(this._consumeAttr(this._advance())); | ||
| if (this._peek.type === 41) { | ||
| while (this._peek.type === 15) attributes.push(this._consumeAttr(this._advance())); | ||
| if (this._peek.type === 42) { | ||
| endSourceSpan = this._peek.sourceSpan; | ||
@@ -420,7 +424,7 @@ this._advance(); | ||
| const parameters = []; | ||
| while (this._peek.type === 28) { | ||
| while (this._peek.type === 29) { | ||
| const paramToken = this._advance(); | ||
| parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan)); | ||
| } | ||
| if (this._peek.type === 26) this._advance(); | ||
| if (this._peek.type === 27) this._advance(); | ||
| const end = this._peek.sourceSpan.fullStart; | ||
@@ -446,3 +450,3 @@ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart); | ||
| const parameters = []; | ||
| while (this._peek.type === 28) { | ||
| while (this._peek.type === 29) { | ||
| const paramToken = this._advance(); | ||
@@ -463,7 +467,7 @@ parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan)); | ||
| let endToken; | ||
| if (this._peek.type !== 31) { | ||
| if (this._peek.type !== 32) { | ||
| this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Invalid @let declaration "${name}". Declaration must have a value.`)); | ||
| return; | ||
| } else valueToken = this._advance(); | ||
| if (this._peek.type !== 32) { | ||
| if (this._peek.type !== 33) { | ||
| this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Unterminated @let declaration "${name}". Declaration must be terminated with a semicolon.`)); | ||
@@ -526,3 +530,3 @@ return; | ||
| let tagName; | ||
| if (token.type === 34 || token.type === 38 || token.type === 37) { | ||
| if (token.type === 35 || token.type === 39 || token.type === 38) { | ||
| prefix = token.parts[1]; | ||
@@ -529,0 +533,0 @@ tagName = token.parts[2]; |
@@ -24,33 +24,34 @@ import { ParseSourceSpan } from "../parse_util.mjs"; | ||
| 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 | ||
| IN_ELEMENT_COMMENT = 12, | ||
| CDATA_START = 13, | ||
| CDATA_END = 14, | ||
| ATTR_NAME = 15, | ||
| ATTR_QUOTE = 16, | ||
| ATTR_VALUE_TEXT = 17, | ||
| ATTR_VALUE_INTERPOLATION = 18, | ||
| DOC_TYPE_START = 19, | ||
| DOC_TYPE_END = 20, | ||
| EXPANSION_FORM_START = 21, | ||
| EXPANSION_CASE_VALUE = 22, | ||
| EXPANSION_CASE_EXP_START = 23, | ||
| EXPANSION_CASE_EXP_END = 24, | ||
| EXPANSION_FORM_END = 25, | ||
| BLOCK_OPEN_START = 26, | ||
| BLOCK_OPEN_END = 27, | ||
| BLOCK_CLOSE = 28, | ||
| BLOCK_PARAMETER = 29, | ||
| INCOMPLETE_BLOCK_OPEN = 30, | ||
| LET_START = 31, | ||
| LET_VALUE = 32, | ||
| LET_END = 33, | ||
| INCOMPLETE_LET = 34, | ||
| COMPONENT_OPEN_START = 35, | ||
| COMPONENT_OPEN_END = 36, | ||
| COMPONENT_OPEN_END_VOID = 37, | ||
| COMPONENT_CLOSE = 38, | ||
| INCOMPLETE_COMPONENT_OPEN = 39, | ||
| DIRECTIVE_NAME = 40, | ||
| DIRECTIVE_OPEN = 41, | ||
| DIRECTIVE_CLOSE = 42, | ||
| EOF = 43 | ||
| } | ||
@@ -57,0 +58,0 @@ type InterpolatedTextToken = TextToken | InterpolationToken | EncodedEntityToken; |
@@ -1,2 +0,2 @@ | ||
| import { SECURITY_SCHEMA } from "./dom_security_schema.mjs"; | ||
| import { checkSecurityContext } from "./dom_security_schema.mjs"; | ||
| import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "../core.mjs"; | ||
@@ -105,3 +105,3 @@ import { isNgContainer, isNgContent, splitNsName } from "../ml_parser/tags.mjs"; | ||
| "html^[HTMLElement]|version", | ||
| "iframe^[HTMLElement]|align,allow,!allowFullscreen,!allowPaymentRequest,csp,frameBorder,height,loading,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width", | ||
| "iframe^[HTMLElement]|align,allow,!allowFullscreen,!allowPaymentRequest,csp,!credentialless,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", | ||
@@ -382,6 +382,4 @@ "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", | ||
| if (isAttribute) propName = this.getMappedPropName(propName); | ||
| const normalizedTag = normalizeTagName(tagName); | ||
| propName = propName.toLowerCase(); | ||
| const securitySchema = SECURITY_SCHEMA(); | ||
| return securitySchema[normalizedTag + "|" + propName] ?? securitySchema["*|" + propName] ?? 0; | ||
| const [ns, name] = splitNsName(tagName, false); | ||
| return checkSecurityContext(name, propName, ns); | ||
| } | ||
@@ -388,0 +386,0 @@ getMappedPropName(propName) { |
@@ -9,8 +9,8 @@ //#region ../compiler/src/schema/dom_security_schema.ts | ||
| */ | ||
| /** | ||
| * Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. | ||
| */ | ||
| let _SECURITY_SCHEMA; | ||
| const SVG_NAMESPACE = "svg"; | ||
| const MATH_ML_NAMESPACE = "math"; | ||
| const NO_NAMESPACE = ""; | ||
| const MATCH_ALL_ELEMENTS = "*"; | ||
| const createNullObj = () => Object.create(null); | ||
| /** | ||
@@ -21,124 +21,118 @@ * @remarks Keep is a copy of DOM Security Schema. | ||
| function SECURITY_SCHEMA() { | ||
| if (!_SECURITY_SCHEMA) { | ||
| _SECURITY_SCHEMA = {}; | ||
| registerContext( | ||
| 1, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["iframe", ["srcdoc"]], ["*", ["innerHTML", "outerHTML"]]] | ||
| ); | ||
| registerContext( | ||
| 2, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["*", ["style"]]] | ||
| ); | ||
| registerContext( | ||
| 4, | ||
| /** Namespace */ | ||
| void 0, | ||
| [ | ||
| ["*", ["formAction"]], | ||
| ["area", ["href"]], | ||
| ["a", ["href", "xlink:href"]], | ||
| ["form", ["action"]], | ||
| ["img", ["src"]], | ||
| ["video", ["src"]] | ||
| ] | ||
| ); | ||
| registerContext(4, MATH_ML_NAMESPACE, [ | ||
| ["annotation", ["href", "xlink:href"]], | ||
| ["annotation-xml", ["href", "xlink:href"]], | ||
| ["maction", ["href", "xlink:href"]], | ||
| ["malignmark", ["href", "xlink:href"]], | ||
| ["math", ["href", "xlink:href"]], | ||
| ["mroot", ["href", "xlink:href"]], | ||
| ["msqrt", ["href", "xlink:href"]], | ||
| ["merror", ["href", "xlink:href"]], | ||
| ["mfrac", ["href", "xlink:href"]], | ||
| ["mglyph", ["href", "xlink:href"]], | ||
| ["msub", ["href", "xlink:href"]], | ||
| ["msup", ["href", "xlink:href"]], | ||
| ["msubsup", ["href", "xlink:href"]], | ||
| ["mmultiscripts", ["href", "xlink:href"]], | ||
| ["mprescripts", ["href", "xlink:href"]], | ||
| ["mi", ["href", "xlink:href"]], | ||
| ["mn", ["href", "xlink:href"]], | ||
| ["mo", ["href", "xlink:href"]], | ||
| ["mpadded", ["href", "xlink:href"]], | ||
| ["mphantom", ["href", "xlink:href"]], | ||
| ["mrow", ["href", "xlink:href"]], | ||
| ["ms", ["href", "xlink:href"]], | ||
| ["mspace", ["href", "xlink:href"]], | ||
| ["mstyle", ["href", "xlink:href"]], | ||
| ["mtable", ["href", "xlink:href"]], | ||
| ["mtd", ["href", "xlink:href"]], | ||
| ["mtr", ["href", "xlink:href"]], | ||
| ["mtext", ["href", "xlink:href"]], | ||
| ["mover", ["href", "xlink:href"]], | ||
| ["munder", ["href", "xlink:href"]], | ||
| ["munderover", ["href", "xlink:href"]], | ||
| ["semantics", ["href", "xlink:href"]], | ||
| ["none", ["href", "xlink:href"]] | ||
| ]); | ||
| registerContext( | ||
| 5, | ||
| /** Namespace */ | ||
| void 0, | ||
| [ | ||
| ["base", ["href"]], | ||
| ["embed", ["src"]], | ||
| ["frame", ["src"]], | ||
| ["iframe", ["src"]], | ||
| ["link", ["href"]], | ||
| ["object", ["codebase", "data"]] | ||
| ] | ||
| ); | ||
| registerContext(4, SVG_NAMESPACE, [["a", ["href", "xlink:href"]]]); | ||
| registerContext(6, SVG_NAMESPACE, [ | ||
| ["animate", [ | ||
| "attributeName", | ||
| "values", | ||
| "to", | ||
| "from" | ||
| ]], | ||
| ["set", ["to", "attributeName"]], | ||
| ["animateMotion", ["attributeName"]], | ||
| ["animateTransform", ["attributeName"]] | ||
| ]); | ||
| registerContext( | ||
| 6, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["unknown", [ | ||
| "attributeName", | ||
| "values", | ||
| "to", | ||
| "from", | ||
| "sandbox", | ||
| "allow", | ||
| "allowFullscreen", | ||
| "referrerPolicy", | ||
| "csp", | ||
| "fetchPriority" | ||
| ]], ["iframe", [ | ||
| "sandbox", | ||
| "allow", | ||
| "allowFullscreen", | ||
| "referrerPolicy", | ||
| "csp", | ||
| "fetchPriority" | ||
| ]]] | ||
| ); | ||
| } | ||
| if (_SECURITY_SCHEMA) return _SECURITY_SCHEMA; | ||
| _SECURITY_SCHEMA = createNullObj(); | ||
| registerContext( | ||
| 1, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["iframe", ["srcdoc"]], ["*", ["innerHTML", "outerHTML"]]] | ||
| ); | ||
| registerContext( | ||
| 2, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["*", ["style"]]] | ||
| ); | ||
| registerContext( | ||
| 4, | ||
| /** Namespace */ | ||
| void 0, | ||
| [ | ||
| ["*", ["formAction"]], | ||
| ["area", ["href"]], | ||
| ["a", ["href", "xlink:href"]], | ||
| ["form", ["action"]], | ||
| ["img", ["src"]], | ||
| ["video", ["src"]] | ||
| ] | ||
| ); | ||
| registerContext(4, MATH_ML_NAMESPACE, [["*", ["href", "xlink:href"]]]); | ||
| registerContext( | ||
| 5, | ||
| /** Namespace */ | ||
| void 0, | ||
| [ | ||
| ["base", ["href"]], | ||
| ["embed", ["src"]], | ||
| ["frame", ["src"]], | ||
| ["iframe", ["src"]], | ||
| ["link", ["href"]], | ||
| ["object", ["codebase", "data"]] | ||
| ] | ||
| ); | ||
| registerContext(4, SVG_NAMESPACE, [["a", ["href", "xlink:href"]]]); | ||
| registerContext(6, SVG_NAMESPACE, [ | ||
| ["animate", [ | ||
| "attributeName", | ||
| "values", | ||
| "to", | ||
| "from" | ||
| ]], | ||
| ["set", ["to", "attributeName"]], | ||
| ["animateMotion", ["attributeName"]], | ||
| ["animateTransform", ["attributeName"]] | ||
| ]); | ||
| registerContext( | ||
| 6, | ||
| /** Namespace */ | ||
| void 0, | ||
| [["unknown", [ | ||
| "attributeName", | ||
| "values", | ||
| "to", | ||
| "from", | ||
| "sandbox", | ||
| "allow", | ||
| "allowFullscreen", | ||
| "referrerPolicy", | ||
| "csp", | ||
| "fetchPriority", | ||
| "credentialless" | ||
| ]], ["iframe", [ | ||
| "sandbox", | ||
| "allow", | ||
| "allowFullscreen", | ||
| "referrerPolicy", | ||
| "csp", | ||
| "fetchPriority", | ||
| "credentialless" | ||
| ]]] | ||
| ); | ||
| return _SECURITY_SCHEMA; | ||
| } | ||
| function registerContext(ctx, namespace, specs) { | ||
| const nsKey = namespace ?? NO_NAMESPACE; | ||
| for (const [element, attributeNames] of specs) { | ||
| let tagName = namespace && element !== "*" && element !== "unknown" ? `:${namespace}:${element}` : element; | ||
| tagName = tagName.toLowerCase(); | ||
| for (const attr of attributeNames) _SECURITY_SCHEMA[`${tagName}|${attr.toLowerCase()}`] = ctx; | ||
| const tagName = element.toLowerCase(); | ||
| for (const attr of attributeNames) { | ||
| var _SECURITY_SCHEMA2; | ||
| const attrLower = attr.toLowerCase(); | ||
| const attrSchema = (_SECURITY_SCHEMA2 = _SECURITY_SCHEMA)[attrLower] ?? (_SECURITY_SCHEMA2[attrLower] = createNullObj()); | ||
| const nsSchema = attrSchema[nsKey] ?? (attrSchema[nsKey] = createNullObj()); | ||
| nsSchema[tagName] = ctx; | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Checks the SecurityContext for a given tag and property. | ||
| * @param tagName The tag name (e.g. 'div', or 'a') | ||
| * @param propName The property or attribute name | ||
| * @param namespace The namespace of the element, if any (e.g. 'svg' or 'math') | ||
| */ | ||
| function checkSecurityContext(tagName, propName, namespace) { | ||
| const attrSchema = SECURITY_SCHEMA()[propName.toLowerCase()]; | ||
| if (!attrSchema) return 0; | ||
| const tagLower = tagName.toLowerCase(); | ||
| let context; | ||
| if (namespace) { | ||
| const nsSchema = attrSchema[namespace]; | ||
| if (nsSchema) context = nsSchema[tagLower] ?? nsSchema[MATCH_ALL_ELEMENTS]; | ||
| } | ||
| if (context === void 0) { | ||
| const defaultSchema = attrSchema[NO_NAMESPACE]; | ||
| if (defaultSchema) context = defaultSchema[tagLower] ?? defaultSchema[MATCH_ALL_ELEMENTS]; | ||
| } | ||
| return context ?? 0; | ||
| } | ||
| //#endregion | ||
| export { SECURITY_SCHEMA }; | ||
| export { checkSecurityContext }; |
+6
-0
@@ -22,2 +22,8 @@ import { TagContentType } from "./compiler/src/ml_parser/tags.mjs"; | ||
| /** | ||
| * allow in-element comments | ||
| * | ||
| * defaults to false | ||
| */ | ||
| allowInElementComments?: boolean; | ||
| /** | ||
| * do not lowercase tag names before querying their tag definitions | ||
@@ -24,0 +30,0 @@ * |
+2
-1
@@ -10,3 +10,3 @@ import { TagContentType } from "./compiler/src/ml_parser/tags.mjs"; | ||
| function parseHtml(input, options = {}) { | ||
| const { canSelfClose = false, allowHtmComponentClosingTags = false, isTagNameCaseSensitive = false, getTagContentType, tokenizeAngularBlocks = false, tokenizeAngularLetDeclaration = false, enableAngularSelectorlessSyntax = false } = options; | ||
| const { canSelfClose = false, allowHtmComponentClosingTags = false, allowInElementComments = false, isTagNameCaseSensitive = false, getTagContentType, tokenizeAngularBlocks = false, tokenizeAngularLetDeclaration = false, enableAngularSelectorlessSyntax = false } = options; | ||
| htmlParser ?? (htmlParser = new HtmlParser()); | ||
@@ -17,2 +17,3 @@ return htmlParser.parse(input, "angular-html-parser", { | ||
| allowHtmComponentClosingTags, | ||
| allowInElementComments, | ||
| tokenizeBlocks: tokenizeAngularBlocks, | ||
@@ -19,0 +20,0 @@ tokenizeLet: tokenizeAngularLetDeclaration, |
+1
-1
| { | ||
| "name": "angular-html-parser", | ||
| "version": "10.7.0", | ||
| "version": "10.8.0", | ||
| "description": "A HTML parser extracted from Angular with some modifications", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/prettier/angular-html-parser", |
191585
0.38%5376
0.32%