@reteps/tree-sitter-htmlmustache 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/browser/index.ts", "../../../src/core/nodeHelpers.ts", "../../../src/core/htmlBalanceChecker.ts", "../../../src/core/mustacheChecks.ts", "../../../src/core/ruleMetadata.ts", "../../../node_modules/parsel-js/dist/parsel.js", "../../../src/core/selectorMatcher.ts", "../../../src/core/collectErrors.ts", "../../../src/core/formatting/printer.ts", "../../../src/core/formatting/ir.ts", "../../../src/core/formatting/utils.ts", "../../../src/core/customCodeTags.ts", "../../../src/core/formatting/classifier.ts", "../../../src/core/formatting/formatters.ts", "../../../src/core/formatting/mergeOptions.ts", "../../../src/core/formatting/index.ts", "../../../src/core/embeddedRegions.ts", "../../../src/core/formatting/embedded.ts", "../../../src/core/diagnostic.ts", "../../../src/core/grammar.ts"],
4
- "sourcesContent": ["/**\n * Browser entry point for `@reteps/tree-sitter-htmlmustache`.\n *\n * Exposes `createLinter({ locateWasm, prettier? })` returning a handle with\n * `lint(source, config)` and `format(source, config, opts)`. Internally reuses\n * the shared rule engine and formatter in `src/core/` \u2014 browser-safe, no fs.\n */\n\nimport { Parser, Language } from 'web-tree-sitter';\nimport { TextDocument } from 'vscode-languageserver-textdocument';\n\nimport { collectErrors } from '../core/collectErrors.js';\nimport type { WalkableTree } from '../core/collectErrors.js';\nimport { formatDocument } from '../core/formatting/index.js';\nimport type { FormattingOptions } from '../core/formatting/index.js';\nimport { mergeOptions } from '../core/formatting/mergeOptions.js';\nimport { formatEmbeddedRegions } from '../core/formatting/embedded.js';\nimport type { PrettierLike } from '../core/formatting/embedded.js';\nimport { RULE_DEFAULTS } from '../core/ruleMetadata.js';\nimport { toDiagnostic } from '../core/diagnostic.js';\nimport type { Diagnostic } from '../core/diagnostic.js';\nimport { GRAMMAR_WASM_FILENAME } from '../core/grammar.js';\nimport type {\n HtmlMustacheConfig,\n RulesConfig,\n RuleSeverity,\n CustomRule as CustomRuleType,\n} from '../core/configSchema.js';\nimport type { CustomCodeTagConfig } from '../core/customCodeTags.js';\n\n/**\n * `include`/`exclude` on custom rules are stripped from the browser surface:\n * the browser API has no filesystem path to match against, so those fields\n * would silently do nothing. Users who share a `.htmlmustache.jsonc` config\n * between the CLI and a web playground should strip them before passing, or\n * let TypeScript catch the mismatch.\n */\nexport type CustomRule = Omit<CustomRuleType, 'include' | 'exclude'>;\nexport type Config =\n Omit<HtmlMustacheConfig, 'include' | 'exclude' | 'customRules'>\n & { customRules?: CustomRule[] };\nexport type CustomTag = CustomCodeTagConfig;\nexport type { RulesConfig, RuleSeverity, PrettierLike, Diagnostic };\n\nexport type LocateWasm = string | ((filename: string) => string);\n\nexport interface CreateLinterOptions {\n /**\n * Locates the grammar WASM (`tree-sitter-htmlmustache.wasm`). If a string,\n * treated as the URL for the grammar \u2014 web-tree-sitter's own\n * `tree-sitter.wasm` will resolve via its default `locateFile`. Pass a\n * callback to resolve both names explicitly.\n */\n locateWasm: LocateWasm;\n /** Default prettier used for embedded-region formatting. */\n prettier?: PrettierLike;\n}\n\nexport interface FormatOptions {\n /** Override the factory-level prettier for this call. */\n prettier?: PrettierLike;\n}\n\nexport interface Linter {\n lint(source: string, config?: Config): Diagnostic[];\n format(source: string, config?: Config, opts?: FormatOptions): Promise<string>;\n}\n\n/** Default severities for every built-in rule. */\nexport const DEFAULT_CONFIG: Config = { rules: RULE_DEFAULTS as RulesConfig };\n\nconst DEFAULT_FORMATTING_OPTIONS: FormattingOptions = { tabSize: 2, insertSpaces: true };\n\nfunction toLocateFile(locateWasm: LocateWasm): ((name: string) => string) | undefined {\n // String form resolves only the grammar; runtime `tree-sitter.wasm` falls\n // through to web-tree-sitter's own default `locateFile`.\n return typeof locateWasm === 'function' ? (name) => locateWasm(name) : undefined;\n}\n\nfunction resolveGrammarUrl(locateWasm: LocateWasm): string {\n return typeof locateWasm === 'string' ? locateWasm : locateWasm(GRAMMAR_WASM_FILENAME);\n}\n\n/**\n * Create a linter/formatter handle. Consumers should cache the result \u2014 each\n * call reloads the grammar WASM.\n */\nexport async function createLinter(opts: CreateLinterOptions): Promise<Linter> {\n const { locateWasm, prettier: factoryPrettier } = opts;\n const locateFile = toLocateFile(locateWasm);\n // `Parser.init` is itself idempotent (Emscripten caches the runtime globally),\n // so repeated calls with different `locateFile` are safe \u2014 the first wins.\n await Parser.init(locateFile ? { locateFile } : undefined);\n const parser = new Parser();\n const language = await Language.load(resolveGrammarUrl(locateWasm));\n parser.setLanguage(language);\n\n return {\n lint(source, config) {\n const tree = parser.parse(source);\n if (!tree) throw new Error('Failed to parse document');\n try {\n const customTagNames = config?.customTags?.map((t) => t.name);\n const errors = collectErrors(\n tree as unknown as WalkableTree,\n config?.rules,\n customTagNames,\n config?.customRules,\n );\n return errors.map(toDiagnostic);\n } finally {\n tree.delete();\n }\n },\n\n async format(source, config, callOpts) {\n const prettier = callOpts?.prettier ?? factoryPrettier;\n const options = mergeOptions(DEFAULT_FORMATTING_OPTIONS, config ?? null);\n const tree = parser.parse(source);\n if (!tree) throw new Error('Failed to parse document');\n try {\n const embeddedFormatted = await formatEmbeddedRegions(tree.rootNode, options, prettier);\n const document = TextDocument.create('file:///input', 'htmlmustache', 1, source);\n const edits = formatDocument(tree, document, options, {\n customTags: config?.customTags,\n printWidth: config?.printWidth,\n mustacheSpaces: config?.mustacheSpaces,\n noBreakDelimiters: config?.noBreakDelimiters,\n embeddedFormatted: embeddedFormatted.size > 0 ? embeddedFormatted : undefined,\n });\n return edits.length === 0 ? source : edits[0].newText;\n } finally {\n tree.delete();\n }\n },\n };\n}\n", "/**\n * Shared node helper functions and type constants for working with\n * tree-sitter syntax nodes across the LSP and CLI.\n *\n * Uses a minimal interface compatible with both web-tree-sitter's SyntaxNode\n * and the BalanceNode interface from htmlBalanceChecker.\n */\n\n/** Minimal node interface compatible with both SyntaxNode and BalanceNode. */\nexport interface MinimalNode {\n type: string;\n text: string;\n children: MinimalNode[];\n}\n\n// --- Node type constants ---\n\nexport const MUSTACHE_SECTION_TYPES = new Set([\n 'mustache_section',\n 'mustache_inverted_section',\n]);\n\nexport const INTERPOLATION_TYPES = new Set([\n 'mustache_interpolation', // {{foo}}\n 'mustache_triple', // {{{foo}}} \u2014 unescaped\n]);\n\nexport const RAW_CONTENT_ELEMENT_TYPES = new Set([\n 'html_script_element',\n 'html_style_element',\n 'html_raw_element',\n]);\n\nexport const HTML_ELEMENT_TYPES = new Set([\n 'html_element',\n 'html_script_element',\n 'html_style_element',\n 'html_raw_element',\n]);\n\n// --- Node type predicates ---\n\nexport function isMustacheSection(node: MinimalNode): boolean {\n return MUSTACHE_SECTION_TYPES.has(node.type);\n}\n\nexport function isRawContentElement(node: MinimalNode): boolean {\n return RAW_CONTENT_ELEMENT_TYPES.has(node.type);\n}\n\nexport function isHtmlElementType(node: MinimalNode): boolean {\n return HTML_ELEMENT_TYPES.has(node.type);\n}\n\n// --- Node name extraction ---\n\n/**\n * Get the tag name from an HTML element node.\n * Works with any node that has children with type 'html_start_tag' or\n * 'html_self_closing_tag' containing an 'html_tag_name' child.\n */\nexport function getTagName(node: MinimalNode): string | null {\n for (const child of node.children) {\n if (child.type === 'html_start_tag' || child.type === 'html_self_closing_tag') {\n const tagNameNode = child.children.find(c => c.type === 'html_tag_name');\n if (tagNameNode) return tagNameNode.text;\n }\n }\n return null;\n}\n\n/**\n * Get the section name from a mustache section node.\n * Looks for mustache_tag_name inside mustache_section_begin or\n * mustache_inverted_section_begin.\n */\nexport function getSectionName(node: MinimalNode): string | null {\n const beginNode = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n if (!beginNode) return null;\n const tagNameNode = beginNode.children.find(c => c.type === 'mustache_tag_name');\n return tagNameNode?.text ?? null;\n}\n\n/**\n * Get the tag name from an erroneous end tag node.\n */\nexport function getErroneousEndTagName(node: MinimalNode): string | null {\n const nameNode = node.children.find(c => c.type === 'html_erroneous_end_tag_name');\n return nameNode?.text?.toLowerCase() ?? null;\n}\n\n/**\n * Get the dotted path text from a mustache_interpolation or mustache_triple\n * node \u2014 e.g. `{{data.foo}}` \u2192 `\"data.foo\"`. Returns `\".\"` for the\n * context-marker interpolation `{{.}}`. Returns null if the node has no\n * recognisable expression child.\n */\nexport function getInterpolationPath(node: MinimalNode): string | null {\n for (const child of node.children) {\n if (child.type === 'mustache_path_expression' || child.type === 'mustache_identifier') {\n return child.text;\n }\n if (child.type === '.') return '.';\n }\n return null;\n}\n\n/**\n * Get the content text of a mustache_comment node (`{{!foo}}` \u2192 `\"foo\"`).\n * Returns null if no content child is present.\n */\nexport function getCommentContent(node: MinimalNode): string | null {\n const child = node.children.find(c => c.type === 'mustache_comment_content');\n return child ? child.text.trim() : null;\n}\n\n/**\n * Get the partial name of a mustache_partial node (`{{>header}}` \u2192 `\"header\"`).\n * Returns null if no content child is present.\n */\nexport function getPartialName(node: MinimalNode): string | null {\n const child = node.children.find(c => c.type === 'mustache_partial_content');\n return child ? child.text.trim() : null;\n}\n", "import {\n getTagName,\n getSectionName,\n getErroneousEndTagName,\n} from './nodeHelpers.js';\n\n// Minimal syntax node interface for balance checking.\n// Compatible with web-tree-sitter's SyntaxNode.\nexport interface BalanceNode {\n type: string;\n text: string;\n startPosition: { row: number; column: number };\n endPosition: { row: number; column: number };\n startIndex: number;\n endIndex: number;\n children: BalanceNode[];\n}\n\nexport interface BalanceError {\n node: BalanceNode;\n message: string;\n}\n\n// --- Internal types ---\n\ninterface TagEvent {\n type: 'open' | 'close';\n tagName: string;\n node: BalanceNode;\n}\n\ninterface ConditionalFork {\n type: 'fork';\n sectionName: string;\n truthy: PathItem[];\n falsy: PathItem[];\n}\n\ntype PathItem = TagEvent | ConditionalFork;\n\n// --- Phase 1: Extract tag events from parse tree ---\n\n// Re-export for consumers that import from this module\nexport { getSectionName } from './nodeHelpers.js';\n\nfunction getTagNameLower(element: BalanceNode): string | null {\n return getTagName(element)?.toLowerCase() ?? null;\n}\n\nfunction getErroneousEndTagNameLower(node: BalanceNode): string | null {\n return getErroneousEndTagName(node)?.toLowerCase() ?? null;\n}\n\nfunction hasForcedEndTag(element: BalanceNode): boolean {\n return element.children.some(c => c.type === 'html_forced_end_tag');\n}\n\nfunction extractFromNodes(nodes: BalanceNode[]): PathItem[] {\n const items: PathItem[] = [];\n for (const node of nodes) {\n items.push(...extractFromNode(node));\n }\n return items;\n}\n\nfunction extractFromNode(node: BalanceNode): PathItem[] {\n if (node.type === 'html_element') {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'html_start_tag' &&\n c.type !== 'html_end_tag' &&\n c.type !== 'html_forced_end_tag',\n );\n\n if (hasForcedEndTag(node)) {\n const tagName = getTagNameLower(node);\n const items: PathItem[] = [];\n if (tagName) {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n items.push({ type: 'open', tagName, node: startTag ?? node });\n }\n items.push(...extractFromNodes(contentChildren));\n return items;\n }\n\n // Balanced or implicit close \u2014 recurse into content for inner forks\n return extractFromNodes(contentChildren);\n }\n\n if (node.type === 'html_self_closing_tag') {\n return [];\n }\n\n if (node.type === 'html_erroneous_end_tag') {\n const tagName = getErroneousEndTagNameLower(node);\n if (tagName) {\n return [{ type: 'close', tagName, node }];\n }\n return [];\n }\n\n if (node.type === 'mustache_section') {\n const sectionName = getSectionName(node);\n if (sectionName) {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'mustache_section_begin' &&\n c.type !== 'mustache_section_end' &&\n c.type !== 'mustache_erroneous_section_end',\n );\n return [\n {\n type: 'fork',\n sectionName,\n truthy: extractFromNodes(contentChildren),\n falsy: [],\n },\n ];\n }\n return [];\n }\n\n if (node.type === 'mustache_inverted_section') {\n const sectionName = getSectionName(node);\n if (sectionName) {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'mustache_inverted_section_begin' &&\n c.type !== 'mustache_inverted_section_end' &&\n c.type !== 'mustache_erroneous_inverted_section_end',\n );\n return [\n {\n type: 'fork',\n sectionName,\n truthy: [],\n falsy: extractFromNodes(contentChildren),\n },\n ];\n }\n return [];\n }\n\n // For any other node type, recurse into children\n return extractFromNodes(node.children);\n}\n\n// --- Phase 2: Merge adjacent same-named forks ---\n\nfunction mergeAdjacentForks(items: PathItem[]): PathItem[] {\n if (items.length === 0) return items;\n\n const result: PathItem[] = [];\n let i = 0;\n\n while (i < items.length) {\n const item = items[i];\n if (item.type !== 'fork') {\n result.push(item);\n i++;\n continue;\n }\n\n // Merge consecutive forks with the same section name\n const truthy = [...item.truthy];\n const falsy = [...item.falsy];\n let j = i + 1;\n while (j < items.length) {\n const next = items[j];\n if (next.type !== 'fork' || next.sectionName !== item.sectionName) break;\n truthy.push(...next.truthy);\n falsy.push(...next.falsy);\n j++;\n }\n\n // Recursively merge within branches\n result.push({\n type: 'fork',\n sectionName: item.sectionName,\n truthy: mergeAdjacentForks(truthy),\n falsy: mergeAdjacentForks(falsy),\n });\n i = j;\n }\n\n return result;\n}\n\n// --- Phase 3: Enumerate paths and validate balance ---\n\n/**\n * Check if a branch (list of PathItems) is self-balanced: all opens are matched\n * by closes in LIFO order, leaving the stack empty. Nested forks are balanced\n * only if both their branches are independently balanced (making the fork a no-op).\n */\nfunction isBranchBalanced(items: PathItem[]): boolean {\n const stack: string[] = [];\n for (const item of items) {\n if (item.type === 'fork') {\n if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {\n return false;\n }\n } else if (item.type === 'open') {\n stack.push(item.tagName);\n } else {\n if (stack.length === 0 || stack[stack.length - 1] !== item.tagName) {\n return false;\n }\n stack.pop();\n }\n }\n return stack.length === 0;\n}\n\n/**\n * Collect only section names that affect HTML tag balance.\n * A fork only matters if at least one of its branches is unbalanced.\n * Forks where both branches are independently balanced (e.g. truthy has\n * matched open/close pairs and falsy is empty) are no-ops and skipped.\n * This reduces 2^N enumeration to only the relevant variables.\n */\nfunction collectSectionNames(items: PathItem[]): Set<string> {\n const names = new Set<string>();\n for (const item of items) {\n if (item.type === 'fork') {\n if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {\n names.add(item.sectionName);\n }\n for (const name of collectSectionNames(item.truthy)) names.add(name);\n for (const name of collectSectionNames(item.falsy)) names.add(name);\n }\n }\n return names;\n}\n\nfunction flattenPath(items: PathItem[], assignment: Map<string, boolean>): TagEvent[] {\n const events: TagEvent[] = [];\n for (const item of items) {\n if (item.type === 'fork') {\n const value = assignment.get(item.sectionName) ?? true;\n const branch = value ? item.truthy : item.falsy;\n events.push(...flattenPath(branch, assignment));\n } else {\n events.push(item);\n }\n }\n return events;\n}\n\nfunction formatCondition(assignment: Map<string, boolean>): string {\n if (assignment.size === 0) return '';\n const parts: string[] = [];\n for (const [name, value] of assignment) {\n parts.push(`${name} is ${value ? 'truthy' : 'falsy'}`);\n }\n return ` (when ${parts.join(', ')})`;\n}\n\nfunction validateBalance(events: TagEvent[], condition: string): BalanceError[] {\n const errors: BalanceError[] = [];\n const stack: TagEvent[] = [];\n\n for (const event of events) {\n if (event.type === 'open') {\n stack.push(event);\n } else {\n if (stack.length === 0) {\n errors.push({\n node: event.node,\n message: `Mismatched HTML end tag: </${event.tagName}>${condition}`,\n });\n } else {\n const top = stack[stack.length - 1];\n if (top.tagName !== event.tagName) {\n errors.push({\n node: event.node,\n message: `Mismatched HTML end tag: </${event.tagName}>${condition}`,\n });\n } else {\n stack.pop();\n }\n }\n }\n }\n\n for (const event of stack) {\n errors.push({\n node: event.node,\n message: `Unclosed HTML tag: <${event.tagName}>${condition}`,\n });\n }\n\n return errors;\n}\n\n// --- Unclosed tag detection ---\n\nconst VOID_ELEMENTS = new Set([\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n]);\n\nconst OPTIONAL_END_TAG_ELEMENTS = new Set([\n 'li', 'dt', 'dd', 'p', 'colgroup',\n 'rb', 'rt', 'rp', 'rtc',\n 'optgroup', 'option',\n 'tr', 'td', 'th',\n 'thead', 'tbody', 'tfoot',\n 'caption',\n 'html', 'head', 'body',\n]);\n\nexport function checkUnclosedTags(rootNode: BalanceNode): BalanceError[] {\n const errors: BalanceError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element') {\n const hasEndTag = node.children.some(c => c.type === 'html_end_tag');\n const hasForcedEnd = node.children.some(c => c.type === 'html_forced_end_tag');\n\n if (!hasEndTag && !hasForcedEnd) {\n const tagName = getTagNameLower(node);\n if (tagName && !VOID_ELEMENTS.has(tagName) && !OPTIONAL_END_TAG_ELEMENTS.has(tagName)) {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n errors.push({\n node: startTag ?? node,\n message: `Unclosed HTML tag: <${tagName}>`,\n });\n }\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nconst MAX_SECTION_NAMES = 15;\n\nexport function checkHtmlBalance(rootNode: BalanceNode): BalanceError[] {\n // Phase 1: Extract tag events\n const rawItems = extractFromNode(rootNode);\n\n // Phase 2: Merge adjacent same-named forks\n const items = mergeAdjacentForks(rawItems);\n\n // Phase 3: Enumerate all boolean paths and validate\n const sectionNames = [...collectSectionNames(items)];\n if (sectionNames.length > MAX_SECTION_NAMES) {\n return []; // Safety valve: too many combinations\n }\n\n const allErrors: BalanceError[] = [];\n const errorNodes = new Set<BalanceNode>();\n const totalPaths = 1 << sectionNames.length;\n\n for (let mask = 0; mask < totalPaths; mask++) {\n const assignment = new Map<string, boolean>();\n for (let i = 0; i < sectionNames.length; i++) {\n assignment.set(sectionNames[i], (mask & (1 << i)) !== 0);\n }\n\n const events = flattenPath(items, assignment);\n const condition = formatCondition(assignment);\n const pathErrors = validateBalance(events, condition);\n\n for (const error of pathErrors) {\n if (!errorNodes.has(error.node)) {\n errorNodes.add(error.node);\n allErrors.push(error);\n }\n }\n }\n\n return allErrors;\n}\n", "import type { BalanceNode, BalanceError } from './htmlBalanceChecker.js';\nimport { getSectionName } from './htmlBalanceChecker.js';\nimport { isMustacheSection } from './nodeHelpers.js';\n\nexport interface TextReplacement {\n startIndex: number;\n endIndex: number;\n newText: string;\n}\n\nexport interface FixableError extends BalanceError {\n severity?: 'error' | 'warning';\n fix?: TextReplacement[];\n fixDescription?: string;\n}\n\n// 1. Nested same-name sections\nexport function checkNestedSameNameSections(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode, ancestors: Set<string>) {\n if (isMustacheSection(node)) {\n const name = getSectionName(node);\n if (name) {\n if (ancestors.has(name)) {\n const beginNode = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n errors.push({\n node: beginNode ?? node,\n message: `Nested duplicate section: {{#${name}}} is already open in an ancestor`,\n });\n }\n const next = new Set(ancestors);\n next.add(name);\n for (const child of node.children) {\n visit(child, next);\n }\n return;\n }\n }\n\n for (const child of node.children) {\n visit(child, ancestors);\n }\n }\n\n visit(rootNode, new Set());\n return errors;\n}\n\n// 2. Unquoted mustache attribute value\nexport function checkUnquotedMustacheAttributes(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_attribute') {\n const mustacheNode = node.children.find(c => c.type === 'mustache_interpolation');\n if (mustacheNode) {\n errors.push({\n node: mustacheNode,\n message: `Unquoted mustache attribute value: ${mustacheNode.text}`,\n fix: [{\n startIndex: mustacheNode.startIndex,\n endIndex: mustacheNode.endIndex,\n newText: `\"${mustacheNode.text}\"`,\n }],\n fixDescription: 'Wrap mustache value in quotes',\n });\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 3. Consecutive same-name same-type sections\nexport function checkConsecutiveSameNameSections(rootNode: BalanceNode, sourceText: string): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n const children = node.children;\n for (let i = 0; i < children.length - 1; i++) {\n const current = children[i];\n const next = children[i + 1];\n\n // Both must be the same section type\n if (!isMustacheSection(current) || current.type !== next.type) {\n continue;\n }\n\n const currentName = getSectionName(current);\n const nextName = getSectionName(next);\n if (!currentName || !nextName || currentName !== nextName) continue;\n\n // Check that the gap between them is whitespace-only\n const gap = sourceText.slice(current.endIndex, next.startIndex);\n if (gap.length > 0 && !/^\\s*$/.test(gap)) continue;\n\n // Find the end tag of current section and begin tag of next section\n const endTagType = current.type === 'mustache_section'\n ? 'mustache_section_end'\n : 'mustache_inverted_section_end';\n const beginTagType = next.type === 'mustache_section'\n ? 'mustache_section_begin'\n : 'mustache_inverted_section_begin';\n\n const currentEndTag = current.children.find(c => c.type === endTagType);\n const nextBeginTag = next.children.find(c => c.type === beginTagType);\n\n if (!currentEndTag || !nextBeginTag) continue;\n\n const sectionTypeStr = current.type === 'mustache_section' ? '#' : '^';\n const nextBeginNode = next.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n\n errors.push({\n node: nextBeginNode ?? next,\n message: `Consecutive duplicate section: {{${sectionTypeStr}${nextName}}} can be merged with previous {{${sectionTypeStr}${nextName}}}`,\n severity: 'warning',\n fix: [{\n startIndex: currentEndTag.startIndex,\n endIndex: nextBeginTag.endIndex,\n newText: '',\n }],\n fixDescription: 'Merge consecutive sections',\n });\n }\n\n // Recurse into children\n for (const child of children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 4. Self-closing non-void tags\nconst VOID_ELEMENTS = new Set([\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n]);\n\nexport function checkSelfClosingNonVoidTags(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_self_closing_tag') {\n const tagNameNode = node.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName && !VOID_ELEMENTS.has(tagName)) {\n errors.push({\n node,\n message: `Self-closing non-void element: <${tagNameNode!.text}/>`,\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: node.text.replace(/\\s*\\/>$/, '>') + `</${tagNameNode!.text}>`,\n }],\n fixDescription: 'Replace self-closing syntax with explicit close tag',\n });\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 5. Duplicate attributes (including across mustache conditionals)\ninterface Condition {\n name: string;\n inverted: boolean;\n}\n\ninterface AttributeOccurrence {\n nameNode: BalanceNode;\n conditions: Condition[];\n}\n\nfunction areMutuallyExclusive(a: Condition[], b: Condition[]): boolean {\n // Two condition chains are mutually exclusive if some variable X\n // appears as truthy in one and falsy in the other\n for (const ac of a) {\n for (const bc of b) {\n if (ac.name === bc.name && ac.inverted !== bc.inverted) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction formatConditionClause(a: Condition[], b: Condition[]): string {\n // Combine conditions from both occurrences, deduplicating\n const seen = new Map<string, boolean>(); // name -> inverted\n for (const c of [...a, ...b]) {\n if (!seen.has(c.name)) {\n seen.set(c.name, c.inverted);\n }\n }\n if (seen.size === 0) return '';\n const parts: string[] = [];\n for (const [name, inverted] of seen) {\n parts.push(`${name} is ${inverted ? 'falsy' : 'truthy'}`);\n }\n return ` (when ${parts.join(', ')})`;\n}\n\nfunction collectAttributes(node: BalanceNode, conditions: Condition[], out: AttributeOccurrence[]) {\n for (const child of node.children) {\n if (child.type === 'html_attribute') {\n const nameNode = child.children.find(c => c.type === 'html_attribute_name');\n if (nameNode) {\n out.push({ nameNode, conditions: [...conditions] });\n }\n } else if (child.type === 'mustache_attribute') {\n // Descend into the mustache section/inverted section inside\n const section = child.children.find(c => isMustacheSection(c));\n if (section) {\n const name = getSectionName(section);\n if (name) {\n const inverted = section.type === 'mustache_inverted_section';\n collectAttributes(section, [...conditions, { name, inverted }], out);\n }\n }\n }\n // Skip mustache_interpolation / mustache_triple \u2014 dynamic, names unknown\n }\n}\n\n// 6. Unescaped HTML entities in text content\nexport function checkUnescapedEntities(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'text') {\n // Bare & (from _text_ampersand rule \u2014 node text is exactly \"&\")\n if (node.text === '&') {\n errors.push({\n node,\n message: 'Unescaped \"&\" in text content \u2014 use &amp; instead',\n severity: 'warning',\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: '&amp;',\n }],\n fixDescription: 'Replace & with &amp;',\n });\n return;\n }\n\n // > characters in text (from the text rule which allows >)\n if (node.text.includes('>')) {\n const fixes: TextReplacement[] = [];\n let searchFrom = 0;\n const text = node.text;\n while (true) {\n const idx = text.indexOf('>', searchFrom);\n if (idx === -1) break;\n fixes.push({\n startIndex: node.startIndex + idx,\n endIndex: node.startIndex + idx + 1,\n newText: '&gt;',\n });\n searchFrom = idx + 1;\n }\n errors.push({\n node,\n message: 'Unescaped \">\" in text content \u2014 use &gt; instead',\n severity: 'warning',\n fix: fixes,\n fixDescription: 'Replace > with &gt;',\n });\n return;\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 7. Prefer mustache comments over HTML comments\nexport function checkHtmlComments(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_comment') {\n // Extract text between <!-- and -->\n const raw = node.text;\n let content = raw;\n if (content.startsWith('<!--')) content = content.slice(4);\n if (content.endsWith('-->')) content = content.slice(0, -3);\n content = content.trim();\n\n errors.push({\n node,\n message: `HTML comment found \u2014 use mustache comment {{! ... }} instead`,\n severity: 'warning',\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: `{{! ${content} }}`,\n }],\n fixDescription: 'Replace HTML comment with mustache comment',\n });\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 8. Unrecognized HTML tags\nconst KNOWN_HTML_TAGS = new Set([\n // Void elements\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n // Non-void elements\n 'a', 'abbr', 'address', 'article', 'aside', 'audio',\n 'b', 'bdi', 'bdo', 'blockquote', 'body', 'button',\n 'canvas', 'caption', 'cite', 'code', 'colgroup',\n 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt',\n 'em',\n 'fieldset', 'figcaption', 'figure', 'footer', 'form',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'html',\n 'i', 'iframe', 'ins',\n 'kbd',\n 'label', 'legend', 'li',\n 'main', 'map', 'mark', 'math', 'menu', 'meter',\n 'nav', 'noscript',\n 'object', 'ol', 'optgroup', 'option', 'output',\n 'p', 'picture', 'pre', 'progress',\n 'q',\n 'rb', 'rp', 'rt', 'rtc', 'ruby',\n 's', 'samp', 'script', 'search', 'section', 'select', 'slot', 'small', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'svg',\n 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr',\n 'u', 'ul',\n 'var', 'video',\n]);\n\nexport function checkUnrecognizedHtmlTags(rootNode: BalanceNode, customTagNames?: string[]): FixableError[] {\n const errors: FixableError[] = [];\n const customSet = customTagNames ? new Set(customTagNames.map(n => n.toLowerCase())) : undefined;\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element' || node.type === 'html_self_closing_tag') {\n // Check tag name for svg/math to skip their subtrees\n const tagNameNode = node.type === 'html_self_closing_tag'\n ? node.children.find(c => c.type === 'html_tag_name')\n : node.children.find(c => c.type === 'html_start_tag')?.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName === 'svg' || tagName === 'math') return;\n }\n\n if (node.type === 'html_start_tag' || node.type === 'html_self_closing_tag') {\n const tagNameNode = node.children.find(c => c.type === 'html_tag_name');\n if (tagNameNode) {\n const tagName = tagNameNode.text.toLowerCase();\n if (\n !KNOWN_HTML_TAGS.has(tagName) &&\n !customSet?.has(tagName)\n ) {\n errors.push({\n node: tagNameNode,\n message: `Unrecognized HTML tag: <${tagNameNode.text}>`,\n });\n }\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nexport function checkDuplicateAttributes(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_start_tag' || node.type === 'html_self_closing_tag') {\n const occurrences: AttributeOccurrence[] = [];\n collectAttributes(node, [], occurrences);\n\n // Group by attribute name (case-insensitive)\n const groups = new Map<string, AttributeOccurrence[]>();\n for (const occ of occurrences) {\n const key = occ.nameNode.text.toLowerCase();\n let group = groups.get(key);\n if (!group) {\n group = [];\n groups.set(key, group);\n }\n group.push(occ);\n }\n\n for (const [, group] of groups) {\n if (group.length < 2) continue;\n // Check each pair \u2014 report the later one if any non-exclusive pair exists\n for (let i = 1; i < group.length; i++) {\n let conflictIdx = -1;\n for (let j = 0; j < i; j++) {\n if (!areMutuallyExclusive(group[i].conditions, group[j].conditions)) {\n conflictIdx = j;\n break;\n }\n }\n if (conflictIdx >= 0) {\n const clause = formatConditionClause(group[conflictIdx].conditions, group[i].conditions);\n errors.push({\n node: group[i].nameNode,\n message: `Duplicate attribute \"${group[i].nameNode.text}\"${clause}`,\n });\n }\n }\n }\n return; // Don't recurse into tag children (already processed)\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nexport function checkElementContentTooLong(\n rootNode: BalanceNode,\n elements: ReadonlyArray<{ tag: string; maxBytes: number }>,\n): FixableError[] {\n const errors: FixableError[] = [];\n if (elements.length === 0) return errors;\n\n const thresholds = new Map<string, number>();\n for (const { tag, maxBytes } of elements) {\n const key = tag.toLowerCase();\n const existing = thresholds.get(key);\n if (existing === undefined || maxBytes < existing) thresholds.set(key, maxBytes);\n }\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element') {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n const endTag = node.children.find(c => c.type === 'html_end_tag');\n const tagNameNode = startTag?.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName && startTag && endTag) {\n const maxBytes = thresholds.get(tagName);\n if (maxBytes !== undefined) {\n const innerBytes = endTag.startIndex - startTag.endIndex;\n if (innerBytes > maxBytes) {\n errors.push({\n node: startTag,\n message: `<${tagName}> content is ${innerBytes} bytes, exceeds limit of ${maxBytes}`,\n });\n }\n }\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n", "import type { RuleSeverity } from './configSchema.js';\n\nexport interface RuleDefinition {\n name: string;\n defaultSeverity: RuleSeverity;\n description: string;\n}\n\nexport const RULES: RuleDefinition[] = [\n {\n name: 'nestedDuplicateSections',\n defaultSeverity: 'error',\n description: 'Flags `{{#name}}` nested inside another `{{#name}}` with the same name',\n },\n {\n name: 'unquotedMustacheAttributes',\n defaultSeverity: 'error',\n description: 'Requires quotes around mustache expressions used as attribute values',\n },\n {\n name: 'consecutiveDuplicateSections',\n defaultSeverity: 'warning',\n description: 'Warns when adjacent same-name sections can be merged',\n },\n {\n name: 'selfClosingNonVoidTags',\n defaultSeverity: 'error',\n description: 'Disallows self-closing syntax on non-void HTML elements (e.g. `<div/>`)',\n },\n {\n name: 'duplicateAttributes',\n defaultSeverity: 'error',\n description: 'Detects duplicate HTML attributes on the same element',\n },\n {\n name: 'unescapedEntities',\n defaultSeverity: 'warning',\n description: 'Flags unescaped `&` and `>` characters in text content',\n },\n {\n name: 'preferMustacheComments',\n defaultSeverity: 'off',\n description: 'Suggests replacing HTML comments with mustache comments',\n },\n {\n name: 'unrecognizedHtmlTags',\n defaultSeverity: 'error',\n description: 'Flags HTML tags that are not standard HTML elements or valid custom elements',\n },\n {\n name: 'elementContentTooLong',\n defaultSeverity: 'off',\n description: 'Flags configured elements whose inner content exceeds a byte-length threshold (opt-in; requires `elements: [{ tag, maxBytes }]` option)',\n },\n];\n\n/** Set of all known rule names (for config validation). */\nexport const KNOWN_RULE_NAMES = new Set<string>(RULES.map(r => r.name));\n\n/** Default severity for each rule (for runtime resolution). */\nexport const RULE_DEFAULTS: Record<string, RuleSeverity> = Object.fromEntries(\n RULES.map(r => [r.name, r.defaultSeverity]),\n);\n", "const TOKENS = {\n attribute: /\\[\\s*(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?(?<name>[-\\w\\P{ASCII}]+)\\s*(?:(?<operator>\\W?=)\\s*(?<value>.+?)\\s*(\\s(?<caseSensitive>[iIsS]))?\\s*)?\\]/gu,\n id: /#(?<name>[-\\w\\P{ASCII}]+)/gu,\n class: /\\.(?<name>[-\\w\\P{ASCII}]+)/gu,\n comma: /\\s*,\\s*/g,\n combinator: /\\s*[\\s>+~]\\s*/g,\n 'pseudo-element': /::(?<name>[-\\w\\P{ASCII}]+)(?:\\((?<argument>\u00B6*)\\))?/gu,\n 'pseudo-class': /:(?<name>[-\\w\\P{ASCII}]+)(?:\\((?<argument>\u00B6*)\\))?/gu,\n universal: /(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?\\*/gu,\n type: /(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?(?<name>[-\\w\\P{ASCII}]+)/gu, // this must be last\n};\nconst TRIM_TOKENS = new Set(['combinator', 'comma']);\nconst RECURSIVE_PSEUDO_CLASSES = new Set([\n 'not',\n 'is',\n 'where',\n 'has',\n 'matches',\n '-moz-any',\n '-webkit-any',\n 'nth-child',\n 'nth-last-child',\n]);\nconst nthChildRegExp = /(?<index>[\\dn+-]+)\\s+of\\s+(?<subtree>.+)/;\nconst RECURSIVE_PSEUDO_CLASSES_ARGS = {\n 'nth-child': nthChildRegExp,\n 'nth-last-child': nthChildRegExp,\n};\nconst getArgumentPatternByType = (type) => {\n switch (type) {\n case 'pseudo-element':\n case 'pseudo-class':\n return new RegExp(TOKENS[type].source.replace('(?<argument>\u00B6*)', '(?<argument>.*)'), 'gu');\n default:\n return TOKENS[type];\n }\n};\nfunction gobbleParens(text, offset) {\n let nesting = 0;\n let result = '';\n for (; offset < text.length; offset++) {\n const char = text[offset];\n switch (char) {\n case '(':\n ++nesting;\n break;\n case ')':\n --nesting;\n break;\n }\n result += char;\n if (nesting === 0) {\n return result;\n }\n }\n return result;\n}\nfunction tokenizeBy(text, grammar = TOKENS) {\n if (!text) {\n return [];\n }\n const tokens = [text];\n for (const [type, pattern] of Object.entries(grammar)) {\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (typeof token !== 'string') {\n continue;\n }\n pattern.lastIndex = 0;\n const match = pattern.exec(token);\n if (!match) {\n continue;\n }\n const from = match.index - 1;\n const args = [];\n const content = match[0];\n const before = token.slice(0, from + 1);\n if (before) {\n args.push(before);\n }\n args.push({\n ...match.groups,\n type,\n content,\n });\n const after = token.slice(from + content.length + 1);\n if (after) {\n args.push(after);\n }\n tokens.splice(i, 1, ...args);\n }\n }\n let offset = 0;\n for (const token of tokens) {\n switch (typeof token) {\n case 'string':\n throw new Error(`Unexpected sequence ${token} found at index ${offset}`);\n case 'object':\n offset += token.content.length;\n token.pos = [offset - token.content.length, offset];\n if (TRIM_TOKENS.has(token.type)) {\n token.content = token.content.trim() || ' ';\n }\n break;\n }\n }\n return tokens;\n}\nconst STRING_PATTERN = /(['\"])([^\\\\\\n]*?)\\1/g;\nconst ESCAPE_PATTERN = /\\\\./g;\nfunction tokenize(selector, grammar = TOKENS) {\n // Prevent leading/trailing whitespaces from being interpreted as combinators\n selector = selector.trim();\n if (selector === '') {\n return [];\n }\n const replacements = [];\n // Replace escapes with placeholders.\n selector = selector.replace(ESCAPE_PATTERN, (value, offset) => {\n replacements.push({ value, offset });\n return '\\uE000'.repeat(value.length);\n });\n // Replace strings with placeholders.\n selector = selector.replace(STRING_PATTERN, (value, quote, content, offset) => {\n replacements.push({ value, offset });\n return `${quote}${'\\uE001'.repeat(content.length)}${quote}`;\n });\n // Replace parentheses with placeholders.\n {\n let pos = 0;\n let offset;\n while ((offset = selector.indexOf('(', pos)) > -1) {\n const value = gobbleParens(selector, offset);\n replacements.push({ value, offset });\n selector = `${selector.substring(0, offset)}(${'\u00B6'.repeat(value.length - 2)})${selector.substring(offset + value.length)}`;\n pos = offset + value.length;\n }\n }\n // Now we have no nested structures and we can parse with regexes\n const tokens = tokenizeBy(selector, grammar);\n // Replace placeholders in reverse order.\n const changedTokens = new Set();\n for (const replacement of replacements.reverse()) {\n for (const token of tokens) {\n const { offset, value } = replacement;\n if (!(token.pos[0] <= offset &&\n offset + value.length <= token.pos[1])) {\n continue;\n }\n const { content } = token;\n const tokenOffset = offset - token.pos[0];\n token.content =\n content.slice(0, tokenOffset) +\n value +\n content.slice(tokenOffset + value.length);\n if (token.content !== content) {\n changedTokens.add(token);\n }\n }\n }\n // Update changed tokens.\n for (const token of changedTokens) {\n const pattern = getArgumentPatternByType(token.type);\n if (!pattern) {\n throw new Error(`Unknown token type: ${token.type}`);\n }\n pattern.lastIndex = 0;\n const match = pattern.exec(token.content);\n if (!match) {\n throw new Error(`Unable to parse content for ${token.type}: ${token.content}`);\n }\n Object.assign(token, match.groups);\n }\n return tokens;\n}\n/**\n * Convert a flat list of tokens into a tree of complex & compound selectors\n */\nfunction nestTokens(tokens, { list = true } = {}) {\n if (list && tokens.find((t) => t.type === 'comma')) {\n const selectors = [];\n const temp = [];\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].type === 'comma') {\n if (temp.length === 0) {\n throw new Error('Incorrect comma at ' + i);\n }\n selectors.push(nestTokens(temp, { list: false }));\n temp.length = 0;\n }\n else {\n temp.push(tokens[i]);\n }\n }\n if (temp.length === 0) {\n throw new Error('Trailing comma');\n }\n else {\n selectors.push(nestTokens(temp, { list: false }));\n }\n return { type: 'list', list: selectors };\n }\n for (let i = tokens.length - 1; i >= 0; i--) {\n let token = tokens[i];\n if (token.type === 'combinator') {\n let left = tokens.slice(0, i);\n let right = tokens.slice(i + 1);\n if (left.length === 0) {\n return {\n type: 'relative',\n combinator: token.content,\n right: nestTokens(right),\n };\n }\n return {\n type: 'complex',\n combinator: token.content,\n left: nestTokens(left),\n right: nestTokens(right),\n };\n }\n }\n switch (tokens.length) {\n case 0:\n throw new Error('Could not build AST.');\n case 1:\n // If we're here, there are no combinators, so it's just a list.\n return tokens[0];\n default:\n return {\n type: 'compound',\n list: [...tokens], // clone to avoid pointers messing up the AST\n };\n }\n}\n/**\n * Traverse an AST in depth-first order\n */\nfunction* flatten(node, \n/**\n * @internal\n */\nparent) {\n switch (node.type) {\n case 'list':\n for (let child of node.list) {\n yield* flatten(child, node);\n }\n break;\n case 'complex':\n yield* flatten(node.left, node);\n yield* flatten(node.right, node);\n break;\n case 'relative':\n yield* flatten(node.right, node);\n break;\n case 'compound':\n yield* node.list.map((token) => [token, node]);\n break;\n default:\n yield [node, parent];\n }\n}\n/**\n * Traverse an AST (or part thereof), in depth-first order\n */\nfunction walk(node, visit, \n/**\n * @internal\n */\nparent) {\n if (!node) {\n return;\n }\n for (const [token, ast] of flatten(node, parent)) {\n visit(token, ast);\n }\n}\n/**\n * Parse a CSS selector\n *\n * @param selector - The selector to parse\n * @param options.recursive - Whether to parse the arguments of pseudo-classes like :is(), :has() etc. Defaults to true.\n * @param options.list - Whether this can be a selector list (A, B, C etc). Defaults to true.\n */\nfunction parse(selector, { recursive = true, list = true } = {}) {\n const tokens = tokenize(selector);\n if (!tokens) {\n return;\n }\n const ast = nestTokens(tokens, { list });\n if (!recursive) {\n return ast;\n }\n for (const [token] of flatten(ast)) {\n if (token.type !== 'pseudo-class' || !token.argument) {\n continue;\n }\n if (!RECURSIVE_PSEUDO_CLASSES.has(token.name)) {\n continue;\n }\n let argument = token.argument;\n const childArg = RECURSIVE_PSEUDO_CLASSES_ARGS[token.name];\n if (childArg) {\n const match = childArg.exec(argument);\n if (!match) {\n continue;\n }\n Object.assign(token, match.groups);\n argument = match.groups['subtree'];\n }\n if (!argument) {\n continue;\n }\n Object.assign(token, {\n subtree: parse(argument, {\n recursive: true,\n list: true,\n }),\n });\n }\n return ast;\n}\n/**\n * Converts the given list or (sub)tree to a string.\n */\nfunction stringify(listOrNode) {\n if (Array.isArray(listOrNode)) {\n return listOrNode.map((token) => token.content).join(\"\");\n }\n switch (listOrNode.type) {\n case \"list\":\n return listOrNode.list.map(stringify).join(\",\");\n case \"relative\":\n return (listOrNode.combinator +\n stringify(listOrNode.right));\n case \"complex\":\n return (stringify(listOrNode.left) +\n listOrNode.combinator +\n stringify(listOrNode.right));\n case \"compound\":\n return listOrNode.list.map(stringify).join(\"\");\n default:\n return listOrNode.content;\n }\n}\n/**\n * To convert the specificity array to a number\n */\nfunction specificityToNumber(specificity, base) {\n base = base || Math.max(...specificity) + 1;\n return (specificity[0] * (base << 1) + specificity[1] * base + specificity[2]);\n}\n/**\n * Calculate specificity of a selector.\n *\n * If the selector is a list, the max specificity is returned.\n */\nfunction specificity(selector) {\n let ast = selector;\n if (typeof ast === 'string') {\n ast = parse(ast, { recursive: true });\n }\n if (!ast) {\n return [];\n }\n if (ast.type === 'list' && 'list' in ast) {\n let base = 10;\n const specificities = ast.list.map((ast) => {\n const sp = specificity(ast);\n base = Math.max(base, ...specificity(ast));\n return sp;\n });\n const numbers = specificities.map((ast) => specificityToNumber(ast, base));\n return specificities[numbers.indexOf(Math.max(...numbers))];\n }\n const ret = [0, 0, 0];\n for (const [token] of flatten(ast)) {\n switch (token.type) {\n case 'id':\n ret[0]++;\n break;\n case 'class':\n case 'attribute':\n ret[1]++;\n break;\n case 'pseudo-element':\n case 'type':\n ret[2]++;\n break;\n case 'pseudo-class':\n if (token.name === 'where') {\n break;\n }\n if (!RECURSIVE_PSEUDO_CLASSES.has(token.name) ||\n !token.subtree) {\n ret[1]++;\n break;\n }\n const sub = specificity(token.subtree);\n sub.forEach((s, i) => (ret[i] += s));\n // :nth-child() & :nth-last-child() add (0, 1, 0) to the specificity of their most complex selector\n if (token.name === 'nth-child' ||\n token.name === 'nth-last-child') {\n ret[1]++;\n }\n }\n }\n return ret;\n}\n\nexport { RECURSIVE_PSEUDO_CLASSES, RECURSIVE_PSEUDO_CLASSES_ARGS, TOKENS, TRIM_TOKENS, flatten, gobbleParens, parse, specificity, specificityToNumber, stringify, tokenize, tokenizeBy, walk };\n", "/**\n * CSS-like selector parser and tree matcher for custom lint rules.\n *\n * Mustache constructs are written literally in selectors \u2014 `{{foo}}`,\n * `{{{foo}}}`, `{{#foo}}`, `{{^foo}}`, `{{!foo}}`, `{{>foo}}`. A preprocessor\n * substitutes each form into an internal `:m-*` pseudo-class marker, then the\n * rewritten string is handed to parsel-js. This keeps users in Mustache\n * vocabulary without reinventing a selector parser.\n *\n * Supported user-facing syntax:\n * - Tag names (`div`), universal (`*`), classes (`.foo`), ids (`#foo`)\n * - Attributes: `[attr]`, `[attr=v]`, `[attr^=v]`, `[attr*=v]`, `[attr$=v]`, `[attr~=v]`\n * - Descendant (space), child (`>`), adjacent-sibling (`+`), and\n * general-sibling (`~`) combinators. Sibling combinators skip over text /\n * whitespace nodes (CSS semantics) and work across HTML and Mustache\n * constructs: e.g. `label + input`, `{{foo}} + p`, `h2 ~ {{#items}}`.\n * - Mustache variables: `{{path}}` and `{{{path}}}` (raw)\n * - Mustache sections: `{{#name}}` and `{{^name}}` (inverted)\n * - Mustache comments: `{{!content}}`\n * - Mustache partials: `{{>name}}`\n * - Glob wildcard `*` inside the argument: `{{options.*}}`, `{{*.deprecated}}`, `{{*}}`\n * - `:has(selector)` \u2014 element has a matching descendant\n * - `:not(...)` \u2014 negation. Accepts attributes/class/id/`:has` (folded into\n * the outer compound), plus any other selector (including Mustache\n * literals and type selectors) as a whole-selector check against the\n * node itself. Example: `{{*}}:not({{internal.*}})` matches any\n * interpolation whose path does not start with `internal.`.\n * - `:root` \u2014 the tree-sitter fragment root (the whole document). Unlike\n * browser CSS where `:root` matches `<html>`, this matches the parse-tree\n * root so it works on partials/fragments too. Useful as a document-scoped\n * anchor, e.g. `:root:has(pl-question-panel):not(:has(pl-answer-panel))`\n * matches the root iff a `pl-question-panel` is present anywhere but no\n * `pl-answer-panel` is. Cannot combine with tag/class/id/attribute in the\n * same compound (only with `:has` / `:not(:has(...))`). Inside `:has(...)`,\n * `:root` refers to the element being checked, not the document.\n * - `:is(a, b, ...)` \u2014 matches if any alternative matches. Expanded at parse\n * time into the Cartesian product of alternatives, so `:is(a, b) :is(c, d)`\n * is equivalent to `a c, a d, b c, b d`. Alternatives inside `:is` that\n * contain combinators are only allowed when the `:is(...)` stands alone in\n * its compound (e.g. `:is(div > span, p)` works; `x:is(div > span, p)`\n * does not, since a combinator can't be merged into another compound).\n * - Comma-separated alternatives\n *\n * Unsupported (parseSelector returns null, rule is skipped):\n * - `[attr|=v]`, case-insensitive `i` flag\n * - Mixed HTML + Mustache kinds in one compound (e.g. `img{{foo}}`)\n * - `{{/end}}` (end tags aren't standalone nodes)\n * - `{{=<% %>=}}` (delimiter changes aren't grammar-tracked)\n */\n\nimport { parse as parselParse, type AST, type Token, type AttributeToken, type ClassToken, type IdToken } from 'parsel-js';\nimport type { BalanceNode } from './htmlBalanceChecker.js';\nimport {\n getTagName,\n getSectionName,\n getInterpolationPath,\n getCommentContent,\n getPartialName,\n HTML_ELEMENT_TYPES,\n} from './nodeHelpers.js';\n\n// --- Types ---\n\nexport type AttributeOperator = '=' | '^=' | '*=' | '$=' | '~=';\n\nexport type SegmentKind =\n | 'html'\n | 'section'\n | 'inverted'\n | 'variable'\n | 'raw'\n | 'comment'\n | 'partial';\n\nexport interface AttributeConstraint {\n name: string; // lowercased\n op: AttributeOperator; // meaningful only when value !== undefined\n value?: string; // quotes stripped; undefined => presence check\n negated: boolean; // true when inside :not()\n}\n\nexport interface DescendantCheck {\n selector: ParsedSelector; // :has(selector) \u2014 must match a descendant\n negated: boolean; // true for :not(:has(...))\n}\n\nexport type Combinator = 'descendant' | 'child' | 'adjacent-sibling' | 'general-sibling';\n\nexport interface Segment {\n kind: SegmentKind;\n rootOnly: boolean; // true for `:root` \u2014 matches only the tree-sitter fragment root\n name: string | null; // lowercased identifier/path, null = wildcard\n pathRegex?: RegExp; // compiled glob when `name` contains `*`\n attributes: AttributeConstraint[];\n descendantChecks: DescendantCheck[];\n selfNegations: ParsedSelector[]; // :not(X) where X is a full sub-selector tested against the node itself\n combinator: Combinator;\n}\n\n/** A parsed selector is a list of alternatives (from comma-separated parts). */\nexport type ParsedSelector = Segment[][];\n\n// --- Mustache preprocessor ---\n\nconst MUSTACHE_KIND_PSEUDO = new Set([\n 'm-section', 'm-inverted', 'm-variable', 'm-raw', 'm-comment', 'm-partial',\n]);\n\n/**\n * Rewrite Mustache-literal tokens (`{{...}}` forms) in the selector string into\n * internal `:m-*` pseudo-class markers so parsel-js can handle them. Returns\n * null if the string contains an unsupported or malformed Mustache token.\n *\n * Skips content inside `\"...\"` and `'...'` so that literal `{{...}}` embedded\n * in CSS attribute-value strings is preserved unchanged.\n */\nexport function preprocessMustacheLiterals(raw: string): string | null {\n let out = '';\n let i = 0;\n const len = raw.length;\n\n while (i < len) {\n const ch = raw[i];\n\n // Pass through quoted strings verbatim.\n if (ch === '\"' || ch === \"'\") {\n out += ch;\n i++;\n while (i < len && raw[i] !== ch) {\n if (raw[i] === '\\\\' && i + 1 < len) {\n out += raw[i] + raw[i + 1];\n i += 2;\n } else {\n out += raw[i];\n i++;\n }\n }\n if (i < len) {\n out += raw[i]; // closing quote\n i++;\n }\n continue;\n }\n\n if (ch !== '{' || raw[i + 1] !== '{') {\n out += ch;\n i++;\n continue;\n }\n\n // Triple-brace: {{{path}}}\n if (raw[i + 2] === '{') {\n const end = raw.indexOf('}}}', i + 3);\n if (end < 0) return null;\n const inner = raw.slice(i + 3, end).trim();\n if (inner.length === 0) return null;\n out += `:m-raw(${inner})`;\n i = end + 3;\n continue;\n }\n\n // Double-brace: {{...}}\n const end = raw.indexOf('}}', i + 2);\n if (end < 0) return null;\n const body = raw.slice(i + 2, end);\n i = end + 2;\n\n const sigil = body.trimStart()[0];\n const content = body.replace(/^\\s*[#^!>/]\\s*/, '').replace(/^\\s+|\\s+$/g, '');\n\n switch (sigil) {\n case '#':\n if (content.length === 0) return null;\n out += `:m-section(${content})`;\n break;\n case '^':\n if (content.length === 0) return null;\n out += `:m-inverted(${content})`;\n break;\n case '!':\n if (content.length === 0) return null;\n out += `:m-comment(${content})`;\n break;\n case '>':\n if (content.length === 0) return null;\n out += `:m-partial(${content})`;\n break;\n case '/':\n // Standalone end tags are not a selectable node.\n return null;\n case '=':\n // Delimiter changes are not a grammar-tracked node.\n return null;\n default: {\n const path = body.trim();\n if (path.length === 0) return null;\n out += `:m-variable(${path})`;\n break;\n }\n }\n }\n\n return out;\n}\n\n// --- Selector parsing ---\n\nexport function parseSelector(raw: string): ParsedSelector | null {\n if (typeof raw !== 'string' || raw.trim() === '') return null;\n\n const preprocessed = preprocessMustacheLiterals(raw);\n if (preprocessed === null) return null;\n\n let ast: AST | undefined;\n try {\n ast = parselParse(preprocessed);\n } catch {\n return null;\n }\n if (!ast) return null;\n\n const tops = ast.type === 'list' ? ast.list : [ast];\n const alts: Segment[][] = [];\n for (const top of tops) {\n const expanded = expandIs(top);\n if (expanded === null) return null;\n for (const exp of expanded) {\n const segments: Segment[] = [];\n if (!collectSegments(exp, 'descendant', segments)) return null;\n if (segments.length === 0) return null;\n alts.push(segments);\n }\n }\n return alts.length > 0 ? alts : null;\n}\n\n/**\n * Expand `:is(...)` pseudo-classes into explicit alternatives. Returns an\n * array of equivalent ASTs with every `:is` removed (Cartesian product over\n * alternatives), or `null` if the expansion contains an unsupported shape\n * (e.g. complex alternatives inside a mixed compound).\n */\nfunction expandIs(ast: AST): AST[] | null {\n switch (ast.type) {\n case 'list': {\n const out: AST[] = [];\n for (const alt of ast.list) {\n const expanded = expandIs(alt);\n if (expanded === null) return null;\n out.push(...expanded);\n }\n return out;\n }\n case 'complex': {\n const lefts = expandIs(ast.left);\n if (lefts === null) return null;\n const rights = expandIs(ast.right);\n if (rights === null) return null;\n const out: AST[] = [];\n for (const l of lefts) for (const r of rights) {\n out.push({ ...ast, left: l, right: r });\n }\n return out;\n }\n case 'compound': {\n // A compound whose sole token is `:is(...)` can be replaced by any\n // shape (including complex alternatives). Mixed compounds require each\n // alternative to be mergeable token-by-token.\n if (ast.list.length === 1) {\n const tok = ast.list[0];\n if (tok.type === 'pseudo-class' && tok.name === 'is') {\n if (!tok.subtree) return null;\n return expandIs(tok.subtree);\n }\n }\n return expandCompoundWithIs(ast.list);\n }\n default:\n if (ast.type === 'pseudo-class' && ast.name === 'is') {\n if (!ast.subtree) return null;\n return expandIs(ast.subtree);\n }\n return [ast];\n }\n}\n\nfunction expandCompoundWithIs(tokens: Token[]): AST[] | null {\n let variants: Token[][] = [[]];\n for (const tok of tokens) {\n if (tok.type === 'pseudo-class' && tok.name === 'is') {\n if (!tok.subtree) return null;\n const alts = expandIs(tok.subtree);\n if (alts === null) return null;\n const next: Token[][] = [];\n for (const base of variants) {\n for (const alt of alts) {\n if (alt.type === 'compound') {\n next.push([...base, ...alt.list]);\n } else if (alt.type === 'complex' || alt.type === 'list' || alt.type === 'relative') {\n // Can't splice a combinator-bearing selector into a compound.\n return null;\n } else {\n next.push([...base, alt]);\n }\n }\n }\n variants = next;\n } else {\n variants = variants.map(v => [...v, tok]);\n }\n }\n return variants.map(list =>\n list.length === 1 ? (list[0] as AST) : ({ type: 'compound', list } as AST),\n );\n}\n\nfunction collectSegments(\n ast: AST,\n combinator: Combinator,\n out: Segment[],\n): boolean {\n if (ast.type === 'complex') {\n const mapped = mapCombinator(ast.combinator);\n if (!mapped) return false;\n return collectSegments(ast.left, 'descendant', out)\n && collectSegments(ast.right, mapped, out);\n }\n if (ast.type === 'list' || ast.type === 'relative') return false;\n\n const segment = segmentFromCompound(ast);\n if (!segment) return false;\n segment.combinator = combinator;\n out.push(segment);\n return true;\n}\n\nfunction mapCombinator(c: string): Combinator | null {\n const trimmed = c.trim();\n if (trimmed === '') return 'descendant';\n if (trimmed === '>') return 'child';\n if (trimmed === '+') return 'adjacent-sibling';\n if (trimmed === '~') return 'general-sibling';\n return null;\n}\n\nfunction segmentFromCompound(ast: AST): Segment | null {\n const tokens: Token[] = ast.type === 'compound' ? ast.list : [ast as Token];\n\n let kind: SegmentKind | undefined;\n let name: string | null = null;\n let pathRegex: RegExp | undefined;\n let rootOnly = false;\n const attributes: AttributeConstraint[] = [];\n const descendantChecks: DescendantCheck[] = [];\n const selfNegations: ParsedSelector[] = [];\n\n // Once a Mustache kind is picked, no other kind tokens may appear.\n const forbidChange = (requested: SegmentKind): boolean => {\n if (kind === undefined) return false;\n if (kind === requested) return false;\n // html and Mustache kinds never mix\n return true;\n };\n\n for (const token of tokens) {\n switch (token.type) {\n case 'type':\n if (forbidChange('html')) return null;\n kind = 'html';\n name = token.name.toLowerCase();\n break;\n case 'universal':\n if (forbidChange('html')) return null;\n kind = 'html';\n name = null;\n break;\n case 'class':\n if (forbidChange('html')) return null;\n kind = 'html';\n attributes.push(classConstraint(token, false));\n break;\n case 'id':\n if (forbidChange('html')) return null;\n kind = 'html';\n attributes.push(idConstraint(token, false));\n break;\n case 'attribute': {\n // Attribute selectors only apply to HTML segments.\n if (forbidChange('html')) return null;\n if (kind === undefined) kind = 'html';\n const c = attributeConstraint(token, false);\n if (!c) return null;\n attributes.push(c);\n break;\n }\n case 'pseudo-class': {\n if (MUSTACHE_KIND_PSEUDO.has(token.name)) {\n const mustacheKind = mustacheKindFromMarker(token.name);\n if (mustacheKind === null) return null;\n if (forbidChange(mustacheKind)) return null;\n kind = mustacheKind;\n const glob = parseGlob(token.argument ?? '');\n name = glob.name;\n pathRegex = glob.pathRegex;\n break;\n }\n if (token.name === 'has') {\n const sel = subtreeToSelector(token.subtree);\n if (!sel) return null;\n descendantChecks.push({ selector: sel, negated: false });\n break;\n }\n if (token.name === 'not') {\n if (!applyNegatedSubtree(token.subtree, attributes, descendantChecks, selfNegations)) return null;\n break;\n }\n if (token.name === 'root') {\n rootOnly = true;\n if (kind === undefined) kind = 'html';\n break;\n }\n return null;\n }\n default:\n // pseudo-element, comma, combinator, unknown \u2192 unsupported\n return null;\n }\n }\n\n if (kind === undefined) {\n kind = 'html';\n }\n\n if (rootOnly) {\n // `:root` is only meaningful on its own (optionally with :has / :not(:has)).\n // Reject tag/attribute/class/id combinations \u2014 the root isn't an HTML element.\n if (name !== null || attributes.length > 0 || kind !== 'html') return null;\n }\n\n const isHtml = kind === 'html';\n const finalAttrs = isHtml ? attributes : [];\n return { kind, rootOnly, name, pathRegex, attributes: finalAttrs, descendantChecks, selfNegations, combinator: 'descendant' };\n}\n\nfunction mustacheKindFromMarker(name: string): SegmentKind | null {\n switch (name) {\n case 'm-section': return 'section';\n case 'm-inverted': return 'inverted';\n case 'm-variable': return 'variable';\n case 'm-raw': return 'raw';\n case 'm-comment': return 'comment';\n case 'm-partial': return 'partial';\n default: return null;\n }\n}\n\n/**\n * Parse a Mustache-literal argument into an exact name or a compiled glob.\n * The '*' character is the only wildcard. Bare '*' or empty string returns\n * { name: null } \u2014 a wildcard that matches any value.\n */\nfunction parseGlob(arg: string): { name: string | null; pathRegex?: RegExp } {\n const trimmed = arg.trim();\n if (trimmed === '' || trimmed === '*') {\n return { name: null }; // wildcard \u2014 matches anything\n }\n if (!trimmed.includes('*')) {\n return { name: trimmed.toLowerCase() };\n }\n // Escape regex metacharacters except `*`, then substitute `*` \u2192 `.*`.\n const escaped = trimmed.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n const pathRegex = new RegExp(`^${escaped}$`, 'i');\n return { name: trimmed.toLowerCase(), pathRegex };\n}\n\nfunction attributeConstraint(token: AttributeToken, negated: boolean): AttributeConstraint | null {\n const name = token.name.toLowerCase();\n if (token.operator === undefined) {\n return { name, op: '=', value: undefined, negated };\n }\n let op: AttributeOperator;\n switch (token.operator) {\n case '=': op = '='; break;\n case '^=': op = '^='; break;\n case '*=': op = '*='; break;\n case '$=': op = '$='; break;\n case '~=': op = '~='; break;\n default: return null;\n }\n return { name, op, value: stripQuotes(token.value ?? ''), negated };\n}\n\nfunction classConstraint(token: ClassToken, negated: boolean): AttributeConstraint {\n return { name: 'class', op: '~=', value: token.name, negated };\n}\n\nfunction idConstraint(token: IdToken, negated: boolean): AttributeConstraint {\n return { name: 'id', op: '=', value: token.name, negated };\n}\n\nfunction applyNegatedSubtree(\n subtree: AST | undefined,\n attributes: AttributeConstraint[],\n descendantChecks: DescendantCheck[],\n selfNegations: ParsedSelector[],\n): boolean {\n if (!subtree) return false;\n if (subtree.type === 'attribute') {\n const c = attributeConstraint(subtree, true);\n if (!c) return false;\n attributes.push(c);\n return true;\n }\n if (subtree.type === 'class') {\n attributes.push(classConstraint(subtree, true));\n return true;\n }\n if (subtree.type === 'id') {\n attributes.push(idConstraint(subtree, true));\n return true;\n }\n if (subtree.type === 'pseudo-class' && subtree.name === 'has') {\n const sel = subtreeToSelector(subtree.subtree);\n if (!sel) return false;\n descendantChecks.push({ selector: sel, negated: true });\n return true;\n }\n // Fall back to a whole-selector negation: `:not(X)` where X is a Mustache\n // literal or any other parseable selector, tested against the node itself.\n const sel = subtreeToSelector(subtree);\n if (sel) {\n selfNegations.push(sel);\n return true;\n }\n return false;\n}\n\nfunction subtreeToSelector(subtree: AST | undefined): ParsedSelector | null {\n if (!subtree) return null;\n const tops = subtree.type === 'list' ? subtree.list : [subtree];\n const alts: Segment[][] = [];\n for (const top of tops) {\n const segments: Segment[] = [];\n if (!collectSegments(top, 'descendant', segments)) return null;\n if (segments.length === 0) return null;\n alts.push(segments);\n }\n return alts.length > 0 ? alts : null;\n}\n\nfunction stripQuotes(raw: string): string {\n if (raw.length < 2) return raw;\n const first = raw[0];\n const last = raw[raw.length - 1];\n if ((first === '\"' || first === \"'\") && first === last) {\n return raw.slice(1, -1);\n }\n return raw;\n}\n\n// --- Tree matching ---\n\ninterface AncestorEntry {\n kind: AncestorKind;\n name: string; // lowercased\n node: BalanceNode;\n siblings: BalanceNode[]; // the node's parent's children; empty for root\n indexInSiblings: number; // 0 for root\n}\n\ntype AncestorKind = 'html' | 'section' | 'inverted' | 'root';\n\nfunction ancestorKindForNode(node: BalanceNode): AncestorKind | null {\n if (HTML_ELEMENT_TYPES.has(node.type)) return 'html';\n if (node.type === 'mustache_section') return 'section';\n if (node.type === 'mustache_inverted_section') return 'inverted';\n return null;\n}\n\nfunction getHtmlAttributes(node: BalanceNode): { name: string; value?: string }[] {\n const startTag = node.children.find(\n c => c.type === 'html_start_tag' || c.type === 'html_self_closing_tag',\n );\n if (!startTag) return [];\n\n const attrs: { name: string; value?: string }[] = [];\n for (const child of startTag.children) {\n if (child.type !== 'html_attribute') continue;\n let attrName = '';\n let attrValue: string | undefined;\n for (const part of child.children) {\n if (part.type === 'html_attribute_name') {\n attrName = part.text.toLowerCase();\n } else if (part.type === 'html_quoted_attribute_value') {\n attrValue = part.text.replace(/^[\"']|[\"']$/g, '');\n } else if (part.type === 'html_attribute_value') {\n attrValue = part.text;\n }\n }\n if (attrName) attrs.push({ name: attrName, value: attrValue });\n }\n return attrs;\n}\n\nfunction matchesAttributeValue(has: string | undefined, c: AttributeConstraint): boolean {\n if (has === undefined || c.value === undefined) return false;\n const v = c.value;\n if (v === '') return false;\n switch (c.op) {\n case '=': return has === v;\n case '^=': return has.startsWith(v);\n case '*=': return has.includes(v);\n case '$=': return has.endsWith(v);\n case '~=': return has.split(/\\s+/).includes(v);\n }\n}\n\nfunction checkAttributes(node: BalanceNode, constraints: AttributeConstraint[]): boolean {\n if (constraints.length === 0) return true;\n const nodeAttrs = getHtmlAttributes(node);\n for (const c of constraints) {\n const found = nodeAttrs.find(a => a.name === c.name);\n if (c.negated) {\n if (!found) continue;\n if (c.value === undefined) return false;\n if (matchesAttributeValue(found.value, c)) return false;\n continue;\n }\n if (c.value === undefined) {\n if (!found) return false;\n continue;\n }\n if (!found || !matchesAttributeValue(found.value, c)) return false;\n }\n return true;\n}\n\nfunction checkDescendants(node: BalanceNode, checks: DescendantCheck[]): boolean {\n if (checks.length === 0) return true;\n for (const check of checks) {\n const present = hasDescendantMatch(node, check.selector);\n if (check.negated ? present : !present) return false;\n }\n return true;\n}\n\nfunction hasDescendantMatch(node: BalanceNode, selector: ParsedSelector): boolean {\n for (let i = 0; i < node.children.length; i++) {\n if (matchSelector(node.children[i], selector, node.children, i).length > 0) return true;\n }\n return false;\n}\n\nfunction checkSelfNegations(node: BalanceNode, negations: ParsedSelector[], rootNode: BalanceNode): boolean {\n for (const sel of negations) {\n for (const alt of sel) {\n // A selfNegation selector is a single-segment check against the node itself.\n // Multi-segment alternatives (e.g. `:not(a b)`) aren't sensibly testable\n // against a single node, so they're treated as never matching => pass.\n if (alt.length !== 1) continue;\n if (nodeMatchesSegment(node, alt[0], rootNode)) return false;\n }\n }\n return true;\n}\n\nfunction matchesName(actual: string | null, segment: Segment): boolean {\n if (segment.name === null) return true; // wildcard\n if (actual === null) return false;\n if (segment.pathRegex) return segment.pathRegex.test(actual);\n return actual === segment.name;\n}\n\nfunction nodeMatchesSegment(node: BalanceNode, segment: Segment, rootNode: BalanceNode): boolean {\n if (segment.rootOnly) {\n if (node !== rootNode) return false;\n return checkDescendants(node, segment.descendantChecks)\n && checkSelfNegations(node, segment.selfNegations, rootNode);\n }\n const baseMatches = (() => {\n switch (segment.kind) {\n case 'html': {\n if (!HTML_ELEMENT_TYPES.has(node.type)) return false;\n if (segment.name !== null) {\n const tagName = getTagName(node)?.toLowerCase();\n if (tagName !== segment.name) return false;\n }\n return checkAttributes(node, segment.attributes) && checkDescendants(node, segment.descendantChecks);\n }\n case 'section':\n if (node.type !== 'mustache_section') return false;\n if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'inverted':\n if (node.type !== 'mustache_inverted_section') return false;\n if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'variable':\n if (node.type !== 'mustache_interpolation') return false;\n if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'raw':\n if (node.type !== 'mustache_triple') return false;\n if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'comment':\n if (node.type !== 'mustache_comment') return false;\n if (!matchesName(getCommentContent(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'partial':\n if (node.type !== 'mustache_partial') return false;\n if (!matchesName(getPartialName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n }\n })();\n if (!baseMatches) return false;\n return checkSelfNegations(node, segment.selfNegations, rootNode);\n}\n\ninterface Cursor {\n ancestors: AncestorEntry[]; // nodes on the path from root, excluding the match pointer itself\n siblings: BalanceNode[]; // siblings of the current match pointer\n indexInSiblings: number; // index of the current match pointer in its siblings\n}\n\n/** Does the prefix of segments up to segIdx satisfy the path/sibling context? */\nfunction checkPrefix(\n cursor: Cursor,\n segments: Segment[],\n segIdx: number,\n stepCombinator: Combinator,\n rootNode: BalanceNode,\n): boolean {\n if (segIdx < 0) return true;\n const segment = segments[segIdx];\n\n if (stepCombinator === 'adjacent-sibling' || stepCombinator === 'general-sibling') {\n for (let i = cursor.indexInSiblings - 1; i >= 0; i--) {\n const sib = cursor.siblings[i];\n if (!isMatchableNode(sib)) continue;\n if (!nodeMatchesSegment(sib, segment, rootNode)) {\n if (stepCombinator === 'adjacent-sibling') return false;\n continue;\n }\n const newCursor: Cursor = {\n ancestors: cursor.ancestors,\n siblings: cursor.siblings,\n indexInSiblings: i,\n };\n if (checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;\n if (stepCombinator === 'adjacent-sibling') return false;\n }\n return false;\n }\n\n // descendant or child \u2014 walk up the ancestor stack\n const ancestorKind = ancestorKindForSegment(segment);\n if (ancestorKind === null) return false; // variable/raw/comment/partial can't be ancestors\n\n if (stepCombinator === 'child') {\n for (let a = cursor.ancestors.length - 1; a >= 0; a--) {\n const entry = cursor.ancestors[a];\n if (entry.kind !== ancestorKind) {\n // For `:root > X` (ancestorKind='root'), any html ancestor between\n // X and the document root breaks the direct-child relationship.\n // Mustache sections are transparent (existing braided semantics).\n if (ancestorKind === 'root' && entry.kind === 'html') return false;\n continue;\n }\n if (!matchesName(entry.name, segment)) return false;\n if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) return false;\n if (!checkDescendants(entry.node, segment.descendantChecks)) return false;\n if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode)) return false;\n const newCursor: Cursor = {\n ancestors: cursor.ancestors.slice(0, a),\n siblings: entry.siblings,\n indexInSiblings: entry.indexInSiblings,\n };\n return checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode);\n }\n return false;\n }\n\n for (let a = cursor.ancestors.length - 1; a >= 0; a--) {\n const entry = cursor.ancestors[a];\n if (entry.kind !== ancestorKind) continue;\n if (!matchesName(entry.name, segment)) continue;\n if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) continue;\n if (!checkDescendants(entry.node, segment.descendantChecks)) continue;\n if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode)) continue;\n const newCursor: Cursor = {\n ancestors: cursor.ancestors.slice(0, a),\n siblings: entry.siblings,\n indexInSiblings: entry.indexInSiblings,\n };\n if (checkPrefix(newCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;\n }\n return false;\n}\n\n/** True for nodes that a segment could ever match \u2014 used to skip text/whitespace when walking siblings. */\nfunction isMatchableNode(node: BalanceNode): boolean {\n return HTML_ELEMENT_TYPES.has(node.type)\n || node.type === 'mustache_section'\n || node.type === 'mustache_inverted_section'\n || node.type === 'mustache_interpolation'\n || node.type === 'mustache_triple'\n || node.type === 'mustache_comment'\n || node.type === 'mustache_partial';\n}\n\nfunction ancestorKindForSegment(segment: Segment): AncestorKind | null {\n if (segment.rootOnly) return 'root';\n if (segment.kind === 'html') return 'html';\n if (segment.kind === 'section') return 'section';\n if (segment.kind === 'inverted') return 'inverted';\n return null;\n}\n\nfunction getReportNode(node: BalanceNode, rootNode?: BalanceNode): BalanceNode {\n if (HTML_ELEMENT_TYPES.has(node.type)) {\n const startTag = node.children.find(\n c => c.type === 'html_start_tag' || c.type === 'html_self_closing_tag',\n );\n return startTag ?? node;\n }\n if (node.type === 'mustache_section' || node.type === 'mustache_inverted_section') {\n const begin = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n return begin ?? node;\n }\n // When `:root` matches, the node covers the whole document. Narrow the\n // reported range to a 1-char span at the document start so the diagnostic\n // squiggle isn't the entire file.\n if (rootNode && node === rootNode) {\n return {\n type: node.type,\n text: '',\n startPosition: node.startPosition,\n endPosition: { row: node.startPosition.row, column: node.startPosition.column + 1 },\n startIndex: node.startIndex,\n endIndex: Math.min(node.startIndex + 1, node.endIndex),\n children: [],\n };\n }\n return node;\n}\n\nfunction matchAlternative(\n rootNode: BalanceNode,\n segments: Segment[],\n rootSiblings: BalanceNode[],\n rootIndexInSiblings: number,\n): BalanceNode[] {\n const results: BalanceNode[] = [];\n const lastSegment = segments[segments.length - 1];\n\n function walk(\n node: BalanceNode,\n ancestors: AncestorEntry[],\n siblings: BalanceNode[],\n indexInSiblings: number,\n ) {\n if (nodeMatchesSegment(node, lastSegment, rootNode)) {\n const cursor: Cursor = { ancestors, siblings, indexInSiblings };\n if (\n segments.length === 1 ||\n checkPrefix(cursor, segments, segments.length - 2, lastSegment.combinator, rootNode)\n ) {\n results.push(getReportNode(node, rootNode));\n }\n }\n\n let newAncestors = ancestors;\n const ancestorKind = ancestorKindForNode(node);\n if (ancestorKind !== null) {\n const name =\n ancestorKind === 'html' ? getTagName(node)?.toLowerCase() :\n getSectionName(node)?.toLowerCase();\n if (name) {\n newAncestors = [...ancestors, { kind: ancestorKind, name, node, siblings, indexInSiblings }];\n }\n }\n\n for (let i = 0; i < node.children.length; i++) {\n walk(node.children[i], newAncestors, node.children, i);\n }\n }\n\n // Seed the ancestor stack with a root entry so `:root X` / `:root > X`\n // can find the document root as an ancestor. The root node itself is\n // never an html/section/inverted node, so it's otherwise never pushed.\n const rootEntry: AncestorEntry = {\n kind: 'root', name: '', node: rootNode,\n siblings: rootSiblings, indexInSiblings: rootIndexInSiblings,\n };\n walk(rootNode, [rootEntry], rootSiblings, rootIndexInSiblings);\n return results;\n}\n\nexport function matchSelector(\n rootNode: BalanceNode,\n selector: ParsedSelector,\n siblings: BalanceNode[] = [],\n indexInSiblings = 0,\n): BalanceNode[] {\n const allResults: BalanceNode[] = [];\n const seen = new Set<BalanceNode>();\n for (const alt of selector) {\n for (const node of matchAlternative(rootNode, alt, siblings, indexInSiblings)) {\n if (!seen.has(node)) {\n seen.add(node);\n allResults.push(node);\n }\n }\n }\n return allResults;\n}\n", "/**\n * Shared error collection logic used by both the LSP diagnostics\n * and the CLI linter.\n */\n\nimport type { BalanceNode } from './htmlBalanceChecker.js';\nimport { checkHtmlBalance, checkUnclosedTags } from './htmlBalanceChecker.js';\nimport {\n checkNestedSameNameSections,\n checkUnquotedMustacheAttributes,\n checkConsecutiveSameNameSections,\n checkSelfClosingNonVoidTags,\n checkDuplicateAttributes,\n checkUnescapedEntities,\n checkHtmlComments,\n checkUnrecognizedHtmlTags,\n checkElementContentTooLong,\n} from './mustacheChecks.js';\nimport type { TextReplacement } from './mustacheChecks.js';\nimport type { RulesConfig, RuleSeverity, CustomRule, ElementContentTooLongOptions } from './configSchema.js';\nimport { RULE_DEFAULTS, KNOWN_RULE_NAMES } from './ruleMetadata.js';\nimport { parseSelector, matchSelector } from './selectorMatcher.js';\nimport type { ParsedSelector } from './selectorMatcher.js';\n\n// Parsing a selector is non-trivial (runs parsel-js) and lint() is called\n// per-keystroke in browsers, so cache by raw selector string. `null` cached\n// when the selector is unparseable to avoid retrying.\nconst selectorCache = new Map<string, ParsedSelector | null>();\n\nfunction parseSelectorCached(raw: string): ParsedSelector | null {\n const hit = selectorCache.get(raw);\n if (hit !== undefined) return hit;\n const parsed = parseSelector(raw);\n selectorCache.set(raw, parsed);\n return parsed;\n}\n\n/** A tree that provides walk() and rootNode, compatible with both web-tree-sitter and CLI wasm. */\nexport interface WalkableTree {\n walk(): TreeCursor;\n rootNode: BalanceNode;\n}\n\ninterface TreeCursor {\n currentNode: BalanceNode;\n nodeType: string;\n nodeIsMissing: boolean;\n gotoFirstChild(): boolean;\n gotoNextSibling(): boolean;\n gotoParent(): boolean;\n}\n\n/** Unified error result from all checkers. */\nexport interface CheckError {\n node: BalanceNode;\n message: string;\n severity?: 'error' | 'warning';\n fix?: TextReplacement[];\n fixDescription?: string;\n ruleName?: string;\n}\n\nconst ERROR_NODE_TYPES = new Set([\n 'ERROR',\n 'mustache_erroneous_section_end',\n 'mustache_erroneous_inverted_section_end',\n]);\n\nfunction errorMessageForNode(nodeType: string, node: BalanceNode): string {\n if (nodeType === 'mustache_erroneous_section_end' || nodeType === 'mustache_erroneous_inverted_section_end') {\n const tagNameNode = node.children.find(c => c.type === 'mustache_erroneous_tag_name');\n return `Mismatched mustache section: {{/${tagNameNode?.text || '?'}}}`;\n }\n if (nodeType === 'ERROR') {\n return 'Syntax error';\n }\n // isMissing node\n return `Missing ${nodeType}`;\n}\n\nfunction resolveRuleConfig<K extends keyof RulesConfig>(\n rules: RulesConfig | undefined,\n ruleName: K,\n): { severity: RuleSeverity; entry: RulesConfig[K] } {\n const entry = rules?.[ruleName];\n let severity: RuleSeverity;\n if (entry === undefined) {\n severity = RULE_DEFAULTS[ruleName] ?? 'off';\n } else if (typeof entry === 'string') {\n severity = entry;\n } else {\n severity = (entry as { severity: RuleSeverity }).severity;\n }\n return { severity, entry: entry as RulesConfig[K] };\n}\n\nfunction parseDisableDirective(node: BalanceNode, customRuleIds?: Set<string>): string | null {\n if (node.type !== 'html_comment' && node.type !== 'mustache_comment') return null;\n let inner: string | null = null;\n if (node.type === 'html_comment') {\n const match = node.text.match(/^<!--([\\s\\S]*)-->$/);\n if (match) inner = match[1].trim();\n } else {\n const match = node.text.match(/^\\{\\{!([\\s\\S]*)\\}\\}$/);\n if (match) inner = match[1].trim();\n }\n if (!inner) return null;\n const prefix = 'htmlmustache-disable ';\n if (!inner.startsWith(prefix)) return null;\n const ruleName = inner.slice(prefix.length).trim();\n if (KNOWN_RULE_NAMES.has(ruleName)) return ruleName;\n if (customRuleIds?.has(ruleName)) return ruleName;\n return null;\n}\n\nfunction collectDisabledRules(rootNode: BalanceNode, customRuleIds?: Set<string>): Set<string> {\n const disabled = new Set<string>();\n function walk(node: BalanceNode) {\n const rule = parseDisableDirective(node, customRuleIds);\n if (rule) { disabled.add(rule); return; }\n for (const child of node.children) walk(child);\n }\n walk(rootNode);\n return disabled;\n}\n\n/**\n * Collect all errors from a parsed tree: syntax errors, balance errors,\n * unclosed tags, and mustache lint checks.\n */\nexport function collectErrors(tree: WalkableTree, rules?: RulesConfig, customTagNames?: string[], customRules?: CustomRule[]): CheckError[] {\n const errors: CheckError[] = [];\n const cursor = tree.walk() as unknown as TreeCursor;\n\n function visit() {\n const node = cursor.currentNode;\n const nodeType = cursor.nodeType;\n\n if (ERROR_NODE_TYPES.has(nodeType) || cursor.nodeIsMissing) {\n errors.push({\n node,\n message: errorMessageForNode(nodeType, node),\n });\n\n // Don't recurse into ERROR nodes \u2014 the children are not meaningful\n if (nodeType === 'ERROR') return;\n }\n\n if (cursor.gotoFirstChild()) {\n do { visit(); } while (cursor.gotoNextSibling());\n cursor.gotoParent();\n }\n }\n\n visit();\n\n // Run balance checker for HTML tag mismatch detection across mustache paths\n const balanceErrors = checkHtmlBalance(tree.rootNode);\n for (const error of balanceErrors) {\n errors.push({ node: error.node, message: error.message });\n }\n\n // Check for unclosed non-void HTML tags\n const unclosedErrors = checkUnclosedTags(tree.rootNode);\n for (const error of unclosedErrors) {\n errors.push({ node: error.node, message: error.message });\n }\n\n // Collect inline disable directives and merge into effective rules\n const customRuleIds = customRules ? new Set(customRules.map(r => r.id)) : undefined;\n const disabledRules = collectDisabledRules(tree.rootNode, customRuleIds);\n const effectiveRules = { ...rules };\n for (const rule of disabledRules) {\n (effectiveRules as Record<string, string>)[rule] = 'off';\n }\n\n // Configurable lint checks\n const sourceText = tree.rootNode.text;\n\n const ruleChecks: { rule: keyof RulesConfig; errors: (entry: RulesConfig[keyof RulesConfig]) => import('./mustacheChecks.js').FixableError[] }[] = [\n { rule: 'nestedDuplicateSections', errors: () => checkNestedSameNameSections(tree.rootNode) },\n { rule: 'unquotedMustacheAttributes', errors: () => checkUnquotedMustacheAttributes(tree.rootNode) },\n { rule: 'consecutiveDuplicateSections', errors: () => checkConsecutiveSameNameSections(tree.rootNode, sourceText) },\n { rule: 'selfClosingNonVoidTags', errors: () => checkSelfClosingNonVoidTags(tree.rootNode) },\n { rule: 'duplicateAttributes', errors: () => checkDuplicateAttributes(tree.rootNode) },\n { rule: 'unescapedEntities', errors: () => checkUnescapedEntities(tree.rootNode) },\n { rule: 'preferMustacheComments', errors: () => checkHtmlComments(tree.rootNode) },\n { rule: 'unrecognizedHtmlTags', errors: () => checkUnrecognizedHtmlTags(tree.rootNode, customTagNames) },\n {\n rule: 'elementContentTooLong',\n errors: (entry) => {\n const elements = (entry && typeof entry === 'object' ? (entry as ElementContentTooLongOptions).elements : undefined) ?? [];\n return checkElementContentTooLong(tree.rootNode, elements);\n },\n },\n ];\n\n for (const { rule, errors: getErrors } of ruleChecks) {\n const { severity, entry } = resolveRuleConfig(effectiveRules, rule);\n if (severity === 'off') continue;\n\n for (const error of getErrors(entry)) {\n errors.push({\n node: error.node,\n message: error.message,\n severity,\n fix: error.fix,\n fixDescription: error.fixDescription,\n ruleName: rule,\n });\n }\n }\n\n // Custom selector-based rules\n if (customRules) {\n for (const rule of customRules) {\n if (disabledRules.has(rule.id)) continue;\n const severity = rule.severity ?? 'error';\n if (severity === 'off') continue;\n const parsed = parseSelectorCached(rule.selector);\n if (!parsed) continue;\n const matches = matchSelector(tree.rootNode, parsed);\n for (const node of matches) {\n errors.push({ node, message: rule.message, severity, ruleName: rule.id });\n }\n }\n }\n\n // Filter out preferMustacheComments warnings on disable-directive comments themselves\n return errors.filter(e =>\n !(e.message.includes('HTML comment found') && parseDisableDirective(e.node, customRuleIds) !== null)\n );\n}\n", "/**\n * Printer module - converts Doc IR to formatted string.\n *\n * The printer traverses the Doc tree and produces a string with proper\n * indentation and line breaks.\n */\n\nimport type { Doc } from './ir.js';\n\nexport interface PrinterOptions {\n /** The indentation string (e.g., ' ' for 2 spaces or '\\t' for tab) */\n indentUnit: string;\n /** Maximum line width before breaking (used for group fitting) */\n printWidth?: number;\n}\n\ninterface PrintState {\n indentLevel: number;\n mode: 'flat' | 'break';\n groupModes: Map<symbol, 'flat' | 'break'>;\n}\n\n/**\n * Print a Doc to a string with the given options.\n */\nexport function print(doc: Doc, options: PrinterOptions): string {\n const output: string[] = [];\n const state: PrintState = { indentLevel: 0, mode: 'break', groupModes: new Map() };\n\n printDoc(doc, state, output, options);\n\n return output.join('');\n}\n\n/**\n * Walk the output buffer backward to find the current column position\n * (characters since the last newline).\n */\nfunction currentColumn(output: string[]): number {\n let col = 0;\n for (let i = output.length - 1; i >= 0; i--) {\n const chunk = output[i];\n const nlIndex = chunk.lastIndexOf('\\n');\n if (nlIndex !== -1) {\n col += chunk.length - nlIndex - 1;\n return col;\n }\n col += chunk.length;\n }\n return col;\n}\n\n/**\n * Check if a Doc tree contains a breakParent anywhere.\n */\nfunction containsBreakParent(doc: Doc): boolean {\n if (typeof doc === 'string') return false;\n switch (doc.type) {\n case 'breakParent':\n return true;\n case 'concat':\n return doc.parts.some(containsBreakParent);\n case 'indent':\n return containsBreakParent(doc.contents);\n case 'group':\n return containsBreakParent(doc.contents);\n case 'fill':\n return doc.parts.some(containsBreakParent);\n case 'ifBreak':\n return (\n containsBreakParent(doc.breakContents) ||\n containsBreakParent(doc.flatContents)\n );\n default:\n return false;\n }\n}\n\nfunction printDoc(\n doc: Doc,\n state: PrintState,\n output: string[],\n options: PrinterOptions\n): void {\n if (typeof doc === 'string') {\n output.push(doc);\n return;\n }\n\n switch (doc.type) {\n case 'concat':\n for (const part of doc.parts) {\n printDoc(part, state, output, options);\n }\n break;\n\n case 'indent':\n state.indentLevel++;\n printDoc(doc.contents, state, output, options);\n state.indentLevel--;\n break;\n\n case 'hardline':\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n break;\n\n case 'softline':\n if (state.mode === 'break') {\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n }\n // In flat mode, softline produces nothing\n break;\n\n case 'line':\n if (state.mode === 'break') {\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n } else {\n // In flat mode, line produces a space\n output.push(' ');\n }\n break;\n\n case 'group': {\n if (doc.break || containsBreakParent(doc.contents)) {\n // Forced break\n const prevMode = state.mode;\n state.mode = 'break';\n if (doc.id) state.groupModes.set(doc.id, 'break');\n printDoc(doc.contents, state, output, options);\n state.mode = prevMode;\n } else {\n // Try to fit on one line\n const flatOutput: string[] = [];\n const flatState: PrintState = { ...state, mode: 'flat', groupModes: new Map(state.groupModes) };\n printDoc(doc.contents, flatState, flatOutput, options);\n\n const flatContent = flatOutput.join('');\n const printWidth = options.printWidth ?? 80;\n const col = currentColumn(output);\n\n // Check if it fits (no newlines and within width from current column)\n if (\n !flatContent.includes('\\n') &&\n col + flatContent.length <= printWidth\n ) {\n if (doc.id) state.groupModes.set(doc.id, 'flat');\n output.push(flatContent);\n } else {\n // Break mode\n const prevMode = state.mode;\n state.mode = 'break';\n if (doc.id) state.groupModes.set(doc.id, 'break');\n printDoc(doc.contents, state, output, options);\n state.mode = prevMode;\n }\n }\n break;\n }\n\n case 'fill':\n printFill(doc.parts, state, output, options);\n break;\n\n case 'ifBreak': {\n const effectiveMode = doc.groupId\n ? (state.groupModes.get(doc.groupId) ?? state.mode)\n : state.mode;\n if (effectiveMode === 'break') {\n printDoc(doc.breakContents, state, output, options);\n } else {\n printDoc(doc.flatContents, state, output, options);\n }\n break;\n }\n\n case 'breakParent':\n // breakParent is handled by containsBreakParent() in group evaluation.\n // If we reach here outside a group, force break mode.\n state.mode = 'break';\n break;\n }\n}\n\n/**\n * Print fill: content and separator pairs, keeping items on the same line\n * when they fit, breaking when they don't.\n * Parts alternate: [content, separator, content, separator, ..., content]\n */\nfunction printFill(\n parts: Doc[],\n state: PrintState,\n output: string[],\n options: PrinterOptions\n): void {\n if (parts.length === 0) return;\n\n const printWidth = options.printWidth ?? 80;\n\n for (let i = 0; i < parts.length; i++) {\n const content = parts[i];\n const separator = i + 1 < parts.length ? parts[i + 1] : null;\n\n // Print the content\n printDoc(content, state, output, options);\n\n if (separator === null) break;\n\n // Try printing separator + next content flat\n const nextContent = i + 2 < parts.length ? parts[i + 2] : null;\n if (nextContent !== null) {\n const testOutput: string[] = [];\n const flatState: PrintState = { ...state, mode: 'flat' };\n printDoc(separator, flatState, testOutput, options);\n printDoc(nextContent, flatState, testOutput, options);\n const testStr = testOutput.join('');\n const col = currentColumn(output);\n\n if (!testStr.includes('\\n') && col + testStr.length <= printWidth) {\n // Fits: print separator flat\n const sepOutput: string[] = [];\n printDoc(separator, flatState, sepOutput, options);\n output.push(sepOutput.join(''));\n } else {\n // Doesn't fit: print separator in break mode\n printDoc(separator, { ...state, mode: 'break' }, output, options);\n }\n } else {\n // Last separator with no following content, print in current mode\n printDoc(separator, state, output, options);\n }\n\n // Skip the separator in the loop\n i++;\n }\n}\n\nfunction makeIndent(level: number, options: PrinterOptions): string {\n return options.indentUnit.repeat(level);\n}\n", "/**\n * Intermediate Representation (IR) for document formatting.\n *\n * This module defines the Doc type and builder functions for creating\n * formatting commands. The IR is inspired by Prettier's document model.\n */\n\n// Doc types - the IR for formatting\nexport type Doc =\n | string // literal text\n | Concat\n | Indent\n | Hardline\n | Softline\n | Line\n | Group\n | Fill\n | BreakParent\n | IfBreak;\n\nexport interface Concat {\n type: 'concat';\n parts: Doc[];\n}\n\nexport interface Indent {\n type: 'indent';\n contents: Doc;\n}\n\nexport interface Hardline {\n type: 'hardline';\n}\n\nexport interface Softline {\n type: 'softline';\n}\n\nexport interface Line {\n type: 'line';\n}\n\nexport interface Group {\n type: 'group';\n contents: Doc;\n break?: boolean;\n id?: symbol;\n}\n\nexport interface Fill {\n type: 'fill';\n parts: Doc[];\n}\n\nexport interface BreakParent {\n type: 'breakParent';\n}\n\nexport interface IfBreak {\n type: 'ifBreak';\n breakContents: Doc;\n flatContents: Doc;\n groupId?: symbol;\n}\n\n// Constants\nexport const hardline: Hardline = { type: 'hardline' };\nexport const softline: Softline = { type: 'softline' };\nexport const line: Line = { type: 'line' };\nexport const breakParent: BreakParent = { type: 'breakParent' };\nexport const empty = '';\n\n/**\n * Create a literal text node.\n */\nexport function text(value: string): string {\n return value;\n}\n\n/**\n * Concatenate multiple docs into a single doc.\n */\nexport function concat(parts: Doc[]): Doc {\n // Flatten nested concats and filter empty strings\n const flattened: Doc[] = [];\n for (const part of parts) {\n if (part === '') continue;\n if (typeof part === 'object' && part.type === 'concat') {\n flattened.push(...part.parts);\n } else {\n flattened.push(part);\n }\n }\n\n if (flattened.length === 0) return '';\n if (flattened.length === 1) return flattened[0];\n\n return { type: 'concat', parts: flattened };\n}\n\n/**\n * Indent the contents by one level.\n */\nexport function indent(contents: Doc): Doc {\n if (contents === '') return '';\n return { type: 'indent', contents };\n}\n\n/**\n * Indent the contents by N levels.\n */\nexport function indentN(contents: Doc, n: number): Doc {\n if (n <= 0 || contents === '') return contents;\n let result = contents;\n for (let i = 0; i < n; i++) {\n result = indent(result);\n }\n return result;\n}\n\n/**\n * Create a group that may be printed flat or broken across lines.\n * When `shouldBreak` is true, the group will always break.\n * When `id` is set, the group's mode can be referenced by `ifBreak` nodes.\n */\nexport function group(contents: Doc, options?: { shouldBreak?: boolean; id?: symbol }): Doc {\n if (contents === '') return '';\n const shouldBreak = options?.shouldBreak;\n return { type: 'group', contents, break: shouldBreak || undefined, id: options?.id };\n}\n\n/**\n * Create an ifBreak node that prints different content depending on\n * whether the enclosing group breaks or stays flat.\n * When `groupId` is set, checks that specific group's mode instead.\n */\nexport function ifBreak(breakContents: Doc, flatContents: Doc, options?: { groupId?: symbol }): Doc {\n return { type: 'ifBreak', breakContents, flatContents, groupId: options?.groupId };\n}\n\n/**\n * Create a fill for inline content that wraps when needed.\n * Parts alternate between content and separators.\n */\nexport function fill(parts: Doc[]): Doc {\n const filtered = parts.filter((p) => p !== '');\n if (filtered.length === 0) return '';\n if (filtered.length === 1) return filtered[0];\n return { type: 'fill', parts: filtered };\n}\n\n/**\n * Join docs with a separator.\n */\nexport function join(separator: Doc, docs: Doc[]): Doc {\n const parts: Doc[] = [];\n for (let i = 0; i < docs.length; i++) {\n if (docs[i] === '') continue;\n if (parts.length > 0) {\n parts.push(separator);\n }\n parts.push(docs[i]);\n }\n return concat(parts);\n}\n\n// Type guards for working with Doc types\nexport function isConcat(doc: Doc): doc is Concat {\n return typeof doc === 'object' && doc.type === 'concat';\n}\n\nexport function isIndent(doc: Doc): doc is Indent {\n return typeof doc === 'object' && doc.type === 'indent';\n}\n\nexport function isHardline(doc: Doc): doc is Hardline {\n return typeof doc === 'object' && doc.type === 'hardline';\n}\n\nexport function isSoftline(doc: Doc): doc is Softline {\n return typeof doc === 'object' && doc.type === 'softline';\n}\n\nexport function isLine(doc: Doc): doc is Line {\n return typeof doc === 'object' && doc.type === 'line';\n}\n\nexport function isGroup(doc: Doc): doc is Group {\n return typeof doc === 'object' && doc.type === 'group';\n}\n\nexport function isFill(doc: Doc): doc is Fill {\n return typeof doc === 'object' && doc.type === 'fill';\n}\n\nexport function isBreakParent(doc: Doc): doc is BreakParent {\n return typeof doc === 'object' && doc.type === 'breakParent';\n}\n\nexport function isIfBreak(doc: Doc): doc is IfBreak {\n return typeof doc === 'object' && doc.type === 'ifBreak';\n}\n", "/**\n * Utility functions for formatting.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\n\n// Re-export getTagName from the canonical location\nexport { getTagName } from '../nodeHelpers.js';\n\n/**\n * Normalize text content - collapse horizontal whitespace while preserving line breaks.\n */\nexport function normalizeText(text: string): string {\n // Split by newlines, normalize each line, then rejoin\n // This preserves intentional line breaks while collapsing spaces\n return text\n .split('\\n')\n .map((line) => line.replace(/[ \\t]+/g, ' ').trim())\n .filter((line, i, arr) => line || (i > 0 && i < arr.length - 1)) // Keep non-empty lines\n .join('\\n');\n}\n\n/**\n * Get visible children of a node (excluding anonymous nodes starting with _).\n */\nexport function getVisibleChildren(node: SyntaxNode): SyntaxNode[] {\n const children: SyntaxNode[] = [];\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && !child.type.startsWith('_')) {\n children.push(child);\n }\n }\n return children;\n}\n\n/**\n * Calculate the indent level of a node based on its parent chain.\n */\nexport function calculateIndentLevel(\n node: SyntaxNode,\n isBlockLevel: (node: SyntaxNode) => boolean,\n hasImplicitEndTags: (nodes: SyntaxNode[]) => boolean,\n getContentNodes: (node: SyntaxNode) => SyntaxNode[]\n): number {\n let level = 0;\n let current = node.parent;\n while (current) {\n if (isBlockLevel(current)) {\n // Mustache sections only increase indentation if they have complete HTML\n // (no implicit end tags crossing boundaries)\n if (\n current.type === 'mustache_section' ||\n current.type === 'mustache_inverted_section'\n ) {\n const contentNodes = getContentNodes(current);\n if (!hasImplicitEndTags(contentNodes)) {\n level++;\n }\n } else {\n level++;\n }\n }\n current = current.parent;\n }\n return level;\n}\n\n/**\n * Normalize whitespace inside a single mustache expression.\n * Handles triple ({{{...}}}), prefixed ({{#, {{/, {{^, {{!, {{>), and plain ({{...}}).\n * For multiline comments, preserves internal newlines, only normalizes space adjacent to delimiters.\n */\nexport function normalizeMustacheWhitespace(raw: string, addSpaces: boolean): string {\n const space = addSpaces ? ' ' : '';\n\n // Triple mustache: {{{...}}}\n const tripleMatch = raw.match(/^\\{\\{\\{([\\s\\S]*)\\}\\}\\}$/);\n if (tripleMatch) {\n const inner = tripleMatch[1].trim();\n return `{{{${space}${inner}${space}}}}`;\n }\n\n // Prefixed: {{#, {{/, {{^, {{!, {{>\n const prefixedMatch = raw.match(/^\\{\\{([#/^!>])([\\s\\S]*)\\}\\}$/);\n if (prefixedMatch) {\n const prefix = prefixedMatch[1];\n const inner = prefixedMatch[2];\n\n // Multiline comments: preserve internal newlines, always use spaces\n if (prefix === '!' && inner.includes('\\n')) {\n const lines = inner.split('\\n');\n const first = lines[0].trimStart();\n const last = lines[lines.length - 1].trimEnd();\n if (lines.length === 1) {\n return `{{${prefix} ${first} }}`;\n }\n const middle = lines.slice(1, -1);\n return `{{${prefix} ${first}\\n${middle.join('\\n')}\\n${last} }}`;\n }\n\n const trimmed = inner.trim();\n // Comments always get spaces for readability, regardless of mustacheSpaces setting\n const s = prefix === '!' ? ' ' : space;\n return `{{${prefix}${s}${trimmed}${s}}}`;\n }\n\n // Plain: {{...}}\n const plainMatch = raw.match(/^\\{\\{([\\s\\S]*)\\}\\}$/);\n if (plainMatch) {\n const inner = plainMatch[1].trim();\n return `{{${space}${inner}${space}}}`;\n }\n\n return raw;\n}\n\n/**\n * Normalize whitespace in ALL mustache expressions within a string.\n * Used for force-inlined sections where the full section text (e.g. `{{#plural}}s{{/plural}}`)\n * is emitted as one string.\n */\nexport function normalizeMustacheWhitespaceAll(raw: string, addSpaces: boolean): string {\n // Match triple mustache first, then double\n return raw.replace(/\\{\\{\\{[\\s\\S]*?\\}\\}\\}|\\{\\{[\\s\\S]*?\\}\\}/g, (match) => {\n return normalizeMustacheWhitespace(match, addSpaces);\n });\n}\n\n/**\n * Check if a node is a format-ignore directive comment.\n * Returns the directive type or null if not a directive.\n */\nexport function getIgnoreDirective(\n node: SyntaxNode\n): 'ignore' | 'ignore-start' | 'ignore-end' | null {\n if (node.type !== 'html_comment' && node.type !== 'mustache_comment') {\n return null;\n }\n\n let inner: string | null = null;\n\n if (node.type === 'html_comment') {\n // <!-- ... -->\n const match = node.text.match(/^<!--([\\s\\S]*)-->$/);\n if (match) {\n inner = match[1].trim();\n }\n } else {\n // {{! ... }}\n const match = node.text.match(/^\\{\\{!([\\s\\S]*)\\}\\}$/);\n if (match) {\n inner = match[1].trim();\n }\n }\n\n if (!inner) return null;\n\n if (inner === 'htmlmustache-ignore') return 'ignore';\n if (inner === 'htmlmustache-ignore-start') return 'ignore-start';\n if (inner === 'htmlmustache-ignore-end') return 'ignore-end';\n\n return null;\n}\n\n/**\n * Find the smallest node that contains the entire range.\n */\nexport function findContainingNode(\n node: SyntaxNode,\n startOffset: number,\n endOffset: number\n): SyntaxNode | null {\n if (node.startIndex > endOffset || node.endIndex < startOffset) {\n return null;\n }\n\n // Check children first for a more specific match\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && child.startIndex <= startOffset && child.endIndex >= endOffset) {\n const deeper = findContainingNode(child, startOffset, endOffset);\n if (deeper) return deeper;\n }\n }\n\n // This node contains the range\n if (node.startIndex <= startOffset && node.endIndex >= endOffset) {\n return node;\n }\n\n return null;\n}\n", "import type { Node as SyntaxNode } from 'web-tree-sitter';\nimport type { CSSDisplay } from './formatting/classifier.js';\n\nexport type CustomCodeTagIndentMode = 'never' | 'always' | 'attribute';\n\nexport interface CustomCodeTagConfig {\n name: string;\n display?: CSSDisplay;\n languageAttribute?: string;\n languageMap?: Record<string, string>;\n languageDefault?: string;\n indent?: CustomCodeTagIndentMode;\n indentAttribute?: string;\n}\n\n/** Alias for CustomCodeTagConfig (unified name). */\nexport type CustomTagConfig = CustomCodeTagConfig;\n\n/**\n * Check if a custom tag config represents a code tag (has language settings).\n * Code tags get preserved content and default to block display.\n */\nexport function isCodeTag(config: CustomCodeTagConfig): boolean {\n return !!(config.languageAttribute || config.languageDefault);\n}\n\nexport interface CustomCodeTagContent {\n text: string;\n languageId: string;\n startRow: number;\n startCol: number;\n}\n\n/**\n * Get the attribute value for a given attribute name from an element's start tag.\n */\nexport function getAttributeValue(node: SyntaxNode, attrName: string): string | null {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const attr = child.child(j);\n if (attr?.type === 'html_attribute') {\n let name = '';\n let value = '';\n for (let k = 0; k < attr.childCount; k++) {\n const part = attr.child(k);\n if (part?.type === 'html_attribute_name') name = part.text.toLowerCase();\n if (part?.type === 'html_quoted_attribute_value') value = part.text.replace(/^[\"']|[\"']$/g, '');\n if (part?.type === 'html_attribute_value') value = part.text;\n }\n if (name === attrName.toLowerCase()) {\n return value;\n }\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Resolve the language ID for a custom code tag element.\n */\nfunction resolveCustomCodeLanguage(node: SyntaxNode, config: CustomCodeTagConfig): string | null {\n if (config.languageAttribute) {\n const attrValue = getAttributeValue(node, config.languageAttribute);\n if (attrValue) {\n if (config.languageMap && config.languageMap[attrValue]) {\n return config.languageMap[attrValue];\n }\n return attrValue.toLowerCase();\n }\n }\n return config.languageDefault?.toLowerCase() ?? null;\n}\n\n/**\n * Walk the tree to find custom code tag elements and extract their content + language.\n */\nexport function findCustomCodeTagContent(\n rootNode: SyntaxNode,\n configs: CustomCodeTagConfig[],\n): CustomCodeTagContent[] {\n if (configs.length === 0) return [];\n\n const configsByName = new Map<string, CustomCodeTagConfig>();\n for (const config of configs) {\n if (config.languageAttribute || config.languageDefault) {\n configsByName.set(config.name.toLowerCase(), config);\n }\n }\n if (configsByName.size === 0) return [];\n\n const results: CustomCodeTagContent[] = [];\n\n const walk = (node: SyntaxNode) => {\n if (node.type === 'html_element' || node.type === 'html_raw_element') {\n let tagName = '';\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const nameNode = child.child(j);\n if (nameNode?.type === 'html_tag_name') {\n tagName = nameNode.text.toLowerCase();\n break;\n }\n }\n break;\n }\n }\n\n const config = configsByName.get(tagName);\n if (config) {\n const languageId = resolveCustomCodeLanguage(node, config);\n if (languageId) {\n let startTag: SyntaxNode | null = null;\n let endTag: SyntaxNode | null = null;\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') startTag = child;\n if (child?.type === 'html_end_tag') endTag = child;\n if (child?.type === 'html_raw_text') {\n results.push({\n text: child.text,\n languageId,\n startRow: child.startPosition.row,\n startCol: child.startPosition.column,\n });\n }\n }\n\n if (startTag && node.type === 'html_element') {\n const contentStartIndex = startTag.endIndex;\n const contentEndIndex = endTag ? endTag.startIndex : node.endIndex;\n const contentText = node.tree.rootNode.text.slice(contentStartIndex, contentEndIndex);\n if (contentText.length > 0) {\n results.push({\n text: contentText,\n languageId,\n startRow: startTag.endPosition.row,\n startCol: startTag.endPosition.column,\n });\n }\n }\n }\n }\n }\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child) walk(child);\n }\n };\n\n walk(rootNode);\n return results;\n}\n", "/**\n * Node classifier - determines how to format different node types.\n *\n * This module uses CSS display values to classify HTML elements, matching\n * Prettier's approach to whitespace sensitivity in HTML formatting.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport { getTagName } from './utils.js';\nimport { isMustacheSection, isRawContentElement, isHtmlElementType } from '../nodeHelpers.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\nimport { isCodeTag } from '../customCodeTags.js';\n\nconst EMPTY_MAP: Map<string, CustomCodeTagConfig> = new Map();\n\nexport type CSSDisplay =\n | 'block'\n | 'inline'\n | 'inline-block'\n | 'table-row'\n | 'table-cell'\n | 'table'\n | 'table-row-group'\n | 'table-header-group'\n | 'table-footer-group'\n | 'table-column'\n | 'table-column-group'\n | 'table-caption'\n | 'list-item'\n | 'ruby'\n | 'ruby-base'\n | 'ruby-text'\n | 'none';\n\n/**\n * Default CSS display values for HTML elements, matching browser defaults.\n * Elements not in this map default to 'inline'.\n */\nconst CSS_DISPLAY_MAP: Record<string, CSSDisplay> = {\n // Block elements\n address: 'block',\n article: 'block',\n aside: 'block',\n blockquote: 'block',\n body: 'block',\n center: 'block',\n dd: 'block',\n details: 'block',\n dialog: 'block',\n dir: 'block',\n div: 'block',\n dl: 'block',\n dt: 'block',\n fieldset: 'block',\n figcaption: 'block',\n figure: 'block',\n footer: 'block',\n form: 'block',\n h1: 'block',\n h2: 'block',\n h3: 'block',\n h4: 'block',\n h5: 'block',\n h6: 'block',\n header: 'block',\n hgroup: 'block',\n hr: 'block',\n html: 'block',\n legend: 'block',\n listing: 'block',\n main: 'block',\n menu: 'block',\n nav: 'block',\n ol: 'block',\n p: 'block',\n plaintext: 'block',\n pre: 'block',\n search: 'block',\n section: 'block',\n summary: 'block',\n ul: 'block',\n xmp: 'block',\n\n // List items\n li: 'list-item',\n\n // Table elements\n table: 'table',\n caption: 'table-caption',\n colgroup: 'table-column-group',\n col: 'table-column',\n thead: 'table-header-group',\n tbody: 'table-row-group',\n tfoot: 'table-footer-group',\n tr: 'table-row',\n td: 'table-cell',\n th: 'table-cell',\n\n // Inline-block elements\n button: 'inline-block',\n img: 'inline-block',\n input: 'inline-block',\n select: 'inline-block',\n textarea: 'inline-block',\n video: 'inline-block',\n audio: 'inline-block',\n canvas: 'inline-block',\n embed: 'inline-block',\n iframe: 'inline-block',\n object: 'inline-block',\n\n // None\n head: 'none',\n link: 'none',\n meta: 'none',\n script: 'none',\n style: 'none',\n title: 'none',\n template: 'none',\n\n // Ruby\n ruby: 'ruby',\n rb: 'ruby-base',\n rt: 'ruby-text',\n rp: 'none',\n};\n\n// HTML inline elements that should not cause line breaks\nexport const INLINE_ELEMENTS = new Set([\n 'a',\n 'abbr',\n 'acronym',\n 'b',\n 'bdo',\n 'big',\n 'br',\n 'button',\n 'cite',\n 'code',\n 'dfn',\n 'em',\n 'i',\n 'img',\n 'input',\n 'kbd',\n 'label',\n 'map',\n 'object',\n 'output',\n 'q',\n 'samp',\n 'script',\n 'select',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'sup',\n 'textarea',\n 'time',\n 'tt',\n 'u',\n 'var',\n 'wbr',\n]);\n\n// Elements whose content should be preserved as-is\nexport const PRESERVE_CONTENT_ELEMENTS = new Set([\n 'pre',\n 'code',\n 'textarea',\n 'script',\n 'style',\n]);\n\n/**\n * Get the CSS display value for a node.\n */\nexport function getCSSDisplay(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): CSSDisplay {\n const type = node.type;\n\n if (type === 'html_element') {\n const tagName = getTagName(node);\n if (tagName) {\n const lower = tagName.toLowerCase();\n const config = customTags.get(lower);\n if (config) {\n // Explicit display takes priority\n if (config.display) return config.display;\n // Code tags default to block\n if (isCodeTag(config)) return 'block';\n // Custom tags default to inline-block (inline externally, block internally)\n return 'inline-block';\n }\n return CSS_DISPLAY_MAP[lower] ?? 'inline';\n }\n return 'block'; // Unknown elements default to block\n }\n\n if (isRawContentElement(node)) {\n return 'block';\n }\n\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags) ? 'block' : 'inline';\n }\n\n // Text, interpolation, comments, etc. are inline\n return 'inline';\n}\n\n/**\n * Check if a display value means the element is whitespace-insensitive\n * (i.e., we can freely add/remove whitespace around it).\n */\nexport function isWhitespaceInsensitive(display: CSSDisplay): boolean {\n switch (display) {\n case 'block':\n case 'list-item':\n case 'table':\n case 'table-row':\n case 'table-row-group':\n case 'table-header-group':\n case 'table-footer-group':\n case 'table-column':\n case 'table-column-group':\n case 'table-caption':\n case 'table-cell':\n case 'none':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Check if a node represents a block-level element that should cause indentation.\n * Delegates to getCSSDisplay for classification.\n */\nexport function isBlockLevel(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n // Mustache sections are block-level only if they contain block-level content\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags);\n }\n\n // HTML elements: check CSS display\n if (type === 'html_element') {\n const display = getCSSDisplay(node, customTags);\n return isWhitespaceInsensitive(display);\n }\n\n // Script, style, and raw elements are block-level\n if (isRawContentElement(node)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if an HTML element is an inline element.\n */\nexport function isInlineElement(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n if (node.type !== 'html_element') {\n return false;\n }\n const display = getCSSDisplay(node, customTags);\n return !isWhitespaceInsensitive(display);\n}\n\n/**\n * Check if element content should be preserved as-is.\n */\nexport function shouldPreserveContent(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n if (isRawContentElement(node)) {\n return true;\n }\n\n if (type === 'html_element') {\n const tagName = getTagName(node);\n if (!tagName) return false;\n const lower = tagName.toLowerCase();\n if (PRESERVE_CONTENT_ELEMENTS.has(lower)) return true;\n // Only code tags (with language config) get preserved content, not display-only custom tags\n const config = customTags.get(lower);\n if (config && isCodeTag(config)) return true;\n }\n\n return false;\n}\n\n/**\n * Check if a mustache section contains any block-level content.\n * A section has block content if:\n * - It contains block-level HTML elements, OR\n * - It contains any HTML elements with implicit end tags (HTML crossing boundaries)\n */\nexport function hasBlockContent(sectionNode: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const contentNodes = getContentNodes(sectionNode);\n\n // Check for implicit end tags first - this makes the section block-level\n if (hasImplicitEndTags(contentNodes)) {\n return true;\n }\n\n // Check for block-level elements\n for (const node of contentNodes) {\n if (isBlockLevelContent(node, customTags)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if a node is block-level content (for determining mustache section treatment).\n */\nexport function isBlockLevelContent(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n // Any HTML element is considered block-level content for mustache sections\n // This ensures {{#section}}<span>...</span>{{/section}} gets formatted as a block\n if (type === 'html_element') {\n return true;\n }\n\n // Script/style/raw are block-level\n if (isRawContentElement(node)) {\n return true;\n }\n\n // Nested mustache sections - recurse\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags);\n }\n\n // Text, interpolation, comments, etc. are inline\n return false;\n}\n\n/**\n * Get the content nodes from a mustache section (excluding begin/end tags).\n */\nexport function getContentNodes(sectionNode: SyntaxNode): SyntaxNode[] {\n const isInverted = sectionNode.type === 'mustache_inverted_section';\n const beginType = isInverted\n ? 'mustache_inverted_section_begin'\n : 'mustache_section_begin';\n const endType = isInverted\n ? 'mustache_inverted_section_end'\n : 'mustache_section_end';\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < sectionNode.childCount; i++) {\n const child = sectionNode.child(i);\n if (!child) continue;\n if (\n child.type !== beginType &&\n child.type !== endType &&\n child.type !== 'mustache_erroneous_section_end' &&\n child.type !== 'mustache_erroneous_inverted_section_end' &&\n !child.type.startsWith('_')\n ) {\n contentNodes.push(child);\n }\n }\n return contentNodes;\n}\n\n/**\n * Check if any HTML elements in the given nodes have implicit end tags\n * (forced closed by mustache section end rather than explicit </tag>).\n */\nexport function hasImplicitEndTags(nodes: SyntaxNode[]): boolean {\n for (const node of nodes) {\n if (hasImplicitEndTagsRecursive(node)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasImplicitEndTagsRecursive(node: SyntaxNode): boolean {\n // Check if this HTML element has a forced/implicit end tag\n if (node.type === 'html_element') {\n let hasStartTag = false;\n let hasEndTag = false;\n let hasContentChildren = false;\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n if (child.type === 'html_start_tag') hasStartTag = true;\n else if (child.type === 'html_end_tag') hasEndTag = true;\n else if (child.type === 'html_forced_end_tag') return true;\n else if (!child.type.startsWith('_')) hasContentChildren = true;\n }\n // Void elements (start tag only, no content, no end tag) aren't boundary-crossing\n if (hasStartTag && !hasEndTag && hasContentChildren) return true;\n }\n\n // Check children recursively\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && hasImplicitEndTagsRecursive(child)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if a node is inline content that participates in text flow.\n * Mustache interpolation, triple, and partial nodes behave like text.\n */\nfunction isInlineContentNode(node: SyntaxNode): boolean {\n if (node.type === 'text') return node.text.trim().length > 0;\n return (\n node.type === 'mustache_interpolation' ||\n node.type === 'mustache_triple' ||\n node.type === 'mustache_partial'\n );\n}\n\n/**\n * Check if a node is part of a text flow (adjacent to non-whitespace text).\n * Nodes that are part of text flow should stay inline.\n */\nexport function isInTextFlow(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[]\n): boolean {\n // Check previous sibling\n if (index > 0) {\n const prev = nodes[index - 1];\n if (prev.type === 'text' && prev.text.trim().length > 0) {\n return true;\n }\n }\n\n // Check next sibling\n if (index < nodes.length - 1) {\n const next = nodes[index + 1];\n if (next.type === 'text' && next.text.trim().length > 0) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if there's inline content (mustache interpolation, non-empty text, etc.)\n * adjacent to the node at `index`, looking past whitespace-only text nodes.\n */\nfunction hasAdjacentInlineContent(\n index: number,\n nodes: SyntaxNode[]\n): boolean {\n // Look backward past whitespace-only text\n for (let i = index - 1; i >= 0; i--) {\n const n = nodes[i];\n if (n.type === 'text' && n.text.trim().length === 0) continue;\n if (isInlineContentNode(n)) return true;\n break;\n }\n // Look forward past whitespace-only text\n for (let i = index + 1; i < nodes.length; i++) {\n const n = nodes[i];\n if (n.type === 'text' && n.text.trim().length === 0) continue;\n if (isInlineContentNode(n)) return true;\n break;\n }\n return false;\n}\n\n/**\n * Check if an HTML element should stay inline.\n * Elements stay inline if they're part of a text flow or adjacent to other inline elements.\n */\nexport function shouldHtmlElementStayInline(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[],\n customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP\n): boolean {\n if (node.type !== 'html_element') {\n return false;\n }\n\n // Block-display elements (table, div, etc.) should never stay inline\n if (isWhitespaceInsensitive(getCSSDisplay(node, customTags))) {\n return false;\n }\n\n // If the element is part of a text flow, keep it inline\n if (isInTextFlow(node, index, nodes)) {\n return true;\n }\n\n // Check for adjacent inline content (mustache interpolation, text, etc.)\n // past whitespace-only text nodes \u2014 e.g., <i>icon</i>\\n {{partial}}%\n if (hasAdjacentInlineContent(index, nodes)) {\n return true;\n }\n\n // If adjacent to another inline HTML element, stay inline (e.g., <code>5</code><code>-17</code>)\n // Check if there's a chain of HTML elements with text - they should all stay inline together\n if (index > 0) {\n const prev = nodes[index - 1];\n if (prev.type === 'html_element' && isInTextFlow(prev, index - 1, nodes)) {\n return true;\n }\n }\n if (index < nodes.length - 1) {\n const next = nodes[index + 1];\n if (next.type === 'html_element' && isInTextFlow(next, index + 1, nodes)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine if a node should be treated as block-level for formatting purposes.\n */\nexport function shouldTreatAsBlock(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[],\n customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP\n): boolean {\n const isHtmlEl = isHtmlElementType(node);\n const isMustacheSec = isMustacheSection(node);\n\n if (node.type === 'html_erroneous_end_tag') return true;\n\n return (\n (isHtmlEl && !shouldHtmlElementStayInline(node, index, nodes, customTags)) ||\n (isMustacheSec && !isInTextFlow(node, index, nodes)) ||\n (isBlockLevel(node, customTags) && !isInTextFlow(node, index, nodes))\n );\n}\n", "/**\n * Formatters - convert AST nodes to Doc IR.\n *\n * This module converts tree-sitter AST nodes to the Doc intermediate\n * representation. It uses CSS display-based classification to determine\n * whitespace sensitivity and wraps elements in groups so the printer\n * can decide flat vs break based on print width.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport type { TextDocument } from 'vscode-languageserver-textdocument';\nimport {\n Doc,\n concat,\n fill,\n hardline,\n softline,\n line,\n indent,\n indentN,\n group,\n text,\n empty,\n ifBreak,\n isLine,\n} from './ir.js';\nimport {\n isBlockLevel,\n shouldPreserveContent,\n hasImplicitEndTags,\n isInTextFlow,\n shouldTreatAsBlock,\n getCSSDisplay,\n isWhitespaceInsensitive,\n} from './classifier.js';\nimport { normalizeText, getVisibleChildren, normalizeMustacheWhitespace, normalizeMustacheWhitespaceAll, getIgnoreDirective, getTagName } from './utils.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\nimport { getAttributeValue } from '../customCodeTags.js';\nimport { isRawContentElement } from '../nodeHelpers.js';\nimport type { NoBreakDelimiter } from '../configSchema.js';\n\nexport interface FormatterContext {\n document: TextDocument;\n customTags?: Map<string, CustomCodeTagConfig>;\n embeddedFormatted?: Map<number, string>;\n mustacheSpaces?: boolean;\n noBreakDelimiters?: NoBreakDelimiter[];\n}\n\n/**\n * Check if an attribute value is truthy (not null, empty, \"false\", or \"0\").\n */\nexport function isAttributeTruthy(value: string | null): boolean {\n if (value === null || value === '' || value === 'false' || value === '0') {\n return false;\n }\n return true;\n}\n\n/**\n * Dedent content by stripping leading/trailing empty lines and removing the\n * minimum common indentation from all non-empty lines.\n */\nexport function dedentContent(rawContent: string): string {\n const lines = rawContent.split('\\n');\n\n // Strip leading empty lines\n while (lines.length > 0 && lines[0].trim() === '') {\n lines.shift();\n }\n // Strip trailing empty lines\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') {\n lines.pop();\n }\n\n if (lines.length === 0) return '';\n\n // Find minimum indentation across non-empty lines\n let minIndent = Infinity;\n for (const l of lines) {\n if (l.trim() === '') continue;\n const match = l.match(/^(\\s*)/);\n if (match && match[1].length < minIndent) {\n minIndent = match[1].length;\n }\n }\n if (minIndent === Infinity) minIndent = 0;\n\n // Strip common indent\n return lines.map(l => l.trim() === '' ? '' : l.slice(minIndent)).join('\\n');\n}\n\n/**\n * Resolve whether a custom code tag's content should be indented.\n */\nfunction resolveIndentMode(\n node: SyntaxNode,\n config: CustomCodeTagConfig\n): boolean {\n const mode = config.indent ?? 'never';\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n // mode === 'attribute'\n if (!config.indentAttribute) return false;\n const value = getAttributeValue(node, config.indentAttribute);\n return isAttributeTruthy(value);\n}\n\nfunction getTagNameFromStartTag(startTag: SyntaxNode): string | null {\n for (let i = 0; i < startTag.childCount; i++) {\n const child = startTag.child(i);\n if (child?.type === 'html_tag_name') return child.text.toLowerCase();\n }\n return null;\n}\n\nfunction mustacheText(raw: string, context: FormatterContext): string {\n if (context.mustacheSpaces !== undefined) {\n return normalizeMustacheWhitespace(raw, context.mustacheSpaces);\n }\n return raw;\n}\n\n/**\n * Format the document root node.\n */\nexport function formatDocument(node: SyntaxNode, context: FormatterContext): Doc {\n const children = getVisibleChildren(node);\n const content = formatBlockChildren(children, context);\n return concat([content, hardline]);\n}\n\n/**\n * Format a node based on its type.\n * @param forceInline - If true, format as inline even if content would normally be block-level\n */\nexport function formatNode(\n node: SyntaxNode,\n context: FormatterContext,\n forceInline = false\n): Doc {\n const type = node.type;\n\n switch (type) {\n case 'document':\n return formatDocument(node, context);\n\n case 'html_element':\n return formatHtmlElement(node, context, forceInline);\n\n case 'html_script_element':\n case 'html_style_element':\n case 'html_raw_element':\n return formatScriptStyleElement(node, context);\n\n case 'mustache_section':\n case 'mustache_inverted_section':\n if (forceInline) {\n if (context.mustacheSpaces !== undefined) {\n return text(normalizeMustacheWhitespaceAll(node.text, context.mustacheSpaces));\n }\n return text(node.text);\n }\n return formatMustacheSection(node, context);\n\n case 'mustache_interpolation':\n case 'mustache_triple':\n case 'mustache_partial':\n case 'mustache_comment':\n return text(mustacheText(node.text, context));\n\n case 'html_comment':\n case 'html_doctype':\n case 'html_entity':\n case 'html_erroneous_end_tag':\n return text(node.text);\n\n case 'text':\n return formatText(node);\n\n default:\n return text(node.text);\n }\n}\n\n/**\n * Format a text node.\n */\nexport function formatText(node: SyntaxNode): Doc {\n return text(normalizeText(node.text));\n}\n\n/**\n * Format an HTML element.\n */\nexport function formatHtmlElement(node: SyntaxNode, context: FormatterContext, forceInline = false): Doc {\n const tags = context.customTags;\n const display = getCSSDisplay(node, tags);\n const isBlock = isWhitespaceInsensitive(display);\n const preserveContent = shouldPreserveContent(node, tags);\n\n // Self-closing tag\n const selfClosing =\n node.childCount === 1 && node.child(0)?.type === 'html_self_closing_tag';\n\n if (selfClosing) {\n const tag = node.child(0)!;\n return formatStartTag(tag, context);\n }\n\n // Get start tag, children, and end tag\n let startTag: SyntaxNode | null = null;\n let endTag: SyntaxNode | null = null;\n let hasRealEndTag = false;\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_start_tag') {\n startTag = child;\n } else if (child.type === 'html_end_tag') {\n endTag = child;\n hasRealEndTag = true;\n } else if (child.type === 'html_forced_end_tag') {\n endTag = child;\n } else if (!child.type.startsWith('_')) {\n contentNodes.push(child);\n }\n }\n\n const parts: Doc[] = [];\n\n // Format start tag\n if (startTag) {\n parts.push(formatStartTag(startTag, context));\n }\n\n // Check if content contains any HTML element children\n const hasHtmlElementChildren = contentNodes.some(\n (child) =>\n child.type === 'html_element' ||\n isRawContentElement(child) ||\n isBlockLevel(child, tags)\n );\n\n // Handle content\n if (preserveContent) {\n // Check if this custom code tag should be indented\n const tagNameLower = startTag ? getTagNameFromStartTag(startTag) : null;\n const tagConfig = tagNameLower ? context.customTags?.get(tagNameLower) : undefined;\n const shouldIndent = tagConfig ? resolveIndentMode(node, tagConfig) : false;\n\n if (shouldIndent && startTag && endTag) {\n const rawContent = context.document.getText().slice(\n startTag.endIndex,\n endTag.startIndex\n );\n const dedented = dedentContent(rawContent);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n // Empty line: literal \\n avoids indentation from the printer\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else if (startTag && endTag) {\n // Use raw document text to preserve all whitespace, since tree-sitter\n // text nodes strip boundary whitespace from regular html_element children\n const rawContent = context.document.getText().slice(\n startTag.endIndex,\n endTag.startIndex\n );\n // For block-level elements, replace trailing newline+whitespace with\n // a hardline so the closing tag gets proper indentation from the printer\n const trailingMatch = isBlock ? rawContent.match(/\\n[\\t ]*$/) : null;\n if (trailingMatch) {\n parts.push(text(rawContent.slice(0, -trailingMatch[0].length)));\n parts.push(hardline);\n } else {\n parts.push(text(rawContent));\n }\n } else {\n for (const child of contentNodes) {\n parts.push(text(child.text));\n }\n }\n } else if (!isBlock && (!hasHtmlElementChildren || (forceInline && display !== 'inline-block' && !contentNodes.some(\n (child) => isRawContentElement(child) || isBlockLevel(child, tags)\n )))) {\n // Standalone element with attributes: use outer group wrapping so content\n // goes on its own line when attributes wrap (matches Prettier's printTag)\n if (!forceInline && startTag && startTagHasAttributes(startTag)) {\n const formattedContent = formatBlockChildren(contentNodes, context);\n if (hasDocContent(formattedContent)) {\n const bareStartTag = formatStartTag(startTag, context, true);\n const outerParts: Doc[] = [\n group(bareStartTag),\n indent(concat([softline, formattedContent])),\n ];\n if (hasRealEndTag) {\n outerParts.push(softline);\n }\n if (endTag) {\n outerParts.push(formatEndTag(endTag));\n }\n return group(concat(outerParts));\n }\n }\n\n // Inline element with only text/interpolation content - keep tight\n // Preserve whitespace gaps between sibling nodes (e.g. space between\n // mustache_interpolation and text that tree-sitter puts in the gap)\n let prevEnd = startTag ? startTag.endIndex : -1;\n for (const child of contentNodes) {\n if (prevEnd >= 0 && child.startIndex > prevEnd) {\n const gap = context.document.getText().slice(prevEnd, child.startIndex);\n if (/\\s/.test(gap)) {\n parts.push(text(' '));\n }\n }\n parts.push(formatNode(child, context, forceInline));\n prevEnd = child.endIndex;\n }\n } else {\n // Block element or inline-with-block-children: use hardline + indent\n const formattedContent = formatBlockChildren(contentNodes, context);\n const hasContent = hasDocContent(formattedContent);\n\n if (hasContent) {\n // Check if content has CSS-block children that would be treated as block\n // by formatBlockChildren. Nodes in text flow (e.g. mustache sections\n // adjacent to text) are inline regardless of their content.\n const hasBlockChildren = contentNodes.some((child, i) => {\n if (!shouldTreatAsBlock(child, i, contentNodes, tags)) {\n return false;\n }\n const childDisplay = getCSSDisplay(child, tags);\n return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);\n });\n\n if (isBlock && !hasBlockChildren) {\n // Block element with only inline content: wrap in group so short ones stay flat\n // e.g. <div>x</div> stays on one line, <div>long content...</div> breaks\n const hasAttrs = startTag && startTagHasAttributes(startTag);\n\n if (hasAttrs && startTag) {\n // Outer group wrapping: match Prettier's printTag pattern\n // group([group(openTag), indent([softline, content]), softline, closingTag])\n const bareStartTag = formatStartTag(startTag, context, true);\n const outerParts: Doc[] = [\n group(bareStartTag),\n indent(concat([softline, formattedContent])),\n ];\n if (hasRealEndTag) {\n outerParts.push(softline);\n }\n if (endTag) {\n outerParts.push(formatEndTag(endTag));\n }\n return group(concat(outerParts));\n }\n\n // No attributes \u2014 existing logic\n const doc = group(\n concat([\n indent(concat([softline, formattedContent])),\n softline,\n ])\n );\n parts.push(doc);\n // If no real end tag, don't add closing softline\n if (!hasRealEndTag && endTag) {\n // Remove the trailing softline we just added \u2014 content goes\n // right up to forced end\n parts.pop();\n parts.push(\n group(\n concat([\n indent(concat([softline, formattedContent])),\n ])\n )\n );\n }\n } else {\n // Has block children: always break\n parts.push(indent(concat([hardline, formattedContent])));\n if (hasRealEndTag) {\n parts.push(hardline);\n }\n }\n } else if (contentNodes.length === 0 && hasRealEndTag) {\n // Empty block element: <div>\\n</div>\n parts.push(hardline);\n }\n }\n\n // Format end tag\n if (endTag) {\n parts.push(formatEndTag(endTag));\n }\n\n return concat(parts);\n}\n\n/**\n * Format script or style element.\n * Uses pre-formatted content from embeddedFormatted map when available,\n * otherwise preserves raw content as-is.\n */\nexport function formatScriptStyleElement(\n node: SyntaxNode,\n context: FormatterContext\n): Doc {\n const parts: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_start_tag') {\n parts.push(formatStartTag(child, context));\n } else if (child.type === 'html_end_tag') {\n parts.push(formatEndTag(child));\n } else if (child.type === 'html_raw_text') {\n const formatted = context.embeddedFormatted?.get(child.startIndex);\n if (formatted !== undefined) {\n const trimmed = formatted.replace(/^\\n+/, '').replace(/\\n+$/, '');\n if (trimmed.length === 0) {\n // Empty content \u2014 no lines between tags\n } else {\n const lines = trimmed.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < lines.length; j++) {\n if (j > 0) {\n lineDocs.push(hardline);\n }\n lineDocs.push(text(lines[j]));\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else {\n // Fallback: preserve raw content as-is (also used for html_raw_element)\n // Check if this is a custom code tag that should be indented\n if (node.type === 'html_raw_element') {\n const startTagNode = node.child(0);\n const tagNameLower = startTagNode?.type === 'html_start_tag' ? getTagNameFromStartTag(startTagNode) : null;\n const tagConfig = tagNameLower ? context.customTags?.get(tagNameLower) : undefined;\n if (tagConfig && resolveIndentMode(node, tagConfig)) {\n const dedented = dedentContent(child.text);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else {\n parts.push(text(child.text));\n }\n } else {\n // Script/style fallback: dedent and re-emit with hardlines so the\n // printer can apply proper indentation from parent context.\n const dedented = dedentContent(child.text);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n }\n }\n }\n }\n\n return concat(parts);\n}\n\n/**\n * Format a mustache section ({{#...}} or {{^...}}).\n */\nexport function formatMustacheSection(\n node: SyntaxNode,\n context: FormatterContext\n): Doc {\n const isInverted = node.type === 'mustache_inverted_section';\n const beginType = isInverted\n ? 'mustache_inverted_section_begin'\n : 'mustache_section_begin';\n const endType = isInverted\n ? 'mustache_inverted_section_end'\n : 'mustache_section_end';\n\n let beginNode: SyntaxNode | null = null;\n let endNode: SyntaxNode | null = null;\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === beginType) {\n beginNode = child;\n } else if (\n child.type === endType ||\n child.type === 'mustache_erroneous_section_end' ||\n child.type === 'mustache_erroneous_inverted_section_end'\n ) {\n endNode = child;\n } else if (!child.type.startsWith('_')) {\n contentNodes.push(child);\n }\n }\n\n const parts: Doc[] = [];\n\n // Opening tag\n if (beginNode) {\n parts.push(text(mustacheText(beginNode.text, context)));\n }\n\n // Determine indentation: if content has implicit end tags (HTML crossing mustache\n // boundaries), don't indent. Otherwise, indent normally.\n const hasImplicit = hasImplicitEndTags(contentNodes);\n\n // Staircase indentation: when content includes erroneous end tags (closing tags\n // from a cross-section split). Each erroneous end tag gets a descending indent\n // level so the outermost closing tag aligns at indent 0 (matching its opening).\n // Non-erroneous content between erroneous end tags is indented one level deeper\n // than the surrounding erroneous tags (it's a child of that scope).\n const erroneousCount = contentNodes.filter(n => n.type === 'html_erroneous_end_tag').length;\n const hasStaircase = !hasImplicit && erroneousCount > 0;\n\n if (hasStaircase) {\n let virtualDepth = erroneousCount - 1;\n const groupNodes: SyntaxNode[] = [];\n let lastNodeEnd = -1;\n let pendingBlankLine = false;\n let groupBlankLine = false;\n\n const emitGroup = () => {\n if (groupNodes.length === 0) return;\n const formatted = formatBlockChildren(groupNodes, context);\n if (hasDocContent(formatted)) {\n if (groupBlankLine) parts.push('\\n');\n const depth = Math.max(0, virtualDepth + 1);\n parts.push(depth > 0\n ? indentN(concat([hardline, formatted]), depth)\n : concat([hardline, formatted]));\n }\n groupNodes.length = 0;\n groupBlankLine = false;\n };\n\n for (const node of contentNodes) {\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n if ((gap.match(/\\n/g) || []).length >= 2) {\n pendingBlankLine = true;\n }\n }\n\n if (node.type === 'html_erroneous_end_tag') {\n emitGroup();\n if (pendingBlankLine) parts.push('\\n');\n pendingBlankLine = false;\n const formatted = formatNode(node, context);\n const depth = Math.max(0, virtualDepth);\n parts.push(depth > 0\n ? indentN(concat([hardline, formatted]), depth)\n : concat([hardline, formatted]));\n virtualDepth--;\n } else {\n if (groupNodes.length === 0) {\n groupBlankLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n groupNodes.push(node);\n }\n lastNodeEnd = node.endIndex;\n }\n emitGroup();\n parts.push(hardline);\n } else {\n const formattedContent = formatBlockChildren(contentNodes, context);\n const hasContent = hasDocContent(formattedContent);\n\n if (hasContent) {\n if (hasImplicit) {\n // No indent for content with implicit end tags\n parts.push(hardline);\n parts.push(formattedContent);\n parts.push(hardline);\n } else {\n // Check if content has CSS-block children (accounting for text flow)\n const hasBlockChildren = contentNodes.some((child, i) => {\n if (!shouldTreatAsBlock(child, i, contentNodes, context.customTags)) {\n return false;\n }\n const childDisplay = getCSSDisplay(child, context.customTags);\n return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);\n });\n\n if (!hasBlockChildren) {\n // Inline content only: use group so short sections stay flat\n parts.push(indent(concat([softline, formattedContent])));\n parts.push(softline);\n } else {\n // Block content: always break\n parts.push(indent(concat([hardline, formattedContent])));\n parts.push(hardline);\n }\n }\n }\n }\n\n // Closing tag\n if (endNode) {\n parts.push(text(mustacheText(endNode.text, context)));\n }\n\n // Wrap in group so inline-only content can stay flat\n return group(concat(parts));\n}\n\n/**\n * Check if a start tag has any attributes.\n */\nfunction startTagHasAttributes(startTag: SyntaxNode): boolean {\n for (let i = 0; i < startTag.childCount; i++) {\n const child = startTag.child(i);\n if (!child) continue;\n if (\n child.type === 'html_attribute' ||\n child.type === 'mustache_attribute' ||\n child.type === 'mustache_interpolation' ||\n child.type === 'mustache_triple'\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Format a start tag with attributes.\n * Wraps in a group so attributes break onto separate lines when\n * the tag exceeds print width.\n * When `bare` is true, returns the tag IR without the outer group wrapper.\n */\nexport function formatStartTag(node: SyntaxNode, context?: FormatterContext, bare = false): Doc {\n let tagNameText = '';\n const attrs: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_tag_name') {\n tagNameText = child.text;\n } else if (child.type === 'html_attribute') {\n attrs.push(formatAttribute(child, context));\n } else if (child.type === 'mustache_attribute') {\n if (context?.mustacheSpaces !== undefined) {\n attrs.push(text(normalizeMustacheWhitespaceAll(child.text, context.mustacheSpaces)));\n } else {\n attrs.push(text(child.text));\n }\n } else if (child.type === 'mustache_interpolation' || child.type === 'mustache_triple') {\n attrs.push(text(context ? mustacheText(child.text, context) : child.text));\n }\n }\n\n const isSelfClosing = node.type === 'html_self_closing_tag';\n const closingBracket = isSelfClosing ? ' />' : '>';\n\n if (attrs.length === 0) {\n return text('<' + tagNameText + closingBracket);\n }\n\n // Build attribute list with line separators\n const attrParts: Doc[] = [];\n for (let i = 0; i < attrs.length; i++) {\n if (i > 0) {\n attrParts.push(line);\n }\n attrParts.push(attrs[i]);\n }\n\n // In break mode, self-closing /> has no leading space (aligns with <tagName)\n const breakClosingBracket = isSelfClosing ? '/>' : '>';\n\n // Wrap tag in group: flat puts attrs on one line, break wraps them\n const inner = concat([\n text('<'),\n text(tagNameText),\n indent(concat([line, concat(attrParts)])),\n ifBreak(concat([hardline, text(breakClosingBracket)]), text(closingBracket)),\n ]);\n return bare ? inner : group(inner);\n}\n\n/**\n * Format an end tag.\n */\nexport function formatEndTag(node: SyntaxNode): Doc {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && child.type === 'html_tag_name') {\n return text('</' + child.text + '>');\n }\n }\n return text(node.text);\n}\n\n/**\n * Format an HTML attribute.\n */\nexport function formatAttribute(node: SyntaxNode, context?: FormatterContext): Doc {\n const parts: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_attribute_name') {\n parts.push(text(child.text));\n } else if (child.type === 'html_attribute_value') {\n parts.push(text('='));\n parts.push(text(child.text));\n } else if (child.type === 'html_quoted_attribute_value') {\n parts.push(text('='));\n if (context?.mustacheSpaces !== undefined) {\n parts.push(text(normalizeMustacheWhitespaceAll(child.text, context.mustacheSpaces)));\n } else {\n parts.push(text(child.text));\n }\n } else if (child.type === 'mustache_interpolation') {\n parts.push(text('='));\n parts.push(text(context ? mustacheText(child.text, context) : child.text));\n }\n }\n\n return concat(parts);\n}\n\n/**\n * Split a single-line text string into alternating words and `line` separators.\n * Returns an array of fill-ready parts to spread into `currentLine`.\n */\nfunction textWords(str: string): Doc[] {\n const words = str.split(/\\s+/).filter((w) => w.length > 0);\n if (words.length === 0) return [];\n const parts: Doc[] = [words[0]];\n for (let i = 1; i < words.length; i++) {\n parts.push(line);\n parts.push(words[i]);\n }\n return parts;\n}\n\n/**\n * Replace `line` separators with `\" \"` inside delimited regions so the\n * fill algorithm treats delimited content as unbreakable.\n *\n * Scans string parts for delimiter boundaries. Between an opening and closing\n * delimiter, any `line` separator is replaced with a literal space string.\n * Delimiters are matched longest-first to handle e.g. `$$` before `$`.\n */\nexport function collapseDelimitedRegions(parts: Doc[], delimiters: NoBreakDelimiter[]): Doc[] {\n if (delimiters.length === 0) return parts;\n\n // Sort longest-first by max(start.length, end.length) so $$ is checked before $\n const sorted = [...delimiters].sort(\n (a, b) => Math.max(b.start.length, b.end.length) - Math.max(a.start.length, a.end.length)\n );\n\n const result = [...parts];\n let activeDelimiter: NoBreakDelimiter | null = null;\n\n for (let i = 0; i < result.length; i++) {\n const part = result[i];\n\n if (typeof part === 'string') {\n if (activeDelimiter === null) {\n // Look for an opening delimiter\n for (const delim of sorted) {\n const startIdx = part.indexOf(delim.start);\n if (startIdx >= 0) {\n // Check if it also closes in the same string\n const afterOpen = startIdx + delim.start.length;\n const closeIdx = part.indexOf(delim.end, afterOpen);\n if (closeIdx >= 0) {\n // Self-contained (e.g. \"$x$\") \u2014 no state change, already atomic\n continue;\n }\n activeDelimiter = delim;\n break;\n }\n }\n } else {\n // Look for the closing delimiter\n if (part.includes(activeDelimiter.end)) {\n activeDelimiter = null;\n }\n }\n } else if (activeDelimiter !== null && isLine(part)) {\n // Inside a delimited region: replace line with non-breaking space\n result[i] = ' ';\n }\n }\n\n return result;\n}\n\n/**\n * Convert inline content parts into a fill Doc that wraps at word boundaries.\n *\n * `currentLine` is already fill-ready: text nodes are pre-split into\n * alternating word/`line` parts by `textWords`, and inter-node gaps are\n * `line` separators. This function enforces proper alternating\n * content/separator structure, concatenates adjacent content, and attaches\n * leading punctuation to the preceding content.\n */\nfunction inlineContentToFill(parts: Doc[]): Doc {\n if (parts.length === 0) return empty;\n if (parts.length === 1) return parts[0];\n\n const fillParts: Doc[] = [];\n for (const item of parts) {\n if (isLine(item)) {\n // Only push separator after content (skip leading/duplicate separators)\n if (fillParts.length > 0 && !isLine(fillParts[fillParts.length - 1])) {\n fillParts.push(item);\n }\n } else {\n const lastIdx = fillParts.length - 1;\n if (lastIdx >= 0 && !isLine(fillParts[lastIdx])) {\n // Adjacent content (no separator) \u2014 concat with previous\n fillParts[lastIdx] = concat([fillParts[lastIdx], item]);\n } else if (\n typeof item === 'string' &&\n /^[,.:;!?)\\]]/.test(item) &&\n lastIdx >= 0 &&\n isLine(fillParts[lastIdx])\n ) {\n // Punctuation after separator \u2014 attach to preceding content\n fillParts.pop();\n if (fillParts.length > 0) {\n fillParts[fillParts.length - 1] = concat([\n fillParts[fillParts.length - 1],\n item,\n ]);\n } else {\n fillParts.push(item);\n }\n } else {\n fillParts.push(item);\n }\n }\n }\n\n // Remove trailing separator\n if (fillParts.length > 0 && isLine(fillParts[fillParts.length - 1])) {\n fillParts.pop();\n }\n\n return fill(fillParts);\n}\n\n/**\n * Format block-level children with display-aware separators.\n */\nexport function formatBlockChildren(\n nodes: SyntaxNode[],\n context: FormatterContext\n): Doc {\n const lines: { doc: Doc; blankLineBefore: boolean; rawLine?: boolean }[] = [];\n let currentLine: Doc[] = [];\n let lastNodeEnd = -1;\n let pendingBlankLine = false;\n let blankLineBeforeCurrentLine = false;\n let ignoreNext = false;\n let inIgnoreRegion = false;\n let ignoreRegionStartIndex = -1;\n\n const noBreakDelims = context.noBreakDelimiters;\n function flushCurrentLine(): Doc {\n const parts = noBreakDelims ? collapseDelimitedRegions(currentLine, noBreakDelims) : currentLine;\n return inlineContentToFill(parts);\n }\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n // Detect blank lines in gap between nodes (before directive handling)\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd && !inIgnoreRegion) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n const newlineCount = (gap.match(/\\n/g) || []).length;\n if (newlineCount >= 2) {\n pendingBlankLine = true;\n }\n }\n\n const directive = getIgnoreDirective(node);\n\n // --- Ignore directive handling ---\n\n // ignore-end: close a region\n if (directive === 'ignore-end' && inIgnoreRegion) {\n // Flush any pending inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n // Emit raw text from region start to this comment, trimming boundary newlines\n const rawText = context.document.getText().slice(ignoreRegionStartIndex, node.startIndex)\n .replace(/^\\n/, '').replace(/\\n$/, '');\n if (rawText.length > 0) {\n lines.push({ doc: text(rawText), blankLineBefore: false, rawLine: true });\n }\n // Emit the ignore-end comment itself (rawLine to avoid adding indent after raw text)\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: false, rawLine: true });\n inIgnoreRegion = false;\n ignoreRegionStartIndex = -1;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // Inside ignore region: skip (content captured as raw text at ignore-end)\n if (inIgnoreRegion) {\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore-start: begin a region\n if (directive === 'ignore-start') {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n inIgnoreRegion = true;\n ignoreRegionStartIndex = node.endIndex;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore (next-node): emit the comment, set flag\n if (directive === 'ignore') {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n ignoreNext = true;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // Ignored next-node: emit raw text, clear flag\n if (ignoreNext) {\n lines.push({ doc: text(node.text), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n ignoreNext = false;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore-end without ignore-start: treat as normal comment (fall through)\n\n const treatAsBlock = shouldTreatAsBlock(node, i, nodes, context.customTags);\n\n // Check for whitespace between nodes in original document (inline gap handling)\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd) {\n const prevNode = nodes[i - 1];\n const prevTreatAsBlock = shouldTreatAsBlock(prevNode, i - 1, nodes, context.customTags);\n\n if (!prevTreatAsBlock && !treatAsBlock) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n if (/\\s/.test(gap)) {\n currentLine.push(line);\n }\n }\n }\n\n if (treatAsBlock) {\n // Flush current inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n // Add block element\n lines.push({ doc: formatNode(node, context), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n } else if (node.type === 'html_comment' || node.type === 'mustache_comment') {\n // Comments on their own line if multi-line or on their own line in source\n const isMultiline = node.startPosition.row !== node.endPosition.row;\n const isOnOwnLine = i > 0 && node.startPosition.row > nodes[i - 1].endPosition.row;\n if (isMultiline || isOnOwnLine) {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n } else {\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n currentLine.push(text(commentText));\n }\n } else {\n // Inline content\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n const forceInline = isInTextFlow(node, i, nodes);\n const formatted = formatNode(node, context, forceInline);\n\n // Check if formatted content contains newlines (multi-line text)\n if (typeof formatted === 'string' && formatted.includes('\\n')) {\n const contentLines = formatted.split('\\n');\n const isTextNode = node.type === 'text';\n\n if (isTextNode) {\n // Re-flow: treat source newlines as word boundaries, only flush at\n // blank lines. This lets the fill algorithm handle all wrapping.\n for (let j = 0; j < contentLines.length; j++) {\n const trimmed = contentLines[j].trim();\n if (!trimmed) {\n // Empty line = paragraph break \u2014 flush current inline flow\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = false;\n }\n currentLine = [];\n }\n pendingBlankLine = true;\n } else {\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n // Add a line separator between joined source lines (j > 0),\n // but not before the first line \u2014 it continues the existing flow\n if (j > 0 && currentLine.length > 0) {\n currentLine.push(line);\n }\n currentLine.push(...textWords(trimmed));\n }\n }\n } else {\n // Non-text nodes (force-inline mustache sections, etc.):\n // preserve source newlines as hard line breaks.\n const firstTrimmed = contentLines[0].trim();\n if (firstTrimmed) {\n currentLine.push(firstTrimmed);\n }\n\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n currentLine = [];\n }\n\n let sawBlankLine = false;\n for (let j = 1; j < contentLines.length - 1; j++) {\n const trimmed = contentLines[j].trim();\n if (trimmed) {\n lines.push({ doc: text(trimmed), blankLineBefore: blankLineBeforeCurrentLine || sawBlankLine });\n blankLineBeforeCurrentLine = false;\n sawBlankLine = false;\n } else {\n sawBlankLine = true;\n }\n }\n\n if (contentLines.length > 1) {\n const lastTrimmed = contentLines[contentLines.length - 1].trim();\n if (lastTrimmed) {\n blankLineBeforeCurrentLine = sawBlankLine;\n sawBlankLine = false;\n currentLine = [lastTrimmed];\n }\n if (sawBlankLine) {\n pendingBlankLine = true;\n }\n }\n }\n } else {\n // For text nodes, spread word/line parts directly into currentLine\n if (node.type === 'text' && typeof formatted === 'string') {\n const words = textWords(formatted);\n if (words.length > 0) {\n currentLine.push(...words);\n } else if (node.text.trim() === '' && currentLine.length > 0) {\n // Whitespace-only text between inline content: preserve as line separator\n currentLine.push(line);\n }\n } else {\n currentLine.push(formatted);\n }\n }\n }\n\n // Force line break after <br> tags\n if (node.type === 'html_element' && currentLine.length > 0) {\n const tagName = getTagName(node);\n if (tagName?.toLowerCase() === 'br') {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = false;\n }\n currentLine = [];\n }\n }\n\n lastNodeEnd = node.endIndex;\n }\n\n // Handle unterminated ignore region: emit remaining raw text\n if (inIgnoreRegion && nodes.length > 0) {\n const lastNode = nodes[nodes.length - 1];\n const rawText = context.document.getText().slice(ignoreRegionStartIndex, lastNode.endIndex)\n .replace(/^\\n/, '');\n if (rawText.length > 0) {\n lines.push({ doc: text(rawText), blankLineBefore: false, rawLine: true });\n }\n }\n\n // Flush remaining inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n }\n\n // Join lines with hardlines\n if (lines.length === 0) {\n return empty;\n }\n\n const parts: Doc[] = [];\n for (let i = 0; i < lines.length; i++) {\n if (i > 0) {\n if (lines[i].blankLineBefore) {\n // Emit a blank line: literal \\n (no indent) + hardline (with indent)\n parts.push('\\n');\n }\n if (lines[i].rawLine) {\n // Raw lines (ignored regions): literal \\n to avoid adding indentation\n parts.push('\\n');\n } else {\n parts.push(hardline);\n }\n }\n parts.push(lines[i].doc);\n }\n\n return concat(parts);\n}\n\n/**\n * Check if a Doc has any meaningful content.\n */\nfunction hasDocContent(doc: Doc): boolean {\n if (typeof doc === 'string') {\n return doc.trim().length > 0;\n }\n if (doc.type === 'concat') {\n return doc.parts.some(hasDocContent);\n }\n if (doc.type === 'indent') {\n return hasDocContent(doc.contents);\n }\n if (doc.type === 'group') {\n return hasDocContent(doc.contents);\n }\n if (doc.type === 'fill') {\n return doc.parts.some(hasDocContent);\n }\n if (doc.type === 'ifBreak') {\n return hasDocContent(doc.breakContents) || hasDocContent(doc.flatContents);\n }\n // hardline, softline, line, breakParent are structural\n return false;\n}\n\n/**\n * Trim whitespace from the beginning and end of a Doc string.\n */\nfunction trimDoc(doc: Doc): Doc {\n if (typeof doc === 'string') {\n return doc.trim();\n }\n return doc;\n}\n", "/**\n * Pure option merging + indent-unit construction.\n *\n * EditorConfig-aware merging lives in `lsp/server/src/formatting/editorconfig.ts`\n * and layers on top of these results by passing its result as `overrides`.\n */\n\nimport type { FormattingOptions } from './index.js';\nimport type { HtmlMustacheConfig } from '../configSchema.js';\n\n/**\n * Merge base options with `configFile` (indentSize only) and optional\n * `overrides` (tabSize / insertSpaces). Pure; no fs.\n *\n * Priority (low \u2192 high): lspOptions < configFile.indentSize < overrides.\n * `insertSpaces` never comes from `configFile` \u2014 only `lspOptions` or `overrides`.\n */\nexport function mergeOptions(\n lspOptions: FormattingOptions,\n configFile?: HtmlMustacheConfig | null,\n overrides?: Partial<FormattingOptions>,\n): FormattingOptions {\n let tabSize = lspOptions.tabSize;\n if (configFile?.indentSize !== undefined) tabSize = configFile.indentSize;\n if (overrides?.tabSize !== undefined) tabSize = overrides.tabSize;\n\n const insertSpaces = overrides?.insertSpaces ?? lspOptions.insertSpaces;\n\n return { tabSize, insertSpaces };\n}\n\nexport function createIndentUnit(options: FormattingOptions): string {\n return options.insertSpaces ? ' '.repeat(options.tabSize) : '\\t';\n}\n", "/**\n * IR-Based Formatter for HTML with Mustache templates.\n *\n * Architecture: AST Node \u2192 Doc IR \u2192 String\n *\n * Three phases:\n * 1. Classification - Determine node type (block/inline/preserve)\n * 2. AST \u2192 IR - Convert nodes to formatting commands\n * 3. IR \u2192 String - Print with proper indentation\n */\n\nimport type { Node as SyntaxNode, Tree } from 'web-tree-sitter';\nimport type { TextDocument } from 'vscode-languageserver-textdocument';\n\n/** Formatting options (structurally compatible with LSP FormattingOptions). */\nexport interface FormattingOptions {\n tabSize: number;\n insertSpaces: boolean;\n}\n\n/** A position in a text document (0-based line and character). */\nexport interface Position {\n line: number;\n character: number;\n}\n\n/** A range in a text document. */\nexport interface Range {\n start: Position;\n end: Position;\n}\n\n/** A text edit to apply to a document. */\nexport interface TextEdit {\n range: Range;\n newText: string;\n}\n\nimport { print } from './printer.js';\nimport { formatDocument as formatDocumentToDoc, FormatterContext } from './formatters.js';\nimport { createIndentUnit } from './mergeOptions.js';\nimport type { NoBreakDelimiter } from '../configSchema.js';\nimport { findContainingNode, calculateIndentLevel } from './utils.js';\nimport { isBlockLevel, getContentNodes, hasImplicitEndTags } from './classifier.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\n\nexport interface FormatDocumentParams {\n customTags?: CustomCodeTagConfig[];\n printWidth?: number;\n embeddedFormatted?: Map<number, string>;\n mustacheSpaces?: boolean;\n noBreakDelimiters?: NoBreakDelimiter[];\n}\n\nfunction buildCustomTagMap(customTags?: CustomCodeTagConfig[]): Map<string, CustomCodeTagConfig> | undefined {\n if (!customTags || customTags.length === 0) return undefined;\n const map = new Map<string, CustomCodeTagConfig>();\n for (const config of customTags) {\n map.set(config.name.toLowerCase(), config);\n }\n return map;\n}\n\nexport function formatDocument(\n tree: Tree,\n document: TextDocument,\n options: FormattingOptions,\n params: FormatDocumentParams = {},\n): TextEdit[] {\n const { printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters } = params;\n const indentUnit = createIndentUnit(options);\n\n if (tree.rootNode.hasError) return [];\n\n const customTagMap = buildCustomTagMap(params.customTags);\n const context: FormatterContext = {\n document,\n customTags: customTagMap,\n embeddedFormatted,\n mustacheSpaces,\n noBreakDelimiters,\n };\n const doc = formatDocumentToDoc(tree.rootNode, context);\n const formatted = print(doc, { indentUnit, printWidth });\n\n const fullRange: Range = {\n start: { line: 0, character: 0 },\n end: document.positionAt(document.getText().length),\n };\n\n return [{ range: fullRange, newText: formatted }];\n}\n\nexport function formatDocumentRange(\n tree: Tree,\n document: TextDocument,\n range: Range,\n options: FormattingOptions,\n params: FormatDocumentParams = {},\n): TextEdit[] {\n const { customTags, printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters } = params;\n const indentUnit = createIndentUnit(options);\n\n if (tree.rootNode.hasError) return [];\n\n const customTagMap = buildCustomTagMap(customTags);\n\n const startOffset = document.offsetAt(range.start);\n const endOffset = document.offsetAt(range.end);\n\n let targetNode = findContainingNode(tree.rootNode, startOffset, endOffset) ?? tree.rootNode;\n\n // Walk up to the nearest block-level boundary so the output is anchored to a\n // whole element, not mid-inline content.\n while (\n targetNode.parent &&\n !isBlockLevel(targetNode, customTagMap) &&\n targetNode.type !== 'document'\n ) {\n targetNode = targetNode.parent;\n }\n\n const indentLevel = calculateIndentLevel(\n targetNode,\n isBlockLevel,\n hasImplicitEndTags,\n getContentNodes\n );\n\n const context: FormatterContext = {\n document,\n customTags: customTagMap,\n embeddedFormatted,\n mustacheSpaces,\n noBreakDelimiters,\n };\n const doc = formatNodeForRange(targetNode, context);\n const formatted = print(doc, { indentUnit, printWidth });\n\n const indentedFormatted = applyBaseIndent(formatted, indentLevel, indentUnit);\n\n const nodeRange: Range = {\n start: {\n line: targetNode.startPosition.row,\n character: targetNode.startPosition.column,\n },\n end: {\n line: targetNode.endPosition.row,\n character: targetNode.endPosition.column,\n },\n };\n\n return [{ range: nodeRange, newText: indentedFormatted }];\n}\n\nimport { formatNode } from './formatters.js';\n\nfunction formatNodeForRange(\n node: SyntaxNode,\n context: FormatterContext\n): import('./ir.js').Doc {\n return formatNode(node, context);\n}\n\nfunction applyBaseIndent(\n formatted: string,\n indentLevel: number,\n indentUnit: string\n): string {\n if (indentLevel === 0) {\n return formatted;\n }\n\n const baseIndent = indentUnit.repeat(indentLevel);\n return formatted\n .split('\\n')\n .map((line, index) => {\n // Don't indent empty lines or the first line (it's at the node position)\n if (line.trim() === '' || index === 0) {\n return line;\n }\n return baseIndent + line;\n })\n .join('\\n');\n}\n", "import type { Node as SyntaxNode } from 'web-tree-sitter';\n\nexport interface EmbeddedRegion {\n startIndex: number;\n content: string;\n languageId: string;\n}\n\n/**\n * Get the language ID for a script or style element.\n * Returns \"javascript\" for script (or \"typescript\" if type=\"text/typescript\"),\n * \"css\" for style.\n */\nfunction getEmbeddedLanguageId(node: SyntaxNode): string {\n if (node.type === 'html_style_element') {\n return 'css';\n }\n // Check for type attribute on script elements\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const attr = child.child(j);\n if (attr?.type === 'html_attribute') {\n let name = '';\n let value = '';\n for (let k = 0; k < attr.childCount; k++) {\n const part = attr.child(k);\n if (part?.type === 'html_attribute_name') name = part.text.toLowerCase();\n if (part?.type === 'html_quoted_attribute_value') value = part.text.replace(/^[\"']|[\"']$/g, '').toLowerCase();\n if (part?.type === 'html_attribute_value') value = part.text.toLowerCase();\n }\n if (name === 'type' && (value === 'text/typescript' || value === 'ts')) {\n return 'typescript';\n }\n }\n }\n }\n }\n return 'javascript';\n}\n\n/**\n * Walk the tree to collect embedded script/style regions.\n * Skips html_raw_element (custom raw tags).\n */\nexport function collectEmbeddedRegions(rootNode: SyntaxNode): EmbeddedRegion[] {\n const regions: EmbeddedRegion[] = [];\n const walk = (node: SyntaxNode) => {\n if (node.type === 'html_script_element' || node.type === 'html_style_element') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_raw_text') {\n regions.push({\n startIndex: child.startIndex,\n content: child.text,\n languageId: getEmbeddedLanguageId(node),\n });\n }\n }\n return;\n }\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child) walk(child);\n }\n };\n walk(rootNode);\n return regions;\n}\n", "/**\n * Shared embedded-region formatter used by both the CLI and the browser entry.\n * Takes the already-parsed rootNode, extracts `<script>` / `<style>` regions,\n * and returns a map of startIndex \u2192 prettier-formatted content. If no prettier\n * is provided, returns an empty map (caller falls back to leaving regions as-is).\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport { collectEmbeddedRegions } from '../embeddedRegions.js';\nimport type { FormattingOptions } from './index.js';\n\nexport const LANGUAGE_TO_PRETTIER_PARSER: Record<string, string> = {\n javascript: 'babel',\n typescript: 'typescript',\n css: 'css',\n};\n\nexport interface PrettierLike {\n format(source: string, options: {\n parser: string;\n tabWidth?: number;\n useTabs?: boolean;\n plugins?: unknown[];\n }): string | Promise<string>;\n}\n\nexport async function formatEmbeddedRegions(\n rootNode: SyntaxNode,\n options: FormattingOptions,\n prettier: PrettierLike | null | undefined,\n): Promise<Map<number, string>> {\n const result = new Map<number, string>();\n if (!prettier) return result;\n\n const regions = collectEmbeddedRegions(rootNode);\n if (regions.length === 0) return result;\n\n await Promise.all(\n regions.map(async (region) => {\n const parser = LANGUAGE_TO_PRETTIER_PARSER[region.languageId];\n if (!parser) return;\n try {\n const formatted = await prettier.format(region.content, {\n parser,\n tabWidth: options.tabSize,\n useTabs: !options.insertSpaces,\n });\n result.set(region.startIndex, formatted);\n } catch {\n // Snippet had a syntax error \u2014 skip, leave the region as-is.\n }\n })\n );\n\n return result;\n}\n", "/**\n * Shared CheckError \u2192 public `Diagnostic` projection used by the browser\n * entry and the CLI wrapper. 1-based line/column per the public contract;\n * multi-edit fix array; severity defaults to `'error'` when the source\n * checker didn't set one (parse errors, balance errors).\n */\n\nimport type { CheckError } from './collectErrors.js';\nimport type { TextReplacement } from './mustacheChecks.js';\n\nexport interface DiagnosticFix {\n range: [number, number];\n newText: string;\n}\n\nexport interface Diagnostic {\n line: number;\n column: number;\n endLine: number;\n endColumn: number;\n message: string;\n severity: 'error' | 'warning';\n ruleName?: string;\n fix?: DiagnosticFix[];\n fixDescription?: string;\n}\n\nfunction toFix(r: TextReplacement): DiagnosticFix {\n return { range: [r.startIndex, r.endIndex], newText: r.newText };\n}\n\nexport function toDiagnostic(err: CheckError): Diagnostic {\n const { node } = err;\n return {\n line: node.startPosition.row + 1,\n column: node.startPosition.column + 1,\n endLine: node.endPosition.row + 1,\n endColumn: node.endPosition.column + 1,\n message: err.message,\n severity: err.severity ?? 'error',\n ruleName: err.ruleName,\n fix: err.fix && err.fix.length > 0 ? err.fix.map(toFix) : undefined,\n fixDescription: err.fixDescription,\n };\n}\n", "/** Filename of the compiled grammar WASM, as shipped in this package. */\nexport const GRAMMAR_WASM_FILENAME = 'tree-sitter-htmlmustache.wasm';\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Browser entry point for `@reteps/tree-sitter-htmlmustache`.\n *\n * Exposes `createLinter({ locateWasm, prettier? })` returning a handle with\n * `lint(source, config)` and `format(source, config, opts)`. Internally reuses\n * the shared rule engine and formatter in `src/core/` \u2014 browser-safe, no fs.\n */\n\nimport { Parser, Language } from 'web-tree-sitter';\nimport { TextDocument } from 'vscode-languageserver-textdocument';\n\nimport { collectErrors } from '../core/collectErrors.js';\nimport type { WalkableTree } from '../core/collectErrors.js';\nimport { formatDocument } from '../core/formatting/index.js';\nimport type { FormattingOptions } from '../core/formatting/index.js';\nimport { mergeOptions } from '../core/formatting/mergeOptions.js';\nimport { formatEmbeddedRegions } from '../core/formatting/embedded.js';\nimport type { PrettierLike } from '../core/formatting/embedded.js';\nimport { RULE_DEFAULTS } from '../core/ruleMetadata.js';\nimport { toDiagnostic } from '../core/diagnostic.js';\nimport type { Diagnostic } from '../core/diagnostic.js';\nimport { GRAMMAR_WASM_FILENAME } from '../core/grammar.js';\nimport type {\n HtmlMustacheConfig,\n RulesConfig,\n RuleSeverity,\n CustomRule as CustomRuleType,\n} from '../core/configSchema.js';\nimport type { CustomCodeTagConfig } from '../core/customCodeTags.js';\n\n/**\n * `include`/`exclude` on custom rules are stripped from the browser surface:\n * the browser API has no filesystem path to match against, so those fields\n * would silently do nothing. Users who share a `.htmlmustache.jsonc` config\n * between the CLI and a web playground should strip them before passing, or\n * let TypeScript catch the mismatch.\n */\nexport type CustomRule = Omit<CustomRuleType, 'include' | 'exclude'>;\nexport type Config =\n Omit<HtmlMustacheConfig, 'include' | 'exclude' | 'customRules'>\n & { customRules?: CustomRule[] };\nexport type CustomTag = CustomCodeTagConfig;\nexport type { RulesConfig, RuleSeverity, PrettierLike, Diagnostic };\n\nexport type LocateWasm = string | ((filename: string) => string);\n\nexport interface CreateLinterOptions {\n /**\n * Locates the grammar WASM (`tree-sitter-htmlmustache.wasm`). If a string,\n * treated as the URL for the grammar \u2014 web-tree-sitter's own\n * `tree-sitter.wasm` will resolve via its default `locateFile`. Pass a\n * callback to resolve both names explicitly.\n */\n locateWasm: LocateWasm;\n /** Default prettier used for embedded-region formatting. */\n prettier?: PrettierLike;\n}\n\nexport interface FormatOptions {\n /** Override the factory-level prettier for this call. */\n prettier?: PrettierLike;\n}\n\nexport interface Linter {\n lint(source: string, config?: Config): Diagnostic[];\n format(source: string, config?: Config, opts?: FormatOptions): Promise<string>;\n}\n\n/** Default severities for every built-in rule. */\nexport const DEFAULT_CONFIG: Config = { rules: RULE_DEFAULTS as RulesConfig };\n\nconst DEFAULT_FORMATTING_OPTIONS: FormattingOptions = { tabSize: 2, insertSpaces: true };\n\nfunction toLocateFile(locateWasm: LocateWasm): ((name: string) => string) | undefined {\n // String form resolves only the grammar; runtime `tree-sitter.wasm` falls\n // through to web-tree-sitter's own default `locateFile`.\n return typeof locateWasm === 'function' ? (name) => locateWasm(name) : undefined;\n}\n\nfunction resolveGrammarUrl(locateWasm: LocateWasm): string {\n return typeof locateWasm === 'string' ? locateWasm : locateWasm(GRAMMAR_WASM_FILENAME);\n}\n\n/**\n * Create a linter/formatter handle. Consumers should cache the result \u2014 each\n * call reloads the grammar WASM.\n */\nexport async function createLinter(opts: CreateLinterOptions): Promise<Linter> {\n const { locateWasm, prettier: factoryPrettier } = opts;\n const locateFile = toLocateFile(locateWasm);\n // `Parser.init` is itself idempotent (Emscripten caches the runtime globally),\n // so repeated calls with different `locateFile` are safe \u2014 the first wins.\n await Parser.init(locateFile ? { locateFile } : undefined);\n const parser = new Parser();\n const language = await Language.load(resolveGrammarUrl(locateWasm));\n parser.setLanguage(language);\n\n return {\n lint(source, config) {\n const tree = parser.parse(source);\n if (!tree) throw new Error('Failed to parse document');\n try {\n const customTagNames = config?.customTags?.map((t) => t.name);\n const errors = collectErrors(\n tree as unknown as WalkableTree,\n config?.rules,\n customTagNames,\n config?.customRules,\n );\n return errors.map(toDiagnostic);\n } finally {\n tree.delete();\n }\n },\n\n async format(source, config, callOpts) {\n const prettier = callOpts?.prettier ?? factoryPrettier;\n const options = mergeOptions(DEFAULT_FORMATTING_OPTIONS, config ?? null);\n const tree = parser.parse(source);\n if (!tree) throw new Error('Failed to parse document');\n try {\n const embeddedFormatted = await formatEmbeddedRegions(tree.rootNode, options, prettier);\n const document = TextDocument.create('file:///input', 'htmlmustache', 1, source);\n const edits = formatDocument(tree, document, options, {\n customTags: config?.customTags,\n printWidth: config?.printWidth,\n mustacheSpaces: config?.mustacheSpaces,\n noBreakDelimiters: config?.noBreakDelimiters,\n embeddedFormatted: embeddedFormatted.size > 0 ? embeddedFormatted : undefined,\n });\n return edits.length === 0 ? source : edits[0].newText;\n } finally {\n tree.delete();\n }\n },\n };\n}\n", "/**\n * Shared node helper functions and type constants for working with\n * tree-sitter syntax nodes across the LSP and CLI.\n *\n * Uses a minimal interface compatible with both web-tree-sitter's SyntaxNode\n * and the BalanceNode interface from htmlBalanceChecker.\n */\n\n/** Minimal node interface compatible with both SyntaxNode and BalanceNode. */\nexport interface MinimalNode {\n type: string;\n text: string;\n children: MinimalNode[];\n}\n\n// --- Node type constants ---\n\nexport const MUSTACHE_SECTION_TYPES = new Set([\n 'mustache_section',\n 'mustache_inverted_section',\n]);\n\nexport const INTERPOLATION_TYPES = new Set([\n 'mustache_interpolation', // {{foo}}\n 'mustache_triple', // {{{foo}}} \u2014 unescaped\n]);\n\nexport const RAW_CONTENT_ELEMENT_TYPES = new Set([\n 'html_script_element',\n 'html_style_element',\n 'html_raw_element',\n]);\n\nexport const HTML_ELEMENT_TYPES = new Set([\n 'html_element',\n 'html_script_element',\n 'html_style_element',\n 'html_raw_element',\n]);\n\n// --- Node type predicates ---\n\nexport function isMustacheSection(node: MinimalNode): boolean {\n return MUSTACHE_SECTION_TYPES.has(node.type);\n}\n\nexport function isRawContentElement(node: MinimalNode): boolean {\n return RAW_CONTENT_ELEMENT_TYPES.has(node.type);\n}\n\nexport function isHtmlElementType(node: MinimalNode): boolean {\n return HTML_ELEMENT_TYPES.has(node.type);\n}\n\n// --- Node name extraction ---\n\n/**\n * Get the tag name from an HTML element node.\n * Works with any node that has children with type 'html_start_tag' or\n * 'html_self_closing_tag' containing an 'html_tag_name' child.\n */\nexport function getTagName(node: MinimalNode): string | null {\n for (const child of node.children) {\n if (child.type === 'html_start_tag' || child.type === 'html_self_closing_tag') {\n const tagNameNode = child.children.find(c => c.type === 'html_tag_name');\n if (tagNameNode) return tagNameNode.text;\n }\n }\n return null;\n}\n\n/**\n * Get the section name from a mustache section node.\n * Looks for mustache_tag_name inside mustache_section_begin or\n * mustache_inverted_section_begin.\n */\nexport function getSectionName(node: MinimalNode): string | null {\n const beginNode = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n if (!beginNode) return null;\n const tagNameNode = beginNode.children.find(c => c.type === 'mustache_tag_name');\n return tagNameNode?.text ?? null;\n}\n\n/**\n * Get the tag name from an erroneous end tag node.\n */\nexport function getErroneousEndTagName(node: MinimalNode): string | null {\n const nameNode = node.children.find(c => c.type === 'html_erroneous_end_tag_name');\n return nameNode?.text?.toLowerCase() ?? null;\n}\n\n/**\n * Get the dotted path text from a mustache_interpolation or mustache_triple\n * node \u2014 e.g. `{{data.foo}}` \u2192 `\"data.foo\"`. Returns `\".\"` for the\n * context-marker interpolation `{{.}}`. Returns null if the node has no\n * recognisable expression child.\n */\nexport function getInterpolationPath(node: MinimalNode): string | null {\n for (const child of node.children) {\n if (child.type === 'mustache_path_expression' || child.type === 'mustache_identifier') {\n return child.text;\n }\n if (child.type === '.') return '.';\n }\n return null;\n}\n\n/**\n * Get the content text of a mustache_comment node (`{{!foo}}` \u2192 `\"foo\"`).\n * Returns null if no content child is present.\n */\nexport function getCommentContent(node: MinimalNode): string | null {\n const child = node.children.find(c => c.type === 'mustache_comment_content');\n return child ? child.text.trim() : null;\n}\n\n/**\n * Get the partial name of a mustache_partial node (`{{>header}}` \u2192 `\"header\"`).\n * Returns null if no content child is present.\n */\nexport function getPartialName(node: MinimalNode): string | null {\n const child = node.children.find(c => c.type === 'mustache_partial_content');\n return child ? child.text.trim() : null;\n}\n", "import {\n getTagName,\n getSectionName,\n getErroneousEndTagName,\n} from './nodeHelpers.js';\n\n// Minimal syntax node interface for balance checking.\n// Compatible with web-tree-sitter's SyntaxNode.\nexport interface BalanceNode {\n type: string;\n text: string;\n startPosition: { row: number; column: number };\n endPosition: { row: number; column: number };\n startIndex: number;\n endIndex: number;\n children: BalanceNode[];\n}\n\nexport interface BalanceError {\n node: BalanceNode;\n message: string;\n}\n\n// --- Internal types ---\n\ninterface TagEvent {\n type: 'open' | 'close';\n tagName: string;\n node: BalanceNode;\n}\n\ninterface ConditionalFork {\n type: 'fork';\n sectionName: string;\n truthy: PathItem[];\n falsy: PathItem[];\n}\n\ntype PathItem = TagEvent | ConditionalFork;\n\n// --- Phase 1: Extract tag events from parse tree ---\n\n// Re-export for consumers that import from this module\nexport { getSectionName } from './nodeHelpers.js';\n\nfunction getTagNameLower(element: BalanceNode): string | null {\n return getTagName(element)?.toLowerCase() ?? null;\n}\n\nfunction getErroneousEndTagNameLower(node: BalanceNode): string | null {\n return getErroneousEndTagName(node)?.toLowerCase() ?? null;\n}\n\nfunction hasForcedEndTag(element: BalanceNode): boolean {\n return element.children.some(c => c.type === 'html_forced_end_tag');\n}\n\nfunction extractFromNodes(nodes: BalanceNode[]): PathItem[] {\n const items: PathItem[] = [];\n for (const node of nodes) {\n items.push(...extractFromNode(node));\n }\n return items;\n}\n\nfunction extractFromNode(node: BalanceNode): PathItem[] {\n if (node.type === 'html_element') {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'html_start_tag' &&\n c.type !== 'html_end_tag' &&\n c.type !== 'html_forced_end_tag',\n );\n\n if (hasForcedEndTag(node)) {\n const tagName = getTagNameLower(node);\n const items: PathItem[] = [];\n if (tagName) {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n items.push({ type: 'open', tagName, node: startTag ?? node });\n }\n items.push(...extractFromNodes(contentChildren));\n return items;\n }\n\n // Balanced or implicit close \u2014 recurse into content for inner forks\n return extractFromNodes(contentChildren);\n }\n\n if (node.type === 'html_self_closing_tag') {\n return [];\n }\n\n if (node.type === 'html_erroneous_end_tag') {\n const tagName = getErroneousEndTagNameLower(node);\n if (tagName) {\n return [{ type: 'close', tagName, node }];\n }\n return [];\n }\n\n if (node.type === 'mustache_section') {\n const sectionName = getSectionName(node);\n if (sectionName) {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'mustache_section_begin' &&\n c.type !== 'mustache_section_end' &&\n c.type !== 'mustache_erroneous_section_end',\n );\n return [\n {\n type: 'fork',\n sectionName,\n truthy: extractFromNodes(contentChildren),\n falsy: [],\n },\n ];\n }\n return [];\n }\n\n if (node.type === 'mustache_inverted_section') {\n const sectionName = getSectionName(node);\n if (sectionName) {\n const contentChildren = node.children.filter(\n c =>\n c.type !== 'mustache_inverted_section_begin' &&\n c.type !== 'mustache_inverted_section_end' &&\n c.type !== 'mustache_erroneous_inverted_section_end',\n );\n return [\n {\n type: 'fork',\n sectionName,\n truthy: [],\n falsy: extractFromNodes(contentChildren),\n },\n ];\n }\n return [];\n }\n\n // For any other node type, recurse into children\n return extractFromNodes(node.children);\n}\n\n// --- Phase 2: Merge adjacent same-named forks ---\n\nfunction mergeAdjacentForks(items: PathItem[]): PathItem[] {\n if (items.length === 0) return items;\n\n const result: PathItem[] = [];\n let i = 0;\n\n while (i < items.length) {\n const item = items[i];\n if (item.type !== 'fork') {\n result.push(item);\n i++;\n continue;\n }\n\n // Merge consecutive forks with the same section name\n const truthy = [...item.truthy];\n const falsy = [...item.falsy];\n let j = i + 1;\n while (j < items.length) {\n const next = items[j];\n if (next.type !== 'fork' || next.sectionName !== item.sectionName) break;\n truthy.push(...next.truthy);\n falsy.push(...next.falsy);\n j++;\n }\n\n // Recursively merge within branches\n result.push({\n type: 'fork',\n sectionName: item.sectionName,\n truthy: mergeAdjacentForks(truthy),\n falsy: mergeAdjacentForks(falsy),\n });\n i = j;\n }\n\n return result;\n}\n\n// --- Phase 3: Enumerate paths and validate balance ---\n\n/**\n * Check if a branch (list of PathItems) is self-balanced: all opens are matched\n * by closes in LIFO order, leaving the stack empty. Nested forks are balanced\n * only if both their branches are independently balanced (making the fork a no-op).\n */\nfunction isBranchBalanced(items: PathItem[]): boolean {\n const stack: string[] = [];\n for (const item of items) {\n if (item.type === 'fork') {\n if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {\n return false;\n }\n } else if (item.type === 'open') {\n stack.push(item.tagName);\n } else {\n if (stack.length === 0 || stack[stack.length - 1] !== item.tagName) {\n return false;\n }\n stack.pop();\n }\n }\n return stack.length === 0;\n}\n\n/**\n * Collect only section names that affect HTML tag balance.\n * A fork only matters if at least one of its branches is unbalanced.\n * Forks where both branches are independently balanced (e.g. truthy has\n * matched open/close pairs and falsy is empty) are no-ops and skipped.\n * This reduces 2^N enumeration to only the relevant variables.\n */\nfunction collectSectionNames(items: PathItem[]): Set<string> {\n const names = new Set<string>();\n for (const item of items) {\n if (item.type === 'fork') {\n if (!isBranchBalanced(item.truthy) || !isBranchBalanced(item.falsy)) {\n names.add(item.sectionName);\n }\n for (const name of collectSectionNames(item.truthy)) names.add(name);\n for (const name of collectSectionNames(item.falsy)) names.add(name);\n }\n }\n return names;\n}\n\nfunction flattenPath(items: PathItem[], assignment: Map<string, boolean>): TagEvent[] {\n const events: TagEvent[] = [];\n for (const item of items) {\n if (item.type === 'fork') {\n const value = assignment.get(item.sectionName) ?? true;\n const branch = value ? item.truthy : item.falsy;\n events.push(...flattenPath(branch, assignment));\n } else {\n events.push(item);\n }\n }\n return events;\n}\n\nfunction formatCondition(assignment: Map<string, boolean>): string {\n if (assignment.size === 0) return '';\n const parts: string[] = [];\n for (const [name, value] of assignment) {\n parts.push(`${name} is ${value ? 'truthy' : 'falsy'}`);\n }\n return ` (when ${parts.join(', ')})`;\n}\n\nfunction validateBalance(events: TagEvent[], condition: string): BalanceError[] {\n const errors: BalanceError[] = [];\n const stack: TagEvent[] = [];\n\n for (const event of events) {\n if (event.type === 'open') {\n stack.push(event);\n } else {\n if (stack.length === 0) {\n errors.push({\n node: event.node,\n message: `Mismatched HTML end tag: </${event.tagName}>${condition}`,\n });\n } else {\n const top = stack[stack.length - 1];\n if (top.tagName !== event.tagName) {\n errors.push({\n node: event.node,\n message: `Mismatched HTML end tag: </${event.tagName}>${condition}`,\n });\n } else {\n stack.pop();\n }\n }\n }\n }\n\n for (const event of stack) {\n errors.push({\n node: event.node,\n message: `Unclosed HTML tag: <${event.tagName}>${condition}`,\n });\n }\n\n return errors;\n}\n\n// --- Unclosed tag detection ---\n\nconst VOID_ELEMENTS = new Set([\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n]);\n\nconst OPTIONAL_END_TAG_ELEMENTS = new Set([\n 'li', 'dt', 'dd', 'p', 'colgroup',\n 'rb', 'rt', 'rp', 'rtc',\n 'optgroup', 'option',\n 'tr', 'td', 'th',\n 'thead', 'tbody', 'tfoot',\n 'caption',\n 'html', 'head', 'body',\n]);\n\nexport function checkUnclosedTags(rootNode: BalanceNode): BalanceError[] {\n const errors: BalanceError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element') {\n const hasEndTag = node.children.some(c => c.type === 'html_end_tag');\n const hasForcedEnd = node.children.some(c => c.type === 'html_forced_end_tag');\n\n if (!hasEndTag && !hasForcedEnd) {\n const tagName = getTagNameLower(node);\n if (tagName && !VOID_ELEMENTS.has(tagName) && !OPTIONAL_END_TAG_ELEMENTS.has(tagName)) {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n errors.push({\n node: startTag ?? node,\n message: `Unclosed HTML tag: <${tagName}>`,\n });\n }\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nconst MAX_SECTION_NAMES = 15;\n\nexport function checkHtmlBalance(rootNode: BalanceNode): BalanceError[] {\n // Phase 1: Extract tag events\n const rawItems = extractFromNode(rootNode);\n\n // Phase 2: Merge adjacent same-named forks\n const items = mergeAdjacentForks(rawItems);\n\n // Phase 3: Enumerate all boolean paths and validate\n const sectionNames = [...collectSectionNames(items)];\n if (sectionNames.length > MAX_SECTION_NAMES) {\n return []; // Safety valve: too many combinations\n }\n\n const allErrors: BalanceError[] = [];\n const errorNodes = new Set<BalanceNode>();\n const totalPaths = 1 << sectionNames.length;\n\n for (let mask = 0; mask < totalPaths; mask++) {\n const assignment = new Map<string, boolean>();\n for (let i = 0; i < sectionNames.length; i++) {\n assignment.set(sectionNames[i], (mask & (1 << i)) !== 0);\n }\n\n const events = flattenPath(items, assignment);\n const condition = formatCondition(assignment);\n const pathErrors = validateBalance(events, condition);\n\n for (const error of pathErrors) {\n if (!errorNodes.has(error.node)) {\n errorNodes.add(error.node);\n allErrors.push(error);\n }\n }\n }\n\n return allErrors;\n}\n", "import type { BalanceNode, BalanceError } from './htmlBalanceChecker.js';\nimport { getSectionName } from './htmlBalanceChecker.js';\nimport { isMustacheSection } from './nodeHelpers.js';\n\nexport interface TextReplacement {\n startIndex: number;\n endIndex: number;\n newText: string;\n}\n\nexport interface FixableError extends BalanceError {\n severity?: 'error' | 'warning';\n fix?: TextReplacement[];\n fixDescription?: string;\n}\n\n// 1. Nested same-name sections\nexport function checkNestedSameNameSections(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode, ancestors: Set<string>) {\n if (isMustacheSection(node)) {\n const name = getSectionName(node);\n if (name) {\n if (ancestors.has(name)) {\n const beginNode = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n errors.push({\n node: beginNode ?? node,\n message: `Nested duplicate section: {{#${name}}} is already open in an ancestor`,\n });\n }\n const next = new Set(ancestors);\n next.add(name);\n for (const child of node.children) {\n visit(child, next);\n }\n return;\n }\n }\n\n for (const child of node.children) {\n visit(child, ancestors);\n }\n }\n\n visit(rootNode, new Set());\n return errors;\n}\n\n// 2. Unquoted mustache attribute value\nexport function checkUnquotedMustacheAttributes(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_attribute') {\n const mustacheNode = node.children.find(c => c.type === 'mustache_interpolation');\n if (mustacheNode) {\n errors.push({\n node: mustacheNode,\n message: `Unquoted mustache attribute value: ${mustacheNode.text}`,\n fix: [{\n startIndex: mustacheNode.startIndex,\n endIndex: mustacheNode.endIndex,\n newText: `\"${mustacheNode.text}\"`,\n }],\n fixDescription: 'Wrap mustache value in quotes',\n });\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 3. Consecutive same-name same-type sections\nexport function checkConsecutiveSameNameSections(rootNode: BalanceNode, sourceText: string): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n const children = node.children;\n for (let i = 0; i < children.length - 1; i++) {\n const current = children[i];\n const next = children[i + 1];\n\n // Both must be the same section type\n if (!isMustacheSection(current) || current.type !== next.type) {\n continue;\n }\n\n const currentName = getSectionName(current);\n const nextName = getSectionName(next);\n if (!currentName || !nextName || currentName !== nextName) continue;\n\n // Check that the gap between them is whitespace-only\n const gap = sourceText.slice(current.endIndex, next.startIndex);\n if (gap.length > 0 && !/^\\s*$/.test(gap)) continue;\n\n // Find the end tag of current section and begin tag of next section\n const endTagType = current.type === 'mustache_section'\n ? 'mustache_section_end'\n : 'mustache_inverted_section_end';\n const beginTagType = next.type === 'mustache_section'\n ? 'mustache_section_begin'\n : 'mustache_inverted_section_begin';\n\n const currentEndTag = current.children.find(c => c.type === endTagType);\n const nextBeginTag = next.children.find(c => c.type === beginTagType);\n\n if (!currentEndTag || !nextBeginTag) continue;\n\n const sectionTypeStr = current.type === 'mustache_section' ? '#' : '^';\n const nextBeginNode = next.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n\n errors.push({\n node: nextBeginNode ?? next,\n message: `Consecutive duplicate section: {{${sectionTypeStr}${nextName}}} can be merged with previous {{${sectionTypeStr}${nextName}}}`,\n severity: 'warning',\n fix: [{\n startIndex: currentEndTag.startIndex,\n endIndex: nextBeginTag.endIndex,\n newText: '',\n }],\n fixDescription: 'Merge consecutive sections',\n });\n }\n\n // Recurse into children\n for (const child of children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 4. Self-closing non-void tags\nconst VOID_ELEMENTS = new Set([\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n]);\n\nexport function checkSelfClosingNonVoidTags(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_self_closing_tag') {\n const tagNameNode = node.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName && !VOID_ELEMENTS.has(tagName)) {\n errors.push({\n node,\n message: `Self-closing non-void element: <${tagNameNode!.text}/>`,\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: node.text.replace(/\\s*\\/>$/, '>') + `</${tagNameNode!.text}>`,\n }],\n fixDescription: 'Replace self-closing syntax with explicit close tag',\n });\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 5. Duplicate attributes (including across mustache conditionals)\ninterface Condition {\n name: string;\n inverted: boolean;\n}\n\ninterface AttributeOccurrence {\n nameNode: BalanceNode;\n conditions: Condition[];\n}\n\nfunction areMutuallyExclusive(a: Condition[], b: Condition[]): boolean {\n // Two condition chains are mutually exclusive if some variable X\n // appears as truthy in one and falsy in the other\n for (const ac of a) {\n for (const bc of b) {\n if (ac.name === bc.name && ac.inverted !== bc.inverted) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction formatConditionClause(a: Condition[], b: Condition[]): string {\n // Combine conditions from both occurrences, deduplicating\n const seen = new Map<string, boolean>(); // name -> inverted\n for (const c of [...a, ...b]) {\n if (!seen.has(c.name)) {\n seen.set(c.name, c.inverted);\n }\n }\n if (seen.size === 0) return '';\n const parts: string[] = [];\n for (const [name, inverted] of seen) {\n parts.push(`${name} is ${inverted ? 'falsy' : 'truthy'}`);\n }\n return ` (when ${parts.join(', ')})`;\n}\n\nfunction collectAttributes(node: BalanceNode, conditions: Condition[], out: AttributeOccurrence[]) {\n for (const child of node.children) {\n if (child.type === 'html_attribute') {\n const nameNode = child.children.find(c => c.type === 'html_attribute_name');\n if (nameNode) {\n out.push({ nameNode, conditions: [...conditions] });\n }\n } else if (child.type === 'mustache_attribute') {\n // Descend into the mustache section/inverted section inside\n const section = child.children.find(c => isMustacheSection(c));\n if (section) {\n const name = getSectionName(section);\n if (name) {\n const inverted = section.type === 'mustache_inverted_section';\n collectAttributes(section, [...conditions, { name, inverted }], out);\n }\n }\n }\n // Skip mustache_interpolation / mustache_triple \u2014 dynamic, names unknown\n }\n}\n\n// 6. Unescaped HTML entities in text content\nexport function checkUnescapedEntities(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'text') {\n // Bare & (from _text_ampersand rule \u2014 node text is exactly \"&\")\n if (node.text === '&') {\n errors.push({\n node,\n message: 'Unescaped \"&\" in text content \u2014 use &amp; instead',\n severity: 'warning',\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: '&amp;',\n }],\n fixDescription: 'Replace & with &amp;',\n });\n return;\n }\n\n // > characters in text (from the text rule which allows >)\n if (node.text.includes('>')) {\n const fixes: TextReplacement[] = [];\n let searchFrom = 0;\n const text = node.text;\n while (true) {\n const idx = text.indexOf('>', searchFrom);\n if (idx === -1) break;\n fixes.push({\n startIndex: node.startIndex + idx,\n endIndex: node.startIndex + idx + 1,\n newText: '&gt;',\n });\n searchFrom = idx + 1;\n }\n errors.push({\n node,\n message: 'Unescaped \">\" in text content \u2014 use &gt; instead',\n severity: 'warning',\n fix: fixes,\n fixDescription: 'Replace > with &gt;',\n });\n return;\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 7. Prefer mustache comments over HTML comments\nexport function checkHtmlComments(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_comment') {\n // Extract text between <!-- and -->\n const raw = node.text;\n let content = raw;\n if (content.startsWith('<!--')) content = content.slice(4);\n if (content.endsWith('-->')) content = content.slice(0, -3);\n content = content.trim();\n\n errors.push({\n node,\n message: `HTML comment found \u2014 use mustache comment {{! ... }} instead`,\n severity: 'warning',\n fix: [{\n startIndex: node.startIndex,\n endIndex: node.endIndex,\n newText: `{{! ${content} }}`,\n }],\n fixDescription: 'Replace HTML comment with mustache comment',\n });\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\n// 8. Unrecognized HTML tags\nconst KNOWN_HTML_TAGS = new Set([\n // Void elements\n 'area', 'base', 'basefont', 'bgsound', 'br', 'col', 'command',\n 'embed', 'frame', 'hr', 'image', 'img', 'input', 'isindex',\n 'keygen', 'link', 'menuitem', 'meta', 'nextid', 'param',\n 'source', 'track', 'wbr',\n // Non-void elements\n 'a', 'abbr', 'address', 'article', 'aside', 'audio',\n 'b', 'bdi', 'bdo', 'blockquote', 'body', 'button',\n 'canvas', 'caption', 'cite', 'code', 'colgroup',\n 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt',\n 'em',\n 'fieldset', 'figcaption', 'figure', 'footer', 'form',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'html',\n 'i', 'iframe', 'ins',\n 'kbd',\n 'label', 'legend', 'li',\n 'main', 'map', 'mark', 'math', 'menu', 'meter',\n 'nav', 'noscript',\n 'object', 'ol', 'optgroup', 'option', 'output',\n 'p', 'picture', 'pre', 'progress',\n 'q',\n 'rb', 'rp', 'rt', 'rtc', 'ruby',\n 's', 'samp', 'script', 'search', 'section', 'select', 'slot', 'small', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'svg',\n 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr',\n 'u', 'ul',\n 'var', 'video',\n]);\n\nexport function checkUnrecognizedHtmlTags(rootNode: BalanceNode, customTagNames?: string[]): FixableError[] {\n const errors: FixableError[] = [];\n const customSet = customTagNames ? new Set(customTagNames.map(n => n.toLowerCase())) : undefined;\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element' || node.type === 'html_self_closing_tag') {\n // Check tag name for svg/math to skip their subtrees\n const tagNameNode = node.type === 'html_self_closing_tag'\n ? node.children.find(c => c.type === 'html_tag_name')\n : node.children.find(c => c.type === 'html_start_tag')?.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName === 'svg' || tagName === 'math') return;\n }\n\n if (node.type === 'html_start_tag' || node.type === 'html_self_closing_tag') {\n const tagNameNode = node.children.find(c => c.type === 'html_tag_name');\n if (tagNameNode) {\n const tagName = tagNameNode.text.toLowerCase();\n if (\n !KNOWN_HTML_TAGS.has(tagName) &&\n !customSet?.has(tagName)\n ) {\n errors.push({\n node: tagNameNode,\n message: `Unrecognized HTML tag: <${tagNameNode.text}>`,\n });\n }\n }\n return;\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nexport function checkDuplicateAttributes(rootNode: BalanceNode): FixableError[] {\n const errors: FixableError[] = [];\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_start_tag' || node.type === 'html_self_closing_tag') {\n const occurrences: AttributeOccurrence[] = [];\n collectAttributes(node, [], occurrences);\n\n // Group by attribute name (case-insensitive)\n const groups = new Map<string, AttributeOccurrence[]>();\n for (const occ of occurrences) {\n const key = occ.nameNode.text.toLowerCase();\n let group = groups.get(key);\n if (!group) {\n group = [];\n groups.set(key, group);\n }\n group.push(occ);\n }\n\n for (const [, group] of groups) {\n if (group.length < 2) continue;\n // Check each pair \u2014 report the later one if any non-exclusive pair exists\n for (let i = 1; i < group.length; i++) {\n let conflictIdx = -1;\n for (let j = 0; j < i; j++) {\n if (!areMutuallyExclusive(group[i].conditions, group[j].conditions)) {\n conflictIdx = j;\n break;\n }\n }\n if (conflictIdx >= 0) {\n const clause = formatConditionClause(group[conflictIdx].conditions, group[i].conditions);\n errors.push({\n node: group[i].nameNode,\n message: `Duplicate attribute \"${group[i].nameNode.text}\"${clause}`,\n });\n }\n }\n }\n return; // Don't recurse into tag children (already processed)\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n\nexport function checkElementContentTooLong(\n rootNode: BalanceNode,\n elements: ReadonlyArray<{ tag: string; maxBytes: number }>,\n): FixableError[] {\n const errors: FixableError[] = [];\n if (elements.length === 0) return errors;\n\n const thresholds = new Map<string, number>();\n for (const { tag, maxBytes } of elements) {\n const key = tag.toLowerCase();\n const existing = thresholds.get(key);\n if (existing === undefined || maxBytes < existing) thresholds.set(key, maxBytes);\n }\n\n function visit(node: BalanceNode) {\n if (node.type === 'html_element') {\n const startTag = node.children.find(c => c.type === 'html_start_tag');\n const endTag = node.children.find(c => c.type === 'html_end_tag');\n const tagNameNode = startTag?.children.find(c => c.type === 'html_tag_name');\n const tagName = tagNameNode?.text.toLowerCase();\n if (tagName && startTag && endTag) {\n const maxBytes = thresholds.get(tagName);\n if (maxBytes !== undefined) {\n const innerBytes = endTag.startIndex - startTag.endIndex;\n if (innerBytes > maxBytes) {\n errors.push({\n node: startTag,\n message: `<${tagName}> content is ${innerBytes} bytes, exceeds limit of ${maxBytes}`,\n });\n }\n }\n }\n }\n\n for (const child of node.children) {\n visit(child);\n }\n }\n\n visit(rootNode);\n return errors;\n}\n", "import type { RuleSeverity } from './configSchema.js';\n\nexport interface RuleDefinition {\n name: string;\n defaultSeverity: RuleSeverity;\n description: string;\n}\n\nexport const RULES: RuleDefinition[] = [\n {\n name: 'nestedDuplicateSections',\n defaultSeverity: 'error',\n description: 'Flags `{{#name}}` nested inside another `{{#name}}` with the same name',\n },\n {\n name: 'unquotedMustacheAttributes',\n defaultSeverity: 'error',\n description: 'Requires quotes around mustache expressions used as attribute values',\n },\n {\n name: 'consecutiveDuplicateSections',\n defaultSeverity: 'warning',\n description: 'Warns when adjacent same-name sections can be merged',\n },\n {\n name: 'selfClosingNonVoidTags',\n defaultSeverity: 'error',\n description: 'Disallows self-closing syntax on non-void HTML elements (e.g. `<div/>`)',\n },\n {\n name: 'duplicateAttributes',\n defaultSeverity: 'error',\n description: 'Detects duplicate HTML attributes on the same element',\n },\n {\n name: 'unescapedEntities',\n defaultSeverity: 'warning',\n description: 'Flags unescaped `&` and `>` characters in text content',\n },\n {\n name: 'preferMustacheComments',\n defaultSeverity: 'off',\n description: 'Suggests replacing HTML comments with mustache comments',\n },\n {\n name: 'unrecognizedHtmlTags',\n defaultSeverity: 'error',\n description: 'Flags HTML tags that are not standard HTML elements or valid custom elements',\n },\n {\n name: 'elementContentTooLong',\n defaultSeverity: 'off',\n description: 'Flags configured elements whose inner content exceeds a byte-length threshold (opt-in; requires `elements: [{ tag, maxBytes }]` option)',\n },\n];\n\n/** Set of all known rule names (for config validation). */\nexport const KNOWN_RULE_NAMES = new Set<string>(RULES.map(r => r.name));\n\n/** Default severity for each rule (for runtime resolution). */\nexport const RULE_DEFAULTS: Record<string, RuleSeverity> = Object.fromEntries(\n RULES.map(r => [r.name, r.defaultSeverity]),\n);\n", "const TOKENS = {\n attribute: /\\[\\s*(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?(?<name>[-\\w\\P{ASCII}]+)\\s*(?:(?<operator>\\W?=)\\s*(?<value>.+?)\\s*(\\s(?<caseSensitive>[iIsS]))?\\s*)?\\]/gu,\n id: /#(?<name>[-\\w\\P{ASCII}]+)/gu,\n class: /\\.(?<name>[-\\w\\P{ASCII}]+)/gu,\n comma: /\\s*,\\s*/g,\n combinator: /\\s*[\\s>+~]\\s*/g,\n 'pseudo-element': /::(?<name>[-\\w\\P{ASCII}]+)(?:\\((?<argument>\u00B6*)\\))?/gu,\n 'pseudo-class': /:(?<name>[-\\w\\P{ASCII}]+)(?:\\((?<argument>\u00B6*)\\))?/gu,\n universal: /(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?\\*/gu,\n type: /(?:(?<namespace>\\*|[-\\w\\P{ASCII}]*)\\|)?(?<name>[-\\w\\P{ASCII}]+)/gu, // this must be last\n};\nconst TRIM_TOKENS = new Set(['combinator', 'comma']);\nconst RECURSIVE_PSEUDO_CLASSES = new Set([\n 'not',\n 'is',\n 'where',\n 'has',\n 'matches',\n '-moz-any',\n '-webkit-any',\n 'nth-child',\n 'nth-last-child',\n]);\nconst nthChildRegExp = /(?<index>[\\dn+-]+)\\s+of\\s+(?<subtree>.+)/;\nconst RECURSIVE_PSEUDO_CLASSES_ARGS = {\n 'nth-child': nthChildRegExp,\n 'nth-last-child': nthChildRegExp,\n};\nconst getArgumentPatternByType = (type) => {\n switch (type) {\n case 'pseudo-element':\n case 'pseudo-class':\n return new RegExp(TOKENS[type].source.replace('(?<argument>\u00B6*)', '(?<argument>.*)'), 'gu');\n default:\n return TOKENS[type];\n }\n};\nfunction gobbleParens(text, offset) {\n let nesting = 0;\n let result = '';\n for (; offset < text.length; offset++) {\n const char = text[offset];\n switch (char) {\n case '(':\n ++nesting;\n break;\n case ')':\n --nesting;\n break;\n }\n result += char;\n if (nesting === 0) {\n return result;\n }\n }\n return result;\n}\nfunction tokenizeBy(text, grammar = TOKENS) {\n if (!text) {\n return [];\n }\n const tokens = [text];\n for (const [type, pattern] of Object.entries(grammar)) {\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (typeof token !== 'string') {\n continue;\n }\n pattern.lastIndex = 0;\n const match = pattern.exec(token);\n if (!match) {\n continue;\n }\n const from = match.index - 1;\n const args = [];\n const content = match[0];\n const before = token.slice(0, from + 1);\n if (before) {\n args.push(before);\n }\n args.push({\n ...match.groups,\n type,\n content,\n });\n const after = token.slice(from + content.length + 1);\n if (after) {\n args.push(after);\n }\n tokens.splice(i, 1, ...args);\n }\n }\n let offset = 0;\n for (const token of tokens) {\n switch (typeof token) {\n case 'string':\n throw new Error(`Unexpected sequence ${token} found at index ${offset}`);\n case 'object':\n offset += token.content.length;\n token.pos = [offset - token.content.length, offset];\n if (TRIM_TOKENS.has(token.type)) {\n token.content = token.content.trim() || ' ';\n }\n break;\n }\n }\n return tokens;\n}\nconst STRING_PATTERN = /(['\"])([^\\\\\\n]*?)\\1/g;\nconst ESCAPE_PATTERN = /\\\\./g;\nfunction tokenize(selector, grammar = TOKENS) {\n // Prevent leading/trailing whitespaces from being interpreted as combinators\n selector = selector.trim();\n if (selector === '') {\n return [];\n }\n const replacements = [];\n // Replace escapes with placeholders.\n selector = selector.replace(ESCAPE_PATTERN, (value, offset) => {\n replacements.push({ value, offset });\n return '\\uE000'.repeat(value.length);\n });\n // Replace strings with placeholders.\n selector = selector.replace(STRING_PATTERN, (value, quote, content, offset) => {\n replacements.push({ value, offset });\n return `${quote}${'\\uE001'.repeat(content.length)}${quote}`;\n });\n // Replace parentheses with placeholders.\n {\n let pos = 0;\n let offset;\n while ((offset = selector.indexOf('(', pos)) > -1) {\n const value = gobbleParens(selector, offset);\n replacements.push({ value, offset });\n selector = `${selector.substring(0, offset)}(${'\u00B6'.repeat(value.length - 2)})${selector.substring(offset + value.length)}`;\n pos = offset + value.length;\n }\n }\n // Now we have no nested structures and we can parse with regexes\n const tokens = tokenizeBy(selector, grammar);\n // Replace placeholders in reverse order.\n const changedTokens = new Set();\n for (const replacement of replacements.reverse()) {\n for (const token of tokens) {\n const { offset, value } = replacement;\n if (!(token.pos[0] <= offset &&\n offset + value.length <= token.pos[1])) {\n continue;\n }\n const { content } = token;\n const tokenOffset = offset - token.pos[0];\n token.content =\n content.slice(0, tokenOffset) +\n value +\n content.slice(tokenOffset + value.length);\n if (token.content !== content) {\n changedTokens.add(token);\n }\n }\n }\n // Update changed tokens.\n for (const token of changedTokens) {\n const pattern = getArgumentPatternByType(token.type);\n if (!pattern) {\n throw new Error(`Unknown token type: ${token.type}`);\n }\n pattern.lastIndex = 0;\n const match = pattern.exec(token.content);\n if (!match) {\n throw new Error(`Unable to parse content for ${token.type}: ${token.content}`);\n }\n Object.assign(token, match.groups);\n }\n return tokens;\n}\n/**\n * Convert a flat list of tokens into a tree of complex & compound selectors\n */\nfunction nestTokens(tokens, { list = true } = {}) {\n if (list && tokens.find((t) => t.type === 'comma')) {\n const selectors = [];\n const temp = [];\n for (let i = 0; i < tokens.length; i++) {\n if (tokens[i].type === 'comma') {\n if (temp.length === 0) {\n throw new Error('Incorrect comma at ' + i);\n }\n selectors.push(nestTokens(temp, { list: false }));\n temp.length = 0;\n }\n else {\n temp.push(tokens[i]);\n }\n }\n if (temp.length === 0) {\n throw new Error('Trailing comma');\n }\n else {\n selectors.push(nestTokens(temp, { list: false }));\n }\n return { type: 'list', list: selectors };\n }\n for (let i = tokens.length - 1; i >= 0; i--) {\n let token = tokens[i];\n if (token.type === 'combinator') {\n let left = tokens.slice(0, i);\n let right = tokens.slice(i + 1);\n if (left.length === 0) {\n return {\n type: 'relative',\n combinator: token.content,\n right: nestTokens(right),\n };\n }\n return {\n type: 'complex',\n combinator: token.content,\n left: nestTokens(left),\n right: nestTokens(right),\n };\n }\n }\n switch (tokens.length) {\n case 0:\n throw new Error('Could not build AST.');\n case 1:\n // If we're here, there are no combinators, so it's just a list.\n return tokens[0];\n default:\n return {\n type: 'compound',\n list: [...tokens], // clone to avoid pointers messing up the AST\n };\n }\n}\n/**\n * Traverse an AST in depth-first order\n */\nfunction* flatten(node, \n/**\n * @internal\n */\nparent) {\n switch (node.type) {\n case 'list':\n for (let child of node.list) {\n yield* flatten(child, node);\n }\n break;\n case 'complex':\n yield* flatten(node.left, node);\n yield* flatten(node.right, node);\n break;\n case 'relative':\n yield* flatten(node.right, node);\n break;\n case 'compound':\n yield* node.list.map((token) => [token, node]);\n break;\n default:\n yield [node, parent];\n }\n}\n/**\n * Traverse an AST (or part thereof), in depth-first order\n */\nfunction walk(node, visit, \n/**\n * @internal\n */\nparent) {\n if (!node) {\n return;\n }\n for (const [token, ast] of flatten(node, parent)) {\n visit(token, ast);\n }\n}\n/**\n * Parse a CSS selector\n *\n * @param selector - The selector to parse\n * @param options.recursive - Whether to parse the arguments of pseudo-classes like :is(), :has() etc. Defaults to true.\n * @param options.list - Whether this can be a selector list (A, B, C etc). Defaults to true.\n */\nfunction parse(selector, { recursive = true, list = true } = {}) {\n const tokens = tokenize(selector);\n if (!tokens) {\n return;\n }\n const ast = nestTokens(tokens, { list });\n if (!recursive) {\n return ast;\n }\n for (const [token] of flatten(ast)) {\n if (token.type !== 'pseudo-class' || !token.argument) {\n continue;\n }\n if (!RECURSIVE_PSEUDO_CLASSES.has(token.name)) {\n continue;\n }\n let argument = token.argument;\n const childArg = RECURSIVE_PSEUDO_CLASSES_ARGS[token.name];\n if (childArg) {\n const match = childArg.exec(argument);\n if (!match) {\n continue;\n }\n Object.assign(token, match.groups);\n argument = match.groups['subtree'];\n }\n if (!argument) {\n continue;\n }\n Object.assign(token, {\n subtree: parse(argument, {\n recursive: true,\n list: true,\n }),\n });\n }\n return ast;\n}\n/**\n * Converts the given list or (sub)tree to a string.\n */\nfunction stringify(listOrNode) {\n if (Array.isArray(listOrNode)) {\n return listOrNode.map((token) => token.content).join(\"\");\n }\n switch (listOrNode.type) {\n case \"list\":\n return listOrNode.list.map(stringify).join(\",\");\n case \"relative\":\n return (listOrNode.combinator +\n stringify(listOrNode.right));\n case \"complex\":\n return (stringify(listOrNode.left) +\n listOrNode.combinator +\n stringify(listOrNode.right));\n case \"compound\":\n return listOrNode.list.map(stringify).join(\"\");\n default:\n return listOrNode.content;\n }\n}\n/**\n * To convert the specificity array to a number\n */\nfunction specificityToNumber(specificity, base) {\n base = base || Math.max(...specificity) + 1;\n return (specificity[0] * (base << 1) + specificity[1] * base + specificity[2]);\n}\n/**\n * Calculate specificity of a selector.\n *\n * If the selector is a list, the max specificity is returned.\n */\nfunction specificity(selector) {\n let ast = selector;\n if (typeof ast === 'string') {\n ast = parse(ast, { recursive: true });\n }\n if (!ast) {\n return [];\n }\n if (ast.type === 'list' && 'list' in ast) {\n let base = 10;\n const specificities = ast.list.map((ast) => {\n const sp = specificity(ast);\n base = Math.max(base, ...specificity(ast));\n return sp;\n });\n const numbers = specificities.map((ast) => specificityToNumber(ast, base));\n return specificities[numbers.indexOf(Math.max(...numbers))];\n }\n const ret = [0, 0, 0];\n for (const [token] of flatten(ast)) {\n switch (token.type) {\n case 'id':\n ret[0]++;\n break;\n case 'class':\n case 'attribute':\n ret[1]++;\n break;\n case 'pseudo-element':\n case 'type':\n ret[2]++;\n break;\n case 'pseudo-class':\n if (token.name === 'where') {\n break;\n }\n if (!RECURSIVE_PSEUDO_CLASSES.has(token.name) ||\n !token.subtree) {\n ret[1]++;\n break;\n }\n const sub = specificity(token.subtree);\n sub.forEach((s, i) => (ret[i] += s));\n // :nth-child() & :nth-last-child() add (0, 1, 0) to the specificity of their most complex selector\n if (token.name === 'nth-child' ||\n token.name === 'nth-last-child') {\n ret[1]++;\n }\n }\n }\n return ret;\n}\n\nexport { RECURSIVE_PSEUDO_CLASSES, RECURSIVE_PSEUDO_CLASSES_ARGS, TOKENS, TRIM_TOKENS, flatten, gobbleParens, parse, specificity, specificityToNumber, stringify, tokenize, tokenizeBy, walk };\n", "/**\n * CSS-like selector parser and tree matcher for custom lint rules.\n *\n * Mustache constructs are written literally in selectors \u2014 `{{foo}}`,\n * `{{{foo}}}`, `{{#foo}}`, `{{^foo}}`, `{{!foo}}`, `{{>foo}}`. A preprocessor\n * substitutes each form into an internal `:m-*` pseudo-class marker, then the\n * rewritten string is handed to parsel-js. This keeps users in Mustache\n * vocabulary without reinventing a selector parser.\n *\n * Supported user-facing syntax:\n * - Tag names (`div`), universal (`*`), classes (`.foo`), ids (`#foo`)\n * - Attributes: `[attr]`, `[attr=v]`, `[attr^=v]`, `[attr*=v]`, `[attr$=v]`, `[attr~=v]`\n * - Descendant (space), child (`>`), adjacent-sibling (`+`), and\n * general-sibling (`~`) combinators. Sibling combinators skip over text /\n * whitespace nodes (CSS semantics) and work across HTML and Mustache\n * constructs: e.g. `label + input`, `{{foo}} + p`, `h2 ~ {{#items}}`.\n * - Mustache variables: `{{path}}` and `{{{path}}}` (raw)\n * - Mustache sections: `{{#name}}` and `{{^name}}` (inverted)\n * - Mustache comments: `{{!content}}`\n * - Mustache partials: `{{>name}}`\n * - Glob wildcard `*` inside the argument: `{{options.*}}`, `{{*.deprecated}}`, `{{*}}`\n * - `:has(selector)` \u2014 element has a matching descendant\n * - `:not(...)` \u2014 negation. Accepts attributes/class/id/`:has` (folded into\n * the outer compound), plus any other selector (including Mustache\n * literals and type selectors) as a whole-selector check against the\n * node itself. Example: `{{*}}:not({{internal.*}})` matches any\n * interpolation whose path does not start with `internal.`. Multi-segment\n * selectors with combinators are supported and tested against the node's\n * ancestor/sibling context, matching `Element.matches` semantics \u2014 e.g.\n * `img:not(pl-overlay img)` matches any `img` that is not a descendant of\n * `pl-overlay`, and `td:not(thead td)` matches `td`s outside a `thead`.\n * - `:root` \u2014 the tree-sitter fragment root (the whole document). Unlike\n * browser CSS where `:root` matches `<html>`, this matches the parse-tree\n * root so it works on partials/fragments too. Useful as a document-scoped\n * anchor, e.g. `:root:has(pl-question-panel):not(:has(pl-answer-panel))`\n * matches the root iff a `pl-question-panel` is present anywhere but no\n * `pl-answer-panel` is. Cannot combine with tag/class/id/attribute in the\n * same compound (only with `:has` / `:not(:has(...))`). Inside `:has(...)`,\n * `:root` refers to the element being checked, not the document.\n * - `:is(a, b, ...)` \u2014 matches if any alternative matches. Expanded at parse\n * time into the Cartesian product of alternatives, so `:is(a, b) :is(c, d)`\n * is equivalent to `a c, a d, b c, b d`. Alternatives inside `:is` that\n * contain combinators are only allowed when the `:is(...)` stands alone in\n * its compound (e.g. `:is(div > span, p)` works; `x:is(div > span, p)`\n * does not, since a combinator can't be merged into another compound).\n * - Comma-separated alternatives\n *\n * Unsupported (parseSelector returns null, rule is skipped):\n * - `[attr|=v]`, case-insensitive `i` flag\n * - Mixed HTML + Mustache kinds in one compound (e.g. `img{{foo}}`)\n * - `{{/end}}` (end tags aren't standalone nodes)\n * - `{{=<% %>=}}` (delimiter changes aren't grammar-tracked)\n */\n\nimport { parse as parselParse, type AST, type Token, type AttributeToken, type ClassToken, type IdToken } from 'parsel-js';\nimport type { BalanceNode } from './htmlBalanceChecker.js';\nimport {\n getTagName,\n getSectionName,\n getInterpolationPath,\n getCommentContent,\n getPartialName,\n HTML_ELEMENT_TYPES,\n} from './nodeHelpers.js';\n\n// --- Types ---\n\nexport type AttributeOperator = '=' | '^=' | '*=' | '$=' | '~=';\n\nexport type SegmentKind =\n | 'html'\n | 'section'\n | 'inverted'\n | 'variable'\n | 'raw'\n | 'comment'\n | 'partial';\n\nexport interface AttributeConstraint {\n name: string; // lowercased\n op: AttributeOperator; // meaningful only when value !== undefined\n value?: string; // quotes stripped; undefined => presence check\n negated: boolean; // true when inside :not()\n}\n\nexport interface DescendantCheck {\n selector: ParsedSelector; // :has(selector) \u2014 must match a descendant\n negated: boolean; // true for :not(:has(...))\n}\n\nexport type Combinator = 'descendant' | 'child' | 'adjacent-sibling' | 'general-sibling';\n\nexport interface Segment {\n kind: SegmentKind;\n rootOnly: boolean; // true for `:root` \u2014 matches only the tree-sitter fragment root\n name: string | null; // lowercased identifier/path, null = wildcard\n pathRegex?: RegExp; // compiled glob when `name` contains `*`\n attributes: AttributeConstraint[];\n descendantChecks: DescendantCheck[];\n selfNegations: ParsedSelector[]; // :not(X) where X is a full sub-selector tested against the node itself\n combinator: Combinator;\n}\n\n/** A parsed selector is a list of alternatives (from comma-separated parts). */\nexport type ParsedSelector = Segment[][];\n\n// --- Mustache preprocessor ---\n\nconst MUSTACHE_KIND_PSEUDO = new Set([\n 'm-section', 'm-inverted', 'm-variable', 'm-raw', 'm-comment', 'm-partial',\n]);\n\n/**\n * Rewrite Mustache-literal tokens (`{{...}}` forms) in the selector string into\n * internal `:m-*` pseudo-class markers so parsel-js can handle them. Returns\n * null if the string contains an unsupported or malformed Mustache token.\n *\n * Skips content inside `\"...\"` and `'...'` so that literal `{{...}}` embedded\n * in CSS attribute-value strings is preserved unchanged.\n */\nexport function preprocessMustacheLiterals(raw: string): string | null {\n let out = '';\n let i = 0;\n const len = raw.length;\n\n while (i < len) {\n const ch = raw[i];\n\n // Pass through quoted strings verbatim.\n if (ch === '\"' || ch === \"'\") {\n out += ch;\n i++;\n while (i < len && raw[i] !== ch) {\n if (raw[i] === '\\\\' && i + 1 < len) {\n out += raw[i] + raw[i + 1];\n i += 2;\n } else {\n out += raw[i];\n i++;\n }\n }\n if (i < len) {\n out += raw[i]; // closing quote\n i++;\n }\n continue;\n }\n\n if (ch !== '{' || raw[i + 1] !== '{') {\n out += ch;\n i++;\n continue;\n }\n\n // Triple-brace: {{{path}}}\n if (raw[i + 2] === '{') {\n const end = raw.indexOf('}}}', i + 3);\n if (end < 0) return null;\n const inner = raw.slice(i + 3, end).trim();\n if (inner.length === 0) return null;\n out += `:m-raw(${inner})`;\n i = end + 3;\n continue;\n }\n\n // Double-brace: {{...}}\n const end = raw.indexOf('}}', i + 2);\n if (end < 0) return null;\n const body = raw.slice(i + 2, end);\n i = end + 2;\n\n const sigil = body.trimStart()[0];\n const content = body.replace(/^\\s*[#^!>/]\\s*/, '').replace(/^\\s+|\\s+$/g, '');\n\n switch (sigil) {\n case '#':\n if (content.length === 0) return null;\n out += `:m-section(${content})`;\n break;\n case '^':\n if (content.length === 0) return null;\n out += `:m-inverted(${content})`;\n break;\n case '!':\n if (content.length === 0) return null;\n out += `:m-comment(${content})`;\n break;\n case '>':\n if (content.length === 0) return null;\n out += `:m-partial(${content})`;\n break;\n case '/':\n // Standalone end tags are not a selectable node.\n return null;\n case '=':\n // Delimiter changes are not a grammar-tracked node.\n return null;\n default: {\n const path = body.trim();\n if (path.length === 0) return null;\n out += `:m-variable(${path})`;\n break;\n }\n }\n }\n\n return out;\n}\n\n// --- Selector parsing ---\n\nexport function parseSelector(raw: string): ParsedSelector | null {\n if (typeof raw !== 'string' || raw.trim() === '') return null;\n\n const preprocessed = preprocessMustacheLiterals(raw);\n if (preprocessed === null) return null;\n\n let ast: AST | undefined;\n try {\n ast = parselParse(preprocessed);\n } catch {\n return null;\n }\n if (!ast) return null;\n\n const tops = ast.type === 'list' ? ast.list : [ast];\n const alts: Segment[][] = [];\n for (const top of tops) {\n const expanded = expandIs(top);\n if (expanded === null) return null;\n for (const exp of expanded) {\n const segments: Segment[] = [];\n if (!collectSegments(exp, 'descendant', segments)) return null;\n if (segments.length === 0) return null;\n alts.push(segments);\n }\n }\n return alts.length > 0 ? alts : null;\n}\n\n/**\n * Expand `:is(...)` pseudo-classes into explicit alternatives. Returns an\n * array of equivalent ASTs with every `:is` removed (Cartesian product over\n * alternatives), or `null` if the expansion contains an unsupported shape\n * (e.g. complex alternatives inside a mixed compound).\n */\nfunction expandIs(ast: AST): AST[] | null {\n switch (ast.type) {\n case 'list': {\n const out: AST[] = [];\n for (const alt of ast.list) {\n const expanded = expandIs(alt);\n if (expanded === null) return null;\n out.push(...expanded);\n }\n return out;\n }\n case 'complex': {\n const lefts = expandIs(ast.left);\n if (lefts === null) return null;\n const rights = expandIs(ast.right);\n if (rights === null) return null;\n const out: AST[] = [];\n for (const l of lefts) for (const r of rights) {\n out.push({ ...ast, left: l, right: r });\n }\n return out;\n }\n case 'compound': {\n // A compound whose sole token is `:is(...)` can be replaced by any\n // shape (including complex alternatives). Mixed compounds require each\n // alternative to be mergeable token-by-token.\n if (ast.list.length === 1) {\n const tok = ast.list[0];\n if (tok.type === 'pseudo-class' && tok.name === 'is') {\n if (!tok.subtree) return null;\n return expandIs(tok.subtree);\n }\n }\n return expandCompoundWithIs(ast.list);\n }\n default:\n if (ast.type === 'pseudo-class' && ast.name === 'is') {\n if (!ast.subtree) return null;\n return expandIs(ast.subtree);\n }\n return [ast];\n }\n}\n\nfunction expandCompoundWithIs(tokens: Token[]): AST[] | null {\n let variants: Token[][] = [[]];\n for (const tok of tokens) {\n if (tok.type === 'pseudo-class' && tok.name === 'is') {\n if (!tok.subtree) return null;\n const alts = expandIs(tok.subtree);\n if (alts === null) return null;\n const next: Token[][] = [];\n for (const base of variants) {\n for (const alt of alts) {\n if (alt.type === 'compound') {\n next.push([...base, ...alt.list]);\n } else if (alt.type === 'complex' || alt.type === 'list' || alt.type === 'relative') {\n // Can't splice a combinator-bearing selector into a compound.\n return null;\n } else {\n next.push([...base, alt]);\n }\n }\n }\n variants = next;\n } else {\n variants = variants.map(v => [...v, tok]);\n }\n }\n return variants.map(list =>\n list.length === 1 ? (list[0] as AST) : ({ type: 'compound', list } as AST),\n );\n}\n\nfunction collectSegments(\n ast: AST,\n combinator: Combinator,\n out: Segment[],\n): boolean {\n if (ast.type === 'complex') {\n const mapped = mapCombinator(ast.combinator);\n if (!mapped) return false;\n return collectSegments(ast.left, 'descendant', out)\n && collectSegments(ast.right, mapped, out);\n }\n if (ast.type === 'list' || ast.type === 'relative') return false;\n\n const segment = segmentFromCompound(ast);\n if (!segment) return false;\n segment.combinator = combinator;\n out.push(segment);\n return true;\n}\n\nfunction mapCombinator(c: string): Combinator | null {\n const trimmed = c.trim();\n if (trimmed === '') return 'descendant';\n if (trimmed === '>') return 'child';\n if (trimmed === '+') return 'adjacent-sibling';\n if (trimmed === '~') return 'general-sibling';\n return null;\n}\n\nfunction segmentFromCompound(ast: AST): Segment | null {\n const tokens: Token[] = ast.type === 'compound' ? ast.list : [ast as Token];\n\n let kind: SegmentKind | undefined;\n let name: string | null = null;\n let pathRegex: RegExp | undefined;\n let rootOnly = false;\n const attributes: AttributeConstraint[] = [];\n const descendantChecks: DescendantCheck[] = [];\n const selfNegations: ParsedSelector[] = [];\n\n // Once a Mustache kind is picked, no other kind tokens may appear.\n const forbidChange = (requested: SegmentKind): boolean => {\n if (kind === undefined) return false;\n if (kind === requested) return false;\n // html and Mustache kinds never mix\n return true;\n };\n\n for (const token of tokens) {\n switch (token.type) {\n case 'type':\n if (forbidChange('html')) return null;\n kind = 'html';\n name = token.name.toLowerCase();\n break;\n case 'universal':\n if (forbidChange('html')) return null;\n kind = 'html';\n name = null;\n break;\n case 'class':\n if (forbidChange('html')) return null;\n kind = 'html';\n attributes.push(classConstraint(token, false));\n break;\n case 'id':\n if (forbidChange('html')) return null;\n kind = 'html';\n attributes.push(idConstraint(token, false));\n break;\n case 'attribute': {\n // Attribute selectors only apply to HTML segments.\n if (forbidChange('html')) return null;\n if (kind === undefined) kind = 'html';\n const c = attributeConstraint(token, false);\n if (!c) return null;\n attributes.push(c);\n break;\n }\n case 'pseudo-class': {\n if (MUSTACHE_KIND_PSEUDO.has(token.name)) {\n const mustacheKind = mustacheKindFromMarker(token.name);\n if (mustacheKind === null) return null;\n if (forbidChange(mustacheKind)) return null;\n kind = mustacheKind;\n const glob = parseGlob(token.argument ?? '');\n name = glob.name;\n pathRegex = glob.pathRegex;\n break;\n }\n if (token.name === 'has') {\n const sel = subtreeToSelector(token.subtree);\n if (!sel) return null;\n descendantChecks.push({ selector: sel, negated: false });\n break;\n }\n if (token.name === 'not') {\n if (!applyNegatedSubtree(token.subtree, attributes, descendantChecks, selfNegations)) return null;\n break;\n }\n if (token.name === 'root') {\n rootOnly = true;\n if (kind === undefined) kind = 'html';\n break;\n }\n return null;\n }\n default:\n // pseudo-element, comma, combinator, unknown \u2192 unsupported\n return null;\n }\n }\n\n if (kind === undefined) {\n kind = 'html';\n }\n\n if (rootOnly) {\n // `:root` is only meaningful on its own (optionally with :has / :not(:has)).\n // Reject tag/attribute/class/id combinations \u2014 the root isn't an HTML element.\n if (name !== null || attributes.length > 0 || kind !== 'html') return null;\n }\n\n const isHtml = kind === 'html';\n const finalAttrs = isHtml ? attributes : [];\n return { kind, rootOnly, name, pathRegex, attributes: finalAttrs, descendantChecks, selfNegations, combinator: 'descendant' };\n}\n\nfunction mustacheKindFromMarker(name: string): SegmentKind | null {\n switch (name) {\n case 'm-section': return 'section';\n case 'm-inverted': return 'inverted';\n case 'm-variable': return 'variable';\n case 'm-raw': return 'raw';\n case 'm-comment': return 'comment';\n case 'm-partial': return 'partial';\n default: return null;\n }\n}\n\n/**\n * Parse a Mustache-literal argument into an exact name or a compiled glob.\n * The '*' character is the only wildcard. Bare '*' or empty string returns\n * { name: null } \u2014 a wildcard that matches any value.\n */\nfunction parseGlob(arg: string): { name: string | null; pathRegex?: RegExp } {\n const trimmed = arg.trim();\n if (trimmed === '' || trimmed === '*') {\n return { name: null }; // wildcard \u2014 matches anything\n }\n if (!trimmed.includes('*')) {\n return { name: trimmed.toLowerCase() };\n }\n // Escape regex metacharacters except `*`, then substitute `*` \u2192 `.*`.\n const escaped = trimmed.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n const pathRegex = new RegExp(`^${escaped}$`, 'i');\n return { name: trimmed.toLowerCase(), pathRegex };\n}\n\nfunction attributeConstraint(token: AttributeToken, negated: boolean): AttributeConstraint | null {\n const name = token.name.toLowerCase();\n if (token.operator === undefined) {\n return { name, op: '=', value: undefined, negated };\n }\n let op: AttributeOperator;\n switch (token.operator) {\n case '=': op = '='; break;\n case '^=': op = '^='; break;\n case '*=': op = '*='; break;\n case '$=': op = '$='; break;\n case '~=': op = '~='; break;\n default: return null;\n }\n return { name, op, value: stripQuotes(token.value ?? ''), negated };\n}\n\nfunction classConstraint(token: ClassToken, negated: boolean): AttributeConstraint {\n return { name: 'class', op: '~=', value: token.name, negated };\n}\n\nfunction idConstraint(token: IdToken, negated: boolean): AttributeConstraint {\n return { name: 'id', op: '=', value: token.name, negated };\n}\n\nfunction applyNegatedSubtree(\n subtree: AST | undefined,\n attributes: AttributeConstraint[],\n descendantChecks: DescendantCheck[],\n selfNegations: ParsedSelector[],\n): boolean {\n if (!subtree) return false;\n if (subtree.type === 'attribute') {\n const c = attributeConstraint(subtree, true);\n if (!c) return false;\n attributes.push(c);\n return true;\n }\n if (subtree.type === 'class') {\n attributes.push(classConstraint(subtree, true));\n return true;\n }\n if (subtree.type === 'id') {\n attributes.push(idConstraint(subtree, true));\n return true;\n }\n if (subtree.type === 'pseudo-class' && subtree.name === 'has') {\n const sel = subtreeToSelector(subtree.subtree);\n if (!sel) return false;\n descendantChecks.push({ selector: sel, negated: true });\n return true;\n }\n // Fall back to a whole-selector negation: `:not(X)` where X is a Mustache\n // literal or any other parseable selector, tested against the node itself.\n const sel = subtreeToSelector(subtree);\n if (sel) {\n selfNegations.push(sel);\n return true;\n }\n return false;\n}\n\nfunction subtreeToSelector(subtree: AST | undefined): ParsedSelector | null {\n if (!subtree) return null;\n const tops = subtree.type === 'list' ? subtree.list : [subtree];\n const alts: Segment[][] = [];\n for (const top of tops) {\n const segments: Segment[] = [];\n if (!collectSegments(top, 'descendant', segments)) return null;\n if (segments.length === 0) return null;\n alts.push(segments);\n }\n return alts.length > 0 ? alts : null;\n}\n\nfunction stripQuotes(raw: string): string {\n if (raw.length < 2) return raw;\n const first = raw[0];\n const last = raw[raw.length - 1];\n if ((first === '\"' || first === \"'\") && first === last) {\n return raw.slice(1, -1);\n }\n return raw;\n}\n\n// --- Tree matching ---\n\ninterface AncestorEntry {\n kind: AncestorKind;\n name: string; // lowercased\n node: BalanceNode;\n siblings: BalanceNode[]; // the node's parent's children; empty for root\n indexInSiblings: number; // 0 for root\n}\n\ntype AncestorKind = 'html' | 'section' | 'inverted' | 'root';\n\nfunction ancestorKindForNode(node: BalanceNode): AncestorKind | null {\n if (HTML_ELEMENT_TYPES.has(node.type)) return 'html';\n if (node.type === 'mustache_section') return 'section';\n if (node.type === 'mustache_inverted_section') return 'inverted';\n return null;\n}\n\nfunction getHtmlAttributes(node: BalanceNode): { name: string; value?: string }[] {\n const startTag = node.children.find(\n c => c.type === 'html_start_tag' || c.type === 'html_self_closing_tag',\n );\n if (!startTag) return [];\n\n const attrs: { name: string; value?: string }[] = [];\n for (const child of startTag.children) {\n if (child.type !== 'html_attribute') continue;\n let attrName = '';\n let attrValue: string | undefined;\n for (const part of child.children) {\n if (part.type === 'html_attribute_name') {\n attrName = part.text.toLowerCase();\n } else if (part.type === 'html_quoted_attribute_value') {\n attrValue = part.text.replace(/^[\"']|[\"']$/g, '');\n } else if (part.type === 'html_attribute_value') {\n attrValue = part.text;\n }\n }\n if (attrName) attrs.push({ name: attrName, value: attrValue });\n }\n return attrs;\n}\n\nfunction matchesAttributeValue(has: string | undefined, c: AttributeConstraint): boolean {\n if (has === undefined || c.value === undefined) return false;\n const v = c.value;\n if (v === '') return false;\n switch (c.op) {\n case '=': return has === v;\n case '^=': return has.startsWith(v);\n case '*=': return has.includes(v);\n case '$=': return has.endsWith(v);\n case '~=': return has.split(/\\s+/).includes(v);\n }\n}\n\nfunction checkAttributes(node: BalanceNode, constraints: AttributeConstraint[]): boolean {\n if (constraints.length === 0) return true;\n const nodeAttrs = getHtmlAttributes(node);\n for (const c of constraints) {\n const found = nodeAttrs.find(a => a.name === c.name);\n if (c.negated) {\n if (!found) continue;\n if (c.value === undefined) return false;\n if (matchesAttributeValue(found.value, c)) return false;\n continue;\n }\n if (c.value === undefined) {\n if (!found) return false;\n continue;\n }\n if (!found || !matchesAttributeValue(found.value, c)) return false;\n }\n return true;\n}\n\nfunction checkDescendants(node: BalanceNode, checks: DescendantCheck[]): boolean {\n if (checks.length === 0) return true;\n for (const check of checks) {\n const present = hasDescendantMatch(node, check.selector);\n if (check.negated ? present : !present) return false;\n }\n return true;\n}\n\nfunction hasDescendantMatch(node: BalanceNode, selector: ParsedSelector): boolean {\n for (let i = 0; i < node.children.length; i++) {\n if (matchSelector(node.children[i], selector, node.children, i).length > 0) return true;\n }\n return false;\n}\n\nfunction checkSelfNegations(\n node: BalanceNode,\n negations: ParsedSelector[],\n rootNode: BalanceNode,\n cursor: Cursor,\n): boolean {\n for (const sel of negations) {\n for (const alt of sel) {\n if (alt.length === 0) continue;\n const lastSegment = alt[alt.length - 1];\n if (!nodeMatchesSegment(node, lastSegment, rootNode, cursor)) continue;\n if (alt.length === 1) return false;\n // Multi-segment negation (e.g. `:not(ancestor descendant)`): the last\n // segment matched the node itself; walk back through the remaining\n // segments against the node's ancestor/sibling cursor. If the chain\n // also matches, the negation fires.\n if (checkPrefix(cursor, alt, alt.length - 2, lastSegment.combinator, rootNode)) {\n return false;\n }\n }\n }\n return true;\n}\n\nfunction matchesName(actual: string | null, segment: Segment): boolean {\n if (segment.name === null) return true; // wildcard\n if (actual === null) return false;\n if (segment.pathRegex) return segment.pathRegex.test(actual);\n return actual === segment.name;\n}\n\nfunction nodeMatchesSegment(\n node: BalanceNode,\n segment: Segment,\n rootNode: BalanceNode,\n cursor: Cursor,\n): boolean {\n if (segment.rootOnly) {\n if (node !== rootNode) return false;\n return checkDescendants(node, segment.descendantChecks)\n && checkSelfNegations(node, segment.selfNegations, rootNode, cursor);\n }\n const baseMatches = (() => {\n switch (segment.kind) {\n case 'html': {\n if (!HTML_ELEMENT_TYPES.has(node.type)) return false;\n if (segment.name !== null) {\n const tagName = getTagName(node)?.toLowerCase();\n if (tagName !== segment.name) return false;\n }\n return checkAttributes(node, segment.attributes) && checkDescendants(node, segment.descendantChecks);\n }\n case 'section':\n if (node.type !== 'mustache_section') return false;\n if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'inverted':\n if (node.type !== 'mustache_inverted_section') return false;\n if (!matchesName(getSectionName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'variable':\n if (node.type !== 'mustache_interpolation') return false;\n if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'raw':\n if (node.type !== 'mustache_triple') return false;\n if (!matchesName(getInterpolationPath(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'comment':\n if (node.type !== 'mustache_comment') return false;\n if (!matchesName(getCommentContent(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n case 'partial':\n if (node.type !== 'mustache_partial') return false;\n if (!matchesName(getPartialName(node)?.toLowerCase() ?? null, segment)) return false;\n return checkDescendants(node, segment.descendantChecks);\n }\n })();\n if (!baseMatches) return false;\n return checkSelfNegations(node, segment.selfNegations, rootNode, cursor);\n}\n\ninterface Cursor {\n ancestors: AncestorEntry[]; // nodes on the path from root, excluding the match pointer itself\n siblings: BalanceNode[]; // siblings of the current match pointer\n indexInSiblings: number; // index of the current match pointer in its siblings\n}\n\n/** Does the prefix of segments up to segIdx satisfy the path/sibling context? */\nfunction checkPrefix(\n cursor: Cursor,\n segments: Segment[],\n segIdx: number,\n stepCombinator: Combinator,\n rootNode: BalanceNode,\n): boolean {\n if (segIdx < 0) return true;\n const segment = segments[segIdx];\n\n if (stepCombinator === 'adjacent-sibling' || stepCombinator === 'general-sibling') {\n for (let i = cursor.indexInSiblings - 1; i >= 0; i--) {\n const sib = cursor.siblings[i];\n if (!isMatchableNode(sib)) continue;\n const sibCursor: Cursor = {\n ancestors: cursor.ancestors,\n siblings: cursor.siblings,\n indexInSiblings: i,\n };\n if (!nodeMatchesSegment(sib, segment, rootNode, sibCursor)) {\n if (stepCombinator === 'adjacent-sibling') return false;\n continue;\n }\n if (checkPrefix(sibCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;\n if (stepCombinator === 'adjacent-sibling') return false;\n }\n return false;\n }\n\n // descendant or child \u2014 walk up the ancestor stack\n const ancestorKind = ancestorKindForSegment(segment);\n if (ancestorKind === null) return false; // variable/raw/comment/partial can't be ancestors\n\n if (stepCombinator === 'child') {\n for (let a = cursor.ancestors.length - 1; a >= 0; a--) {\n const entry = cursor.ancestors[a];\n if (entry.kind !== ancestorKind) {\n // For `:root > X` (ancestorKind='root'), any html ancestor between\n // X and the document root breaks the direct-child relationship.\n // Mustache sections are transparent (existing braided semantics).\n if (ancestorKind === 'root' && entry.kind === 'html') return false;\n continue;\n }\n if (!matchesName(entry.name, segment)) return false;\n if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) return false;\n if (!checkDescendants(entry.node, segment.descendantChecks)) return false;\n const ancestorCursor: Cursor = {\n ancestors: cursor.ancestors.slice(0, a),\n siblings: entry.siblings,\n indexInSiblings: entry.indexInSiblings,\n };\n if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) return false;\n return checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode);\n }\n return false;\n }\n\n for (let a = cursor.ancestors.length - 1; a >= 0; a--) {\n const entry = cursor.ancestors[a];\n if (entry.kind !== ancestorKind) continue;\n if (!matchesName(entry.name, segment)) continue;\n if (segment.kind === 'html' && !checkAttributes(entry.node, segment.attributes)) continue;\n if (!checkDescendants(entry.node, segment.descendantChecks)) continue;\n const ancestorCursor: Cursor = {\n ancestors: cursor.ancestors.slice(0, a),\n siblings: entry.siblings,\n indexInSiblings: entry.indexInSiblings,\n };\n if (!checkSelfNegations(entry.node, segment.selfNegations, rootNode, ancestorCursor)) continue;\n if (checkPrefix(ancestorCursor, segments, segIdx - 1, segment.combinator, rootNode)) return true;\n }\n return false;\n}\n\n/** True for nodes that a segment could ever match \u2014 used to skip text/whitespace when walking siblings. */\nfunction isMatchableNode(node: BalanceNode): boolean {\n return HTML_ELEMENT_TYPES.has(node.type)\n || node.type === 'mustache_section'\n || node.type === 'mustache_inverted_section'\n || node.type === 'mustache_interpolation'\n || node.type === 'mustache_triple'\n || node.type === 'mustache_comment'\n || node.type === 'mustache_partial';\n}\n\nfunction ancestorKindForSegment(segment: Segment): AncestorKind | null {\n if (segment.rootOnly) return 'root';\n if (segment.kind === 'html') return 'html';\n if (segment.kind === 'section') return 'section';\n if (segment.kind === 'inverted') return 'inverted';\n return null;\n}\n\nfunction getReportNode(node: BalanceNode, rootNode?: BalanceNode): BalanceNode {\n if (HTML_ELEMENT_TYPES.has(node.type)) {\n const startTag = node.children.find(\n c => c.type === 'html_start_tag' || c.type === 'html_self_closing_tag',\n );\n return startTag ?? node;\n }\n if (node.type === 'mustache_section' || node.type === 'mustache_inverted_section') {\n const begin = node.children.find(\n c => c.type === 'mustache_section_begin' || c.type === 'mustache_inverted_section_begin',\n );\n return begin ?? node;\n }\n // When `:root` matches, the node covers the whole document. Narrow the\n // reported range to a 1-char span at the document start so the diagnostic\n // squiggle isn't the entire file.\n if (rootNode && node === rootNode) {\n return {\n type: node.type,\n text: '',\n startPosition: node.startPosition,\n endPosition: { row: node.startPosition.row, column: node.startPosition.column + 1 },\n startIndex: node.startIndex,\n endIndex: Math.min(node.startIndex + 1, node.endIndex),\n children: [],\n };\n }\n return node;\n}\n\nfunction matchAlternative(\n rootNode: BalanceNode,\n segments: Segment[],\n rootSiblings: BalanceNode[],\n rootIndexInSiblings: number,\n): BalanceNode[] {\n const results: BalanceNode[] = [];\n const lastSegment = segments[segments.length - 1];\n\n function walk(\n node: BalanceNode,\n ancestors: AncestorEntry[],\n siblings: BalanceNode[],\n indexInSiblings: number,\n ) {\n const cursor: Cursor = { ancestors, siblings, indexInSiblings };\n if (nodeMatchesSegment(node, lastSegment, rootNode, cursor)) {\n if (\n segments.length === 1 ||\n checkPrefix(cursor, segments, segments.length - 2, lastSegment.combinator, rootNode)\n ) {\n results.push(getReportNode(node, rootNode));\n }\n }\n\n let newAncestors = ancestors;\n const ancestorKind = ancestorKindForNode(node);\n if (ancestorKind !== null) {\n const name =\n ancestorKind === 'html' ? getTagName(node)?.toLowerCase() :\n getSectionName(node)?.toLowerCase();\n if (name) {\n newAncestors = [...ancestors, { kind: ancestorKind, name, node, siblings, indexInSiblings }];\n }\n }\n\n for (let i = 0; i < node.children.length; i++) {\n walk(node.children[i], newAncestors, node.children, i);\n }\n }\n\n // Seed the ancestor stack with a root entry so `:root X` / `:root > X`\n // can find the document root as an ancestor. The root node itself is\n // never an html/section/inverted node, so it's otherwise never pushed.\n const rootEntry: AncestorEntry = {\n kind: 'root', name: '', node: rootNode,\n siblings: rootSiblings, indexInSiblings: rootIndexInSiblings,\n };\n walk(rootNode, [rootEntry], rootSiblings, rootIndexInSiblings);\n return results;\n}\n\nexport function matchSelector(\n rootNode: BalanceNode,\n selector: ParsedSelector,\n siblings: BalanceNode[] = [],\n indexInSiblings = 0,\n): BalanceNode[] {\n const allResults: BalanceNode[] = [];\n const seen = new Set<BalanceNode>();\n for (const alt of selector) {\n for (const node of matchAlternative(rootNode, alt, siblings, indexInSiblings)) {\n if (!seen.has(node)) {\n seen.add(node);\n allResults.push(node);\n }\n }\n }\n return allResults;\n}\n", "/**\n * Shared error collection logic used by both the LSP diagnostics\n * and the CLI linter.\n */\n\nimport type { BalanceNode } from './htmlBalanceChecker.js';\nimport { checkHtmlBalance, checkUnclosedTags } from './htmlBalanceChecker.js';\nimport {\n checkNestedSameNameSections,\n checkUnquotedMustacheAttributes,\n checkConsecutiveSameNameSections,\n checkSelfClosingNonVoidTags,\n checkDuplicateAttributes,\n checkUnescapedEntities,\n checkHtmlComments,\n checkUnrecognizedHtmlTags,\n checkElementContentTooLong,\n} from './mustacheChecks.js';\nimport type { TextReplacement } from './mustacheChecks.js';\nimport type { RulesConfig, RuleSeverity, CustomRule, ElementContentTooLongOptions } from './configSchema.js';\nimport { RULE_DEFAULTS, KNOWN_RULE_NAMES } from './ruleMetadata.js';\nimport { parseSelector, matchSelector } from './selectorMatcher.js';\nimport type { ParsedSelector } from './selectorMatcher.js';\n\n// Parsing a selector is non-trivial (runs parsel-js) and lint() is called\n// per-keystroke in browsers, so cache by raw selector string. `null` cached\n// when the selector is unparseable to avoid retrying.\nconst selectorCache = new Map<string, ParsedSelector | null>();\n\nfunction parseSelectorCached(raw: string): ParsedSelector | null {\n const hit = selectorCache.get(raw);\n if (hit !== undefined) return hit;\n const parsed = parseSelector(raw);\n selectorCache.set(raw, parsed);\n return parsed;\n}\n\n/** A tree that provides walk() and rootNode, compatible with both web-tree-sitter and CLI wasm. */\nexport interface WalkableTree {\n walk(): TreeCursor;\n rootNode: BalanceNode;\n}\n\ninterface TreeCursor {\n currentNode: BalanceNode;\n nodeType: string;\n nodeIsMissing: boolean;\n gotoFirstChild(): boolean;\n gotoNextSibling(): boolean;\n gotoParent(): boolean;\n}\n\n/** Unified error result from all checkers. */\nexport interface CheckError {\n node: BalanceNode;\n message: string;\n severity?: 'error' | 'warning';\n fix?: TextReplacement[];\n fixDescription?: string;\n ruleName?: string;\n}\n\nconst ERROR_NODE_TYPES = new Set([\n 'ERROR',\n 'mustache_erroneous_section_end',\n 'mustache_erroneous_inverted_section_end',\n]);\n\nfunction errorMessageForNode(nodeType: string, node: BalanceNode): string {\n if (nodeType === 'mustache_erroneous_section_end' || nodeType === 'mustache_erroneous_inverted_section_end') {\n const tagNameNode = node.children.find(c => c.type === 'mustache_erroneous_tag_name');\n return `Mismatched mustache section: {{/${tagNameNode?.text || '?'}}}`;\n }\n if (nodeType === 'ERROR') {\n return 'Syntax error';\n }\n // isMissing node\n return `Missing ${nodeType}`;\n}\n\nfunction resolveRuleConfig<K extends keyof RulesConfig>(\n rules: RulesConfig | undefined,\n ruleName: K,\n): { severity: RuleSeverity; entry: RulesConfig[K] } {\n const entry = rules?.[ruleName];\n let severity: RuleSeverity;\n if (entry === undefined) {\n severity = RULE_DEFAULTS[ruleName] ?? 'off';\n } else if (typeof entry === 'string') {\n severity = entry;\n } else {\n severity = (entry as { severity: RuleSeverity }).severity;\n }\n return { severity, entry: entry as RulesConfig[K] };\n}\n\nfunction parseDisableDirective(node: BalanceNode, customRuleIds?: Set<string>): string | null {\n if (node.type !== 'html_comment' && node.type !== 'mustache_comment') return null;\n let inner: string | null = null;\n if (node.type === 'html_comment') {\n const match = node.text.match(/^<!--([\\s\\S]*)-->$/);\n if (match) inner = match[1].trim();\n } else {\n const match = node.text.match(/^\\{\\{!([\\s\\S]*)\\}\\}$/);\n if (match) inner = match[1].trim();\n }\n if (!inner) return null;\n const prefix = 'htmlmustache-disable ';\n if (!inner.startsWith(prefix)) return null;\n const ruleName = inner.slice(prefix.length).trim();\n if (KNOWN_RULE_NAMES.has(ruleName)) return ruleName;\n if (customRuleIds?.has(ruleName)) return ruleName;\n return null;\n}\n\nfunction collectDisabledRules(rootNode: BalanceNode, customRuleIds?: Set<string>): Set<string> {\n const disabled = new Set<string>();\n function walk(node: BalanceNode) {\n const rule = parseDisableDirective(node, customRuleIds);\n if (rule) { disabled.add(rule); return; }\n for (const child of node.children) walk(child);\n }\n walk(rootNode);\n return disabled;\n}\n\n/**\n * Collect all errors from a parsed tree: syntax errors, balance errors,\n * unclosed tags, and mustache lint checks.\n */\nexport function collectErrors(tree: WalkableTree, rules?: RulesConfig, customTagNames?: string[], customRules?: CustomRule[]): CheckError[] {\n const errors: CheckError[] = [];\n const cursor = tree.walk() as unknown as TreeCursor;\n\n function visit() {\n const node = cursor.currentNode;\n const nodeType = cursor.nodeType;\n\n if (ERROR_NODE_TYPES.has(nodeType) || cursor.nodeIsMissing) {\n errors.push({\n node,\n message: errorMessageForNode(nodeType, node),\n });\n\n // Don't recurse into ERROR nodes \u2014 the children are not meaningful\n if (nodeType === 'ERROR') return;\n }\n\n if (cursor.gotoFirstChild()) {\n do { visit(); } while (cursor.gotoNextSibling());\n cursor.gotoParent();\n }\n }\n\n visit();\n\n // Run balance checker for HTML tag mismatch detection across mustache paths\n const balanceErrors = checkHtmlBalance(tree.rootNode);\n for (const error of balanceErrors) {\n errors.push({ node: error.node, message: error.message });\n }\n\n // Check for unclosed non-void HTML tags\n const unclosedErrors = checkUnclosedTags(tree.rootNode);\n for (const error of unclosedErrors) {\n errors.push({ node: error.node, message: error.message });\n }\n\n // Collect inline disable directives and merge into effective rules\n const customRuleIds = customRules ? new Set(customRules.map(r => r.id)) : undefined;\n const disabledRules = collectDisabledRules(tree.rootNode, customRuleIds);\n const effectiveRules = { ...rules };\n for (const rule of disabledRules) {\n (effectiveRules as Record<string, string>)[rule] = 'off';\n }\n\n // Configurable lint checks\n const sourceText = tree.rootNode.text;\n\n const ruleChecks: { rule: keyof RulesConfig; errors: (entry: RulesConfig[keyof RulesConfig]) => import('./mustacheChecks.js').FixableError[] }[] = [\n { rule: 'nestedDuplicateSections', errors: () => checkNestedSameNameSections(tree.rootNode) },\n { rule: 'unquotedMustacheAttributes', errors: () => checkUnquotedMustacheAttributes(tree.rootNode) },\n { rule: 'consecutiveDuplicateSections', errors: () => checkConsecutiveSameNameSections(tree.rootNode, sourceText) },\n { rule: 'selfClosingNonVoidTags', errors: () => checkSelfClosingNonVoidTags(tree.rootNode) },\n { rule: 'duplicateAttributes', errors: () => checkDuplicateAttributes(tree.rootNode) },\n { rule: 'unescapedEntities', errors: () => checkUnescapedEntities(tree.rootNode) },\n { rule: 'preferMustacheComments', errors: () => checkHtmlComments(tree.rootNode) },\n { rule: 'unrecognizedHtmlTags', errors: () => checkUnrecognizedHtmlTags(tree.rootNode, customTagNames) },\n {\n rule: 'elementContentTooLong',\n errors: (entry) => {\n const elements = (entry && typeof entry === 'object' ? (entry as ElementContentTooLongOptions).elements : undefined) ?? [];\n return checkElementContentTooLong(tree.rootNode, elements);\n },\n },\n ];\n\n for (const { rule, errors: getErrors } of ruleChecks) {\n const { severity, entry } = resolveRuleConfig(effectiveRules, rule);\n if (severity === 'off') continue;\n\n for (const error of getErrors(entry)) {\n errors.push({\n node: error.node,\n message: error.message,\n severity,\n fix: error.fix,\n fixDescription: error.fixDescription,\n ruleName: rule,\n });\n }\n }\n\n // Custom selector-based rules\n if (customRules) {\n for (const rule of customRules) {\n if (disabledRules.has(rule.id)) continue;\n const severity = rule.severity ?? 'error';\n if (severity === 'off') continue;\n const parsed = parseSelectorCached(rule.selector);\n if (!parsed) continue;\n const matches = matchSelector(tree.rootNode, parsed);\n for (const node of matches) {\n errors.push({ node, message: rule.message, severity, ruleName: rule.id });\n }\n }\n }\n\n // Filter out preferMustacheComments warnings on disable-directive comments themselves\n return errors.filter(e =>\n !(e.message.includes('HTML comment found') && parseDisableDirective(e.node, customRuleIds) !== null)\n );\n}\n", "/**\n * Printer module - converts Doc IR to formatted string.\n *\n * The printer traverses the Doc tree and produces a string with proper\n * indentation and line breaks.\n */\n\nimport type { Doc } from './ir.js';\n\nexport interface PrinterOptions {\n /** The indentation string (e.g., ' ' for 2 spaces or '\\t' for tab) */\n indentUnit: string;\n /** Maximum line width before breaking (used for group fitting) */\n printWidth?: number;\n}\n\ninterface PrintState {\n indentLevel: number;\n mode: 'flat' | 'break';\n groupModes: Map<symbol, 'flat' | 'break'>;\n}\n\n/**\n * Print a Doc to a string with the given options.\n */\nexport function print(doc: Doc, options: PrinterOptions): string {\n const output: string[] = [];\n const state: PrintState = { indentLevel: 0, mode: 'break', groupModes: new Map() };\n\n printDoc(doc, state, output, options);\n\n return output.join('');\n}\n\n/**\n * Walk the output buffer backward to find the current column position\n * (characters since the last newline).\n */\nfunction currentColumn(output: string[]): number {\n let col = 0;\n for (let i = output.length - 1; i >= 0; i--) {\n const chunk = output[i];\n const nlIndex = chunk.lastIndexOf('\\n');\n if (nlIndex !== -1) {\n col += chunk.length - nlIndex - 1;\n return col;\n }\n col += chunk.length;\n }\n return col;\n}\n\n/**\n * Check if a Doc tree contains a breakParent anywhere.\n */\nfunction containsBreakParent(doc: Doc): boolean {\n if (typeof doc === 'string') return false;\n switch (doc.type) {\n case 'breakParent':\n return true;\n case 'concat':\n return doc.parts.some(containsBreakParent);\n case 'indent':\n return containsBreakParent(doc.contents);\n case 'group':\n return containsBreakParent(doc.contents);\n case 'fill':\n return doc.parts.some(containsBreakParent);\n case 'ifBreak':\n return (\n containsBreakParent(doc.breakContents) ||\n containsBreakParent(doc.flatContents)\n );\n default:\n return false;\n }\n}\n\nfunction printDoc(\n doc: Doc,\n state: PrintState,\n output: string[],\n options: PrinterOptions\n): void {\n if (typeof doc === 'string') {\n output.push(doc);\n return;\n }\n\n switch (doc.type) {\n case 'concat':\n for (const part of doc.parts) {\n printDoc(part, state, output, options);\n }\n break;\n\n case 'indent':\n state.indentLevel++;\n printDoc(doc.contents, state, output, options);\n state.indentLevel--;\n break;\n\n case 'hardline':\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n break;\n\n case 'softline':\n if (state.mode === 'break') {\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n }\n // In flat mode, softline produces nothing\n break;\n\n case 'line':\n if (state.mode === 'break') {\n output.push('\\n');\n output.push(makeIndent(state.indentLevel, options));\n } else {\n // In flat mode, line produces a space\n output.push(' ');\n }\n break;\n\n case 'group': {\n if (doc.break || containsBreakParent(doc.contents)) {\n // Forced break\n const prevMode = state.mode;\n state.mode = 'break';\n if (doc.id) state.groupModes.set(doc.id, 'break');\n printDoc(doc.contents, state, output, options);\n state.mode = prevMode;\n } else {\n // Try to fit on one line\n const flatOutput: string[] = [];\n const flatState: PrintState = { ...state, mode: 'flat', groupModes: new Map(state.groupModes) };\n printDoc(doc.contents, flatState, flatOutput, options);\n\n const flatContent = flatOutput.join('');\n const printWidth = options.printWidth ?? 80;\n const col = currentColumn(output);\n\n // Check if it fits (no newlines and within width from current column)\n if (\n !flatContent.includes('\\n') &&\n col + flatContent.length <= printWidth\n ) {\n if (doc.id) state.groupModes.set(doc.id, 'flat');\n output.push(flatContent);\n } else {\n // Break mode\n const prevMode = state.mode;\n state.mode = 'break';\n if (doc.id) state.groupModes.set(doc.id, 'break');\n printDoc(doc.contents, state, output, options);\n state.mode = prevMode;\n }\n }\n break;\n }\n\n case 'fill':\n printFill(doc.parts, state, output, options);\n break;\n\n case 'ifBreak': {\n const effectiveMode = doc.groupId\n ? (state.groupModes.get(doc.groupId) ?? state.mode)\n : state.mode;\n if (effectiveMode === 'break') {\n printDoc(doc.breakContents, state, output, options);\n } else {\n printDoc(doc.flatContents, state, output, options);\n }\n break;\n }\n\n case 'breakParent':\n // breakParent is handled by containsBreakParent() in group evaluation.\n // If we reach here outside a group, force break mode.\n state.mode = 'break';\n break;\n }\n}\n\n/**\n * Print fill: content and separator pairs, keeping items on the same line\n * when they fit, breaking when they don't.\n * Parts alternate: [content, separator, content, separator, ..., content]\n */\nfunction printFill(\n parts: Doc[],\n state: PrintState,\n output: string[],\n options: PrinterOptions\n): void {\n if (parts.length === 0) return;\n\n const printWidth = options.printWidth ?? 80;\n\n for (let i = 0; i < parts.length; i++) {\n const content = parts[i];\n const separator = i + 1 < parts.length ? parts[i + 1] : null;\n\n // Print the content\n printDoc(content, state, output, options);\n\n if (separator === null) break;\n\n // Try printing separator + next content flat\n const nextContent = i + 2 < parts.length ? parts[i + 2] : null;\n if (nextContent !== null) {\n const testOutput: string[] = [];\n const flatState: PrintState = { ...state, mode: 'flat' };\n printDoc(separator, flatState, testOutput, options);\n printDoc(nextContent, flatState, testOutput, options);\n const testStr = testOutput.join('');\n const col = currentColumn(output);\n\n if (!testStr.includes('\\n') && col + testStr.length <= printWidth) {\n // Fits: print separator flat\n const sepOutput: string[] = [];\n printDoc(separator, flatState, sepOutput, options);\n output.push(sepOutput.join(''));\n } else {\n // Doesn't fit: print separator in break mode\n printDoc(separator, { ...state, mode: 'break' }, output, options);\n }\n } else {\n // Last separator with no following content, print in current mode\n printDoc(separator, state, output, options);\n }\n\n // Skip the separator in the loop\n i++;\n }\n}\n\nfunction makeIndent(level: number, options: PrinterOptions): string {\n return options.indentUnit.repeat(level);\n}\n", "/**\n * Intermediate Representation (IR) for document formatting.\n *\n * This module defines the Doc type and builder functions for creating\n * formatting commands. The IR is inspired by Prettier's document model.\n */\n\n// Doc types - the IR for formatting\nexport type Doc =\n | string // literal text\n | Concat\n | Indent\n | Hardline\n | Softline\n | Line\n | Group\n | Fill\n | BreakParent\n | IfBreak;\n\nexport interface Concat {\n type: 'concat';\n parts: Doc[];\n}\n\nexport interface Indent {\n type: 'indent';\n contents: Doc;\n}\n\nexport interface Hardline {\n type: 'hardline';\n}\n\nexport interface Softline {\n type: 'softline';\n}\n\nexport interface Line {\n type: 'line';\n}\n\nexport interface Group {\n type: 'group';\n contents: Doc;\n break?: boolean;\n id?: symbol;\n}\n\nexport interface Fill {\n type: 'fill';\n parts: Doc[];\n}\n\nexport interface BreakParent {\n type: 'breakParent';\n}\n\nexport interface IfBreak {\n type: 'ifBreak';\n breakContents: Doc;\n flatContents: Doc;\n groupId?: symbol;\n}\n\n// Constants\nexport const hardline: Hardline = { type: 'hardline' };\nexport const softline: Softline = { type: 'softline' };\nexport const line: Line = { type: 'line' };\nexport const breakParent: BreakParent = { type: 'breakParent' };\nexport const empty = '';\n\n/**\n * Create a literal text node.\n */\nexport function text(value: string): string {\n return value;\n}\n\n/**\n * Concatenate multiple docs into a single doc.\n */\nexport function concat(parts: Doc[]): Doc {\n // Flatten nested concats and filter empty strings\n const flattened: Doc[] = [];\n for (const part of parts) {\n if (part === '') continue;\n if (typeof part === 'object' && part.type === 'concat') {\n flattened.push(...part.parts);\n } else {\n flattened.push(part);\n }\n }\n\n if (flattened.length === 0) return '';\n if (flattened.length === 1) return flattened[0];\n\n return { type: 'concat', parts: flattened };\n}\n\n/**\n * Indent the contents by one level.\n */\nexport function indent(contents: Doc): Doc {\n if (contents === '') return '';\n return { type: 'indent', contents };\n}\n\n/**\n * Indent the contents by N levels.\n */\nexport function indentN(contents: Doc, n: number): Doc {\n if (n <= 0 || contents === '') return contents;\n let result = contents;\n for (let i = 0; i < n; i++) {\n result = indent(result);\n }\n return result;\n}\n\n/**\n * Create a group that may be printed flat or broken across lines.\n * When `shouldBreak` is true, the group will always break.\n * When `id` is set, the group's mode can be referenced by `ifBreak` nodes.\n */\nexport function group(contents: Doc, options?: { shouldBreak?: boolean; id?: symbol }): Doc {\n if (contents === '') return '';\n const shouldBreak = options?.shouldBreak;\n return { type: 'group', contents, break: shouldBreak || undefined, id: options?.id };\n}\n\n/**\n * Create an ifBreak node that prints different content depending on\n * whether the enclosing group breaks or stays flat.\n * When `groupId` is set, checks that specific group's mode instead.\n */\nexport function ifBreak(breakContents: Doc, flatContents: Doc, options?: { groupId?: symbol }): Doc {\n return { type: 'ifBreak', breakContents, flatContents, groupId: options?.groupId };\n}\n\n/**\n * Create a fill for inline content that wraps when needed.\n * Parts alternate between content and separators.\n */\nexport function fill(parts: Doc[]): Doc {\n const filtered = parts.filter((p) => p !== '');\n if (filtered.length === 0) return '';\n if (filtered.length === 1) return filtered[0];\n return { type: 'fill', parts: filtered };\n}\n\n/**\n * Join docs with a separator.\n */\nexport function join(separator: Doc, docs: Doc[]): Doc {\n const parts: Doc[] = [];\n for (let i = 0; i < docs.length; i++) {\n if (docs[i] === '') continue;\n if (parts.length > 0) {\n parts.push(separator);\n }\n parts.push(docs[i]);\n }\n return concat(parts);\n}\n\n// Type guards for working with Doc types\nexport function isConcat(doc: Doc): doc is Concat {\n return typeof doc === 'object' && doc.type === 'concat';\n}\n\nexport function isIndent(doc: Doc): doc is Indent {\n return typeof doc === 'object' && doc.type === 'indent';\n}\n\nexport function isHardline(doc: Doc): doc is Hardline {\n return typeof doc === 'object' && doc.type === 'hardline';\n}\n\nexport function isSoftline(doc: Doc): doc is Softline {\n return typeof doc === 'object' && doc.type === 'softline';\n}\n\nexport function isLine(doc: Doc): doc is Line {\n return typeof doc === 'object' && doc.type === 'line';\n}\n\nexport function isGroup(doc: Doc): doc is Group {\n return typeof doc === 'object' && doc.type === 'group';\n}\n\nexport function isFill(doc: Doc): doc is Fill {\n return typeof doc === 'object' && doc.type === 'fill';\n}\n\nexport function isBreakParent(doc: Doc): doc is BreakParent {\n return typeof doc === 'object' && doc.type === 'breakParent';\n}\n\nexport function isIfBreak(doc: Doc): doc is IfBreak {\n return typeof doc === 'object' && doc.type === 'ifBreak';\n}\n", "/**\n * Utility functions for formatting.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\n\n// Re-export getTagName from the canonical location\nexport { getTagName } from '../nodeHelpers.js';\n\n/**\n * Normalize text content - collapse horizontal whitespace while preserving line breaks.\n */\nexport function normalizeText(text: string): string {\n // Split by newlines, normalize each line, then rejoin\n // This preserves intentional line breaks while collapsing spaces\n return text\n .split('\\n')\n .map((line) => line.replace(/[ \\t]+/g, ' ').trim())\n .filter((line, i, arr) => line || (i > 0 && i < arr.length - 1)) // Keep non-empty lines\n .join('\\n');\n}\n\n/**\n * Get visible children of a node (excluding anonymous nodes starting with _).\n */\nexport function getVisibleChildren(node: SyntaxNode): SyntaxNode[] {\n const children: SyntaxNode[] = [];\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && !child.type.startsWith('_')) {\n children.push(child);\n }\n }\n return children;\n}\n\n/**\n * Calculate the indent level of a node based on its parent chain.\n */\nexport function calculateIndentLevel(\n node: SyntaxNode,\n isBlockLevel: (node: SyntaxNode) => boolean,\n hasImplicitEndTags: (nodes: SyntaxNode[]) => boolean,\n getContentNodes: (node: SyntaxNode) => SyntaxNode[]\n): number {\n let level = 0;\n let current = node.parent;\n while (current) {\n if (isBlockLevel(current)) {\n // Mustache sections only increase indentation if they have complete HTML\n // (no implicit end tags crossing boundaries)\n if (\n current.type === 'mustache_section' ||\n current.type === 'mustache_inverted_section'\n ) {\n const contentNodes = getContentNodes(current);\n if (!hasImplicitEndTags(contentNodes)) {\n level++;\n }\n } else {\n level++;\n }\n }\n current = current.parent;\n }\n return level;\n}\n\n/**\n * Normalize whitespace inside a single mustache expression.\n * Handles triple ({{{...}}}), prefixed ({{#, {{/, {{^, {{!, {{>), and plain ({{...}}).\n * For multiline comments, preserves internal newlines, only normalizes space adjacent to delimiters.\n */\nexport function normalizeMustacheWhitespace(raw: string, addSpaces: boolean): string {\n const space = addSpaces ? ' ' : '';\n\n // Triple mustache: {{{...}}}\n const tripleMatch = raw.match(/^\\{\\{\\{([\\s\\S]*)\\}\\}\\}$/);\n if (tripleMatch) {\n const inner = tripleMatch[1].trim();\n return `{{{${space}${inner}${space}}}}`;\n }\n\n // Prefixed: {{#, {{/, {{^, {{!, {{>\n const prefixedMatch = raw.match(/^\\{\\{([#/^!>])([\\s\\S]*)\\}\\}$/);\n if (prefixedMatch) {\n const prefix = prefixedMatch[1];\n const inner = prefixedMatch[2];\n\n // Multiline comments: preserve internal newlines, always use spaces\n if (prefix === '!' && inner.includes('\\n')) {\n const lines = inner.split('\\n');\n const first = lines[0].trimStart();\n const last = lines[lines.length - 1].trimEnd();\n if (lines.length === 1) {\n return `{{${prefix} ${first} }}`;\n }\n const middle = lines.slice(1, -1);\n return `{{${prefix} ${first}\\n${middle.join('\\n')}\\n${last} }}`;\n }\n\n const trimmed = inner.trim();\n // Comments always get spaces for readability, regardless of mustacheSpaces setting\n const s = prefix === '!' ? ' ' : space;\n return `{{${prefix}${s}${trimmed}${s}}}`;\n }\n\n // Plain: {{...}}\n const plainMatch = raw.match(/^\\{\\{([\\s\\S]*)\\}\\}$/);\n if (plainMatch) {\n const inner = plainMatch[1].trim();\n return `{{${space}${inner}${space}}}`;\n }\n\n return raw;\n}\n\n/**\n * Normalize whitespace in ALL mustache expressions within a string.\n * Used for force-inlined sections where the full section text (e.g. `{{#plural}}s{{/plural}}`)\n * is emitted as one string.\n */\nexport function normalizeMustacheWhitespaceAll(raw: string, addSpaces: boolean): string {\n // Match triple mustache first, then double\n return raw.replace(/\\{\\{\\{[\\s\\S]*?\\}\\}\\}|\\{\\{[\\s\\S]*?\\}\\}/g, (match) => {\n return normalizeMustacheWhitespace(match, addSpaces);\n });\n}\n\n/**\n * Check if a node is a format-ignore directive comment.\n * Returns the directive type or null if not a directive.\n */\nexport function getIgnoreDirective(\n node: SyntaxNode\n): 'ignore' | 'ignore-start' | 'ignore-end' | null {\n if (node.type !== 'html_comment' && node.type !== 'mustache_comment') {\n return null;\n }\n\n let inner: string | null = null;\n\n if (node.type === 'html_comment') {\n // <!-- ... -->\n const match = node.text.match(/^<!--([\\s\\S]*)-->$/);\n if (match) {\n inner = match[1].trim();\n }\n } else {\n // {{! ... }}\n const match = node.text.match(/^\\{\\{!([\\s\\S]*)\\}\\}$/);\n if (match) {\n inner = match[1].trim();\n }\n }\n\n if (!inner) return null;\n\n if (inner === 'htmlmustache-ignore') return 'ignore';\n if (inner === 'htmlmustache-ignore-start') return 'ignore-start';\n if (inner === 'htmlmustache-ignore-end') return 'ignore-end';\n\n return null;\n}\n\n/**\n * Find the smallest node that contains the entire range.\n */\nexport function findContainingNode(\n node: SyntaxNode,\n startOffset: number,\n endOffset: number\n): SyntaxNode | null {\n if (node.startIndex > endOffset || node.endIndex < startOffset) {\n return null;\n }\n\n // Check children first for a more specific match\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && child.startIndex <= startOffset && child.endIndex >= endOffset) {\n const deeper = findContainingNode(child, startOffset, endOffset);\n if (deeper) return deeper;\n }\n }\n\n // This node contains the range\n if (node.startIndex <= startOffset && node.endIndex >= endOffset) {\n return node;\n }\n\n return null;\n}\n", "import type { Node as SyntaxNode } from 'web-tree-sitter';\nimport type { CSSDisplay } from './formatting/classifier.js';\n\nexport type CustomCodeTagIndentMode = 'never' | 'always' | 'attribute';\n\nexport interface CustomCodeTagConfig {\n name: string;\n display?: CSSDisplay;\n languageAttribute?: string;\n languageMap?: Record<string, string>;\n languageDefault?: string;\n indent?: CustomCodeTagIndentMode;\n indentAttribute?: string;\n}\n\n/** Alias for CustomCodeTagConfig (unified name). */\nexport type CustomTagConfig = CustomCodeTagConfig;\n\n/**\n * Check if a custom tag config represents a code tag (has language settings).\n * Code tags get preserved content and default to block display.\n */\nexport function isCodeTag(config: CustomCodeTagConfig): boolean {\n return !!(config.languageAttribute || config.languageDefault);\n}\n\nexport interface CustomCodeTagContent {\n text: string;\n languageId: string;\n startRow: number;\n startCol: number;\n}\n\n/**\n * Get the attribute value for a given attribute name from an element's start tag.\n */\nexport function getAttributeValue(node: SyntaxNode, attrName: string): string | null {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const attr = child.child(j);\n if (attr?.type === 'html_attribute') {\n let name = '';\n let value = '';\n for (let k = 0; k < attr.childCount; k++) {\n const part = attr.child(k);\n if (part?.type === 'html_attribute_name') name = part.text.toLowerCase();\n if (part?.type === 'html_quoted_attribute_value') value = part.text.replace(/^[\"']|[\"']$/g, '');\n if (part?.type === 'html_attribute_value') value = part.text;\n }\n if (name === attrName.toLowerCase()) {\n return value;\n }\n }\n }\n }\n }\n return null;\n}\n\n/**\n * Resolve the language ID for a custom code tag element.\n */\nfunction resolveCustomCodeLanguage(node: SyntaxNode, config: CustomCodeTagConfig): string | null {\n if (config.languageAttribute) {\n const attrValue = getAttributeValue(node, config.languageAttribute);\n if (attrValue) {\n if (config.languageMap && config.languageMap[attrValue]) {\n return config.languageMap[attrValue];\n }\n return attrValue.toLowerCase();\n }\n }\n return config.languageDefault?.toLowerCase() ?? null;\n}\n\n/**\n * Walk the tree to find custom code tag elements and extract their content + language.\n */\nexport function findCustomCodeTagContent(\n rootNode: SyntaxNode,\n configs: CustomCodeTagConfig[],\n): CustomCodeTagContent[] {\n if (configs.length === 0) return [];\n\n const configsByName = new Map<string, CustomCodeTagConfig>();\n for (const config of configs) {\n if (config.languageAttribute || config.languageDefault) {\n configsByName.set(config.name.toLowerCase(), config);\n }\n }\n if (configsByName.size === 0) return [];\n\n const results: CustomCodeTagContent[] = [];\n\n const walk = (node: SyntaxNode) => {\n if (node.type === 'html_element' || node.type === 'html_raw_element') {\n let tagName = '';\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const nameNode = child.child(j);\n if (nameNode?.type === 'html_tag_name') {\n tagName = nameNode.text.toLowerCase();\n break;\n }\n }\n break;\n }\n }\n\n const config = configsByName.get(tagName);\n if (config) {\n const languageId = resolveCustomCodeLanguage(node, config);\n if (languageId) {\n let startTag: SyntaxNode | null = null;\n let endTag: SyntaxNode | null = null;\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') startTag = child;\n if (child?.type === 'html_end_tag') endTag = child;\n if (child?.type === 'html_raw_text') {\n results.push({\n text: child.text,\n languageId,\n startRow: child.startPosition.row,\n startCol: child.startPosition.column,\n });\n }\n }\n\n if (startTag && node.type === 'html_element') {\n const contentStartIndex = startTag.endIndex;\n const contentEndIndex = endTag ? endTag.startIndex : node.endIndex;\n const contentText = node.tree.rootNode.text.slice(contentStartIndex, contentEndIndex);\n if (contentText.length > 0) {\n results.push({\n text: contentText,\n languageId,\n startRow: startTag.endPosition.row,\n startCol: startTag.endPosition.column,\n });\n }\n }\n }\n }\n }\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child) walk(child);\n }\n };\n\n walk(rootNode);\n return results;\n}\n", "/**\n * Node classifier - determines how to format different node types.\n *\n * This module uses CSS display values to classify HTML elements, matching\n * Prettier's approach to whitespace sensitivity in HTML formatting.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport { getTagName } from './utils.js';\nimport { isMustacheSection, isRawContentElement, isHtmlElementType } from '../nodeHelpers.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\nimport { isCodeTag } from '../customCodeTags.js';\n\nconst EMPTY_MAP: Map<string, CustomCodeTagConfig> = new Map();\n\nexport type CSSDisplay =\n | 'block'\n | 'inline'\n | 'inline-block'\n | 'table-row'\n | 'table-cell'\n | 'table'\n | 'table-row-group'\n | 'table-header-group'\n | 'table-footer-group'\n | 'table-column'\n | 'table-column-group'\n | 'table-caption'\n | 'list-item'\n | 'ruby'\n | 'ruby-base'\n | 'ruby-text'\n | 'none';\n\n/**\n * Default CSS display values for HTML elements, matching browser defaults.\n * Elements not in this map default to 'inline'.\n */\nconst CSS_DISPLAY_MAP: Record<string, CSSDisplay> = {\n // Block elements\n address: 'block',\n article: 'block',\n aside: 'block',\n blockquote: 'block',\n body: 'block',\n center: 'block',\n dd: 'block',\n details: 'block',\n dialog: 'block',\n dir: 'block',\n div: 'block',\n dl: 'block',\n dt: 'block',\n fieldset: 'block',\n figcaption: 'block',\n figure: 'block',\n footer: 'block',\n form: 'block',\n h1: 'block',\n h2: 'block',\n h3: 'block',\n h4: 'block',\n h5: 'block',\n h6: 'block',\n header: 'block',\n hgroup: 'block',\n hr: 'block',\n html: 'block',\n legend: 'block',\n listing: 'block',\n main: 'block',\n menu: 'block',\n nav: 'block',\n ol: 'block',\n p: 'block',\n plaintext: 'block',\n pre: 'block',\n search: 'block',\n section: 'block',\n summary: 'block',\n ul: 'block',\n xmp: 'block',\n\n // List items\n li: 'list-item',\n\n // Table elements\n table: 'table',\n caption: 'table-caption',\n colgroup: 'table-column-group',\n col: 'table-column',\n thead: 'table-header-group',\n tbody: 'table-row-group',\n tfoot: 'table-footer-group',\n tr: 'table-row',\n td: 'table-cell',\n th: 'table-cell',\n\n // Inline-block elements\n button: 'inline-block',\n img: 'inline-block',\n input: 'inline-block',\n select: 'inline-block',\n textarea: 'inline-block',\n video: 'inline-block',\n audio: 'inline-block',\n canvas: 'inline-block',\n embed: 'inline-block',\n iframe: 'inline-block',\n object: 'inline-block',\n\n // None\n head: 'none',\n link: 'none',\n meta: 'none',\n script: 'none',\n style: 'none',\n title: 'none',\n template: 'none',\n\n // Ruby\n ruby: 'ruby',\n rb: 'ruby-base',\n rt: 'ruby-text',\n rp: 'none',\n};\n\n// HTML inline elements that should not cause line breaks\nexport const INLINE_ELEMENTS = new Set([\n 'a',\n 'abbr',\n 'acronym',\n 'b',\n 'bdo',\n 'big',\n 'br',\n 'button',\n 'cite',\n 'code',\n 'dfn',\n 'em',\n 'i',\n 'img',\n 'input',\n 'kbd',\n 'label',\n 'map',\n 'object',\n 'output',\n 'q',\n 'samp',\n 'script',\n 'select',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'sup',\n 'textarea',\n 'time',\n 'tt',\n 'u',\n 'var',\n 'wbr',\n]);\n\n// Elements whose content should be preserved as-is\nexport const PRESERVE_CONTENT_ELEMENTS = new Set([\n 'pre',\n 'code',\n 'textarea',\n 'script',\n 'style',\n]);\n\n/**\n * Get the CSS display value for a node.\n */\nexport function getCSSDisplay(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): CSSDisplay {\n const type = node.type;\n\n if (type === 'html_element') {\n const tagName = getTagName(node);\n if (tagName) {\n const lower = tagName.toLowerCase();\n const config = customTags.get(lower);\n if (config) {\n // Explicit display takes priority\n if (config.display) return config.display;\n // Code tags default to block\n if (isCodeTag(config)) return 'block';\n // Custom tags default to inline-block (inline externally, block internally)\n return 'inline-block';\n }\n return CSS_DISPLAY_MAP[lower] ?? 'inline';\n }\n return 'block'; // Unknown elements default to block\n }\n\n if (isRawContentElement(node)) {\n return 'block';\n }\n\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags) ? 'block' : 'inline';\n }\n\n // Text, interpolation, comments, etc. are inline\n return 'inline';\n}\n\n/**\n * Check if a display value means the element is whitespace-insensitive\n * (i.e., we can freely add/remove whitespace around it).\n */\nexport function isWhitespaceInsensitive(display: CSSDisplay): boolean {\n switch (display) {\n case 'block':\n case 'list-item':\n case 'table':\n case 'table-row':\n case 'table-row-group':\n case 'table-header-group':\n case 'table-footer-group':\n case 'table-column':\n case 'table-column-group':\n case 'table-caption':\n case 'table-cell':\n case 'none':\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Check if a node represents a block-level element that should cause indentation.\n * Delegates to getCSSDisplay for classification.\n */\nexport function isBlockLevel(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n // Mustache sections are block-level only if they contain block-level content\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags);\n }\n\n // HTML elements: check CSS display\n if (type === 'html_element') {\n const display = getCSSDisplay(node, customTags);\n return isWhitespaceInsensitive(display);\n }\n\n // Script, style, and raw elements are block-level\n if (isRawContentElement(node)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if an HTML element is an inline element.\n */\nexport function isInlineElement(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n if (node.type !== 'html_element') {\n return false;\n }\n const display = getCSSDisplay(node, customTags);\n return !isWhitespaceInsensitive(display);\n}\n\n/**\n * Check if element content should be preserved as-is.\n */\nexport function shouldPreserveContent(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n if (isRawContentElement(node)) {\n return true;\n }\n\n if (type === 'html_element') {\n const tagName = getTagName(node);\n if (!tagName) return false;\n const lower = tagName.toLowerCase();\n if (PRESERVE_CONTENT_ELEMENTS.has(lower)) return true;\n // Only code tags (with language config) get preserved content, not display-only custom tags\n const config = customTags.get(lower);\n if (config && isCodeTag(config)) return true;\n }\n\n return false;\n}\n\n/**\n * Check if a mustache section contains any block-level content.\n * A section has block content if:\n * - It contains block-level HTML elements, OR\n * - It contains any HTML elements with implicit end tags (HTML crossing boundaries)\n */\nexport function hasBlockContent(sectionNode: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const contentNodes = getContentNodes(sectionNode);\n\n // Check for implicit end tags first - this makes the section block-level\n if (hasImplicitEndTags(contentNodes)) {\n return true;\n }\n\n // Check for block-level elements\n for (const node of contentNodes) {\n if (isBlockLevelContent(node, customTags)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if a node is block-level content (for determining mustache section treatment).\n */\nexport function isBlockLevelContent(node: SyntaxNode, customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP): boolean {\n const type = node.type;\n\n // Any HTML element is considered block-level content for mustache sections\n // This ensures {{#section}}<span>...</span>{{/section}} gets formatted as a block\n if (type === 'html_element') {\n return true;\n }\n\n // Script/style/raw are block-level\n if (isRawContentElement(node)) {\n return true;\n }\n\n // Nested mustache sections - recurse\n if (isMustacheSection(node)) {\n return hasBlockContent(node, customTags);\n }\n\n // Text, interpolation, comments, etc. are inline\n return false;\n}\n\n/**\n * Get the content nodes from a mustache section (excluding begin/end tags).\n */\nexport function getContentNodes(sectionNode: SyntaxNode): SyntaxNode[] {\n const isInverted = sectionNode.type === 'mustache_inverted_section';\n const beginType = isInverted\n ? 'mustache_inverted_section_begin'\n : 'mustache_section_begin';\n const endType = isInverted\n ? 'mustache_inverted_section_end'\n : 'mustache_section_end';\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < sectionNode.childCount; i++) {\n const child = sectionNode.child(i);\n if (!child) continue;\n if (\n child.type !== beginType &&\n child.type !== endType &&\n child.type !== 'mustache_erroneous_section_end' &&\n child.type !== 'mustache_erroneous_inverted_section_end' &&\n !child.type.startsWith('_')\n ) {\n contentNodes.push(child);\n }\n }\n return contentNodes;\n}\n\n/**\n * Check if any HTML elements in the given nodes have implicit end tags\n * (forced closed by mustache section end rather than explicit </tag>).\n */\nexport function hasImplicitEndTags(nodes: SyntaxNode[]): boolean {\n for (const node of nodes) {\n if (hasImplicitEndTagsRecursive(node)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasImplicitEndTagsRecursive(node: SyntaxNode): boolean {\n // Check if this HTML element has a forced/implicit end tag\n if (node.type === 'html_element') {\n let hasStartTag = false;\n let hasEndTag = false;\n let hasContentChildren = false;\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n if (child.type === 'html_start_tag') hasStartTag = true;\n else if (child.type === 'html_end_tag') hasEndTag = true;\n else if (child.type === 'html_forced_end_tag') return true;\n else if (!child.type.startsWith('_')) hasContentChildren = true;\n }\n // Void elements (start tag only, no content, no end tag) aren't boundary-crossing\n if (hasStartTag && !hasEndTag && hasContentChildren) return true;\n }\n\n // Check children recursively\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && hasImplicitEndTagsRecursive(child)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if a node is inline content that participates in text flow.\n * Mustache interpolation, triple, and partial nodes behave like text.\n */\nfunction isInlineContentNode(node: SyntaxNode): boolean {\n if (node.type === 'text') return node.text.trim().length > 0;\n return (\n node.type === 'mustache_interpolation' ||\n node.type === 'mustache_triple' ||\n node.type === 'mustache_partial'\n );\n}\n\n/**\n * Check if a node is part of a text flow (adjacent to non-whitespace text).\n * Nodes that are part of text flow should stay inline.\n */\nexport function isInTextFlow(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[]\n): boolean {\n // Check previous sibling\n if (index > 0) {\n const prev = nodes[index - 1];\n if (prev.type === 'text' && prev.text.trim().length > 0) {\n return true;\n }\n }\n\n // Check next sibling\n if (index < nodes.length - 1) {\n const next = nodes[index + 1];\n if (next.type === 'text' && next.text.trim().length > 0) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if there's inline content (mustache interpolation, non-empty text, etc.)\n * adjacent to the node at `index`, looking past whitespace-only text nodes.\n */\nfunction hasAdjacentInlineContent(\n index: number,\n nodes: SyntaxNode[]\n): boolean {\n // Look backward past whitespace-only text\n for (let i = index - 1; i >= 0; i--) {\n const n = nodes[i];\n if (n.type === 'text' && n.text.trim().length === 0) continue;\n if (isInlineContentNode(n)) return true;\n break;\n }\n // Look forward past whitespace-only text\n for (let i = index + 1; i < nodes.length; i++) {\n const n = nodes[i];\n if (n.type === 'text' && n.text.trim().length === 0) continue;\n if (isInlineContentNode(n)) return true;\n break;\n }\n return false;\n}\n\n/**\n * Check if an HTML element should stay inline.\n * Elements stay inline if they're part of a text flow or adjacent to other inline elements.\n */\nexport function shouldHtmlElementStayInline(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[],\n customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP\n): boolean {\n if (node.type !== 'html_element') {\n return false;\n }\n\n // Block-display elements (table, div, etc.) should never stay inline\n if (isWhitespaceInsensitive(getCSSDisplay(node, customTags))) {\n return false;\n }\n\n // If the element is part of a text flow, keep it inline\n if (isInTextFlow(node, index, nodes)) {\n return true;\n }\n\n // Check for adjacent inline content (mustache interpolation, text, etc.)\n // past whitespace-only text nodes \u2014 e.g., <i>icon</i>\\n {{partial}}%\n if (hasAdjacentInlineContent(index, nodes)) {\n return true;\n }\n\n // If adjacent to another inline HTML element, stay inline (e.g., <code>5</code><code>-17</code>)\n // Check if there's a chain of HTML elements with text - they should all stay inline together\n if (index > 0) {\n const prev = nodes[index - 1];\n if (prev.type === 'html_element' && isInTextFlow(prev, index - 1, nodes)) {\n return true;\n }\n }\n if (index < nodes.length - 1) {\n const next = nodes[index + 1];\n if (next.type === 'html_element' && isInTextFlow(next, index + 1, nodes)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine if a node should be treated as block-level for formatting purposes.\n */\nexport function shouldTreatAsBlock(\n node: SyntaxNode,\n index: number,\n nodes: SyntaxNode[],\n customTags: Map<string, CustomCodeTagConfig> = EMPTY_MAP\n): boolean {\n const isHtmlEl = isHtmlElementType(node);\n const isMustacheSec = isMustacheSection(node);\n\n if (node.type === 'html_erroneous_end_tag') return true;\n\n return (\n (isHtmlEl && !shouldHtmlElementStayInline(node, index, nodes, customTags)) ||\n (isMustacheSec && !isInTextFlow(node, index, nodes)) ||\n (isBlockLevel(node, customTags) && !isInTextFlow(node, index, nodes))\n );\n}\n", "/**\n * Formatters - convert AST nodes to Doc IR.\n *\n * This module converts tree-sitter AST nodes to the Doc intermediate\n * representation. It uses CSS display-based classification to determine\n * whitespace sensitivity and wraps elements in groups so the printer\n * can decide flat vs break based on print width.\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport type { TextDocument } from 'vscode-languageserver-textdocument';\nimport {\n Doc,\n concat,\n fill,\n hardline,\n softline,\n line,\n indent,\n indentN,\n group,\n text,\n empty,\n ifBreak,\n isLine,\n} from './ir.js';\nimport {\n isBlockLevel,\n shouldPreserveContent,\n hasImplicitEndTags,\n isInTextFlow,\n shouldTreatAsBlock,\n getCSSDisplay,\n isWhitespaceInsensitive,\n} from './classifier.js';\nimport { normalizeText, getVisibleChildren, normalizeMustacheWhitespace, normalizeMustacheWhitespaceAll, getIgnoreDirective, getTagName } from './utils.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\nimport { getAttributeValue } from '../customCodeTags.js';\nimport { isRawContentElement } from '../nodeHelpers.js';\nimport type { NoBreakDelimiter } from '../configSchema.js';\n\nexport interface FormatterContext {\n document: TextDocument;\n customTags?: Map<string, CustomCodeTagConfig>;\n embeddedFormatted?: Map<number, string>;\n mustacheSpaces?: boolean;\n noBreakDelimiters?: NoBreakDelimiter[];\n}\n\n/**\n * Check if an attribute value is truthy (not null, empty, \"false\", or \"0\").\n */\nexport function isAttributeTruthy(value: string | null): boolean {\n if (value === null || value === '' || value === 'false' || value === '0') {\n return false;\n }\n return true;\n}\n\n/**\n * Dedent content by stripping leading/trailing empty lines and removing the\n * minimum common indentation from all non-empty lines.\n */\nexport function dedentContent(rawContent: string): string {\n const lines = rawContent.split('\\n');\n\n // Strip leading empty lines\n while (lines.length > 0 && lines[0].trim() === '') {\n lines.shift();\n }\n // Strip trailing empty lines\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') {\n lines.pop();\n }\n\n if (lines.length === 0) return '';\n\n // Find minimum indentation across non-empty lines\n let minIndent = Infinity;\n for (const l of lines) {\n if (l.trim() === '') continue;\n const match = l.match(/^(\\s*)/);\n if (match && match[1].length < minIndent) {\n minIndent = match[1].length;\n }\n }\n if (minIndent === Infinity) minIndent = 0;\n\n // Strip common indent\n return lines.map(l => l.trim() === '' ? '' : l.slice(minIndent)).join('\\n');\n}\n\n/**\n * Resolve whether a custom code tag's content should be indented.\n */\nfunction resolveIndentMode(\n node: SyntaxNode,\n config: CustomCodeTagConfig\n): boolean {\n const mode = config.indent ?? 'never';\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n // mode === 'attribute'\n if (!config.indentAttribute) return false;\n const value = getAttributeValue(node, config.indentAttribute);\n return isAttributeTruthy(value);\n}\n\nfunction getTagNameFromStartTag(startTag: SyntaxNode): string | null {\n for (let i = 0; i < startTag.childCount; i++) {\n const child = startTag.child(i);\n if (child?.type === 'html_tag_name') return child.text.toLowerCase();\n }\n return null;\n}\n\nfunction mustacheText(raw: string, context: FormatterContext): string {\n if (context.mustacheSpaces !== undefined) {\n return normalizeMustacheWhitespace(raw, context.mustacheSpaces);\n }\n return raw;\n}\n\n/**\n * Format the document root node.\n */\nexport function formatDocument(node: SyntaxNode, context: FormatterContext): Doc {\n const children = getVisibleChildren(node);\n const content = formatBlockChildren(children, context);\n return concat([content, hardline]);\n}\n\n/**\n * Format a node based on its type.\n * @param forceInline - If true, format as inline even if content would normally be block-level\n */\nexport function formatNode(\n node: SyntaxNode,\n context: FormatterContext,\n forceInline = false\n): Doc {\n const type = node.type;\n\n switch (type) {\n case 'document':\n return formatDocument(node, context);\n\n case 'html_element':\n return formatHtmlElement(node, context, forceInline);\n\n case 'html_script_element':\n case 'html_style_element':\n case 'html_raw_element':\n return formatScriptStyleElement(node, context);\n\n case 'mustache_section':\n case 'mustache_inverted_section':\n if (forceInline) {\n if (context.mustacheSpaces !== undefined) {\n return text(normalizeMustacheWhitespaceAll(node.text, context.mustacheSpaces));\n }\n return text(node.text);\n }\n return formatMustacheSection(node, context);\n\n case 'mustache_interpolation':\n case 'mustache_triple':\n case 'mustache_partial':\n case 'mustache_comment':\n return text(mustacheText(node.text, context));\n\n case 'html_comment':\n case 'html_doctype':\n case 'html_entity':\n case 'html_erroneous_end_tag':\n return text(node.text);\n\n case 'text':\n return formatText(node);\n\n default:\n return text(node.text);\n }\n}\n\n/**\n * Format a text node.\n */\nexport function formatText(node: SyntaxNode): Doc {\n return text(normalizeText(node.text));\n}\n\n/**\n * Format an HTML element.\n */\nexport function formatHtmlElement(node: SyntaxNode, context: FormatterContext, forceInline = false): Doc {\n const tags = context.customTags;\n const display = getCSSDisplay(node, tags);\n const isBlock = isWhitespaceInsensitive(display);\n const preserveContent = shouldPreserveContent(node, tags);\n\n // Self-closing tag\n const selfClosing =\n node.childCount === 1 && node.child(0)?.type === 'html_self_closing_tag';\n\n if (selfClosing) {\n const tag = node.child(0)!;\n return formatStartTag(tag, context);\n }\n\n // Get start tag, children, and end tag\n let startTag: SyntaxNode | null = null;\n let endTag: SyntaxNode | null = null;\n let hasRealEndTag = false;\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_start_tag') {\n startTag = child;\n } else if (child.type === 'html_end_tag') {\n endTag = child;\n hasRealEndTag = true;\n } else if (child.type === 'html_forced_end_tag') {\n endTag = child;\n } else if (!child.type.startsWith('_')) {\n contentNodes.push(child);\n }\n }\n\n const parts: Doc[] = [];\n\n // Format start tag\n if (startTag) {\n parts.push(formatStartTag(startTag, context));\n }\n\n // Check if content contains any HTML element children\n const hasHtmlElementChildren = contentNodes.some(\n (child) =>\n child.type === 'html_element' ||\n isRawContentElement(child) ||\n isBlockLevel(child, tags)\n );\n\n // Handle content\n if (preserveContent) {\n // Check if this custom code tag should be indented\n const tagNameLower = startTag ? getTagNameFromStartTag(startTag) : null;\n const tagConfig = tagNameLower ? context.customTags?.get(tagNameLower) : undefined;\n const shouldIndent = tagConfig ? resolveIndentMode(node, tagConfig) : false;\n\n if (shouldIndent && startTag && endTag) {\n const rawContent = context.document.getText().slice(\n startTag.endIndex,\n endTag.startIndex\n );\n const dedented = dedentContent(rawContent);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n // Empty line: literal \\n avoids indentation from the printer\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else if (startTag && endTag) {\n // Use raw document text to preserve all whitespace, since tree-sitter\n // text nodes strip boundary whitespace from regular html_element children\n const rawContent = context.document.getText().slice(\n startTag.endIndex,\n endTag.startIndex\n );\n // For block-level elements, replace trailing newline+whitespace with\n // a hardline so the closing tag gets proper indentation from the printer\n const trailingMatch = isBlock ? rawContent.match(/\\n[\\t ]*$/) : null;\n if (trailingMatch) {\n parts.push(text(rawContent.slice(0, -trailingMatch[0].length)));\n parts.push(hardline);\n } else {\n parts.push(text(rawContent));\n }\n } else {\n for (const child of contentNodes) {\n parts.push(text(child.text));\n }\n }\n } else if (!isBlock && (!hasHtmlElementChildren || (forceInline && display !== 'inline-block' && !contentNodes.some(\n (child) => isRawContentElement(child) || isBlockLevel(child, tags)\n )))) {\n // Standalone element with attributes: use outer group wrapping so content\n // goes on its own line when attributes wrap (matches Prettier's printTag)\n if (!forceInline && startTag && startTagHasAttributes(startTag)) {\n const formattedContent = formatBlockChildren(contentNodes, context);\n if (hasDocContent(formattedContent)) {\n const bareStartTag = formatStartTag(startTag, context, true);\n const outerParts: Doc[] = [\n group(bareStartTag),\n indent(concat([softline, formattedContent])),\n ];\n if (hasRealEndTag) {\n outerParts.push(softline);\n }\n if (endTag) {\n outerParts.push(formatEndTag(endTag));\n }\n return group(concat(outerParts));\n }\n }\n\n // Inline element with only text/interpolation content - keep tight\n // Preserve whitespace gaps between sibling nodes (e.g. space between\n // mustache_interpolation and text that tree-sitter puts in the gap)\n let prevEnd = startTag ? startTag.endIndex : -1;\n for (const child of contentNodes) {\n if (prevEnd >= 0 && child.startIndex > prevEnd) {\n const gap = context.document.getText().slice(prevEnd, child.startIndex);\n if (/\\s/.test(gap)) {\n parts.push(text(' '));\n }\n }\n parts.push(formatNode(child, context, forceInline));\n prevEnd = child.endIndex;\n }\n } else {\n // Block element or inline-with-block-children: use hardline + indent\n const formattedContent = formatBlockChildren(contentNodes, context);\n const hasContent = hasDocContent(formattedContent);\n\n if (hasContent) {\n // Check if content has CSS-block children that would be treated as block\n // by formatBlockChildren. Nodes in text flow (e.g. mustache sections\n // adjacent to text) are inline regardless of their content.\n const hasBlockChildren = contentNodes.some((child, i) => {\n if (!shouldTreatAsBlock(child, i, contentNodes, tags)) {\n return false;\n }\n const childDisplay = getCSSDisplay(child, tags);\n return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);\n });\n\n if (isBlock && !hasBlockChildren) {\n // Block element with only inline content: wrap in group so short ones stay flat\n // e.g. <div>x</div> stays on one line, <div>long content...</div> breaks\n const hasAttrs = startTag && startTagHasAttributes(startTag);\n\n if (hasAttrs && startTag) {\n // Outer group wrapping: match Prettier's printTag pattern\n // group([group(openTag), indent([softline, content]), softline, closingTag])\n const bareStartTag = formatStartTag(startTag, context, true);\n const outerParts: Doc[] = [\n group(bareStartTag),\n indent(concat([softline, formattedContent])),\n ];\n if (hasRealEndTag) {\n outerParts.push(softline);\n }\n if (endTag) {\n outerParts.push(formatEndTag(endTag));\n }\n return group(concat(outerParts));\n }\n\n // No attributes \u2014 existing logic\n const doc = group(\n concat([\n indent(concat([softline, formattedContent])),\n softline,\n ])\n );\n parts.push(doc);\n // If no real end tag, don't add closing softline\n if (!hasRealEndTag && endTag) {\n // Remove the trailing softline we just added \u2014 content goes\n // right up to forced end\n parts.pop();\n parts.push(\n group(\n concat([\n indent(concat([softline, formattedContent])),\n ])\n )\n );\n }\n } else {\n // Has block children: always break\n parts.push(indent(concat([hardline, formattedContent])));\n if (hasRealEndTag) {\n parts.push(hardline);\n }\n }\n } else if (contentNodes.length === 0 && hasRealEndTag) {\n // Empty block element: <div>\\n</div>\n parts.push(hardline);\n }\n }\n\n // Format end tag\n if (endTag) {\n parts.push(formatEndTag(endTag));\n }\n\n return concat(parts);\n}\n\n/**\n * Format script or style element.\n * Uses pre-formatted content from embeddedFormatted map when available,\n * otherwise preserves raw content as-is.\n */\nexport function formatScriptStyleElement(\n node: SyntaxNode,\n context: FormatterContext\n): Doc {\n const parts: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_start_tag') {\n parts.push(formatStartTag(child, context));\n } else if (child.type === 'html_end_tag') {\n parts.push(formatEndTag(child));\n } else if (child.type === 'html_raw_text') {\n const formatted = context.embeddedFormatted?.get(child.startIndex);\n if (formatted !== undefined) {\n const trimmed = formatted.replace(/^\\n+/, '').replace(/\\n+$/, '');\n if (trimmed.length === 0) {\n // Empty content \u2014 no lines between tags\n } else {\n const lines = trimmed.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < lines.length; j++) {\n if (j > 0) {\n lineDocs.push(hardline);\n }\n lineDocs.push(text(lines[j]));\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else {\n // Fallback: preserve raw content as-is (also used for html_raw_element)\n // Check if this is a custom code tag that should be indented\n if (node.type === 'html_raw_element') {\n const startTagNode = node.child(0);\n const tagNameLower = startTagNode?.type === 'html_start_tag' ? getTagNameFromStartTag(startTagNode) : null;\n const tagConfig = tagNameLower ? context.customTags?.get(tagNameLower) : undefined;\n if (tagConfig && resolveIndentMode(node, tagConfig)) {\n const dedented = dedentContent(child.text);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n } else {\n parts.push(text(child.text));\n }\n } else {\n // Script/style fallback: dedent and re-emit with hardlines so the\n // printer can apply proper indentation from parent context.\n const dedented = dedentContent(child.text);\n if (dedented.length > 0) {\n const contentLines = dedented.split('\\n');\n const lineDocs: Doc[] = [];\n for (let j = 0; j < contentLines.length; j++) {\n if (j > 0) {\n if (contentLines[j] === '') {\n lineDocs.push('\\n');\n } else {\n lineDocs.push(hardline);\n }\n }\n if (contentLines[j] !== '') {\n lineDocs.push(text(contentLines[j]));\n }\n }\n parts.push(indent(concat([hardline, ...lineDocs])));\n parts.push(hardline);\n }\n }\n }\n }\n }\n\n return concat(parts);\n}\n\n/**\n * Format a mustache section ({{#...}} or {{^...}}).\n */\nexport function formatMustacheSection(\n node: SyntaxNode,\n context: FormatterContext\n): Doc {\n const isInverted = node.type === 'mustache_inverted_section';\n const beginType = isInverted\n ? 'mustache_inverted_section_begin'\n : 'mustache_section_begin';\n const endType = isInverted\n ? 'mustache_inverted_section_end'\n : 'mustache_section_end';\n\n let beginNode: SyntaxNode | null = null;\n let endNode: SyntaxNode | null = null;\n const contentNodes: SyntaxNode[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === beginType) {\n beginNode = child;\n } else if (\n child.type === endType ||\n child.type === 'mustache_erroneous_section_end' ||\n child.type === 'mustache_erroneous_inverted_section_end'\n ) {\n endNode = child;\n } else if (!child.type.startsWith('_')) {\n contentNodes.push(child);\n }\n }\n\n const parts: Doc[] = [];\n\n // Opening tag\n if (beginNode) {\n parts.push(text(mustacheText(beginNode.text, context)));\n }\n\n // Determine indentation: if content has implicit end tags (HTML crossing mustache\n // boundaries), don't indent. Otherwise, indent normally.\n const hasImplicit = hasImplicitEndTags(contentNodes);\n\n // Staircase indentation: when content includes erroneous end tags (closing tags\n // from a cross-section split). Each erroneous end tag gets a descending indent\n // level so the outermost closing tag aligns at indent 0 (matching its opening).\n // Non-erroneous content between erroneous end tags is indented one level deeper\n // than the surrounding erroneous tags (it's a child of that scope).\n const erroneousCount = contentNodes.filter(n => n.type === 'html_erroneous_end_tag').length;\n const hasStaircase = !hasImplicit && erroneousCount > 0;\n\n if (hasStaircase) {\n let virtualDepth = erroneousCount - 1;\n const groupNodes: SyntaxNode[] = [];\n let lastNodeEnd = -1;\n let pendingBlankLine = false;\n let groupBlankLine = false;\n\n const emitGroup = () => {\n if (groupNodes.length === 0) return;\n const formatted = formatBlockChildren(groupNodes, context);\n if (hasDocContent(formatted)) {\n if (groupBlankLine) parts.push('\\n');\n const depth = Math.max(0, virtualDepth + 1);\n parts.push(depth > 0\n ? indentN(concat([hardline, formatted]), depth)\n : concat([hardline, formatted]));\n }\n groupNodes.length = 0;\n groupBlankLine = false;\n };\n\n for (const node of contentNodes) {\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n if ((gap.match(/\\n/g) || []).length >= 2) {\n pendingBlankLine = true;\n }\n }\n\n if (node.type === 'html_erroneous_end_tag') {\n emitGroup();\n if (pendingBlankLine) parts.push('\\n');\n pendingBlankLine = false;\n const formatted = formatNode(node, context);\n const depth = Math.max(0, virtualDepth);\n parts.push(depth > 0\n ? indentN(concat([hardline, formatted]), depth)\n : concat([hardline, formatted]));\n virtualDepth--;\n } else {\n if (groupNodes.length === 0) {\n groupBlankLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n groupNodes.push(node);\n }\n lastNodeEnd = node.endIndex;\n }\n emitGroup();\n parts.push(hardline);\n } else {\n const formattedContent = formatBlockChildren(contentNodes, context);\n const hasContent = hasDocContent(formattedContent);\n\n if (hasContent) {\n if (hasImplicit) {\n // No indent for content with implicit end tags\n parts.push(hardline);\n parts.push(formattedContent);\n parts.push(hardline);\n } else {\n // Check if content has CSS-block children (accounting for text flow)\n const hasBlockChildren = contentNodes.some((child, i) => {\n if (!shouldTreatAsBlock(child, i, contentNodes, context.customTags)) {\n return false;\n }\n const childDisplay = getCSSDisplay(child, context.customTags);\n return isWhitespaceInsensitive(childDisplay) || isRawContentElement(child);\n });\n\n if (!hasBlockChildren) {\n // Inline content only: use group so short sections stay flat\n parts.push(indent(concat([softline, formattedContent])));\n parts.push(softline);\n } else {\n // Block content: always break\n parts.push(indent(concat([hardline, formattedContent])));\n parts.push(hardline);\n }\n }\n }\n }\n\n // Closing tag\n if (endNode) {\n parts.push(text(mustacheText(endNode.text, context)));\n }\n\n // Wrap in group so inline-only content can stay flat\n return group(concat(parts));\n}\n\n/**\n * Check if a start tag has any attributes.\n */\nfunction startTagHasAttributes(startTag: SyntaxNode): boolean {\n for (let i = 0; i < startTag.childCount; i++) {\n const child = startTag.child(i);\n if (!child) continue;\n if (\n child.type === 'html_attribute' ||\n child.type === 'mustache_attribute' ||\n child.type === 'mustache_interpolation' ||\n child.type === 'mustache_triple'\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Format a start tag with attributes.\n * Wraps in a group so attributes break onto separate lines when\n * the tag exceeds print width.\n * When `bare` is true, returns the tag IR without the outer group wrapper.\n */\nexport function formatStartTag(node: SyntaxNode, context?: FormatterContext, bare = false): Doc {\n let tagNameText = '';\n const attrs: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_tag_name') {\n tagNameText = child.text;\n } else if (child.type === 'html_attribute') {\n attrs.push(formatAttribute(child, context));\n } else if (child.type === 'mustache_attribute') {\n if (context?.mustacheSpaces !== undefined) {\n attrs.push(text(normalizeMustacheWhitespaceAll(child.text, context.mustacheSpaces)));\n } else {\n attrs.push(text(child.text));\n }\n } else if (child.type === 'mustache_interpolation' || child.type === 'mustache_triple') {\n attrs.push(text(context ? mustacheText(child.text, context) : child.text));\n }\n }\n\n const isSelfClosing = node.type === 'html_self_closing_tag';\n const closingBracket = isSelfClosing ? ' />' : '>';\n\n if (attrs.length === 0) {\n return text('<' + tagNameText + closingBracket);\n }\n\n // Build attribute list with line separators\n const attrParts: Doc[] = [];\n for (let i = 0; i < attrs.length; i++) {\n if (i > 0) {\n attrParts.push(line);\n }\n attrParts.push(attrs[i]);\n }\n\n // In break mode, self-closing /> has no leading space (aligns with <tagName)\n const breakClosingBracket = isSelfClosing ? '/>' : '>';\n\n // Wrap tag in group: flat puts attrs on one line, break wraps them\n const inner = concat([\n text('<'),\n text(tagNameText),\n indent(concat([line, concat(attrParts)])),\n ifBreak(concat([hardline, text(breakClosingBracket)]), text(closingBracket)),\n ]);\n return bare ? inner : group(inner);\n}\n\n/**\n * Format an end tag.\n */\nexport function formatEndTag(node: SyntaxNode): Doc {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child && child.type === 'html_tag_name') {\n return text('</' + child.text + '>');\n }\n }\n return text(node.text);\n}\n\n/**\n * Format an HTML attribute.\n */\nexport function formatAttribute(node: SyntaxNode, context?: FormatterContext): Doc {\n const parts: Doc[] = [];\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (!child) continue;\n\n if (child.type === 'html_attribute_name') {\n parts.push(text(child.text));\n } else if (child.type === 'html_attribute_value') {\n parts.push(text('='));\n parts.push(text(child.text));\n } else if (child.type === 'html_quoted_attribute_value') {\n parts.push(text('='));\n if (context?.mustacheSpaces !== undefined) {\n parts.push(text(normalizeMustacheWhitespaceAll(child.text, context.mustacheSpaces)));\n } else {\n parts.push(text(child.text));\n }\n } else if (child.type === 'mustache_interpolation') {\n parts.push(text('='));\n parts.push(text(context ? mustacheText(child.text, context) : child.text));\n }\n }\n\n return concat(parts);\n}\n\n/**\n * Split a single-line text string into alternating words and `line` separators.\n * Returns an array of fill-ready parts to spread into `currentLine`.\n */\nfunction textWords(str: string): Doc[] {\n const words = str.split(/\\s+/).filter((w) => w.length > 0);\n if (words.length === 0) return [];\n const parts: Doc[] = [words[0]];\n for (let i = 1; i < words.length; i++) {\n parts.push(line);\n parts.push(words[i]);\n }\n return parts;\n}\n\n/**\n * Replace `line` separators with `\" \"` inside delimited regions so the\n * fill algorithm treats delimited content as unbreakable.\n *\n * Scans string parts for delimiter boundaries. Between an opening and closing\n * delimiter, any `line` separator is replaced with a literal space string.\n * Delimiters are matched longest-first to handle e.g. `$$` before `$`.\n */\nexport function collapseDelimitedRegions(parts: Doc[], delimiters: NoBreakDelimiter[]): Doc[] {\n if (delimiters.length === 0) return parts;\n\n // Sort longest-first by max(start.length, end.length) so $$ is checked before $\n const sorted = [...delimiters].sort(\n (a, b) => Math.max(b.start.length, b.end.length) - Math.max(a.start.length, a.end.length)\n );\n\n const result = [...parts];\n let activeDelimiter: NoBreakDelimiter | null = null;\n\n for (let i = 0; i < result.length; i++) {\n const part = result[i];\n\n if (typeof part === 'string') {\n if (activeDelimiter === null) {\n // Look for an opening delimiter\n for (const delim of sorted) {\n const startIdx = part.indexOf(delim.start);\n if (startIdx >= 0) {\n // Check if it also closes in the same string\n const afterOpen = startIdx + delim.start.length;\n const closeIdx = part.indexOf(delim.end, afterOpen);\n if (closeIdx >= 0) {\n // Self-contained (e.g. \"$x$\") \u2014 no state change, already atomic\n continue;\n }\n activeDelimiter = delim;\n break;\n }\n }\n } else {\n // Look for the closing delimiter\n if (part.includes(activeDelimiter.end)) {\n activeDelimiter = null;\n }\n }\n } else if (activeDelimiter !== null && isLine(part)) {\n // Inside a delimited region: replace line with non-breaking space\n result[i] = ' ';\n }\n }\n\n return result;\n}\n\n/**\n * Convert inline content parts into a fill Doc that wraps at word boundaries.\n *\n * `currentLine` is already fill-ready: text nodes are pre-split into\n * alternating word/`line` parts by `textWords`, and inter-node gaps are\n * `line` separators. This function enforces proper alternating\n * content/separator structure, concatenates adjacent content, and attaches\n * leading punctuation to the preceding content.\n */\nfunction inlineContentToFill(parts: Doc[]): Doc {\n if (parts.length === 0) return empty;\n if (parts.length === 1) return parts[0];\n\n const fillParts: Doc[] = [];\n for (const item of parts) {\n if (isLine(item)) {\n // Only push separator after content (skip leading/duplicate separators)\n if (fillParts.length > 0 && !isLine(fillParts[fillParts.length - 1])) {\n fillParts.push(item);\n }\n } else {\n const lastIdx = fillParts.length - 1;\n if (lastIdx >= 0 && !isLine(fillParts[lastIdx])) {\n // Adjacent content (no separator) \u2014 concat with previous\n fillParts[lastIdx] = concat([fillParts[lastIdx], item]);\n } else if (\n typeof item === 'string' &&\n /^[,.:;!?)\\]]/.test(item) &&\n lastIdx >= 0 &&\n isLine(fillParts[lastIdx])\n ) {\n // Punctuation after separator \u2014 attach to preceding content\n fillParts.pop();\n if (fillParts.length > 0) {\n fillParts[fillParts.length - 1] = concat([\n fillParts[fillParts.length - 1],\n item,\n ]);\n } else {\n fillParts.push(item);\n }\n } else {\n fillParts.push(item);\n }\n }\n }\n\n // Remove trailing separator\n if (fillParts.length > 0 && isLine(fillParts[fillParts.length - 1])) {\n fillParts.pop();\n }\n\n return fill(fillParts);\n}\n\n/**\n * Format block-level children with display-aware separators.\n */\nexport function formatBlockChildren(\n nodes: SyntaxNode[],\n context: FormatterContext\n): Doc {\n const lines: { doc: Doc; blankLineBefore: boolean; rawLine?: boolean }[] = [];\n let currentLine: Doc[] = [];\n let lastNodeEnd = -1;\n let pendingBlankLine = false;\n let blankLineBeforeCurrentLine = false;\n let ignoreNext = false;\n let inIgnoreRegion = false;\n let ignoreRegionStartIndex = -1;\n\n const noBreakDelims = context.noBreakDelimiters;\n function flushCurrentLine(): Doc {\n const parts = noBreakDelims ? collapseDelimitedRegions(currentLine, noBreakDelims) : currentLine;\n return inlineContentToFill(parts);\n }\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n // Detect blank lines in gap between nodes (before directive handling)\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd && !inIgnoreRegion) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n const newlineCount = (gap.match(/\\n/g) || []).length;\n if (newlineCount >= 2) {\n pendingBlankLine = true;\n }\n }\n\n const directive = getIgnoreDirective(node);\n\n // --- Ignore directive handling ---\n\n // ignore-end: close a region\n if (directive === 'ignore-end' && inIgnoreRegion) {\n // Flush any pending inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n // Emit raw text from region start to this comment, trimming boundary newlines\n const rawText = context.document.getText().slice(ignoreRegionStartIndex, node.startIndex)\n .replace(/^\\n/, '').replace(/\\n$/, '');\n if (rawText.length > 0) {\n lines.push({ doc: text(rawText), blankLineBefore: false, rawLine: true });\n }\n // Emit the ignore-end comment itself (rawLine to avoid adding indent after raw text)\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: false, rawLine: true });\n inIgnoreRegion = false;\n ignoreRegionStartIndex = -1;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // Inside ignore region: skip (content captured as raw text at ignore-end)\n if (inIgnoreRegion) {\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore-start: begin a region\n if (directive === 'ignore-start') {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n inIgnoreRegion = true;\n ignoreRegionStartIndex = node.endIndex;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore (next-node): emit the comment, set flag\n if (directive === 'ignore') {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n ignoreNext = true;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // Ignored next-node: emit raw text, clear flag\n if (ignoreNext) {\n lines.push({ doc: text(node.text), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n ignoreNext = false;\n lastNodeEnd = node.endIndex;\n continue;\n }\n\n // ignore-end without ignore-start: treat as normal comment (fall through)\n\n const treatAsBlock = shouldTreatAsBlock(node, i, nodes, context.customTags);\n\n // Check for whitespace between nodes in original document (inline gap handling)\n if (lastNodeEnd >= 0 && node.startIndex > lastNodeEnd) {\n const prevNode = nodes[i - 1];\n const prevTreatAsBlock = shouldTreatAsBlock(prevNode, i - 1, nodes, context.customTags);\n\n if (!prevTreatAsBlock && !treatAsBlock) {\n const gap = context.document.getText().slice(lastNodeEnd, node.startIndex);\n if (/\\s/.test(gap)) {\n currentLine.push(line);\n }\n }\n }\n\n if (treatAsBlock) {\n // Flush current inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n // Add block element\n lines.push({ doc: formatNode(node, context), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n } else if (node.type === 'html_comment' || node.type === 'mustache_comment') {\n // Comments on their own line if multi-line or on their own line in source\n const isMultiline = node.startPosition.row !== node.endPosition.row;\n const isOnOwnLine = i > 0 && node.startPosition.row > nodes[i - 1].endPosition.row;\n if (isMultiline || isOnOwnLine) {\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n currentLine = [];\n blankLineBeforeCurrentLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n lines.push({ doc: text(commentText), blankLineBefore: pendingBlankLine });\n pendingBlankLine = false;\n } else {\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n const commentText = node.type === 'mustache_comment' ? mustacheText(node.text, context) : node.text;\n currentLine.push(text(commentText));\n }\n } else {\n // Inline content\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n const forceInline = isInTextFlow(node, i, nodes);\n const formatted = formatNode(node, context, forceInline);\n\n // Check if formatted content contains newlines (multi-line text)\n if (typeof formatted === 'string' && formatted.includes('\\n')) {\n const contentLines = formatted.split('\\n');\n const isTextNode = node.type === 'text';\n\n if (isTextNode) {\n // Re-flow: treat source newlines as word boundaries, only flush at\n // blank lines. This lets the fill algorithm handle all wrapping.\n for (let j = 0; j < contentLines.length; j++) {\n const trimmed = contentLines[j].trim();\n if (!trimmed) {\n // Empty line = paragraph break \u2014 flush current inline flow\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = false;\n }\n currentLine = [];\n }\n pendingBlankLine = true;\n } else {\n if (currentLine.length === 0) {\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n // Add a line separator between joined source lines (j > 0),\n // but not before the first line \u2014 it continues the existing flow\n if (j > 0 && currentLine.length > 0) {\n currentLine.push(line);\n }\n currentLine.push(...textWords(trimmed));\n }\n }\n } else {\n // Non-text nodes (force-inline mustache sections, etc.):\n // preserve source newlines as hard line breaks.\n const firstTrimmed = contentLines[0].trim();\n if (firstTrimmed) {\n currentLine.push(firstTrimmed);\n }\n\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = pendingBlankLine;\n pendingBlankLine = false;\n }\n currentLine = [];\n }\n\n let sawBlankLine = false;\n for (let j = 1; j < contentLines.length - 1; j++) {\n const trimmed = contentLines[j].trim();\n if (trimmed) {\n lines.push({ doc: text(trimmed), blankLineBefore: blankLineBeforeCurrentLine || sawBlankLine });\n blankLineBeforeCurrentLine = false;\n sawBlankLine = false;\n } else {\n sawBlankLine = true;\n }\n }\n\n if (contentLines.length > 1) {\n const lastTrimmed = contentLines[contentLines.length - 1].trim();\n if (lastTrimmed) {\n blankLineBeforeCurrentLine = sawBlankLine;\n sawBlankLine = false;\n currentLine = [lastTrimmed];\n }\n if (sawBlankLine) {\n pendingBlankLine = true;\n }\n }\n }\n } else {\n // For text nodes, spread word/line parts directly into currentLine\n if (node.type === 'text' && typeof formatted === 'string') {\n const words = textWords(formatted);\n if (words.length > 0) {\n currentLine.push(...words);\n } else if (node.text.trim() === '' && currentLine.length > 0) {\n // Whitespace-only text between inline content: preserve as line separator\n currentLine.push(line);\n }\n } else {\n currentLine.push(formatted);\n }\n }\n }\n\n // Force line break after <br> tags\n if (node.type === 'html_element' && currentLine.length > 0) {\n const tagName = getTagName(node);\n if (tagName?.toLowerCase() === 'br') {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n blankLineBeforeCurrentLine = false;\n }\n currentLine = [];\n }\n }\n\n lastNodeEnd = node.endIndex;\n }\n\n // Handle unterminated ignore region: emit remaining raw text\n if (inIgnoreRegion && nodes.length > 0) {\n const lastNode = nodes[nodes.length - 1];\n const rawText = context.document.getText().slice(ignoreRegionStartIndex, lastNode.endIndex)\n .replace(/^\\n/, '');\n if (rawText.length > 0) {\n lines.push({ doc: text(rawText), blankLineBefore: false, rawLine: true });\n }\n }\n\n // Flush remaining inline content\n if (currentLine.length > 0) {\n const lineContent = trimDoc(flushCurrentLine());\n if (hasDocContent(lineContent)) {\n lines.push({ doc: lineContent, blankLineBefore: blankLineBeforeCurrentLine });\n }\n }\n\n // Join lines with hardlines\n if (lines.length === 0) {\n return empty;\n }\n\n const parts: Doc[] = [];\n for (let i = 0; i < lines.length; i++) {\n if (i > 0) {\n if (lines[i].blankLineBefore) {\n // Emit a blank line: literal \\n (no indent) + hardline (with indent)\n parts.push('\\n');\n }\n if (lines[i].rawLine) {\n // Raw lines (ignored regions): literal \\n to avoid adding indentation\n parts.push('\\n');\n } else {\n parts.push(hardline);\n }\n }\n parts.push(lines[i].doc);\n }\n\n return concat(parts);\n}\n\n/**\n * Check if a Doc has any meaningful content.\n */\nfunction hasDocContent(doc: Doc): boolean {\n if (typeof doc === 'string') {\n return doc.trim().length > 0;\n }\n if (doc.type === 'concat') {\n return doc.parts.some(hasDocContent);\n }\n if (doc.type === 'indent') {\n return hasDocContent(doc.contents);\n }\n if (doc.type === 'group') {\n return hasDocContent(doc.contents);\n }\n if (doc.type === 'fill') {\n return doc.parts.some(hasDocContent);\n }\n if (doc.type === 'ifBreak') {\n return hasDocContent(doc.breakContents) || hasDocContent(doc.flatContents);\n }\n // hardline, softline, line, breakParent are structural\n return false;\n}\n\n/**\n * Trim whitespace from the beginning and end of a Doc string.\n */\nfunction trimDoc(doc: Doc): Doc {\n if (typeof doc === 'string') {\n return doc.trim();\n }\n return doc;\n}\n", "/**\n * Pure option merging + indent-unit construction.\n *\n * EditorConfig-aware merging lives in `lsp/server/src/formatting/editorconfig.ts`\n * and layers on top of these results by passing its result as `overrides`.\n */\n\nimport type { FormattingOptions } from './index.js';\nimport type { HtmlMustacheConfig } from '../configSchema.js';\n\n/**\n * Merge base options with `configFile` (indentSize only) and optional\n * `overrides` (tabSize / insertSpaces). Pure; no fs.\n *\n * Priority (low \u2192 high): lspOptions < configFile.indentSize < overrides.\n * `insertSpaces` never comes from `configFile` \u2014 only `lspOptions` or `overrides`.\n */\nexport function mergeOptions(\n lspOptions: FormattingOptions,\n configFile?: HtmlMustacheConfig | null,\n overrides?: Partial<FormattingOptions>,\n): FormattingOptions {\n let tabSize = lspOptions.tabSize;\n if (configFile?.indentSize !== undefined) tabSize = configFile.indentSize;\n if (overrides?.tabSize !== undefined) tabSize = overrides.tabSize;\n\n const insertSpaces = overrides?.insertSpaces ?? lspOptions.insertSpaces;\n\n return { tabSize, insertSpaces };\n}\n\nexport function createIndentUnit(options: FormattingOptions): string {\n return options.insertSpaces ? ' '.repeat(options.tabSize) : '\\t';\n}\n", "/**\n * IR-Based Formatter for HTML with Mustache templates.\n *\n * Architecture: AST Node \u2192 Doc IR \u2192 String\n *\n * Three phases:\n * 1. Classification - Determine node type (block/inline/preserve)\n * 2. AST \u2192 IR - Convert nodes to formatting commands\n * 3. IR \u2192 String - Print with proper indentation\n */\n\nimport type { Node as SyntaxNode, Tree } from 'web-tree-sitter';\nimport type { TextDocument } from 'vscode-languageserver-textdocument';\n\n/** Formatting options (structurally compatible with LSP FormattingOptions). */\nexport interface FormattingOptions {\n tabSize: number;\n insertSpaces: boolean;\n}\n\n/** A position in a text document (0-based line and character). */\nexport interface Position {\n line: number;\n character: number;\n}\n\n/** A range in a text document. */\nexport interface Range {\n start: Position;\n end: Position;\n}\n\n/** A text edit to apply to a document. */\nexport interface TextEdit {\n range: Range;\n newText: string;\n}\n\nimport { print } from './printer.js';\nimport { formatDocument as formatDocumentToDoc, FormatterContext } from './formatters.js';\nimport { createIndentUnit } from './mergeOptions.js';\nimport type { NoBreakDelimiter } from '../configSchema.js';\nimport { findContainingNode, calculateIndentLevel } from './utils.js';\nimport { isBlockLevel, getContentNodes, hasImplicitEndTags } from './classifier.js';\nimport type { CustomCodeTagConfig } from '../customCodeTags.js';\n\nexport interface FormatDocumentParams {\n customTags?: CustomCodeTagConfig[];\n printWidth?: number;\n embeddedFormatted?: Map<number, string>;\n mustacheSpaces?: boolean;\n noBreakDelimiters?: NoBreakDelimiter[];\n}\n\nfunction buildCustomTagMap(customTags?: CustomCodeTagConfig[]): Map<string, CustomCodeTagConfig> | undefined {\n if (!customTags || customTags.length === 0) return undefined;\n const map = new Map<string, CustomCodeTagConfig>();\n for (const config of customTags) {\n map.set(config.name.toLowerCase(), config);\n }\n return map;\n}\n\nexport function formatDocument(\n tree: Tree,\n document: TextDocument,\n options: FormattingOptions,\n params: FormatDocumentParams = {},\n): TextEdit[] {\n const { printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters } = params;\n const indentUnit = createIndentUnit(options);\n\n if (tree.rootNode.hasError) return [];\n\n const customTagMap = buildCustomTagMap(params.customTags);\n const context: FormatterContext = {\n document,\n customTags: customTagMap,\n embeddedFormatted,\n mustacheSpaces,\n noBreakDelimiters,\n };\n const doc = formatDocumentToDoc(tree.rootNode, context);\n const formatted = print(doc, { indentUnit, printWidth });\n\n const fullRange: Range = {\n start: { line: 0, character: 0 },\n end: document.positionAt(document.getText().length),\n };\n\n return [{ range: fullRange, newText: formatted }];\n}\n\nexport function formatDocumentRange(\n tree: Tree,\n document: TextDocument,\n range: Range,\n options: FormattingOptions,\n params: FormatDocumentParams = {},\n): TextEdit[] {\n const { customTags, printWidth = 80, embeddedFormatted, mustacheSpaces, noBreakDelimiters } = params;\n const indentUnit = createIndentUnit(options);\n\n if (tree.rootNode.hasError) return [];\n\n const customTagMap = buildCustomTagMap(customTags);\n\n const startOffset = document.offsetAt(range.start);\n const endOffset = document.offsetAt(range.end);\n\n let targetNode = findContainingNode(tree.rootNode, startOffset, endOffset) ?? tree.rootNode;\n\n // Walk up to the nearest block-level boundary so the output is anchored to a\n // whole element, not mid-inline content.\n while (\n targetNode.parent &&\n !isBlockLevel(targetNode, customTagMap) &&\n targetNode.type !== 'document'\n ) {\n targetNode = targetNode.parent;\n }\n\n const indentLevel = calculateIndentLevel(\n targetNode,\n isBlockLevel,\n hasImplicitEndTags,\n getContentNodes\n );\n\n const context: FormatterContext = {\n document,\n customTags: customTagMap,\n embeddedFormatted,\n mustacheSpaces,\n noBreakDelimiters,\n };\n const doc = formatNodeForRange(targetNode, context);\n const formatted = print(doc, { indentUnit, printWidth });\n\n const indentedFormatted = applyBaseIndent(formatted, indentLevel, indentUnit);\n\n const nodeRange: Range = {\n start: {\n line: targetNode.startPosition.row,\n character: targetNode.startPosition.column,\n },\n end: {\n line: targetNode.endPosition.row,\n character: targetNode.endPosition.column,\n },\n };\n\n return [{ range: nodeRange, newText: indentedFormatted }];\n}\n\nimport { formatNode } from './formatters.js';\n\nfunction formatNodeForRange(\n node: SyntaxNode,\n context: FormatterContext\n): import('./ir.js').Doc {\n return formatNode(node, context);\n}\n\nfunction applyBaseIndent(\n formatted: string,\n indentLevel: number,\n indentUnit: string\n): string {\n if (indentLevel === 0) {\n return formatted;\n }\n\n const baseIndent = indentUnit.repeat(indentLevel);\n return formatted\n .split('\\n')\n .map((line, index) => {\n // Don't indent empty lines or the first line (it's at the node position)\n if (line.trim() === '' || index === 0) {\n return line;\n }\n return baseIndent + line;\n })\n .join('\\n');\n}\n", "import type { Node as SyntaxNode } from 'web-tree-sitter';\n\nexport interface EmbeddedRegion {\n startIndex: number;\n content: string;\n languageId: string;\n}\n\n/**\n * Get the language ID for a script or style element.\n * Returns \"javascript\" for script (or \"typescript\" if type=\"text/typescript\"),\n * \"css\" for style.\n */\nfunction getEmbeddedLanguageId(node: SyntaxNode): string {\n if (node.type === 'html_style_element') {\n return 'css';\n }\n // Check for type attribute on script elements\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_start_tag') {\n for (let j = 0; j < child.childCount; j++) {\n const attr = child.child(j);\n if (attr?.type === 'html_attribute') {\n let name = '';\n let value = '';\n for (let k = 0; k < attr.childCount; k++) {\n const part = attr.child(k);\n if (part?.type === 'html_attribute_name') name = part.text.toLowerCase();\n if (part?.type === 'html_quoted_attribute_value') value = part.text.replace(/^[\"']|[\"']$/g, '').toLowerCase();\n if (part?.type === 'html_attribute_value') value = part.text.toLowerCase();\n }\n if (name === 'type' && (value === 'text/typescript' || value === 'ts')) {\n return 'typescript';\n }\n }\n }\n }\n }\n return 'javascript';\n}\n\n/**\n * Walk the tree to collect embedded script/style regions.\n * Skips html_raw_element (custom raw tags).\n */\nexport function collectEmbeddedRegions(rootNode: SyntaxNode): EmbeddedRegion[] {\n const regions: EmbeddedRegion[] = [];\n const walk = (node: SyntaxNode) => {\n if (node.type === 'html_script_element' || node.type === 'html_style_element') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child?.type === 'html_raw_text') {\n regions.push({\n startIndex: child.startIndex,\n content: child.text,\n languageId: getEmbeddedLanguageId(node),\n });\n }\n }\n return;\n }\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n if (child) walk(child);\n }\n };\n walk(rootNode);\n return regions;\n}\n", "/**\n * Shared embedded-region formatter used by both the CLI and the browser entry.\n * Takes the already-parsed rootNode, extracts `<script>` / `<style>` regions,\n * and returns a map of startIndex \u2192 prettier-formatted content. If no prettier\n * is provided, returns an empty map (caller falls back to leaving regions as-is).\n */\n\nimport type { Node as SyntaxNode } from 'web-tree-sitter';\nimport { collectEmbeddedRegions } from '../embeddedRegions.js';\nimport type { FormattingOptions } from './index.js';\n\nexport const LANGUAGE_TO_PRETTIER_PARSER: Record<string, string> = {\n javascript: 'babel',\n typescript: 'typescript',\n css: 'css',\n};\n\nexport interface PrettierLike {\n format(source: string, options: {\n parser: string;\n tabWidth?: number;\n useTabs?: boolean;\n plugins?: unknown[];\n }): string | Promise<string>;\n}\n\nexport async function formatEmbeddedRegions(\n rootNode: SyntaxNode,\n options: FormattingOptions,\n prettier: PrettierLike | null | undefined,\n): Promise<Map<number, string>> {\n const result = new Map<number, string>();\n if (!prettier) return result;\n\n const regions = collectEmbeddedRegions(rootNode);\n if (regions.length === 0) return result;\n\n await Promise.all(\n regions.map(async (region) => {\n const parser = LANGUAGE_TO_PRETTIER_PARSER[region.languageId];\n if (!parser) return;\n try {\n const formatted = await prettier.format(region.content, {\n parser,\n tabWidth: options.tabSize,\n useTabs: !options.insertSpaces,\n });\n result.set(region.startIndex, formatted);\n } catch {\n // Snippet had a syntax error \u2014 skip, leave the region as-is.\n }\n })\n );\n\n return result;\n}\n", "/**\n * Shared CheckError \u2192 public `Diagnostic` projection used by the browser\n * entry and the CLI wrapper. 1-based line/column per the public contract;\n * multi-edit fix array; severity defaults to `'error'` when the source\n * checker didn't set one (parse errors, balance errors).\n */\n\nimport type { CheckError } from './collectErrors.js';\nimport type { TextReplacement } from './mustacheChecks.js';\n\nexport interface DiagnosticFix {\n range: [number, number];\n newText: string;\n}\n\nexport interface Diagnostic {\n line: number;\n column: number;\n endLine: number;\n endColumn: number;\n message: string;\n severity: 'error' | 'warning';\n ruleName?: string;\n fix?: DiagnosticFix[];\n fixDescription?: string;\n}\n\nfunction toFix(r: TextReplacement): DiagnosticFix {\n return { range: [r.startIndex, r.endIndex], newText: r.newText };\n}\n\nexport function toDiagnostic(err: CheckError): Diagnostic {\n const { node } = err;\n return {\n line: node.startPosition.row + 1,\n column: node.startPosition.column + 1,\n endLine: node.endPosition.row + 1,\n endColumn: node.endPosition.column + 1,\n message: err.message,\n severity: err.severity ?? 'error',\n ruleName: err.ruleName,\n fix: err.fix && err.fix.length > 0 ? err.fix.map(toFix) : undefined,\n fixDescription: err.fixDescription,\n };\n}\n", "/** Filename of the compiled grammar WASM, as shipped in this package. */\nexport const GRAMMAR_WASM_FILENAME = 'tree-sitter-htmlmustache.wasm';\n"],
5
+ "mappings": "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",
6
6
  "names": ["VOID_ELEMENTS", "text", "group", "text", "end", "sel", "text", "line", "node", "parts", "formatDocument", "formatDocument"]
7
7
  }