{"version":3,"file":"index.js.map","sources":[".temp/ast/src/ast/errors.ts",".temp/ast/src/ast/nodes.ts",".temp/ast/src/ast/traverse.ts",".temp/common/src/common/lines-and-columns.ts",".temp/common/src/common/location-calculator.ts",".temp/common/src/common/debug.ts",".temp/common/src/common/ast-utils.ts",".temp/common/src/common/parser-options.ts",".temp/common/src/common/create-require.ts",".temp/common/src/common/linter-require.ts",".temp/common/src/common/eslint-scope.ts",".temp/common/src/common/espree.ts",".temp/script/src/script/scope-analyzer.ts",".temp/common/src/common/fix-locations.ts",".temp/script-setup/src/script-setup/parser-options.ts",".temp/script/src/script/index.ts",".temp/common/src/common/token-utils.ts",".temp/common/src/common/error-utils.ts",".temp/template/src/template/index.ts",".temp/html/util/src/html/util/attribute-names.ts",".temp/html/util/src/html/util/tag-names.ts",".temp/html/src/html/intermediate-tokenizer.ts",".temp/html/src/html/parser.ts",".temp/html/util/src/html/util/alternative-cr.ts",".temp/html/util/src/html/util/entities.ts",".temp/html/util/src/html/util/unicode.ts",".temp/html/src/html/tokenizer.ts",".temp/external/src/external/node-event-generator.ts",".temp/external/token-store/src/external/token-store/utils.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/backward-token-comment-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/backward-token-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/decorative-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/filter-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/forward-token-comment-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/forward-token-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/limit-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/skip-cursor.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/index.ts",".temp/external/token-store/cursors/src/external/token-store/cursors/padded-token-cursor.ts",".temp/external/token-store/src/external/token-store/index.ts",".temp/sfc/custom-block/src/sfc/custom-block/index.ts",".temp/src/parser-services.ts",".temp/script-setup/src/script-setup/index.ts",".temp/style/src/style/index.ts",".temp/src/index.ts"],"sourcesContent":["/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\nimport type { Location } from \"./locations\"\n\n/**\n * Check whether the given value has acorn style location information.\n * @param x The value to check.\n * @returns `true` if the value has acorn style location information.\n */\nfunction isAcornStyleParseError(\n x: any,\n): x is { message: string; pos: number; loc: Location } {\n return (\n typeof x.message === \"string\" &&\n typeof x.pos === \"number\" &&\n typeof x.loc === \"object\" &&\n x.loc !== null &&\n typeof x.loc.line === \"number\" &&\n typeof x.loc.column === \"number\"\n )\n}\n\n/**\n * HTML parse errors.\n */\nexport class ParseError extends SyntaxError {\n public code?: ErrorCode\n public index: number\n public lineNumber: number\n public column: number\n\n /**\n * Create new parser error object.\n * @param code The error code. See also: https://html.spec.whatwg.org/multipage/parsing.html#parse-errors\n * @param offset The offset number of this error.\n * @param line The line number of this error.\n * @param column The column number of this error.\n */\n public static fromCode(\n code: ErrorCode,\n offset: number,\n line: number,\n column: number,\n ): ParseError {\n return new ParseError(code, code, offset, line, column)\n }\n\n /**\n * Normalize the error object.\n * @param x The error object to normalize.\n */\n public static normalize(x: any): ParseError | null {\n if (ParseError.isParseError(x)) {\n return x\n }\n if (isAcornStyleParseError(x)) {\n return new ParseError(\n x.message,\n undefined,\n x.pos,\n x.loc.line,\n x.loc.column,\n )\n }\n return null\n }\n\n /**\n * Initialize this ParseError instance.\n * @param message The error message.\n * @param code The error code. See also: https://html.spec.whatwg.org/multipage/parsing.html#parse-errors\n * @param offset The offset number of this error.\n * @param line The line number of this error.\n * @param column The column number of this error.\n */\n public constructor(\n message: string,\n code: ErrorCode | undefined,\n offset: number,\n line: number,\n column: number,\n ) {\n super(message)\n this.code = code\n this.index = offset\n this.lineNumber = line\n this.column = column\n }\n\n /**\n * Type guard for ParseError.\n * @param x The value to check.\n * @returns `true` if the value has `message`, `pos`, `loc` properties.\n */\n public static isParseError(x: any): x is ParseError {\n return (\n x instanceof ParseError ||\n (typeof x.message === \"string\" &&\n typeof x.index === \"number\" &&\n typeof x.lineNumber === \"number\" &&\n typeof x.column === \"number\")\n )\n }\n}\n\n/**\n * The error codes of HTML syntax errors.\n * https://html.spec.whatwg.org/multipage/parsing.html#parse-errors\n */\nexport type ErrorCode =\n | \"abrupt-closing-of-empty-comment\"\n | \"absence-of-digits-in-numeric-character-reference\"\n | \"cdata-in-html-content\"\n | \"character-reference-outside-unicode-range\"\n | \"control-character-in-input-stream\"\n | \"control-character-reference\"\n | \"eof-before-tag-name\"\n | \"eof-in-cdata\"\n | \"eof-in-comment\"\n | \"eof-in-tag\"\n | \"incorrectly-closed-comment\"\n | \"incorrectly-opened-comment\"\n | \"invalid-first-character-of-tag-name\"\n | \"missing-attribute-value\"\n | \"missing-end-tag-name\"\n | \"missing-semicolon-after-character-reference\"\n | \"missing-whitespace-between-attributes\"\n | \"nested-comment\"\n | \"noncharacter-character-reference\"\n | \"noncharacter-in-input-stream\"\n | \"null-character-reference\"\n | \"surrogate-character-reference\"\n | \"surrogate-in-input-stream\"\n | \"unexpected-character-in-attribute-name\"\n | \"unexpected-character-in-unquoted-attribute-value\"\n | \"unexpected-equals-sign-before-attribute-name\"\n | \"unexpected-null-character\"\n | \"unexpected-question-mark-instead-of-tag-name\"\n | \"unexpected-solidus-in-tag\"\n | \"unknown-named-character-reference\"\n | \"end-tag-with-attributes\"\n | \"duplicate-attribute\"\n | \"end-tag-with-trailing-solidus\"\n | \"non-void-html-element-start-tag-with-trailing-solidus\"\n | \"x-invalid-end-tag\"\n | \"x-invalid-namespace\"\n | \"x-missing-interpolation-end\"\n// ---- Use RAWTEXT state for \",\n })\n }\n }\n\n return result\n}\n\n/**\n * Parse the source code of inline scripts.\n * @param code The source code of inline scripts.\n * @param locationCalculator The location calculator for the inline script.\n * @param parserOptions The parser options.\n * @returns The result of parsing.\n */\nexport function parseExpression(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n { allowEmpty = false, allowFilters = false } = {},\n): ExpressionParseResult {\n debug('[script] parse expression: \"%s\"', code)\n\n const [mainCode, ...filterCodes] =\n allowFilters && (parserOptions.vueFeatures?.filter ?? true)\n ? splitFilters(code)\n : [code]\n if (filterCodes.length === 0) {\n return parseExpressionBody(\n code,\n locationCalculator,\n parserOptions,\n allowEmpty,\n )\n }\n\n // Parse expression\n const retB = parseExpressionBody(\n mainCode,\n locationCalculator,\n parserOptions,\n )\n if (!retB.expression) {\n return retB\n }\n const ret =\n retB as unknown as ExpressionParseResult\n\n ret.expression = {\n type: \"VFilterSequenceExpression\",\n parent: null as any,\n expression: retB.expression,\n filters: [],\n range: retB.expression.range.slice(0) as [number, number],\n loc: Object.assign({}, retB.expression.loc),\n }\n ret.expression.expression.parent = ret.expression\n\n // Parse filters\n let prevLoc = mainCode.length\n for (const filterCode of filterCodes) {\n // Pipe token.\n ret.tokens.push(\n fixLocation(\n {\n type: \"Punctuator\",\n value: \"|\",\n range: [prevLoc, prevLoc + 1],\n loc: {} as any,\n },\n locationCalculator,\n ),\n )\n\n // Parse a filter\n const retF = parseFilter(\n filterCode,\n locationCalculator.getSubCalculatorShift(prevLoc + 1),\n parserOptions,\n )\n if (retF) {\n if (retF.expression) {\n ret.expression.filters.push(retF.expression)\n retF.expression.parent = ret.expression\n }\n ret.tokens.push(...retF.tokens)\n ret.comments.push(...retF.comments)\n ret.references.push(...retF.references)\n }\n\n prevLoc += 1 + filterCode.length\n }\n\n // Update range.\n const lastToken = last(ret.tokens)!\n ret.expression.range[1] = lastToken.range[1]\n ret.expression.loc.end = lastToken.loc.end\n\n return ret\n}\n\n/**\n * Parse the source code of inline scripts.\n * @param code The source code of inline scripts.\n * @param locationCalculator The location calculator for the inline script.\n * @param parserOptions The parser options.\n * @returns The result of parsing.\n */\n// eslint-disable-next-line complexity\nexport function parseVForExpression(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n): ExpressionParseResult {\n if (code.trim() === \"\") {\n throwEmptyError(locationCalculator, \"' in '\")\n }\n\n if (isEcmaVersion5(parserOptions)) {\n return parseVForExpressionForEcmaVersion5(\n code,\n locationCalculator,\n parserOptions,\n )\n }\n const processed = processVForAliasAndIterator(code)\n\n if (!processed.aliases.trim()) {\n return throwEmptyError(locationCalculator, \"an alias\")\n }\n try {\n debug(\n '[script] parse v-for expression: \"for(%s%s%s);\"',\n processed.aliasesWithBrackets,\n processed.delimiter,\n processed.iterator,\n )\n\n const ast = parseScriptFragment(\n `for(let ${processed.aliasesWithBrackets}${processed.delimiter}${processed.iterator});`,\n locationCalculator.getSubCalculatorShift(\n processed.hasParens ? -8 : -9,\n ),\n parserOptions,\n ).ast\n const tokens = ast.tokens || []\n const comments = ast.comments || []\n const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)\n const references = scope.references\n const variables = scope.variables\n const statement = ast.body[0] as\n | ESLintForInStatement\n | ESLintForOfStatement\n const varDecl = statement.left as ESLintVariableDeclaration\n const id = varDecl.declarations[0].id as ESLintArrayPattern\n const left = id.elements\n const right = statement.right\n\n if (!processed.hasParens && !left.length) {\n return throwEmptyError(locationCalculator, \"an alias\")\n }\n // Remove `for` `(` `let` `)` `;`.\n tokens.shift()\n tokens.shift()\n tokens.shift()\n tokens.pop()\n tokens.pop()\n\n const closeOffset = statement.left.range[1] - 1\n const closeIndex = tokens.findIndex((t) => t.range[0] === closeOffset)\n\n if (processed.hasParens) {\n // Restore parentheses from array brackets.\n const open = tokens[0]\n if (open != null) {\n open.value = \"(\"\n }\n const close = tokens[closeIndex]\n if (close != null) {\n close.value = \")\"\n }\n } else {\n // Remove array brackets.\n tokens.splice(closeIndex, 1)\n tokens.shift()\n }\n const firstToken = tokens[0] || statement.left\n const lastToken = tokens[tokens.length - 1] || statement.right\n const expression: VForExpression = {\n type: \"VForExpression\",\n range: [firstToken.range[0], lastToken.range[1]],\n loc: { start: firstToken.loc.start, end: lastToken.loc.end },\n parent: DUMMY_PARENT,\n left,\n right,\n }\n\n // Modify parent.\n for (const l of left) {\n if (l != null) {\n l.parent = expression\n }\n }\n right.parent = expression\n\n return { expression, tokens, comments, references, variables }\n } catch (err) {\n return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator)\n }\n}\n\nfunction isEcmaVersion5(parserOptions: ParserOptions) {\n const ecmaVersion = getEcmaVersionIfUseEspree(parserOptions)\n return ecmaVersion != null && ecmaVersion <= 5\n}\n\nfunction parseVForExpressionForEcmaVersion5(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n): ExpressionParseResult {\n const processed = processVForAliasAndIterator(code)\n\n if (!processed.aliases.trim()) {\n return throwEmptyError(locationCalculator, \"an alias\")\n }\n try {\n const tokens: Token[] = []\n const comments: Token[] = []\n\n const parsedAliases = parseVForAliasesForEcmaVersion5(\n processed.aliasesWithBrackets,\n locationCalculator.getSubCalculatorShift(\n processed.hasParens ? 0 : -1,\n ),\n parserOptions,\n )\n\n if (processed.hasParens) {\n // Restore parentheses from array brackets.\n const open = parsedAliases.tokens[0]\n if (open != null) {\n open.value = \"(\"\n }\n const close = last(parsedAliases.tokens)\n if (close != null) {\n close.value = \")\"\n }\n } else {\n // Remove array brackets.\n parsedAliases.tokens.shift()\n parsedAliases.tokens.pop()\n }\n tokens.push(...parsedAliases.tokens)\n comments.push(...parsedAliases.comments)\n const { left, variables } = parsedAliases\n\n if (!processed.hasParens && !left.length) {\n return throwEmptyError(locationCalculator, \"an alias\")\n }\n\n const delimiterStart = processed.aliases.length\n const delimiterEnd = delimiterStart + processed.delimiter.length\n tokens.push(\n fixLocation(\n {\n type:\n processed.delimiter === \"in\" ? \"Keyword\" : \"Identifier\",\n value: processed.delimiter,\n start: delimiterStart,\n end: delimiterEnd,\n loc: {} as any,\n range: [delimiterStart, delimiterEnd],\n } as Token,\n locationCalculator,\n ),\n )\n\n const parsedIterator = parseVForIteratorForEcmaVersion5(\n processed.iterator,\n locationCalculator.getSubCalculatorShift(delimiterEnd),\n parserOptions,\n )\n\n tokens.push(...parsedIterator.tokens)\n comments.push(...parsedIterator.comments)\n const { right, references } = parsedIterator\n const firstToken = tokens[0]\n const lastToken = last(tokens) || firstToken\n const expression: VForExpression = {\n type: \"VForExpression\",\n range: [firstToken.range[0], lastToken.range[1]],\n loc: { start: firstToken.loc.start, end: lastToken.loc.end },\n parent: DUMMY_PARENT,\n left,\n right,\n }\n\n // Modify parent.\n for (const l of left) {\n if (l != null) {\n l.parent = expression\n }\n }\n right.parent = expression\n\n return { expression, tokens, comments, references, variables }\n } catch (err) {\n return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator)\n }\n}\n\nfunction parseVForAliasesForEcmaVersion5(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n) {\n const ast = parseScriptFragment(\n `0(${code})`,\n locationCalculator.getSubCalculatorShift(-2),\n parserOptions,\n ).ast\n const tokens = ast.tokens || []\n const comments = ast.comments || []\n const variables = analyzeExternalReferences(ast, parserOptions).map(\n transformVariable,\n )\n\n const statement = ast.body[0] as ESLintExpressionStatement\n const callExpression = statement.expression as ESLintCallExpression\n const expression = callExpression.arguments[0] as ESLintArrayExpression\n\n const left: ESLintIdentifier[] = expression.elements.filter(\n (e): e is ESLintIdentifier => {\n if (e == null || e.type === \"Identifier\") {\n return true\n }\n const errorToken = tokens.find(\n (t) => e.range[0] <= t.range[0] && t.range[1] <= e.range[1],\n )!\n return throwUnexpectedTokenError(errorToken.value, errorToken)\n },\n )\n // Remove parens.\n tokens.shift()\n tokens.shift()\n tokens.pop()\n\n return { left, tokens, comments, variables }\n\n function transformVariable(reference: Reference): Variable {\n const ret: Variable = {\n id: reference.id,\n kind: \"v-for\",\n references: [],\n }\n Object.defineProperty(ret, \"references\", { enumerable: false })\n\n return ret\n }\n}\n\nfunction parseVForIteratorForEcmaVersion5(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n) {\n const ast = parseScriptFragment(\n `0(${code})`,\n locationCalculator.getSubCalculatorShift(-2),\n parserOptions,\n ).ast\n const tokens = ast.tokens || []\n const comments = ast.comments || []\n const references = analyzeExternalReferences(ast, parserOptions)\n\n const statement = ast.body[0] as ESLintExpressionStatement\n const callExpression = statement.expression as ESLintCallExpression\n const expression = callExpression.arguments[0]\n\n if (!expression) {\n return throwEmptyError(locationCalculator, \"an expression\")\n }\n if (expression && expression.type === \"SpreadElement\") {\n return throwUnexpectedTokenError(\"...\", expression)\n }\n const right = expression\n\n // Remove parens.\n tokens.shift()\n tokens.shift()\n tokens.pop()\n return { right, tokens, comments, references }\n}\n\n/**\n * Parse the source code of inline scripts.\n * @param code The source code of inline scripts.\n * @param locationCalculator The location calculator for the inline script.\n * @param parserOptions The parser options.\n * @returns The result of parsing.\n */\nexport function parseVOnExpression(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n): ExpressionParseResult {\n if (IS_FUNCTION_EXPRESSION.test(code) || IS_SIMPLE_PATH.test(code)) {\n return parseExpressionBody(code, locationCalculator, parserOptions)\n }\n return parseVOnExpressionBody(code, locationCalculator, parserOptions)\n}\n\n/**\n * Parse the source code of inline scripts.\n * @param code The source code of inline scripts.\n * @param locationCalculator The location calculator for the inline script.\n * @param parserOptions The parser options.\n * @returns The result of parsing.\n */\nfunction parseVOnExpressionBody(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n): ExpressionParseResult {\n debug('[script] parse v-on expression: \"void function($event){%s}\"', code)\n\n if (code.trim() === \"\") {\n throwEmptyError(locationCalculator, \"statements\")\n }\n\n try {\n const ast = parseScriptFragment(\n `void function($event){${code}}`,\n locationCalculator.getSubCalculatorShift(-22),\n parserOptions,\n ).ast\n const references = analyzeExternalReferences(ast, parserOptions)\n const outermostStatement = ast.body[0] as ESLintExpressionStatement\n const functionDecl = (\n outermostStatement.expression as ESLintUnaryExpression\n ).argument as ESLintFunctionExpression\n const block = functionDecl.body\n const body = block.body\n const firstStatement = first(body)\n const lastStatement = last(body)\n const expression: VOnExpression = {\n type: \"VOnExpression\",\n range: [\n firstStatement != null\n ? firstStatement.range[0]\n : block.range[0] + 1,\n lastStatement != null\n ? lastStatement.range[1]\n : block.range[1] - 1,\n ],\n loc: {\n start:\n firstStatement != null\n ? firstStatement.loc.start\n : locationCalculator.getLocation(1),\n end:\n lastStatement != null\n ? lastStatement.loc.end\n : locationCalculator.getLocation(code.length + 1),\n },\n parent: DUMMY_PARENT,\n body,\n }\n const tokens = ast.tokens || []\n const comments = ast.comments || []\n\n // Modify parent.\n for (const b of body) {\n b.parent = expression\n }\n\n // Remove braces.\n tokens.splice(0, 6)\n tokens.pop()\n\n return { expression, tokens, comments, references, variables: [] }\n } catch (err) {\n return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator)\n }\n}\n\n/**\n * Parse the source code of `slot-scope` directive.\n * @param code The source code of `slot-scope` directive.\n * @param locationCalculator The location calculator for the inline script.\n * @param parserOptions The parser options.\n * @returns The result of parsing.\n */\nexport function parseSlotScopeExpression(\n code: string,\n locationCalculator: LocationCalculatorForHtml,\n parserOptions: ParserOptions,\n): ExpressionParseResult {\n debug('[script] parse slot-scope expression: \"void function(%s) {}\"', code)\n\n if (code.trim() === \"\") {\n throwEmptyError(\n locationCalculator,\n \"an identifier or an array/object pattern\",\n )\n }\n\n try {\n const ast = parseScriptFragment(\n `void function(${code}) {}`,\n locationCalculator.getSubCalculatorShift(-14),\n parserOptions,\n ).ast\n const statement = ast.body[0] as ESLintExpressionStatement\n const rawExpression = statement.expression as ESLintUnaryExpression\n const functionDecl = rawExpression.argument as ESLintFunctionExpression\n const params = functionDecl.params\n\n if (params.length === 0) {\n return {\n expression: null,\n tokens: [],\n comments: [],\n references: [],\n variables: [],\n }\n }\n\n const tokens = ast.tokens || []\n const comments = ast.comments || []\n const scope = analyzeVariablesAndExternalReferences(ast, parserOptions)\n const references = scope.references\n const variables = scope.variables\n const firstParam = first(params)!\n const lastParam = last(params)!\n const expression: VSlotScopeExpression = {\n type: \"VSlotScopeExpression\",\n range: [firstParam.range[0], lastParam.range[1]],\n loc: { start: firstParam.loc.start, end: lastParam.loc.end },\n parent: DUMMY_PARENT,\n params: functionDecl.params,\n }\n\n // Modify parent.\n for (const param of params) {\n param.parent = expression\n }\n\n // Remove `void` `function` `(` `)` `{` `}`.\n tokens.shift()\n tokens.shift()\n tokens.shift()\n tokens.pop()\n tokens.pop()\n tokens.pop()\n\n return { expression, tokens, comments, references, variables }\n } catch (err) {\n return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator)\n }\n}\n","import sortedIndexBy from \"lodash/sortedIndexBy\"\nimport sortedLastIndexBy from \"lodash/sortedLastIndexBy\"\nimport type { LocationRange, Token, VDocumentFragment } from \"../ast\"\nimport type { LinesAndColumns } from \"./lines-and-columns\"\n\ninterface HasRange {\n range: [number, number]\n}\n/**\n * Replace the tokens in the given range.\n * @param document The document that the node is belonging to.\n * @param node The node to specify the range of replacement.\n * @param newTokens The new tokens.\n */\nexport function replaceTokens(\n document: VDocumentFragment | null,\n node: HasRange,\n newTokens: Token[],\n): void {\n if (document == null) {\n return\n }\n\n const index = sortedIndexBy(document.tokens, node, byRange0)\n const count = sortedLastIndexBy(document.tokens, node, byRange1) - index\n document.tokens.splice(index, count, ...newTokens)\n}\n\n/**\n * Replace and split the tokens in the given range.\n * @param document The document that the node is belonging to.\n * @param node The node to specify the range of replacement.\n * @param newTokens The new tokens.\n */\nexport function replaceAndSplitTokens(\n document: VDocumentFragment | null,\n node: HasRange & {\n loc: LocationRange\n },\n newTokens: Token[],\n): void {\n if (document == null) {\n return\n }\n\n const index = sortedIndexBy(document.tokens, node, byRange0)\n if (\n document.tokens.length === index ||\n node.range[0] < document.tokens[index].range[0]\n ) {\n // split\n const beforeToken = document.tokens[index - 1]\n const value = beforeToken.value\n const splitOffset = node.range[0] - beforeToken.range[0]\n const afterToken: Token = {\n type: beforeToken.type,\n range: [node.range[0], beforeToken.range[1]],\n loc: {\n start: { ...node.loc.start },\n end: { ...beforeToken.loc.end },\n },\n value: value.slice(splitOffset),\n }\n beforeToken.range[1] = node.range[0]\n beforeToken.loc.end = { ...node.loc.start }\n beforeToken.value = value.slice(0, splitOffset)\n document.tokens.splice(index, 0, afterToken)\n }\n let lastIndex = sortedLastIndexBy(document.tokens, node, byRange1)\n if (\n lastIndex === 0 ||\n node.range[1] < document.tokens[lastIndex].range[1]\n ) {\n // split\n const beforeToken = document.tokens[lastIndex]\n const value = beforeToken.value\n const splitOffset =\n beforeToken.range[1] -\n beforeToken.range[0] -\n (beforeToken.range[1] - node.range[1])\n const afterToken: Token = {\n type: beforeToken.type,\n range: [node.range[1], beforeToken.range[1]],\n loc: {\n start: { ...node.loc.end },\n end: { ...beforeToken.loc.end },\n },\n value: value.slice(splitOffset),\n }\n beforeToken.range[1] = node.range[1]\n beforeToken.loc.end = { ...node.loc.end }\n beforeToken.value = value.slice(0, splitOffset)\n document.tokens.splice(lastIndex + 1, 0, afterToken)\n lastIndex++\n }\n const count = lastIndex - index\n document.tokens.splice(index, count, ...newTokens)\n}\n\n/**\n * Insert the given comment tokens.\n * @param document The document that the node is belonging to.\n * @param newComments The comments to insert.\n */\nexport function insertComments(\n document: VDocumentFragment | null,\n newComments: Token[],\n): void {\n if (document == null || newComments.length === 0) {\n return\n }\n\n const index = sortedIndexBy(document.comments, newComments[0], byRange0)\n document.comments.splice(index, 0, ...newComments)\n}\n\n/**\n * Create a simple token.\n * @param type The type of new token.\n * @param start The offset of the start position of new token.\n * @param end The offset of the end position of new token.\n * @param value The value of new token.\n * @returns The new token.\n */\nexport function createSimpleToken(\n type: string,\n start: number,\n end: number,\n value: string,\n linesAndColumns: LinesAndColumns,\n): Token {\n return {\n type,\n range: [start, end],\n loc: {\n start: linesAndColumns.getLocFromIndex(start),\n end: linesAndColumns.getLocFromIndex(end),\n },\n value,\n }\n}\n\n/**\n * Get `x.range[0]`.\n * @param x The object to get.\n * @returns `x.range[0]`.\n */\nfunction byRange0(x: HasRange): number {\n return x.range[0]\n}\n\n/**\n * Get `x.range[1]`.\n * @param x The object to get.\n * @returns `x.range[1]`.\n */\nfunction byRange1(x: HasRange): number {\n return x.range[1]\n}\n","import type { ParseError, VDocumentFragment } from \"../ast\"\nimport sortedIndexBy from \"lodash/sortedIndexBy\"\n/**\n * Insert the given error.\n * @param document The document that the node is belonging to.\n * @param error The error to insert.\n */\nexport function insertError(\n document: VDocumentFragment | null,\n error: ParseError,\n): void {\n if (document == null) {\n return\n }\n\n const index = sortedIndexBy(document.errors, error, byIndex)\n document.errors.splice(index, 0, error)\n}\n\n/**\n * Get `x.pos`.\n * @param x The object to get.\n * @returns `x.pos`.\n */\nfunction byIndex(x: ParseError): number {\n return x.index\n}\n","/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\nimport type { ParserOptions } from \"../common/parser-options\"\nimport { isSFCFile } from \"../common/parser-options\"\nimport type {\n ESLintExpression,\n Reference,\n Token,\n VAttribute,\n VDirective,\n VDirectiveKey,\n VDocumentFragment,\n VElement,\n VExpressionContainer,\n VFilterSequenceExpression,\n VForExpression,\n VIdentifier,\n VLiteral,\n VNode,\n VOnExpression,\n VSlotScopeExpression,\n} from \"../ast\"\nimport { ParseError } from \"../ast\"\nimport { debug } from \"../common/debug\"\nimport type { LocationCalculatorForHtml } from \"../common/location-calculator\"\nimport type { ExpressionParseResult } from \"../script\"\nimport {\n parseExpression,\n parseVForExpression,\n parseVOnExpression,\n parseSlotScopeExpression,\n} from \"../script\"\nimport {\n createSimpleToken,\n insertComments,\n replaceTokens,\n} from \"../common/token-utils\"\nimport { getOwnerDocument } from \"../common/ast-utils\"\nimport { insertError } from \"../common/error-utils\"\n\nconst shorthandSign = /^[.:@#]/u\nconst shorthandNameMap = { \":\": \"bind\", \".\": \"bind\", \"@\": \"on\", \"#\": \"slot\" }\nconst invalidDynamicArgumentNextChar = /^[\\s\\r\\n=/>]$/u\n\n/**\n * Gets the tag name from the given node or token.\n * For SFC, it returns the value of `rawName` to be case sensitive.\n */\nfunction getTagName(\n startTagOrElement: { name: string; rawName: string },\n isSFC: boolean,\n) {\n return isSFC ? startTagOrElement.rawName : startTagOrElement.name\n}\n\n/**\n * Parse the given attribute name as a directive key.\n * @param node The identifier node to parse.\n * @param document The document to add parsing errors.\n * @returns The directive key node.\n */\nfunction parseDirectiveKeyStatically(\n node: VIdentifier,\n document: VDocumentFragment | null,\n): VDirectiveKey {\n const {\n name: text,\n rawName: rawText,\n range: [offset],\n loc: {\n start: { column, line },\n },\n } = node\n const directiveKey: VDirectiveKey = {\n type: \"VDirectiveKey\",\n range: node.range,\n loc: node.loc,\n parent: node.parent as any,\n name: null as any,\n argument: null as VIdentifier | null,\n modifiers: [] as VIdentifier[],\n }\n let i = 0\n\n function createIdentifier(\n start: number,\n end: number,\n name?: string,\n ): VIdentifier {\n return {\n type: \"VIdentifier\",\n parent: directiveKey,\n range: [offset + start, offset + end],\n loc: {\n start: { column: column + start, line },\n end: { column: column + end, line },\n },\n name: name || text.slice(start, end),\n rawName: rawText.slice(start, end),\n }\n }\n\n // Parse.\n if (shorthandSign.test(text)) {\n const sign = text[0] as \":\" | \".\" | \"@\" | \"#\"\n directiveKey.name = createIdentifier(0, 1, shorthandNameMap[sign])\n i = 1\n } else {\n const colon = text.indexOf(\":\")\n if (colon !== -1) {\n directiveKey.name = createIdentifier(0, colon)\n i = colon + 1\n }\n }\n\n if (directiveKey.name != null && text[i] === \"[\") {\n // Dynamic argument.\n const len = text.slice(i).lastIndexOf(\"]\")\n if (len !== -1) {\n directiveKey.argument = createIdentifier(i, i + len + 1)\n i = i + len + 1 + (text[i + len + 1] === \".\" ? 1 : 0)\n }\n }\n\n const modifiers = text\n .slice(i)\n .split(\".\")\n .map((modifierName) => {\n const modifier = createIdentifier(i, i + modifierName.length)\n if (modifierName === \"\" && i < text.length) {\n insertError(\n document,\n new ParseError(\n `Unexpected token '${text[i]}'`,\n undefined,\n offset + i,\n line,\n column + i,\n ),\n )\n }\n i += modifierName.length + 1\n return modifier\n })\n\n if (directiveKey.name == null) {\n directiveKey.name = modifiers.shift()!\n } else if (directiveKey.argument == null && modifiers[0].name !== \"\") {\n directiveKey.argument = modifiers.shift() || null\n }\n directiveKey.modifiers = modifiers.filter(isNotEmptyModifier)\n\n if (directiveKey.name.name === \"v-\") {\n insertError(\n document,\n new ParseError(\n `Unexpected token '${\n text[directiveKey.name.range[1] - offset]\n }'`,\n undefined,\n directiveKey.name.range[1],\n directiveKey.name.loc.end.line,\n directiveKey.name.loc.end.column,\n ),\n )\n }\n\n // v-bind.prop shorthand\n if (\n directiveKey.name.rawName === \".\" &&\n !directiveKey.modifiers.some(isPropModifier)\n ) {\n const pos =\n (directiveKey.argument || directiveKey.name).range[1] - offset\n const propModifier = createIdentifier(pos, pos, \"prop\")\n directiveKey.modifiers.unshift(propModifier)\n }\n\n return directiveKey\n}\n\n/**\n * Check whether a given identifier node is `prop` or not.\n * @param node The identifier node to check.\n */\nfunction isPropModifier(node: VIdentifier): boolean {\n return node.name === \"prop\"\n}\n\n/**\n * Check whether a given identifier node is empty or not.\n * @param node The identifier node to check.\n */\nfunction isNotEmptyModifier(node: VIdentifier): boolean {\n return node.name !== \"\"\n}\n\n/**\n * Parse the tokens of a given key node.\n * @param node The key node to parse.\n */\nfunction parseDirectiveKeyTokens(node: VDirectiveKey): Token[] {\n const { name, argument, modifiers } = node\n const shorthand = name.range[1] - name.range[0] === 1\n const tokens: Token[] = []\n\n if (shorthand) {\n tokens.push({\n type: \"Punctuator\",\n range: name.range,\n loc: name.loc,\n value: name.rawName,\n })\n } else {\n tokens.push({\n type: \"HTMLIdentifier\",\n range: name.range,\n loc: name.loc,\n value: name.rawName,\n })\n\n if (argument) {\n tokens.push({\n type: \"Punctuator\",\n range: [name.range[1], argument.range[0]],\n loc: { start: name.loc.end, end: argument.loc.start },\n value: \":\",\n })\n }\n }\n\n if (argument) {\n tokens.push({\n type: \"HTMLIdentifier\",\n range: argument.range,\n loc: argument.loc,\n value: (argument as VIdentifier).rawName,\n })\n }\n\n let lastNode = (argument as VIdentifier | null) || name\n for (const modifier of modifiers) {\n if (modifier.rawName === \"\") {\n continue\n }\n\n tokens.push(\n {\n type: \"Punctuator\",\n range: [lastNode.range[1], modifier.range[0]],\n loc: { start: lastNode.loc.end, end: modifier.loc.start },\n value: \".\",\n },\n {\n type: \"HTMLIdentifier\",\n range: modifier.range,\n loc: modifier.loc,\n value: modifier.rawName,\n },\n )\n lastNode = modifier\n }\n\n return tokens\n}\n\n/**\n * Convert `node.argument` property to a `VExpressionContainer` node if it's a dynamic argument.\n * @param text The source code text of the directive key node.\n * @param node The directive key node to convert.\n * @param document The belonging document node.\n * @param parserOptions The parser options to parse.\n * @param locationCalculator The location calculator to parse.\n */\nfunction convertDynamicArgument(\n node: VDirectiveKey,\n document: VDocumentFragment | null,\n parserOptions: ParserOptions,\n locationCalculator: LocationCalculatorForHtml,\n): void {\n const { argument } = node\n if (\n !(\n argument != null &&\n argument.type === \"VIdentifier\" &&\n argument.name.startsWith(\"[\") &&\n argument.name.endsWith(\"]\")\n )\n ) {\n return\n }\n\n const { rawName, range, loc } = argument\n try {\n const { comments, expression, references, tokens } = parseExpression(\n rawName.slice(1, -1),\n locationCalculator.getSubCalculatorAfter(range[0] + 1),\n parserOptions,\n )\n\n node.argument = {\n type: \"VExpressionContainer\",\n range,\n loc,\n parent: node,\n expression,\n references,\n }\n\n if (expression != null) {\n expression.parent = node.argument\n }\n\n // Add tokens of `[` and `]`.\n tokens.unshift(\n createSimpleToken(\n \"Punctuator\",\n range[0],\n range[0] + 1,\n \"[\",\n locationCalculator,\n ),\n )\n tokens.push(\n createSimpleToken(\n \"Punctuator\",\n range[1] - 1,\n range[1],\n \"]\",\n locationCalculator,\n ),\n )\n\n replaceTokens(document, node.argument, tokens)\n insertComments(document, comments)\n } catch (error) {\n debug(\"[template] Parse error: %s\", error)\n\n if (ParseError.isParseError(error)) {\n node.argument = {\n type: \"VExpressionContainer\",\n range,\n loc,\n parent: node,\n expression: null,\n references: [],\n }\n insertError(document, error)\n } else {\n throw error\n }\n }\n}\n\n/**\n * Parse the given attribute name as a directive key.\n * @param node The identifier node to parse.\n * @returns The directive key node.\n */\nfunction createDirectiveKey(\n node: VIdentifier,\n document: VDocumentFragment | null,\n parserOptions: ParserOptions,\n locationCalculator: LocationCalculatorForHtml,\n): VDirectiveKey {\n // Parse node and tokens.\n const directiveKey = parseDirectiveKeyStatically(node, document)\n const tokens = parseDirectiveKeyTokens(directiveKey)\n replaceTokens(document, directiveKey, tokens)\n\n // Drop `v-` prefix.\n if (directiveKey.name.name.startsWith(\"v-\")) {\n directiveKey.name.name = directiveKey.name.name.slice(2)\n }\n if (directiveKey.name.rawName.startsWith(\"v-\")) {\n directiveKey.name.rawName = directiveKey.name.rawName.slice(2)\n }\n\n // Parse dynamic argument.\n convertDynamicArgument(\n directiveKey,\n document,\n parserOptions,\n locationCalculator,\n )\n\n return directiveKey\n}\n\n/**\n * Parse the given attribute value as an expression.\n * @param code Whole source code text.\n * @param parserOptions The parser options to parse expressions.\n * @param globalLocationCalculator The location calculator to adjust the locations of nodes.\n * @param node The attribute node to replace. This function modifies this node directly.\n * @param tagName The name of this tag.\n * @param directiveKey The key of this directive.\n */\nfunction parseAttributeValue(\n code: string,\n parserOptions: ParserOptions,\n globalLocationCalculator: LocationCalculatorForHtml,\n node: VLiteral,\n tagName: string,\n directiveKey: VDirectiveKey,\n): ExpressionParseResult<\n | ESLintExpression\n | VFilterSequenceExpression\n | VForExpression\n | VOnExpression\n | VSlotScopeExpression\n> {\n const firstChar = code[node.range[0]]\n const quoted = firstChar === '\"' || firstChar === \"'\"\n const locationCalculator = globalLocationCalculator.getSubCalculatorAfter(\n node.range[0] + (quoted ? 1 : 0),\n )\n const directiveName = directiveKey.name.name\n\n let result: ExpressionParseResult<\n | ESLintExpression\n | VFilterSequenceExpression\n | VForExpression\n | VOnExpression\n | VSlotScopeExpression\n >\n if (quoted && node.value === \"\") {\n result = {\n expression: null,\n tokens: [],\n comments: [],\n variables: [],\n references: [],\n }\n } else if (directiveName === \"for\") {\n result = parseVForExpression(\n node.value,\n locationCalculator,\n parserOptions,\n )\n } else if (directiveName === \"on\" && directiveKey.argument != null) {\n result = parseVOnExpression(\n node.value,\n locationCalculator,\n parserOptions,\n )\n } else if (\n directiveName === \"slot\" ||\n directiveName === \"slot-scope\" ||\n (tagName === \"template\" && directiveName === \"scope\")\n ) {\n result = parseSlotScopeExpression(\n node.value,\n locationCalculator,\n parserOptions,\n )\n } else if (directiveName === \"bind\") {\n result = parseExpression(\n node.value,\n locationCalculator,\n parserOptions,\n { allowFilters: true },\n )\n } else {\n result = parseExpression(node.value, locationCalculator, parserOptions)\n }\n\n // Add the tokens of quotes.\n if (quoted) {\n result.tokens.unshift(\n createSimpleToken(\n \"Punctuator\",\n node.range[0],\n node.range[0] + 1,\n firstChar,\n globalLocationCalculator,\n ),\n )\n result.tokens.push(\n createSimpleToken(\n \"Punctuator\",\n node.range[1] - 1,\n node.range[1],\n firstChar,\n globalLocationCalculator,\n ),\n )\n }\n\n return result\n}\n\n/**\n * Resolve the variable of the given reference.\n * @param referene The reference to resolve.\n * @param element The belonging element of the reference.\n */\nfunction resolveReference(referene: Reference, element: VElement): void {\n let node: VNode | null = element\n\n // Find the variable of this reference.\n while (node != null && node.type === \"VElement\") {\n for (const variable of node.variables) {\n if (variable.id.name === referene.id.name) {\n referene.variable = variable\n variable.references.push(referene)\n return\n }\n }\n\n node = node.parent\n }\n}\n\n/**\n * Information of a mustache.\n */\nexport interface Mustache {\n value: string\n startToken: Token\n endToken: Token\n}\n\n/**\n * Replace the given attribute by a directive.\n * @param code Whole source code text.\n * @param parserOptions The parser options to parse expressions.\n * @param locationCalculator The location calculator to adjust the locations of nodes.\n * @param node The attribute node to replace. This function modifies this node directly.\n */\nexport function convertToDirective(\n code: string,\n parserOptions: ParserOptions,\n locationCalculator: LocationCalculatorForHtml,\n node: VAttribute,\n): void {\n debug(\n '[template] convert to directive: %s=\"%s\" %j',\n node.key.name,\n node.value && node.value.value,\n node.range,\n )\n\n const document = getOwnerDocument(node)\n const directive: VDirective = node as any\n directive.directive = true\n directive.key = createDirectiveKey(\n node.key,\n document,\n parserOptions,\n locationCalculator,\n )\n\n const { argument } = directive.key\n if (\n argument &&\n argument.type === \"VIdentifier\" &&\n argument.name.startsWith(\"[\")\n ) {\n const nextChar = code[argument.range[1]]\n if (nextChar == null || invalidDynamicArgumentNextChar.test(nextChar)) {\n const char =\n nextChar == null ? \"EOF\" : JSON.stringify(nextChar).slice(1, -1)\n insertError(\n document,\n new ParseError(\n `Dynamic argument cannot contain the '${char}' character.`,\n undefined,\n argument.range[1],\n argument.loc.end.line,\n argument.loc.end.column,\n ),\n )\n }\n }\n\n if (node.value == null) {\n return\n }\n\n try {\n const ret = parseAttributeValue(\n code,\n parserOptions,\n locationCalculator,\n node.value,\n getTagName(node.parent.parent, isSFCFile(parserOptions)),\n directive.key,\n )\n\n directive.value = {\n type: \"VExpressionContainer\",\n range: node.value.range,\n loc: node.value.loc,\n parent: directive,\n expression: ret.expression,\n references: ret.references,\n }\n if (ret.expression != null) {\n ret.expression.parent = directive.value\n }\n\n for (const variable of ret.variables) {\n node.parent.parent.variables.push(variable)\n }\n\n replaceTokens(document, node.value, ret.tokens)\n insertComments(document, ret.comments)\n } catch (err) {\n debug(\"[template] Parse error: %s\", err)\n\n if (ParseError.isParseError(err)) {\n directive.value = {\n type: \"VExpressionContainer\",\n range: node.value.range,\n loc: node.value.loc,\n parent: directive,\n expression: null,\n references: [],\n }\n insertError(document, err)\n } else {\n throw err\n }\n }\n}\n\n/**\n * Parse the content of the given mustache.\n * @param parserOptions The parser options to parse expressions.\n * @param globalLocationCalculator The location calculator to adjust the locations of nodes.\n * @param node The expression container node. This function modifies the `expression` and `references` properties of this node.\n * @param mustache The information of mustache to parse.\n */\nexport function processMustache(\n parserOptions: ParserOptions,\n globalLocationCalculator: LocationCalculatorForHtml,\n node: VExpressionContainer,\n mustache: Mustache,\n): void {\n const range: [number, number] = [\n mustache.startToken.range[1],\n mustache.endToken.range[0],\n ]\n debug(\"[template] convert mustache {{%s}} %j\", mustache.value, range)\n\n const document = getOwnerDocument(node)\n try {\n const locationCalculator =\n globalLocationCalculator.getSubCalculatorAfter(range[0])\n const ret = parseExpression(\n mustache.value,\n locationCalculator,\n parserOptions,\n { allowEmpty: true, allowFilters: true },\n )\n\n node.expression = ret.expression || null\n node.references = ret.references\n if (ret.expression != null) {\n ret.expression.parent = node\n }\n\n replaceTokens(document, { range }, ret.tokens)\n insertComments(document, ret.comments)\n } catch (err) {\n debug(\"[template] Parse error: %s\", err)\n\n if (ParseError.isParseError(err)) {\n insertError(document, err)\n } else {\n throw err\n }\n }\n}\n\n/**\n * Resolve all references of the given expression container.\n * @param container The expression container to resolve references.\n */\nexport function resolveReferences(container: VExpressionContainer): void {\n let element: VNode | null = container.parent\n\n // Get the belonging element.\n while (element != null && element.type !== \"VElement\") {\n element = element.parent\n }\n\n // Resolve.\n if (element != null) {\n for (const reference of container.references) {\n resolveReference(reference, element)\n }\n }\n}\n","/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\nexport const SVG_ATTRIBUTE_NAME_MAP = new Map([\n [\"attributename\", \"attributeName\"],\n [\"attributetype\", \"attributeType\"],\n [\"basefrequency\", \"baseFrequency\"],\n [\"baseprofile\", \"baseProfile\"],\n [\"calcmode\", \"calcMode\"],\n [\"clippathunits\", \"clipPathUnits\"],\n [\"diffuseconstant\", \"diffuseConstant\"],\n [\"edgemode\", \"edgeMode\"],\n [\"filterunits\", \"filterUnits\"],\n [\"glyphref\", \"glyphRef\"],\n [\"gradienttransform\", \"gradientTransform\"],\n [\"gradientunits\", \"gradientUnits\"],\n [\"kernelmatrix\", \"kernelMatrix\"],\n [\"kernelunitlength\", \"kernelUnitLength\"],\n [\"keypoints\", \"keyPoints\"],\n [\"keysplines\", \"keySplines\"],\n [\"keytimes\", \"keyTimes\"],\n [\"lengthadjust\", \"lengthAdjust\"],\n [\"limitingconeangle\", \"limitingConeAngle\"],\n [\"markerheight\", \"markerHeight\"],\n [\"markerunits\", \"markerUnits\"],\n [\"markerwidth\", \"markerWidth\"],\n [\"maskcontentunits\", \"maskContentUnits\"],\n [\"maskunits\", \"maskUnits\"],\n [\"numoctaves\", \"numOctaves\"],\n [\"pathlength\", \"pathLength\"],\n [\"patterncontentunits\", \"patternContentUnits\"],\n [\"patterntransform\", \"patternTransform\"],\n [\"patternunits\", \"patternUnits\"],\n [\"pointsatx\", \"pointsAtX\"],\n [\"pointsaty\", \"pointsAtY\"],\n [\"pointsatz\", \"pointsAtZ\"],\n [\"preservealpha\", \"preserveAlpha\"],\n [\"preserveaspectratio\", \"preserveAspectRatio\"],\n [\"primitiveunits\", \"primitiveUnits\"],\n [\"refx\", \"refX\"],\n [\"refy\", \"refY\"],\n [\"repeatcount\", \"repeatCount\"],\n [\"repeatdur\", \"repeatDur\"],\n [\"requiredextensions\", \"requiredExtensions\"],\n [\"requiredfeatures\", \"requiredFeatures\"],\n [\"specularconstant\", \"specularConstant\"],\n [\"specularexponent\", \"specularExponent\"],\n [\"spreadmethod\", \"spreadMethod\"],\n [\"startoffset\", \"startOffset\"],\n [\"stddeviation\", \"stdDeviation\"],\n [\"stitchtiles\", \"stitchTiles\"],\n [\"surfacescale\", \"surfaceScale\"],\n [\"systemlanguage\", \"systemLanguage\"],\n [\"tablevalues\", \"tableValues\"],\n [\"targetx\", \"targetX\"],\n [\"targety\", \"targetY\"],\n [\"textlength\", \"textLength\"],\n [\"viewbox\", \"viewBox\"],\n [\"viewtarget\", \"viewTarget\"],\n [\"xchannelselector\", \"xChannelSelector\"],\n [\"ychannelselector\", \"yChannelSelector\"],\n [\"zoomandpan\", \"zoomAndPan\"],\n])\n\nexport const MATHML_ATTRIBUTE_NAME_MAP = new Map([\n [\"definitionurl\", \"definitionUrl\"]\n])\n","/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\n\n/**\n * HTML tag names.\n */\nexport const HTML_TAGS = new Set([\n \"a\", \"abbr\", \"address\", \"area\", \"article\",\"aside\", \"audio\", \"b\", \"base\",\n \"bdi\", \"bdo\", \"blockquote\", \"body\", \"br\", \"button\", \"canvas\", \"caption\",\n \"cite\", \"code\", \"col\", \"colgroup\", \"data\", \"datalist\", \"dd\", \"del\",\n \"details\", \"dfn\", \"dialog\", \"div\", \"dl\", \"document\", \"dt\", \"em\", \"embed\",\n \"fieldset\", \"figcaption\", \"figure\", \"footer\", \"form\", \"h1\", \"h2\", \"h3\",\n \"h4\", \"h5\", \"h6\", \"head\", \"header\", \"hgroup\", \"hr\", \"html\", \"i\", \"iframe\",\n \"img\", \"input\", \"ins\", \"kbd\", \"label\", \"legend\", \"li\", \"link\", \"main\",\n \"map\", \"mark\", \"marquee\", \"menu\", \"meta\", \"meter\", \"nav\", \"noscript\",\n \"object\", \"ol\", \"optgroup\", \"option\", \"output\", \"p\", \"param\", \"picture\",\n \"pre\", \"progress\", \"q\", \"rp\", \"rt\", \"ruby\", \"s\", \"samp\", \"script\",\n \"section\", \"select\", \"slot\", \"small\", \"source\", \"span\", \"strong\", \"style\",\n \"sub\", \"summary\", \"sup\", \"table\", \"tbody\", \"td\", \"template\", \"textarea\",\n \"tfoot\", \"th\", \"thead\", \"time\", \"title\", \"tr\", \"track\", \"u\", \"ul\", \"var\",\n \"video\", \"wbr\"\n])\n\n/**\n * HTML tag names of void elements.\n */\nexport const HTML_VOID_ELEMENT_TAGS = new Set([\n \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\", \"link\", \"meta\",\n \"param\", \"source\", \"track\", \"wbr\",\n])\n\n/**\n * https://github.com/vuejs/vue/blob/e4da249ab8ef32a0b8156c840c9d2b9773090f8a/src/platforms/web/compiler/util.js#L12\n */\nexport const HTML_CAN_BE_LEFT_OPEN_TAGS = new Set([\n \"colgroup\", \"li\", \"options\", \"p\", \"td\", \"tfoot\", \"th\", \"thead\", \n \"tr\", \"source\",\n])\n\n/**\n * https://github.com/vuejs/vue/blob/e4da249ab8ef32a0b8156c840c9d2b9773090f8a/src/platforms/web/compiler/util.js#L18\n */\nexport const HTML_NON_FHRASING_TAGS = new Set([\n \"address\", \"article\", \"aside\", \"base\", \"blockquote\", \"body\", \"caption\", \n \"col\", \"colgroup\", \"dd\", \"details\", \"dialog\", \"div\", \"dl\", \"dt\", \"fieldset\", \n \"figcaption\", \"figure\", \"footer\", \"form\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \n \"h6\", \"head\", \"header\", \"hgroup\", \"hr\", \"html\", \"legend\", \"li\", \"menuitem\", \n \"meta\", \"optgroup\", \"option\", \"param\", \"rp\", \"rt\", \"source\", \"style\", \n \"summary\", \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"title\", \"tr\", \"track\",\n])\n\n/**\n * HTML tag names of RCDATA.\n */\nexport const HTML_RCDATA_TAGS = new Set([\n \"title\", \"textarea\",\n])\n\n/**\n * HTML tag names of RAWTEXT.\n */\nexport const HTML_RAWTEXT_TAGS = new Set([\n \"style\", \"xmp\", \"iframe\", \"noembed\", \"noframes\", \"noscript\", \"script\",\n])\n\n/**\n * SVG tag names.\n */\nexport const SVG_TAGS = new Set([\n \"a\", \"altGlyph\", \"altGlyphDef\", \"altGlyphItem\", \"animate\", \"animateColor\", \n \"animateMotion\", \"animateTransform\", \"animation\", \"audio\", \"canvas\", \n \"circle\", \"clipPath\", \"color-profile\", \"cursor\", \"defs\", \"desc\", \"discard\", \n \"ellipse\", \"feBlend\", \"feColorMatrix\", \"feComponentTransfer\", \"feComposite\", \n \"feConvolveMatrix\", \"feDiffuseLighting\", \"feDisplacementMap\", \n \"feDistantLight\", \"feDropShadow\", \"feFlood\", \"feFuncA\", \"feFuncB\", \n \"feFuncG\", \"feFuncR\", \"feGaussianBlur\", \"feImage\", \"feMerge\", \"feMergeNode\", \n \"feMorphology\", \"feOffset\", \"fePointLight\", \"feSpecularLighting\", \n \"feSpotLight\", \"feTile\", \"feTurbulence\", \"filter\", \"font\", \"font-face\", \n \"font-face-format\", \"font-face-name\", \"font-face-src\", \"font-face-uri\", \n \"foreignObject\", \"g\", \"glyph\", \"glyphRef\", \"handler\", \"hatch\", \"hatchpath\", \n \"hkern\", \"iframe\", \"image\", \"line\", \"linearGradient\", \"listener\", \"marker\", \n \"mask\", \"mesh\", \"meshgradient\", \"meshpatch\", \"meshrow\", \"metadata\", \n \"missing-glyph\", \"mpath\", \"path\", \"pattern\", \"polygon\", \"polyline\", \n \"prefetch\", \"radialGradient\", \"rect\", \"script\", \"set\", \"solidColor\", \n \"solidcolor\", \"stop\", \"style\", \"svg\", \"switch\", \"symbol\", \"tbreak\", \"text\", \n \"textArea\", \"textPath\", \"title\", \"tref\", \"tspan\", \"unknown\", \"use\", \"video\", \n \"view\", \"vkern\",\n])\n\n/**\n * The map from lowercase names to actual names in SVG.\n */\nexport const SVG_ELEMENT_NAME_MAP = new Map()\nfor (const name of SVG_TAGS) {\n if (/[A-Z]/.test(name)) {\n SVG_ELEMENT_NAME_MAP.set(name.toLowerCase(), name)\n }\n}\n\n/**\n * MathML tag names.\n */\nexport const MATHML_TAGS = new Set([\n \"abs\", \"and\", \"annotation\", \"annotation-xml\", \"apply\", \"approx\", \"arccos\", \n \"arccosh\", \"arccot\", \"arccoth\", \"arccsc\", \"arccsch\", \"arcsec\", \"arcsech\", \n \"arcsin\", \"arcsinh\", \"arctan\", \"arctanh\", \"arg\", \"bind\", \"bvar\", \"card\", \n \"cartesianproduct\", \"cbytes\", \"ceiling\", \"cerror\", \"ci\", \"cn\", \"codomain\", \n \"complexes\", \"compose\", \"condition\", \"conjugate\", \"cos\", \"cosh\", \"cot\", \n \"coth\", \"cs\", \"csc\", \"csch\", \"csymbol\", \"curl\", \"declare\", \"degree\", \n \"determinant\", \"diff\", \"divergence\", \"divide\", \"domain\", \n \"domainofapplication\", \"emptyset\", \"encoding\", \"eq\", \"equivalent\", \n \"eulergamma\", \"exists\", \"exp\", \"exponentiale\", \"factorial\", \"factorof\", \n \"false\", \"floor\", \"fn\", \"forall\", \"function\", \"gcd\", \"geq\", \"grad\", \"gt\", \n \"ident\", \"image\", \"imaginary\", \"imaginaryi\", \"implies\", \"in\", \"infinity\", \n \"int\", \"integers\", \"intersect\", \"interval\", \"inverse\", \"lambda\", \n \"laplacian\", \"lcm\", \"leq\", \"limit\", \"list\", \"ln\", \"log\", \"logbase\", \n \"lowlimit\", \"lt\", \"m:apply\", \"m:mrow\", \"maction\", \"malign\", \"maligngroup\", \n \"malignmark\", \"malignscope\", \"math\", \"matrix\", \"matrixrow\", \"max\", \"mean\", \n \"median\", \"menclose\", \"merror\", \"mfenced\", \"mfrac\", \"mfraction\", \"mglyph\", \n \"mi\", \"mi\\\"\", \"min\", \"minus\", \"mlabeledtr\", \"mlongdiv\", \"mmultiscripts\", \n \"mn\", \"mo\", \"mode\", \"moment\", \"momentabout\", \"mover\", \"mpadded\", \"mphantom\", \n \"mprescripts\", \"mroot\", \"mrow\", \"ms\", \"mscarries\", \"mscarry\", \"msgroup\", \n \"msline\", \"mspace\", \"msqrt\", \"msrow\", \"mstack\", \"mstyle\", \"msub\", \"msubsup\", \n \"msup\", \"mtable\", \"mtd\", \"mtext\", \"mtr\", \"munder\", \"munderover\", \n \"naturalnumbers\", \"neq\", \"none\", \"not\", \"notanumber\", \"notin\", \n \"notprsubset\", \"notsubset\", \"or\", \"otherwise\", \"outerproduct\", \n \"partialdiff\", \"pi\", \"piece\", \"piecewice\", \"piecewise\", \"plus\", \"power\", \n \"primes\", \"product\", \"prsubset\", \"quotient\", \"rationals\", \"real\", \"reals\", \n \"reln\", \"rem\", \"root\", \"scalarproduct\", \"sdev\", \"sec\", \"sech\", \"select\", \n \"selector\", \"semantics\", \"sep\", \"set\", \"setdiff\", \"share\", \"sin\", \"sinh\", \n \"span\", \"subset\", \"sum\", \"tan\", \"tanh\", \"tendsto\", \"times\", \"transpose\", \n \"true\", \"union\", \"uplimit\", \"var\", \"variance\", \"vector\", \"vectorproduct\", \n \"xor\",\n])\n","/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\nimport assert from \"assert\"\nimport last from \"lodash/last\"\nimport type {\n ErrorCode,\n HasLocation,\n Namespace,\n Token,\n VAttribute,\n} from \"../ast\"\nimport { ParseError } from \"../ast\"\nimport { debug } from \"../common/debug\"\nimport type { Tokenizer, TokenizerState, TokenType } from \"./tokenizer\"\n\nconst DUMMY_PARENT: any = Object.freeze({})\n\n/**\n * Concatenate token values.\n * @param text Concatenated text.\n * @param token The token to concatenate.\n */\nfunction concat(text: string, token: Token): string {\n return text + token.value\n}\n\n/**\n * The type of intermediate tokens.\n */\nexport type IntermediateToken = StartTag | EndTag | Text | Mustache\n\n/**\n * The type of start tags.\n */\nexport interface StartTag extends HasLocation {\n type: \"StartTag\"\n name: string\n rawName: string\n selfClosing: boolean\n attributes: VAttribute[]\n}\n\n/**\n * The type of end tags.\n */\nexport interface EndTag extends HasLocation {\n type: \"EndTag\"\n name: string\n}\n\n/**\n * The type of text chunks.\n */\nexport interface Text extends HasLocation {\n type: \"Text\"\n value: string\n}\n\n/**\n * The type of text chunks of an expression container.\n */\nexport interface Mustache extends HasLocation {\n type: \"Mustache\"\n value: string\n startToken: Token\n endToken: Token\n}\n\n/**\n * The class to create HTML tokens from ESTree-like tokens which are created by a Tokenizer.\n */\nexport class IntermediateTokenizer {\n private tokenizer: Tokenizer\n private currentToken: IntermediateToken | null\n private attribute: VAttribute | null\n private attributeNames: Set\n private expressionStartToken: Token | null\n private expressionTokens: Token[]\n\n public readonly tokens: Token[]\n public readonly comments: Token[]\n\n /**\n * The source code text.\n */\n public get text(): string {\n return this.tokenizer.text\n }\n\n /**\n * The parse errors.\n */\n public get errors(): ParseError[] {\n return this.tokenizer.errors\n }\n\n /**\n * The current state.\n */\n public get state(): TokenizerState {\n return this.tokenizer.state\n }\n public set state(value: TokenizerState) {\n this.tokenizer.state = value\n }\n\n /**\n * The current namespace.\n */\n public get namespace(): Namespace {\n return this.tokenizer.namespace\n }\n public set namespace(value: Namespace) {\n this.tokenizer.namespace = value\n }\n\n /**\n * The current flag of expression enabled.\n */\n public get expressionEnabled(): boolean {\n return this.tokenizer.expressionEnabled\n }\n public set expressionEnabled(value: boolean) {\n this.tokenizer.expressionEnabled = value\n }\n\n /**\n * Initialize this intermediate tokenizer.\n * @param tokenizer The tokenizer.\n */\n public constructor(tokenizer: Tokenizer) {\n this.tokenizer = tokenizer\n this.currentToken = null\n this.attribute = null\n this.attributeNames = new Set()\n this.expressionStartToken = null\n this.expressionTokens = []\n this.tokens = []\n this.comments = []\n }\n\n /**\n * Get the next intermediate token.\n * @returns The intermediate token or null.\n */\n public nextToken(): IntermediateToken | null {\n let token: Token | null = null\n let result: IntermediateToken | null = null\n\n while (result == null && (token = this.tokenizer.nextToken()) != null) {\n result = this[token.type as TokenType](token)\n }\n\n if (result == null && token == null && this.currentToken != null) {\n result = this.commit()\n }\n\n return result\n }\n\n /**\n * Commit the current token.\n */\n private commit(): IntermediateToken {\n assert(this.currentToken != null || this.expressionStartToken != null)\n\n let token = this.currentToken\n this.currentToken = null\n this.attribute = null\n\n if (this.expressionStartToken != null) {\n // VExpressionEnd was not found.\n // Concatenate the deferred tokens to the committed token.\n const start = this.expressionStartToken\n const end = last(this.expressionTokens) || start\n const value = this.expressionTokens.reduce(concat, start.value)\n this.expressionStartToken = null\n this.expressionTokens = []\n\n if (token == null) {\n token = {\n type: \"Text\",\n range: [start.range[0], end.range[1]],\n loc: { start: start.loc.start, end: end.loc.end },\n value,\n }\n } else if (token.type === \"Text\") {\n token.range[1] = end.range[1]\n token.loc.end = end.loc.end\n token.value += value\n } else {\n throw new Error(\"unreachable\")\n }\n }\n\n return token as IntermediateToken\n }\n\n /**\n * Report an invalid character error.\n * @param code The error code.\n */\n private reportParseError(token: HasLocation, code: ErrorCode): void {\n const error = ParseError.fromCode(\n code,\n token.range[0],\n token.loc.start.line,\n token.loc.start.column,\n )\n this.errors.push(error)\n\n debug(\"[html] syntax error:\", error.message)\n }\n\n /**\n * Process the given comment token.\n * @param token The comment token to process.\n */\n private processComment(token: Token): IntermediateToken | null {\n this.comments.push(token)\n\n if (this.currentToken != null && this.currentToken.type === \"Text\") {\n return this.commit()\n }\n return null\n }\n\n /**\n * Process the given text token.\n * @param token The text token to process.\n */\n private processText(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n let result: IntermediateToken | null = null\n\n if (this.expressionStartToken != null) {\n // Defer this token until a VExpressionEnd token or a non-text token appear.\n const lastToken =\n last(this.expressionTokens) || this.expressionStartToken\n if (lastToken.range[1] === token.range[0]) {\n this.expressionTokens.push(token)\n return null\n }\n\n result = this.commit()\n } else if (this.currentToken != null) {\n // Concatenate this token to the current text token.\n if (\n this.currentToken.type === \"Text\" &&\n this.currentToken.range[1] === token.range[0]\n ) {\n this.currentToken.value += token.value\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n return null\n }\n\n result = this.commit()\n }\n assert(this.currentToken == null)\n\n this.currentToken = {\n type: \"Text\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n value: token.value,\n }\n\n return result\n }\n\n /**\n * Process a HTMLAssociation token.\n * @param token The token to process.\n */\n protected HTMLAssociation(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n if (this.attribute != null) {\n this.attribute.range[1] = token.range[1]\n this.attribute.loc.end = token.loc.end\n\n if (\n this.currentToken == null ||\n this.currentToken.type !== \"StartTag\"\n ) {\n throw new Error(\"unreachable\")\n }\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n }\n\n return null\n }\n\n /**\n * Process a HTMLBogusComment token.\n * @param token The token to process.\n */\n protected HTMLBogusComment(token: Token): IntermediateToken | null {\n return this.processComment(token)\n }\n\n /**\n * Process a HTMLCDataText token.\n * @param token The token to process.\n */\n protected HTMLCDataText(token: Token): IntermediateToken | null {\n return this.processText(token)\n }\n\n /**\n * Process a HTMLComment token.\n * @param token The token to process.\n */\n protected HTMLComment(token: Token): IntermediateToken | null {\n return this.processComment(token)\n }\n\n /**\n * Process a HTMLEndTagOpen token.\n * @param token The token to process.\n */\n protected HTMLEndTagOpen(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n let result: IntermediateToken | null = null\n\n if (this.currentToken != null || this.expressionStartToken != null) {\n result = this.commit()\n }\n\n this.currentToken = {\n type: \"EndTag\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n name: token.value,\n }\n\n return result\n }\n\n /**\n * Process a HTMLIdentifier token.\n * @param token The token to process.\n */\n protected HTMLIdentifier(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n if (\n this.currentToken == null ||\n this.currentToken.type === \"Text\" ||\n this.currentToken.type === \"Mustache\"\n ) {\n throw new Error(\"unreachable\")\n }\n if (this.currentToken.type === \"EndTag\") {\n this.reportParseError(token, \"end-tag-with-attributes\")\n return null\n }\n if (this.attributeNames.has(token.value)) {\n this.reportParseError(token, \"duplicate-attribute\")\n }\n this.attributeNames.add(token.value)\n\n this.attribute = {\n type: \"VAttribute\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n parent: DUMMY_PARENT,\n directive: false,\n key: {\n type: \"VIdentifier\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n parent: DUMMY_PARENT,\n name: token.value,\n rawName: this.text.slice(token.range[0], token.range[1]),\n },\n value: null,\n }\n this.attribute.key.parent = this.attribute\n\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n this.currentToken.attributes.push(this.attribute)\n\n return null\n }\n\n /**\n * Process a HTMLLiteral token.\n * @param token The token to process.\n */\n protected HTMLLiteral(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n if (this.attribute != null) {\n this.attribute.range[1] = token.range[1]\n this.attribute.loc.end = token.loc.end\n this.attribute.value = {\n type: \"VLiteral\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n parent: this.attribute,\n value: token.value,\n }\n\n if (\n this.currentToken == null ||\n this.currentToken.type !== \"StartTag\"\n ) {\n throw new Error(\"unreachable\")\n }\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n }\n\n return null\n }\n\n /**\n * Process a HTMLRCDataText token.\n * @param token The token to process.\n */\n protected HTMLRCDataText(token: Token): IntermediateToken | null {\n return this.processText(token)\n }\n\n /**\n * Process a HTMLRawText token.\n * @param token The token to process.\n */\n protected HTMLRawText(token: Token): IntermediateToken | null {\n return this.processText(token)\n }\n\n /**\n * Process a HTMLSelfClosingTagClose token.\n * @param token The token to process.\n */\n protected HTMLSelfClosingTagClose(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n if (this.currentToken == null || this.currentToken.type === \"Text\") {\n throw new Error(\"unreachable\")\n }\n\n if (this.currentToken.type === \"StartTag\") {\n this.currentToken.selfClosing = true\n } else {\n this.reportParseError(token, \"end-tag-with-trailing-solidus\")\n }\n\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n\n return this.commit()\n }\n\n /**\n * Process a HTMLTagClose token.\n * @param token The token to process.\n */\n protected HTMLTagClose(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n if (this.currentToken == null || this.currentToken.type === \"Text\") {\n throw new Error(\"unreachable\")\n }\n\n this.currentToken.range[1] = token.range[1]\n this.currentToken.loc.end = token.loc.end\n\n return this.commit()\n }\n\n /**\n * Process a HTMLTagOpen token.\n * @param token The token to process.\n */\n protected HTMLTagOpen(token: Token): IntermediateToken | null {\n this.tokens.push(token)\n\n let result: IntermediateToken | null = null\n\n if (this.currentToken != null || this.expressionStartToken != null) {\n result = this.commit()\n }\n\n this.currentToken = {\n type: \"StartTag\",\n range: [token.range[0], token.range[1]],\n loc: { start: token.loc.start, end: token.loc.end },\n name: token.value,\n rawName: this.text.slice(token.range[0] + 1, token.range[1]),\n selfClosing: false,\n attributes: [],\n }\n this.attribute = null\n this.attributeNames.clear()\n\n return result\n }\n\n /**\n * Process a HTMLText token.\n * @param token The token to process.\n */\n protected HTMLText(token: Token): IntermediateToken | null {\n return this.processText(token)\n }\n\n /**\n * Process a HTMLWhitespace token.\n * @param token The token to process.\n */\n protected HTMLWhitespace(token: Token): IntermediateToken | null {\n return this.processText(token)\n }\n\n /**\n * Process a VExpressionStart token.\n * @param token The token to process.\n */\n protected VExpressionStart(token: Token): IntermediateToken | null {\n if (this.expressionStartToken != null) {\n return this.processText(token)\n }\n const separated =\n this.currentToken != null &&\n this.currentToken.range[1] !== token.range[0]\n const result = separated ? this.commit() : null\n\n this.tokens.push(token)\n this.expressionStartToken = token\n\n return result\n }\n\n /**\n * Process a VExpressionEnd token.\n * @param token The token to process.\n */\n protected VExpressionEnd(token: Token): IntermediateToken | null {\n if (this.expressionStartToken == null) {\n return this.processText(token)\n }\n\n const start = this.expressionStartToken\n const end = last(this.expressionTokens) || start\n\n // If it's '{{}}', it's handled as a text.\n if (token.range[0] === start.range[1]) {\n this.tokens.pop()\n this.expressionStartToken = null\n const result = this.processText(start)\n this.processText(token)\n return result\n }\n\n // If invalid notation `` exists directly before this token, separate it.\n if (end.range[1] !== token.range[0]) {\n const result = this.commit()\n this.processText(token)\n return result\n }\n\n // Clear state.\n const value = this.expressionTokens.reduce(concat, \"\")\n this.tokens.push(token)\n this.expressionStartToken = null\n this.expressionTokens = []\n\n // Create token.\n const result = this.currentToken != null ? this.commit() : null\n this.currentToken = {\n type: \"Mustache\",\n range: [start.range[0], token.range[1]],\n loc: { start: start.loc.start, end: token.loc.end },\n value,\n startToken: start,\n endToken: token,\n }\n\n return result || this.commit()\n }\n}\n","/**\n * @author Toru Nagashima \n * @copyright 2017 Toru Nagashima. All rights reserved.\n * See LICENSE file in root directory for full license.\n */\nimport assert from \"assert\"\nimport last from \"lodash/last\"\nimport findLastIndex from \"lodash/findLastIndex\"\nimport type {\n ErrorCode,\n HasLocation,\n Namespace,\n Token,\n VAttribute,\n VDocumentFragment,\n VElement,\n VExpressionContainer,\n} from \"../ast\"\nimport { NS, ParseError } from \"../ast\"\nimport { debug } from \"../common/debug\"\nimport { LocationCalculatorForHtml } from \"../common/location-calculator\"\nimport {\n convertToDirective,\n processMustache,\n resolveReferences,\n} from \"../template\"\nimport {\n MATHML_ATTRIBUTE_NAME_MAP,\n SVG_ATTRIBUTE_NAME_MAP,\n} from \"./util/attribute-names\"\nimport {\n HTML_CAN_BE_LEFT_OPEN_TAGS,\n HTML_NON_FHRASING_TAGS,\n HTML_RAWTEXT_TAGS,\n HTML_RCDATA_TAGS,\n HTML_VOID_ELEMENT_TAGS,\n SVG_ELEMENT_NAME_MAP,\n} from \"./util/tag-names\"\nimport type {\n IntermediateToken,\n EndTag,\n Mustache,\n StartTag,\n Text,\n} from \"./intermediate-tokenizer\"\nimport { IntermediateTokenizer } from \"./intermediate-tokenizer\"\nimport type { Tokenizer } from \"./tokenizer\"\nimport type { ParserOptions } from \"../common/parser-options\"\nimport {\n isSFCFile,\n getScriptParser,\n getParserLangFromSFC,\n} from \"../common/parser-options\"\n\nconst DIRECTIVE_NAME = /^(?:v-|[.:@#]).*[^.:@#]$/u\nconst DT_DD = /^d[dt]$/u\nconst DUMMY_PARENT: any = Object.freeze({})\n\n/**\n * Gets the tag name from the given node or token.\n * For SFC, it returns the value of `rawName` to be case sensitive.\n */\nfunction getTagName(\n startTagOrElement: { name: string; rawName: string },\n isSFC: boolean,\n) {\n return isSFC ? startTagOrElement.rawName : startTagOrElement.name\n}\n\n/**\n * Check whether the element is a MathML text integration point or not.\n * @see https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher\n * @param element The current element.\n * @param isSFC For SFC, give `true`.\n * @returns `true` if the element is a MathML text integration point.\n */\nfunction isMathMLIntegrationPoint(element: VElement, isSFC: boolean): boolean {\n if (element.namespace === NS.MathML) {\n const name = getTagName(element, isSFC)\n return (\n name === \"mi\" ||\n name === \"mo\" ||\n name === \"mn\" ||\n name === \"ms\" ||\n name === \"mtext\"\n )\n }\n return false\n}\n\n/**\n * Check whether the element is a HTML integration point or not.\n * @see https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher\n * @param element The current element.\n * @param isSFC For SFC, give `true`.\n * @returns `true` if the element is a HTML integration point.\n */\nfunction isHTMLIntegrationPoint(element: VElement, isSFC: boolean): boolean {\n if (element.namespace === NS.MathML) {\n return (\n getTagName(element, isSFC) === \"annotation-xml\" &&\n element.startTag.attributes.some(\n (a) =>\n a.directive === false &&\n a.key.name === \"encoding\" &&\n a.value != null &&\n (a.value.value === \"text/html\" ||\n a.value.value === \"application/xhtml+xml\"),\n )\n )\n }\n if (element.namespace === NS.SVG) {\n const name = getTagName(element, isSFC)\n return name === \"foreignObject\" || name === \"desc\" || name === \"title\"\n }\n\n return false\n}\n\n/**\n * Adjust element names by the current namespace.\n * @param name The lowercase element name to adjust.\n * @param namespace The current namespace.\n * @returns The adjusted element name.\n */\nfunction adjustElementName(name: string, namespace: Namespace): string {\n if (namespace === NS.SVG) {\n return SVG_ELEMENT_NAME_MAP.get(name) || name\n }\n return name\n}\n\n/**\n * Adjust attribute names by the current namespace.\n * @param name The lowercase attribute name to adjust.\n * @param namespace The current namespace.\n * @returns The adjusted attribute name.\n */\nfunction adjustAttributeName(name: string, namespace: Namespace): string {\n if (namespace === NS.SVG) {\n return SVG_ATTRIBUTE_NAME_MAP.get(name) || name\n }\n if (namespace === NS.MathML) {\n return MATHML_ATTRIBUTE_NAME_MAP.get(name) || name\n }\n return name\n}\n\n/**\n * Set the location of the last child node to the end location of the given node.\n * @param node The node to commit the end location.\n */\nfunction propagateEndLocation(node: VDocumentFragment | VElement): void {\n const lastChild =\n (node.type === \"VElement\" ? node.endTag : null) || last(node.children)\n if (lastChild != null) {\n node.range[1] = lastChild.range[1]\n node.loc.end = lastChild.loc.end\n }\n}\n\n/**\n * The parser of HTML.\n * This is not following to the HTML spec completely because Vue.js template spec is pretty different to HTML.\n */\nexport class Parser {\n private tokenizer: IntermediateTokenizer\n private locationCalculator: LocationCalculatorForHtml\n private baseParserOptions: ParserOptions\n private isSFC: boolean\n private document: VDocumentFragment\n private elementStack: VElement[]\n private vPreElement: VElement | null\n private postProcessesForScript: ((parserOptions: ParserOptions) => void)[] =\n []\n\n /**\n * The source code text.\n */\n private get text(): string {\n return this.tokenizer.text\n }\n\n /**\n * The tokens.\n */\n private get tokens(): Token[] {\n return this.tokenizer.tokens\n }\n\n /**\n * The comments.\n */\n private get comments(): Token[] {\n return this.tokenizer.comments\n }\n\n /**\n * The syntax errors which are found in this parsing.\n */\n private get errors(): ParseError[] {\n return this.tokenizer.errors\n }\n\n /**\n * The current namespace.\n */\n private get namespace(): Namespace {\n return this.tokenizer.namespace\n }\n private set namespace(value: Namespace) {\n this.tokenizer.namespace = value\n }\n\n /**\n * The current flag of expression enabled.\n */\n // eslint-disable-next-line @mysticatea/ts/ban-ts-ignore\n // @ts-ignore\n private get expressionEnabled(): boolean {\n return this.tokenizer.expressionEnabled\n }\n private set expressionEnabled(value: boolean) {\n this.tokenizer.expressionEnabled = value\n }\n\n /**\n * Get the current node.\n */\n private get currentNode(): VDocumentFragment | VElement {\n return last(this.elementStack) || this.document\n }\n\n /**\n * Check if the current location is in a v-pre element.\n */\n private get isInVPreElement(): boolean {\n return this.vPreElement != null\n }\n\n /**\n * Initialize this parser.\n * @param tokenizer The tokenizer to parse.\n * @param parserOptions The parser options to parse inline expressions.\n */\n public constructor(tokenizer: Tokenizer, parserOptions: ParserOptions) {\n this.tokenizer = new IntermediateTokenizer(tokenizer)\n this.locationCalculator = new LocationCalculatorForHtml(\n tokenizer.gaps,\n tokenizer.lineTerminators,\n )\n this.baseParserOptions = parserOptions\n this.isSFC = isSFCFile(parserOptions)\n this.document = {\n type: \"VDocumentFragment\",\n range: [0, 0],\n loc: {\n start: { line: 1, column: 0 },\n end: { line: 1, column: 0 },\n },\n parent: null,\n children: [],\n tokens: this.tokens,\n comments: this.comments,\n errors: this.errors,\n }\n this.elementStack = []\n this.vPreElement = null\n\n this.postProcessesForScript = []\n }\n\n /**\n * Parse the HTML which was given in this constructor.\n * @returns The result of parsing.\n */\n public parse(): VDocumentFragment {\n let token: IntermediateToken | null = null\n while ((token = this.tokenizer.nextToken()) != null) {\n ;(this as any)[token.type](token)\n }\n\n this.popElementStackUntil(0)\n propagateEndLocation(this.document)\n\n const doc = this.document\n\n const parserOptions = {\n ...this.baseParserOptions,\n parser: getScriptParser(\n this.baseParserOptions.parser,\n function* () {\n yield \"